<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet href="/feed.xsl" type="text/xsl"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-au" xml:base="https://www.simonholywell.com/"><generator uri="https://gohugo.io/" version="0.125.5">Hugo</generator><title type="html">Home · Simon Holywell on Simon Holywell</title><subtitle type="html">A developer in Brisbane, Australia with a passion for web application development and mountain bikes.</subtitle><link href="https://www.simonholywell.com/feed.xml" rel="self" type="application/atom+xml" title="atom"/><link href="https://www.simonholywell.com/" rel="alternate" type="text/html" title="html"/><link href="https://www.simonholywell.com/feed.xsl" rel="alternate" type="application/xslt+xml" title="atomxsl"/><updated>2024-11-19T02:47:19+00:00</updated><rights>© Simon Holywell. All rights reserved.</rights><id>https://www.simonholywell.com/feed.xml</id><entry xml:base="a-note-on-code-portability"><title type="html">A note on code portability</title><link href="https://www.simonholywell.com/post/a-note-on-code-portability/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2015/07/sql-style-guide/?utm_source=atom_feed" rel="related" type="text/html" title="SQL style guide"/><link href="https://www.simonholywell.com/post/2017/03/mysql-alter-column-in-all-databases/?utm_source=atom_feed" rel="related" type="text/html" title="Alter a MySQL column in all databases"/><link href="https://www.simonholywell.com/post/2016/12/sql-style-guide-misconceptions/?utm_source=atom_feed" rel="related" type="text/html" title="SQL style guide misconceptions"/><link href="https://www.simonholywell.com/post/2016/10/install-pgmodeler-ubuntu/?utm_source=atom_feed" rel="related" type="text/html" title="Installing pgmodeler on Ubuntu"/><link href="https://www.simonholywell.com/post/2012/01/mysql-udf-install-error-function-already-exists/?utm_source=atom_feed" rel="related" type="text/html" title="Installing a MySQL UDF errors with Function already exists"/><id>https://www.simonholywell.com/post/a-note-on-code-portability/</id><author><name>Simon Holywell</name></author><published>2024-11-19T12:36:21+10:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Code portability is the practice of writing code that can be easily reused or transferred between different environments, such as databases or frameworks, with minimal changes. By prioritising portability, developers enhance code maintainability, reduce vendor lock-in, and improve their own adaptability across projects and organisations.</summary><content type="html"><![CDATA[<p>Recently, a friend let me know that the <a href="https://www.sqlstyle.guide/" title="SQL Style Guide by Simon Holywell">SQL style guide</a> I wrote was back on Hacker News.
Against my better judgement, I took a moment to read the latest comments.</p>
<p>One recurring theme stood out—a misunderstanding of code portability.
Although I’ve addressed this before in <a href="/post/2016/12/sql-style-guide-misconceptions#avoiding-vendorproprietary-functions" title="SQL Style Guide Misconceptions">SQL Style Guide Misconceptions</a>, it seems worth revisiting, as many readers still seem to struggle with the concept.</p>
<p>Many readers who have commented in the past and probably will comment in the future have a very limited vision of code portability and its benefits.</p>
<h1 id="what-is-code-portability">What is code portability?</h1>
<p>Code portability is generally refers to the ability to move code from one environment to another with minimal changes.
For example, in the context of the <a href="https://www.sqlstyle.guide/" title="SQL Style Guide by Simon Holywell">SQL style guide</a>, this might mean taking code written for MySQL and adapting it easily for PostgreSQL.</p>
<p>The same principle applies across software development: keeping your business logic decoupled from specific frameworks ensures it can be migrated to another framework with minimal effort.</p>
<p>However, this is unlikely to be something that many developers will experience in their careers.
It is rare that a project will move to a different environment once it has been established.
Where it does happen it is likely to be larger body of work and changing the SQL queries will be the least of your worries.</p>
<p>Whilst this is one aspect of portability it is not the only one.
In my opinion it is not the most compelling reason to write portable code either.</p>
<h1 id="what-is-the-real-benefit-of-code-portability">What is the real benefit of code portability?</h1>
<h2 id="reuse">Reuse</h2>
<p>One major benefit of portability is the ability to reuse code.
You can reuse code in a different project, even if it’s running in a different environment, without making any changes.
For example, a query written for a MySQL-based project could be reused in another project running PostgreSQL with minimal effort.</p>
<p>Reusing code saves time and ensures we avoid reinventing the wheel.</p>
<h2 id="you-the-developer">You, the developer</h2>
<p>A very real benefit of writing portable code that is very often overlooked is that it makes you, the developer, more portable.
If you write portable code then you are able to move between projects, companies and teams more easily.</p>
<p>Take SQL as an example: why would want to pigeonhole yourself as a MySQL developer?
Your next project might use PostgreSQL or MS SQL Server.
If you have only learnt vendor specific SQL functionality then your skills are not going to be transferable to <em>your</em> new environment.</p>
<p>Instead of learning the Laravel way of doing something, learn the PHP way of doing something.
Instead of learning the React or NestJS way of doing something, learn the JavaScript way of doing something.
Sure, use the framework to make your life easier, but do not compromise your business logic to accommodate the framework.</p>
<h2 id="maintainability-and-ease-for-others">Maintainability and ease for others</h2>
<p>Portable code is easier to maintain and understand, both for yourself and for others who might work on it in the future.
Standards-compliant, portable code ensures a wider audience of developers can quickly grasp its intent, making debugging, updating, and extending the codebase simpler.</p>
<p>Remember, you’re not just writing code for now—you’re writing it for your future self and your colleagues.</p>
<h2 id="tooling">Tooling</h2>
<p>When you are writing portable code you are writing code that is more likely to be supported by the tools you use.
This can be your editor, code linters, code formatters, other static analysis tools and dashboards.</p>
<p>In the case of SQL, this could be your desktop database client and its internal code formatting, syntax highlighting and code completion features.</p>
<h2 id="vendor-lock-in">Vendor lock-in</h2>
<p>Writing portable code reduces the risk of vendor lock-in. Relying on vendor-specific features ties your code—and your team—to that vendor.</p>
<p>While this might not seem like a concern for individual developers, it can pose significant challenges for organisations.
However, by writing portable code you are reducing the risk of this happening and you get this advantage for free.</p>
<p>That said, let’s be realistic: with many of us relying on specific cloud providers, some level of lock-in is often inevitable.</p>
<h1 id="what-if-i-cant">What if I can&rsquo;t?</h1>
<p>Sometimes it is just not possible to write portable code and you have to use vendor specific functionality.
This is fine and completely unavoidable.
Do it. There is no need to self-flagellate.</p>
<p>Seriously, just move on and implement the feature.</p>
<h1 id="conclusion">Conclusion</h1>
<p>If you have the option to write portable code, you should. Choosing to write vendor-specific code unnecessarily forfeits the benefits I have outlined above.
Most commenters appear to be blind to this and I hope that this article has helped to explain why I think it is important.</p>
<p>Ultimately, I am some bloke on the internet and you can choose to ignore me.
The results of your choices will be yours to live with.
I would urge you to think of others that will come after you though and make their lives easier by writing portable code where you can.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="sql" label="sql"/><category scheme="taxonomy:Tags" term="mysql" label="mysql"/><category scheme="taxonomy:Tags" term="sql-style-guide" label="sql style guide"/><category scheme="taxonomy:Tags" term="style-guide" label="style guide"/><category scheme="taxonomy:Tags" term="portability" label="portability"/></entry><entry xml:base="bikeyoke-revive-alternative-oils"><title type="html">BikeYoke Revive dropper post alternative oils</title><link href="https://www.simonholywell.com/post/bikeyoke-revive-alternative-oils/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/focus-jam-frame-bearing-replacement/?utm_source=atom_feed" rel="related" type="text/html" title="Focus Jam frame bearing replacement"/><link href="https://www.simonholywell.com/post/2011/10/marco-simoncelli/?utm_source=atom_feed" rel="related" type="text/html" title="The world has lost an excellent and exciting rider in Marco Simoncelli"/><link href="https://www.simonholywell.com/post/2011/04/prince-william-a-squid/?utm_source=atom_feed" rel="related" type="text/html" title="Whilst the wedding is a great event for the participants, I am n…"/><link href="https://www.simonholywell.com/post/2011/01/fulloctane-introduction/?utm_source=atom_feed" rel="related" type="text/html" title="FullOctane: Bike and Car Blog"/><link href="https://www.simonholywell.com/post/2010/06/adenauer-forst-70s-crash-compilation/?utm_source=atom_feed" rel="related" type="text/html" title="sharonov: 1970 Adenauer Forst crashes"/><id>https://www.simonholywell.com/post/bikeyoke-revive-alternative-oils/</id><author><name>Simon Holywell</name></author><published>2024-10-15T11:00:53+10:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>The BikeYoke Revive dropper post is a great piece of kit, but it can be hard to find the correct oil for servicing it. I have found some alternatives that work well and are easier to source.</summary><content type="html"><![CDATA[<p>The oil used in the BikeYoke Revive dropper post is a custom blend of oil and an additive that is designed to work in varied temperature conditions and provide both a smooth and consistent action.
It is a key component of the dropper post system and should be replaced during a full service that is usually only required if the post is not working as expected or if you accidentally spill some — as I did.
The oil can ber purchased directly from BikeYoke, but if you need oil in a hurry or you&rsquo;re wondering if some suspension oil you already have will work, then read on.</p>
<h1 id="bikeyoke-revive-cartridge-service">BikeYoke Revive cartridge service</h1>
<p>The BikeYoke Revive has a user serviceable cartridge system that allows you to replace the oil in the dropper post without having to send it back to the manufacturer.
This is a great feature because it means you can keep your dropper post running smoothly without having to wait for a service or pay for one.
The cartridge system is a simple design that allows you to remove the cartridge from the post, drain the oil, refill it and then reinsert it into the post.</p>
<p>I am not going to go into the details of how to service the cartridge in this post, but I will say that it is a simple process that only requires a few tools and some oil.
You can follow along with the BikeYoke published <a href="https://www.youtube.com/watch?v=YP3oPvRRomQ">instructional video</a> on how to service the cartridge.</p>
<h1 id="bikeyoke-revive-oil">BikeYoke Revive oil</h1>
<p>There are two recommended oils for the BikeYoke Revive dropper post:</p>
<ul>
<li>BikeYoke <a href="https://bikeyoke.com/en/sanguine-dropper-fluid-250ml/sang250" title="Sanguine dropper fluid - 250ml">Sanguine dropper fluid</a> - 250ml</li>
<li>96% <a href="https://www.mobil.com/en/lubricants/for-businesses/industrial/lubricants/products/products/mobil-dte-10-excel-15" title="Mobil DTE 10 Excel 15">Mobil DTE 10 Excel 15</a> with 4% <a href="https://www.rspbikecare.com/shop-english/suspension/">r.s.p No Stick Slip</a> additive</li>
</ul>
<p>The Sanguine dropper fluid is the oil that BikeYoke sells directly and is the recommended oil for the dropper post.
It is also very reasonably priced so if there is stock and you can wait a few days then I would recommend buying it from your local BikeYoke distributor.</p>
<p>From what I can glean Sanguine is actually a pre-mixed version of the Mobil DTE 10 Excel 15 with the r.s.p No Stick Slip additive.
This makes sense because the only way to buy the Mobil DTE 10 Excel 15 is in 20L drums, which is a lot of oil for a single dropper post service.</p>
<p>Speaking of which the Sanguine dropper fluid is sold in a 250ml bottle which is enough for a few services given the small oil capacities of the dropper post.</p>
<h1 id="oil-capacities">Oil capacities</h1>
<p>The BikeYoke Revive dropper post comes in a few different lengths and each length has a different oil capacity.</p>
<table>
<thead>
<tr>
<th>Post length</th>
<th>Oil capacity</th>
<th>Tolerance</th>
</tr>
</thead>
<tbody>
<tr>
<td>125mm</td>
<td>30ml</td>
<td>+/- 2ml</td>
</tr>
<tr>
<td>160mm</td>
<td>41.5ml</td>
<td>+/- 2ml</td>
</tr>
<tr>
<td>185mm</td>
<td>46ml</td>
<td>+/- 2ml</td>
</tr>
<tr>
<td>213mm</td>
<td>60ml</td>
<td>+/- 2ml</td>
</tr>
</tbody>
</table>
<p>So as you can see the oil capacities are not large so you&rsquo;ll get a few services out of a 250ml bottle of the Sanguine dropper fluid, or any other oil you choose to use.</p>
<h1 id="selecting-an-alternative-oil">Selecting an alternative oil</h1>
<p>Whilst BikeYoke are quite clear about the oil they recommend for the dropper post they do note that the best performance will be achieved with the Sanguine dropper fluid.
That said from forum posts by Sacki of BikeYoke they have been discussing the use of alternative oils from the beginning and have tested a few.</p>
<p>Early discussions on the forums reference a specification of 15cSt at 40°C for the oil, but recent technical documents from BikeYoke mention that Sanguine is a 16cSt oil at 40°C.
Something within a reasonable range of this should work well in the dropper post.</p>
<p>Do note that we&rsquo;re talking about cSt here and not the weight of the oil, which does not directly correlate to the viscosity of the oil.
Also, this can be noted with the mm²/s unit that is sometimes used to denote the viscosity of oil, but is the same as cSt.
You want a suspension oil that is as close as possible to 16cSt or 16mm²/s at 40°C.</p>
<p>Note that this value is taken from the <a href="https://bikeyoke.com/media/38/bf/74/1701269042/Oil_Lubricants_2022.pdf" title="Oil and pressure specifications for BikeYoke products">oil and pressure specifications for BikeYoke products</a> document.</p>
<h1 id="alternative-oils">Alternative oils</h1>
<p>I have found a few alternative oils that are close to the 16cSt at 40°C specification of the Sanguine dropper fluid.
These oils may be easier to find as they&rsquo;re more commonly used in motorbikes.</p>
<table>
<thead>
<tr>
<th>Oil</th>
<th>Viscosity at 40°C</th>
</tr>
</thead>
<tbody>
<tr>
<td>IPONE Fork Fluid 3</td>
<td>15.5cSt</td>
</tr>
<tr>
<td>Maxima fork oil 5wt</td>
<td>16.2cSt</td>
</tr>
<tr>
<td>Motorex Racing Fork Oil 4W</td>
<td>16.0cSt</td>
</tr>
<tr>
<td>Motul shock oil factory line</td>
<td>16.3cSt</td>
</tr>
<tr>
<td>Motul factory line fork oil 2.5W</td>
<td>15cSt</td>
</tr>
<tr>
<td>Showa SS-05</td>
<td>15.1cSt</td>
</tr>
<tr>
<td>Suzuki L01</td>
<td>15.5cSt</td>
</tr>
</tbody>
</table>
<p>You are sure to find more oils that are close to the 16cSt at 40°C specification of the Sanguine dropper fluid, but these are the ones that I have found.
I managed to find the Motul factory line fork oil 2.5W at a local motorbike shop, and it has worked well in my dropper post - I have not noticed any difference in the action of the post.</p>
<h1 id="refilling-the-oil">Refilling the oil</h1>
<p>The easiest way to measure and refill the oil in the dropper post is to use a syringe.
I got a syringe from my local chemist and whilst it was only 5ml in capacity with a few syringe refills I was able to measure out the correct amount of oil for my dropper post.</p>
<h1 id="pressurising-the-post">Pressurising the post</h1>
<p>Once you&rsquo;ve changed the oil you will need to repressurise the post with air and a shock pump.</p>
<table>
<thead>
<tr>
<th>Minimum pressure</th>
<th>Standard pressure</th>
<th>Maximum pressure</th>
</tr>
</thead>
<tbody>
<tr>
<td>200psi</td>
<td>250psi</td>
<td>300psi</td>
</tr>
</tbody>
</table>
<p>The post is designed to work with a pressure of 250psi, but you can run it at a lower pressure if you want a softer/slower return or a higher pressure if you want a firmer/faster return to maximum height.</p>
<h1 id="conclusion">Conclusion</h1>
<p>The BikeYoke Revive dropper post is a great post that is easy to service and maintain.
The oil capacities are small so you&rsquo;ll get a few services out of a 250ml bottle of the Sanguine dropper fluid or any other oil you choose to use.
My post has been running well with an alternative oil and I have not noticed any difference in the action of the post.
I do not ride in freezing weather though so if you do then you may want to stick with the Sanguine dropper fluid or performance maybe be affected.</p>
]]></content><category scheme="taxonomy:Categories" term="bikes" label="Bikes"/><category scheme="taxonomy:Tags" term="bikeyoke" label="bikeyoke"/><category scheme="taxonomy:Tags" term="revive" label="revive"/><category scheme="taxonomy:Tags" term="bikes" label="bikes"/><category scheme="taxonomy:Tags" term="maintenance" label="maintenance"/></entry><entry xml:base="focus-jam-frame-bearing-replacement"><title type="html">Focus Jam frame bearing replacement</title><link href="https://www.simonholywell.com/post/focus-jam-frame-bearing-replacement/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2011/10/marco-simoncelli/?utm_source=atom_feed" rel="related" type="text/html" title="The world has lost an excellent and exciting rider in Marco Simoncelli"/><link href="https://www.simonholywell.com/post/2011/04/prince-william-a-squid/?utm_source=atom_feed" rel="related" type="text/html" title="Whilst the wedding is a great event for the participants, I am n…"/><link href="https://www.simonholywell.com/post/2011/01/fulloctane-introduction/?utm_source=atom_feed" rel="related" type="text/html" title="FullOctane: Bike and Car Blog"/><link href="https://www.simonholywell.com/post/2010/06/adenauer-forst-70s-crash-compilation/?utm_source=atom_feed" rel="related" type="text/html" title="sharonov: 1970 Adenauer Forst crashes"/><link href="https://www.simonholywell.com/post/2010/05/pirelli-diablo-rosso-corsa/?utm_source=atom_feed" rel="related" type="text/html" title="Pirelli Diablo Rosso Corsa"/><id>https://www.simonholywell.com/post/focus-jam-frame-bearing-replacement/</id><author><name>Simon Holywell</name></author><published>2024-09-27T22:10:31+10:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>I recently replaced the frame bearings in my 2018 Focus Jam mountain bike and found it hard to find out exactly which bearings I needed until I had the whole thing apart. To make it easier next time I am sharing my notes from the process.</summary><content type="html"><![CDATA[<h1 id="introduction">Introduction</h1>
<p>I have owned a 2018 Focus Jam Elite 29er for a few years now and it has been a great bike.
However, I have noticed that the rear suspension has been feeling a bit rough lately.
I have been meaning to service the bearings in the frame for a while now, so I decided to finally get around to it.</p>
<p>You should do too if the rear suspension feels rough, creaks or you can feel play in the rear triangle.</p>
<h1 id="bearings-required">Bearings required</h1>
<p>The Focus Jam from 2017 to 2021 has the following bearings in the frame:</p>
<ul>
<li>4x 61901-2RS bearings (12mm x 24mm x 6mm)</li>
<li>2x 61902-2RS bearings (15mm x 28mm x 7mm)</li>
<li>2x 63801-2RS-MAX bearings (12mm x 21mm x 7mm)
<ul>
<li>do note that the bearing is 7mm wide and not the more commonly available 8mm wide - be sure to double check this.</li>
<li>alternative names for this bearing:
<ul>
<li>3801-H7 Full complement</li>
<li>63801 Full complement</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>I bought my bearings from my local SKF bearing supplier/factor, but you can also get them as kits.
In fact if I were to do it again I would probably buy the kit as it is cheaper or from a Enduro bearing supplier online.</p>
<p>The DIY MTB wholesaler in Australia has the bearings and a kit for the Focus Sam 2017-2018, which looks like it is the same as the Jam 2017-2021. Do verify with the supplier before purchasing, but the <a href="https://www.diymtb.com.au/displayItems.asp?cid=146" title="DIY MTB GPBSETRSFO2 bearing kit">GPBSETRSFO2 kit</a> looks like it has all the bearings you need.</p>
<h1 id="a-quick-note-on-pressing-the-bearings">A quick note on pressing the bearings</h1>
<p>You do not need any special tools to press the bearings or remove them from the frame.
You can use a socket that is the same size as the bearing and a long bolt or some all-thread combined with some washers &amp; nuts to press the bearing in.</p>
<p><img src="./socket_bearing_press.webp" alt="Bearing pressing tool" title="Bearing pressing tool"></p>
<p>I have couple of photos of this tool in action later in the article that may help you understand how it works.</p>
<h2 id="removing-the-bearings">Removing the bearings</h2>
<p>To remove the blind bearings you can gently them out with a flat head screwdriver like I did or using a bearing puller if you have one.
A blind bearing is one that is pressed into a hole and has no lip to press against.</p>
<p>To press non-bearing blind bearings you can use a socket that is the same size as the bearing and a long bolt or some all-thread to press the bearing out.
As you can see from the image I used a metric socket, a length of all-thread, two nuts and three washers.
Then using two spanners to turn the nuts I was able to press the bearing out.</p>
<h2 id="pressing-the-bearings">Pressing the bearings</h2>
<p>To press the bearings back in you can use a socket that is the same size as the bearing and a long bolt or some all-thread to press the bearing in.
Of course you can buy a bearing press tool if you want to, but it is not necessary.</p>
<p>Sockets are an excellent tool for pressing bearings in and out of frames because they come in many sizes and many people already have a set of sockets.
Be sure to select a socket that is the same size as the outer race/shell of the bearing.
Do not press on the inner race or the ball cage cover as you will damage the bearing.</p>
<p><img src="./pressing_a_bearing_into_a_frame.webp" alt="Pressing a bearing into the frame" title="Pressing a bearing into the frame"></p>
<p>Again, from another angle to show you how I used the tool to press the bearing in.</p>
<p><img src="./pressing_a_bearing_into_a_frame2.webp" alt="Pressing a bearing into the frame - angle two" title="Pressing a bearing into the frame - angle two"></p>
<h1 id="conclusion">Conclusion</h1>
<p>Hopefully this post has been helpful to you if you are looking to replace the bearings in your Focus Jam frame.
It is a relatively simple job that can be done with basic tools and a bit of patience.</p>
]]></content><category scheme="taxonomy:Categories" term="bikes" label="Bikes"/><category scheme="taxonomy:Tags" term="focus-jam-frame-bearing-replacement" label="focus-jam-frame-bearing-replacement"/><category scheme="taxonomy:Tags" term="focus-jam" label="focus-jam"/><category scheme="taxonomy:Tags" term="bikes" label="bikes"/><category scheme="taxonomy:Tags" term="maintenance" label="maintenance"/></entry><entry xml:base="paraiso-dark-vscode-and-zed-theme"><title type="html">Paraíso dark VS Code and Zed themes</title><link href="https://www.simonholywell.com/post/paraiso-dark-vscode-and-zed-theme/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/git-delta/?utm_source=atom_feed" rel="related" type="text/html" title="Git and delta"/><link href="https://www.simonholywell.com/post/git-add-p/?utm_source=atom_feed" rel="related" type="text/html" title="Staging patches with git add"/><link href="https://www.simonholywell.com/post/dynamic-docker-image-loading/?utm_source=atom_feed" rel="related" type="text/html" title="Dynamic docker image loading"/><link href="https://www.simonholywell.com/post/pinning-nix-shell-package-versions-for-reproducibility/?utm_source=atom_feed" rel="related" type="text/html" title="Pinning nix-shell package versions for reproducibility"/><link href="https://www.simonholywell.com/post/yow-2023-brisbane/?utm_source=atom_feed" rel="related" type="text/html" title="YOW! 2023 conference highlights"/><id>https://www.simonholywell.com/post/paraiso-dark-vscode-and-zed-theme/</id><author><name>Simon Holywell</name></author><published>2024-04-04T13:08:12+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>A dark theme for both the Visual Studio Code (vscode) and Zed editors based on the Paraíso theme from TextMate by Jann T. Sott and Chris Kempson.</summary><content type="html"><![CDATA[<h2 id="introduction">Introduction</h2>
<p>I like to use the Paraíso (dark) theme for my editor and the options for <a href="https://code.visualstudio.com/" title="Visual Studio Code">VS Code</a> were no longer maintained or poorly executed and non-existent for <a href="https://zed.dev/" title="Zed editor: Code at the speed of thought">Zed</a>.
So I decided to fork the <a href="https://github.com/gerane/VSCodeThemes/tree/master/gerane.Theme-Paraiso_dark" title="VS Code Paraiso Dark theme">gerane.Theme-Paraiso_dark</a> and create a version for both editors.</p>
<h2 id="screenshot">Screenshot</h2>
<p><img src="./Paraiso_dark.webp" alt="Paraíso dark theme in the Zed editor" title="Paraíso dark theme in the Zed editor"></p>
<h2 id="installing">Installing</h2>
<h3 id="visual-studio-code">Visual Studio Code</h3>
<p>The VS Code theme is available in the <a href="https://marketplace.visualstudio.com/items?itemName=treffynnon.paraiso-dark-vscode-theme" title="VS Code Paraiso Dark theme">marketplace</a> and can be installed from the in-editor marketplace.</p>
<h3 id="zed">Zed</h3>
<p>To install the theme in Zed you can search the extension store for &ldquo;Paraíso&rdquo; and install it from there.</p>
<h2 id="source-code">Source code</h2>
<p>You can see the <a href="https://github.com/treffynnon/paraiso-dark-vscode-theme" title="VS Code Paraíso Dark theme on GitHub">VS Code theme</a> and the <a href="https://github.com/treffynnon/zed-Paraiso" title="Zed Paraíso Dark theme on GitHub">Zed theme</a> on GitHub.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="vscode" label="vscode"/><category scheme="taxonomy:Tags" term="zed" label="zed"/></entry><entry xml:base="git-delta"><title type="html">Git and delta</title><link href="https://www.simonholywell.com/post/git-delta/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/git-add-p/?utm_source=atom_feed" rel="related" type="text/html" title="Staging patches with git add"/><link href="https://www.simonholywell.com/post/2013/12/reverse-github-pull-request/?utm_source=atom_feed" rel="related" type="text/html" title="Reverse a git pull request on GitHub the hard way"/><link href="https://www.simonholywell.com/post/2013/02/php-ssdeep-in-git/?utm_source=atom_feed" rel="related" type="text/html" title="ssdeep PHP extension in git"/><link href="https://www.simonholywell.com/post/2013/02/git-tag-secrets/?utm_source=atom_feed" rel="related" type="text/html" title="Git tag secrets"/><link href="https://www.simonholywell.com/post/2009/08/moving-to-git-and-setting-up-indefero-as-a-web-frontend/?utm_source=atom_feed" rel="related" type="text/html" title="Moving to git and setting up InDefero as a web frontend"/><id>https://www.simonholywell.com/post/git-delta/</id><author><name>Simon Holywell</name></author><published>2024-02-19T12:10:32+10:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Adding delta to your workflow will give you a nice interactive diff so make command line git so much better!</summary><content type="html"><![CDATA[<p>Until recently I was using the <a href="https://git.kernel.org/pub/scm/git/git.git/tree/contrib/diff-highlight" title="diff-highlight source code in git's git repository"><code>diff-highlight</code></a> script that comes with a git installation, but it stopped working and instead of investigating why, I started looking for more modern alternatives.
One of the projects I kept seeing was <a href="https://github.com/dandavison/delta" title="A syntax-highlighting pager for git, diff, and grep output">Delta</a> so I gave it a quick go and it was a great replacement with nice additional features.</p>
<p>It is nice and fast (written in Rust of course) and renders nice diffs when I am using <code>git diff</code> or <code>git add -p</code> (where <code>-p</code> is short for <code>--patch</code>) to add files to commits.</p>
<p>As an aside, if you&rsquo;re not already using <code>git add -p</code> to stage your commits then you&rsquo;re missing out.
It allows you to interactively stage a file or just part of it (git refers to these parts as hunks).
I have previously written about this in <a href="/post/git-add-p/" title="Staging patches with git add by Simon Holywell">Staging patches with git add</a>.</p>
<p>Getting setup is pretty easy by installing the <code>git-delta</code> package from your systems package manager - I am using <a href="https://nixos.org/explore/" title="Nix package manager">Nix</a> with <a href="https://github.com/nix-community/home-manager" title="Home Manager using Nix to manage the user environment">home-manager</a> that has a delta configuration <a href="https://github.com/nix-community/home-manager/blob/master/modules/programs/git.nix#L255" title="Delta configuration in home-manager">built-in</a>, but it could be <a href="https://formulae.brew.sh/formula/git-delta" title="Delta in the Homebrew repository">Homebrew</a> or even <a href="https://community.chocolatey.org/packages/delta" title="Delta in the Chocolately repository">Chocolately</a>.</p>
<p>Now you just need configure git to use it as the pager and for interactive diffs (<code>git add -p</code> for example).
In <code>~/.gitconfig</code> you can add something like the following to get started and as a good base to customise further too.
The configuration options are in the delta <a href="https://dandavison.github.io/delta/introduction.html" title="Delta documentation website">documentation</a>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-plain" data-lang="plain"><span class="line"><span class="cl">[core]
</span></span><span class="line"><span class="cl">  pager = delta
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">[interactive]
</span></span><span class="line"><span class="cl">  diffFilter = delta --color-only
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">[delta]
</span></span><span class="line"><span class="cl">  navigate = true    # use n and N to move between diff sections
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">[merge]
</span></span><span class="line"><span class="cl">  conflictstyle = diff3
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">[diff]
</span></span><span class="line"><span class="cl">  colorMoved = default
</span></span></code></pre></div><p>As I am using home-manager my configuration looks more like this Nix configuration, which automatically handles setting delta as the pager and interactive diff tool.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl">  <span class="n">programs</span><span class="o">.</span><span class="n">git</span> <span class="err">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">delta</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="n">enable</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">      <span class="n">options</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">hyperlinks</span> <span class="o">=</span> <span class="no">true</span><span class="p">;</span> <span class="c1"># makes file paths clickable in the terminal</span>
</span></span><span class="line"><span class="cl">        <span class="n">hyperlinks-file-link-format</span> <span class="o">=</span> <span class="s2">&#34;vscode://file/{path}:{line}&#34;</span><span class="p">;</span> <span class="c1"># opens links in vscode</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="n">features</span> <span class="o">=</span> <span class="s2">&#34;decorations interactive&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="n">interactive</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="n">keep-plus-minus-markers</span> <span class="o">=</span> <span class="no">false</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="n">decorations</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="n">commit-decoration-style</span> <span class="o">=</span> <span class="s2">&#34;bold yellow box ul&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">          <span class="n">file-style</span> <span class="o">=</span> <span class="s2">&#34;bold yellow ul&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">          <span class="n">file-decoration-style</span> <span class="o">=</span> <span class="s2">&#34;none&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">};</span>
</span></span><span class="line"><span class="cl">      <span class="p">};</span>
</span></span><span class="line"><span class="cl">    <span class="p">};</span>
</span></span><span class="line"><span class="cl">  <span class="p">};</span>
</span></span></code></pre></div><p>Now if you run <code>git add -p</code> you&rsquo;ll get nicely highlighted diffs for each hunk that you&rsquo;re staging for commit.
Delta makes it easier to read the diffs and therefore, hopefully, spot mistakes quicker.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="git" label="git"/></entry><entry xml:base="git-add-p"><title type="html">Staging patches with git add</title><link href="https://www.simonholywell.com/post/git-add-p/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2013/12/reverse-github-pull-request/?utm_source=atom_feed" rel="related" type="text/html" title="Reverse a git pull request on GitHub the hard way"/><link href="https://www.simonholywell.com/post/2013/02/php-ssdeep-in-git/?utm_source=atom_feed" rel="related" type="text/html" title="ssdeep PHP extension in git"/><link href="https://www.simonholywell.com/post/2013/02/git-tag-secrets/?utm_source=atom_feed" rel="related" type="text/html" title="Git tag secrets"/><link href="https://www.simonholywell.com/post/2009/08/moving-to-git-and-setting-up-indefero-as-a-web-frontend/?utm_source=atom_feed" rel="related" type="text/html" title="Moving to git and setting up InDefero as a web frontend"/><link href="https://www.simonholywell.com/post/2009/03/using-phing-for-good-unfuddle-add-repository-and-svn-imp/?utm_source=atom_feed" rel="related" type="text/html" title="Using phing for good - Unfuddle Add Repository and SVN Import Ta…"/><id>https://www.simonholywell.com/post/git-add-p/</id><author><name>Simon Holywell</name></author><published>2024-02-15T01:34:07+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Using git add -p to interactively stage specific parts of a file allowing for more precise control over commits in git. It provides a walkthrough on how to split hunks for granular commit control, ensuring that only desired changes are staged. The post emphasizes the utility of this approach in enhancing commit precision and managing contributions more effectively in git.</summary><content type="html"><![CDATA[<h2 id="introduction">Introduction</h2>
<p>If you&rsquo;re not already using <code>git add -p</code> to stage your commits then you&rsquo;re missing out.
It allows you to interactively stage a file or just part of it giving you greater control over your git commit process.</p>
<h2 id="why-should-you-want-to-do-this">Why should you want to do this?</h2>
<p>Here are some of the reasons why I prefer using <code>git add -p</code> in my workflow.
Primarily, because it allows me to review my changes as I stage them and I often find mistakes this way.
By reviewing changes during staging, I catch bugs, typos, and other issues that might have slipped through during initial coding or content creation.</p>
<p>There is an additional benefit though; it allows me to stage only part of file.
Git, rather oddly, refers to these parts as hunks so I will use that term going forward.</p>
<p>This feature is really useful when you have a number changes, but you want to group them up into different commits.
Imagine you’ve made several related changes across different parts of a file.
With <code>git add -p</code>, you can selectively stage these changes together, ensuring cleaner and more organized commits.</p>
<h2 id="staging-part-of-a-file">Staging part of a file</h2>
<p>Here is an example of the interface showing you the diff and then prompting you to &ldquo;Stage this hunk?&rdquo;.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-diff" data-lang="diff"><span class="line"><span class="cl"><span class="gh">diff --git a/main.mts b/main.mts
</span></span></span><span class="line"><span class="cl"><span class="gh">index e1132f2..8f7c279 100644
</span></span></span><span class="line"><span class="cl"><span class="gh"></span><span class="gd">--- a/main.mts
</span></span></span><span class="line"><span class="cl"><span class="gd"></span><span class="gi">+++ b/main.mts
</span></span></span><span class="line"><span class="cl"><span class="gi"></span><span class="gu">@@ -1,2 +1,4 @@
</span></span></span><span class="line"><span class="cl"><span class="gu"></span> export const add = (a, b) =&gt; a + b
</span></span><span class="line"><span class="cl"><span class="gi">+export const div = (a, b) =&gt; a / b
</span></span></span><span class="line"><span class="cl"><span class="gi"></span> export const sum = (xs) =&gt; xs.reduce((acc, x) =&gt; sum(acc, x))
</span></span><span class="line"><span class="cl"><span class="gi">+export const avg = (xs) =&gt; div(sum(xs), xs.length)
</span></span></span><span class="line"><span class="cl"><span class="gi"></span>(1/1) Stage this hunk [y,n,q,a,d,s,e,?]?
</span></span></code></pre></div><p>In its simplest form we can enter <code>y</code> to stage that diff ready for commit or <code>n</code> not to.
For this example I am not ready to commit the <code>avg</code> function, but I want to get <code>div</code> pushed up so I choose to enter <code>s</code> to split the hunk into smaller hunks.
Git then asks me this.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-diff" data-lang="diff"><span class="line"><span class="cl">Split into 2 hunks.
</span></span><span class="line"><span class="cl"><span class="gu">@@ -1,2 +1,3 @@
</span></span></span><span class="line"><span class="cl"><span class="gu"></span> export const add = (a, b) =&gt; a + b
</span></span><span class="line"><span class="cl"><span class="gi">+export const div = (a, b) =&gt; a / b
</span></span></span><span class="line"><span class="cl"><span class="gi"></span> export const sum = (xs) =&gt; xs.reduce((acc, x) =&gt; sum(acc, x))
</span></span><span class="line"><span class="cl">(1/2) Stage this hunk [y,n,q,a,d,j,J,g,/,e,?]?
</span></span></code></pre></div><p>So I enter <code>y</code> to stage that hunk for commit and git responds with the next hunk.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-diff" data-lang="diff"><span class="line"><span class="cl"><span class="gu">@@ -2 +3,2 @@
</span></span></span><span class="line"><span class="cl"><span class="gu"></span> export const sum = (xs) =&gt; xs.reduce((acc, x) =&gt; sum(acc, x))
</span></span><span class="line"><span class="cl"><span class="gi">+export const avg = (xs) =&gt; div(sum(xs), xs.length)
</span></span></span><span class="line"><span class="cl"><span class="gi"></span>(2/2) Stage this hunk [y,n,q,a,d,K,g,/,e,?]?
</span></span></code></pre></div><p>Remembering that I only want to commit the <code>div</code> function I then enter <code>q</code> to quit the interactive hunk staging.</p>
<p>After interacting with the hunk staging, I return to the command prompt.
From there, I can proceed with git commit or any other necessary commands.</p>
<h2 id="checking-it-worked">Checking it worked</h2>
<p>If I were to run a <code>git status</code> to check the staged files I would see that the fil (<code>main.mts</code>) appears in both sections; to be committed and not staged for commit.
This is because we only staged part of the file and it is what we wanted!</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-plain" data-lang="plain"><span class="line"><span class="cl">On branch main
</span></span><span class="line"><span class="cl">Your branch is ahead of &#39;origin/main&#39; by 1 commit.
</span></span><span class="line"><span class="cl">  (use &#34;git push&#34; to publish your local commits)
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Changes to be committed:
</span></span><span class="line"><span class="cl">  (use &#34;git restore --staged &lt;file&gt;...&#34; to unstage)
</span></span><span class="line"><span class="cl">	modified:   main.mts
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Changes not staged for commit:
</span></span><span class="line"><span class="cl">  (use &#34;git add/rm &lt;file&gt;...&#34; to update what will be committed)
</span></span><span class="line"><span class="cl">  (use &#34;git restore &lt;file&gt;...&#34; to discard changes in working directory)
</span></span><span class="line"><span class="cl">	modified:   main.mts
</span></span></code></pre></div><p>By selectively staging only part of the file, we’ve successfully prepared a single hunk—a patch—for our upcoming commit.</p>
<h2 id="other-options">Other options</h2>
<p>The list (<code>[y,n,q,a,d,s,e,?]</code>) of potential responses is shortened, but you can get extended information by entering <code>?</code> to get the help documentation.</p>
<p>Here are some response options you can use during interactive hunk staging taken from the <a href="https://git-scm.com/book/en/v2/Git-Tools-Interactive-Staging#_staging_patches" title="Staging patches with git in git's documentation">git documentation</a>.
You&rsquo;ll notice that there are a lot more options than in the list we saw earlier.</p>
<ul>
<li><code>y</code>: stage this hunk</li>
<li><code>n</code>: do not stage this hunk</li>
<li><code>a</code>: stage this and all the remaining hunks in the file</li>
<li><code>d</code>: do not stage this hunk nor any of the remaining hunks in the file</li>
<li><code>g</code>: select a hunk to go to</li>
<li><code>/</code>: search for a hunk matching the given regex</li>
<li><code>j</code>: leave this hunk undecided, see next undecided hunk</li>
<li><code>J</code>: leave this hunk undecided, see next hunk</li>
<li><code>k</code>: leave this hunk undecided, see previous undecided hunk</li>
<li><code>K</code>: leave this hunk undecided, see previous hunk</li>
<li><code>s</code>: split the current hunk into smaller hunks</li>
<li><code>e</code>: manually edit the current hunk</li>
<li><code>?</code>: print help</li>
</ul>
<h2 id="when-not-to-use-it">When not to use it</h2>
<p>I use <code>git add -p</code> nearly every time I commit every working day.
There are two occasions where I don&rsquo;t:</p>
<ol>
<li>There is a newly created file to commit for the first time - when a file is newly created there is no previous version to diff against of course so <code>git add -p</code> cannot present a diff for you to approve for staging.</li>
<li>In rare cases, when I want to commit an entire directory and am confident about its content, I usually opt for the standard approach.
However, even in such edge cases, I often find myself using git add -p for finer control.</li>
</ol>
<h2 id="conclusion">Conclusion</h2>
<p>By incorporating <code>git add -p</code> into your workflow, you’ll streamline your git and commit process..
I use this technique, without exaggeration, nearly every single time I need to commit a changeset to git.
It allows me to easily review my code as I stage it for commit and control exactly what goes into each of my commits.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="git" label="git"/></entry><entry xml:base="dynamic-docker-image-loading"><title type="html">Dynamic docker image loading</title><link href="https://www.simonholywell.com/post/dynamic-docker-image-loading/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/docker-cross-compilation/?utm_source=atom_feed" rel="related" type="text/html" title="Docker cross-compilation"/><link href="https://www.simonholywell.com/post/pinning-nix-shell-package-versions-for-reproducibility/?utm_source=atom_feed" rel="related" type="text/html" title="Pinning nix-shell package versions for reproducibility"/><link href="https://www.simonholywell.com/post/2013/12/reverse-github-pull-request/?utm_source=atom_feed" rel="related" type="text/html" title="Reverse a git pull request on GitHub the hard way"/><link href="https://www.simonholywell.com/post/yow-2023-brisbane/?utm_source=atom_feed" rel="related" type="text/html" title="YOW! 2023 conference highlights"/><link href="https://www.simonholywell.com/post/duty-free-with-trs-for-australians/?utm_source=atom_feed" rel="related" type="text/html" title="Duty-free with TRS for Australian residents"/><id>https://www.simonholywell.com/post/dynamic-docker-image-loading/</id><author><name>Simon Holywell</name></author><published>2024-02-12T09:36:58+10:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Learn how to dynamically load different base images to build application images and for testing using Docker. Utilize build-time variables in a Dockerfile to specify the Node.js version/tag and even extend the flexibility to customize both the image name and tag. Bonus - Discover a GitHub Actions workflow that builds and tests your project against multiple Node.js versions, ensuring compatibility across different environments.</summary><content type="html"><![CDATA[<h2 id="introduction">Introduction</h2>
<p>In a recent project, I encountered the need to dynamically load different base images based on the Node.js version I wanted for testing.
Docker came to the rescue, offering a simple yet powerful solution using command-line arguments within the <code>FROM</code> section of a Dockerfile.</p>
<h2 id="the-dockerfile">The Dockerfile</h2>
<p>Let&rsquo;s start with a straightforward example of a Dockerfile with the dynamic version loading included.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Dockerfile" data-lang="Dockerfile"><span class="line"><span class="cl"><span class="k">ARG</span> NODE_VERSION_TAG<span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span><span class="k">FROM</span><span class="s"> node:${NODE_VERSION_TAG} as build</span><span class="err">
</span></span></span></code></pre></div><p>The ARG keyword sets up a build-time variable named <code>NODE_VERSION_TAG</code>.
In the <code>FROM</code> clause, we immediately utilize this variable with <code>${NODE_VERSION_TAG}</code>, dynamically loading the specified version/tag of the <a href="https://hub.docker.com/_/node/" title="Official node image on Docker Hub">node image</a>.</p>
<h2 id="building-with-dynamic-arguments">Building with dynamic arguments</h2>
<p>When you execute the build process you can specify an argument as follows:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker build --build-arg <span class="nv">NODE_VERSION_TAG</span><span class="o">=</span>latest -t custom-image-name:v1.0 .
</span></span></code></pre></div><p>You can also choose any <a href="https://hub.docker.com/_/node/tags" title="Official node image tags">other tag</a> associated with different Node.js versions and underlying OS combinations.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker build --build-arg <span class="nv">NODE_VERSION_TAG</span><span class="o">=</span>21.2.0 -t custom-image-name:v1.0 .
</span></span></code></pre></div><p>The container would then be built using the node image at version 21.2.0 as its base.</p>
<h2 id="extending-for-image-name-and-tag">Extending for image name and tag</h2>
<p>To take it a step further, you can dynamically alter both the image name and tag.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Dockerfile" data-lang="Dockerfile"><span class="line"><span class="cl"><span class="k">ARG</span> BASE_IMAGE_NAME<span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span><span class="k">ARG</span> BASE_IMAGE_TAG<span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span><span class="k">FROM</span><span class="s"> ${BASE_IMAGE_NAME}:${BASE_IMAGE_TAG} as build</span><span class="err">
</span></span></span></code></pre></div><p>Now, you can build with different base images.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker build --build-arg <span class="nv">BASE_IMAGE_NAME</span><span class="o">=</span>node --build-arg <span class="nv">BASE_IMAGE_TAG</span><span class="o">=</span>21.2.0 -t custom-image-name-node:v1.0 .
</span></span><span class="line"><span class="cl">docker build --build-arg <span class="nv">BASE_IMAGE_NAME</span><span class="o">=</span>rust --build-arg <span class="nv">BASE_IMAGE_TAG</span><span class="o">=</span>1.74.0 -t custom-image-name-rust:v1.0 .
</span></span></code></pre></div><p>This approach extends the versatility of your Dockerfile, allowing you to seamlessly adapt to various base images and tags.</p>
<h2 id="github-actions-workflow">Github Actions workflow</h2>
<p>As a bonus here is a Github Actions workflow that uses this technique to build a docker image against multiple versions of node.js.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Node.js Version Matrix</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">on</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">push</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">branches</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="l">main</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">jobs</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">test</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">runs-on</span><span class="p">:</span><span class="w"> </span><span class="l">ubuntu-latest</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">strategy</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">matrix</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">node-version</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="m">14</span><span class="p">,</span><span class="w"> </span><span class="m">16</span><span class="p">,</span><span class="w"> </span><span class="m">18</span><span class="p">]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">steps</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Checkout Repository</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">actions/checkout@v2</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Set up Node.js</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">actions/setup-node@v4</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">with</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">node-version</span><span class="p">:</span><span class="w"> </span><span class="l">${{ matrix.node-version }}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Build and Test</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">run</span><span class="p">:</span><span class="w"> </span><span class="p">|</span><span class="sd">
</span></span></span><span class="line"><span class="cl"><span class="sd">          docker build --build-arg NODE_VERSION_TAG=${{ matrix.node-version }} -t myapp-${{ matrix.node-version }}:test .
</span></span></span><span class="line"><span class="cl"><span class="sd">          docker run myapp-${{ matrix.node-version }}:test npm test</span><span class="w">          
</span></span></span></code></pre></div><p>This workflow is performing the following actions.</p>
<ul>
<li>The workflow triggers on pushes to the main branch.</li>
<li>It defines a job named &ldquo;test&rdquo; that runs on the latest version of Ubuntu.</li>
<li>The build matrix is configured with three different Node.js versions: 14, 16, and 18.</li>
<li>The actions/checkout action is used to fetch the repository.</li>
<li>The actions/setup-node action is used to set up the specified Node.js version from the matrix.</li>
<li>The build and test steps use the docker build command with the <code>NODE_VERSION_TAG</code> argument set to the corresponding Node.js version from the matrix.</li>
<li>The docker run command executes your project&rsquo;s tests inside the Docker container.</li>
</ul>
<p>With this workflow, your project will be built and tested against multiple Node.js versions, providing you with valuable insights into its compatibility across different environments.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="docker" label="docker"/><category scheme="taxonomy:Tags" term="github" label="github"/><category scheme="taxonomy:Tags" term="node" label="node"/></entry><entry xml:base="pinning-nix-shell-package-versions-for-reproducibility"><title type="html">Pinning nix-shell package versions for reproducibility</title><link href="https://www.simonholywell.com/post/pinning-nix-shell-package-versions-for-reproducibility/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/docker-cross-compilation/?utm_source=atom_feed" rel="related" type="text/html" title="Docker cross-compilation"/><link href="https://www.simonholywell.com/post/yow-2023-brisbane/?utm_source=atom_feed" rel="related" type="text/html" title="YOW! 2023 conference highlights"/><link href="https://www.simonholywell.com/post/duty-free-with-trs-for-australians/?utm_source=atom_feed" rel="related" type="text/html" title="Duty-free with TRS for Australian residents"/><link href="https://www.simonholywell.com/post/diy-hybrid-valve-amplifier/?utm_source=atom_feed" rel="related" type="text/html" title="DIY hybrid valve headphone amplifier (SSMH)"/><link href="https://www.simonholywell.com/post/windows-10-shortcuts/?utm_source=atom_feed" rel="related" type="text/html" title="Windows 10 shortcuts"/><id>https://www.simonholywell.com/post/pinning-nix-shell-package-versions-for-reproducibility/</id><author><name>Simon Holywell</name></author><published>2024-01-16T10:32:58+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Learn to wield nix-shell&amp;rsquo;s power for precise project dependency management, ensuring hassle-free development environments. Discover techniques for pinning specific Node.js versions, simplifying dependency references, and integrating yarn for enhanced control.</summary><content type="html"><![CDATA[<h2 id="introduction">Introduction</h2>
<p>I rely on nix-shell to manage dependencies for the projects I work on, and when combined with direnv (more on that in a future post!), it automatically configures my shell. All the necessary dependencies are installed with the correct versions for the project, making them readily available in my path.</p>
<p>If you&rsquo;re new to <a href="https://nixos.org/manual/nix/stable/command-ref/nix-shell" title="Nix reference manual: nix-shell">nix-shell</a>, it acts as an environment manager designed to simplify project dependency management, providing a straightforward and reproducible approach to setting up development environments. It ensures that the required dependencies, libraries, and tools are configured consistently, offering a hassle-free development experience. Nix-shell&rsquo;s key advantage lies in its ability to create self-contained environments, particularly valuable for projects with intricate dependencies.</p>
<p>You can create a shell with only the dependencies and versions you need, and nothing more.</p>
<h2 id="practical-example">Practical example</h2>
<p>For example, consider a simple project written in TypeScript/Node.js/JavaScript. Typically, you&rsquo;d have a file named <code>shell.nix</code> in the project&rsquo;s root directory. To enter the shell, navigate to the directory containing the file and run <code>nix-shell</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="p">{</span> <span class="n">pkgs</span> <span class="o">?</span> <span class="kn">import</span> <span class="sr">&lt;nixpkgs&gt;</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl"><span class="p">}:</span>
</span></span><span class="line"><span class="cl"><span class="n">pkgs</span><span class="o">.</span><span class="n">mkShell</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">name</span> <span class="o">=</span> <span class="s2">&#34;projects.my-project-name&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="n">buildInputs</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">    <span class="n">pkgs</span><span class="o">.</span><span class="n">bashInteractive</span>
</span></span><span class="line"><span class="cl">    <span class="n">pkgs</span><span class="o">.</span><span class="n">nodejs</span>
</span></span><span class="line"><span class="cl">  <span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>It will include bash and nodejs from latest nixpkgs when the user enters that shell on the command line.</p>
<h2 id="latest-major-version">Latest major version</h2>
<p>Now what if we need a particular version of Node?
For a major version that is pretty easy - we can just append a major version number to the package reference.
In the following example we pin to Node.js version <code>18.*</code> in semantic versioning terms, but you could also indicate 14, 16, 19 or 20 for example.
Be aware though that not all major versions are available in the latest nixpkgs repository so you should check using the website I&rsquo;ll describe next.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="p">{</span> <span class="n">pkgs</span> <span class="o">?</span> <span class="kn">import</span> <span class="sr">&lt;nixpkgs&gt;</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl"><span class="p">}:</span>
</span></span><span class="line"><span class="cl"><span class="n">pkgs</span><span class="o">.</span><span class="n">mkShell</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">name</span> <span class="o">=</span> <span class="s2">&#34;projects.my-project-name&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="n">buildInputs</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">    <span class="n">pkgs</span><span class="o">.</span><span class="n">bashInteractive</span>
</span></span><span class="line"><span class="cl">    <span class="n">pkgs</span><span class="o">.</span><span class="n">nodejs-18_x</span>
</span></span><span class="line"><span class="cl">  <span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h2 id="using-with-to-simplify-buildinputs">Using <code>with</code> to simplify <code>buildInputs</code></h2>
<p>As an aside we can use little trick to simplify the references in <code>buildInputs</code> so we don&rsquo;t have to prefix each dependency with <code>pkgs.</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="p">{</span> <span class="n">pkgs</span> <span class="o">?</span> <span class="kn">import</span> <span class="sr">&lt;nixpkgs&gt;</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl"><span class="p">}:</span>
</span></span><span class="line"><span class="cl"><span class="n">pkgs</span><span class="o">.</span><span class="n">mkShell</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">name</span> <span class="o">=</span> <span class="s2">&#34;projects.my-project-name&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="n">buildInputs</span> <span class="o">=</span> <span class="k">with</span> <span class="n">pkgs</span><span class="p">;</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">    <span class="n">bashInteractive</span>
</span></span><span class="line"><span class="cl">    <span class="n">nodejs-18_x</span>
</span></span><span class="line"><span class="cl">  <span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Now each reference will be prefixed with <code>pkgs</code> automatically because we included <code>with pkgs;</code> after <code>buildInputs =</code>.</p>
<h2 id="pinning-to-a-specific-version">Pinning to a specific version</h2>
<p>To pin to a specific version of Node.js though we need to add a little more code to the nix-shell file.
This is because we need to pull the package from the nixpkgs repository at the git commit that references that particular version.
Firstly, we can use the <a href="https://lazamar.co.uk/nix-versions/" title="Nix package versions">Nix package versions</a> website to find a SHA hash of the dependency.</p>
<p>The author of that handy page also has an <a href="%22http://lazamar.github.io/download-specific-package-version-with-nix/" title="Searching and installing old versions of Nix packages - Marcelo Lazaroni">interesting blog post</a> that goes into more detail on the problem that you might find interesting as an aside.
He also goes into more detail on how this style of pinning can be imperfect.</p>
<p>Enter the name of the package you want to find and you&rsquo;ll get back a table of available versions.
I searched nodejs and got back a <a href="https://lazamar.co.uk/nix-versions/?channel=nixpkgs-unstable&amp;package=nodejs" title="Nix package versions: nodejs">list of versions</a> and found the version 18.14.0 that I was looking for.
Copy the SHA hash from the Revision column of the table because you&rsquo;ll need this up next - in my case this was <code>55070e598e0e03d1d116c49b9eff322ef07c6ac6</code>.</p>
<p>As an example of how this kind of pinning can be imperfect there is no Node.js version 18.13.0 available because a derivation was never committed for it!</p>
<p>Now we can use the following sample nix-shell file to pull down a particular version of the nodejs package.
We will still pull the latest version of Bash, but we are specifying a particular git commit hash of nixpkgs to pull nodejs from.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="p">{</span> <span class="n">pkgs</span> <span class="o">?</span> <span class="kn">import</span> <span class="sr">&lt;nixpkgs&gt;</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl"><span class="p">}:</span>
</span></span><span class="line"><span class="cl"><span class="k">let</span>
</span></span><span class="line"><span class="cl">  <span class="c1"># node 18.14.0</span>
</span></span><span class="line"><span class="cl">  <span class="n">nodePkgs</span> <span class="o">=</span> <span class="kn">import</span> <span class="p">(</span><span class="nb">fetchTarball</span> <span class="s2">&#34;https://github.com/NixOS/nixpkgs/archive/55070e598e0e03d1d116c49b9eff322ef07c6ac6.tar.gz&#34;</span><span class="p">)</span> <span class="p">{</span> <span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="k">in</span>
</span></span><span class="line"><span class="cl"><span class="n">pkgs</span><span class="o">.</span><span class="n">mkShell</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">name</span> <span class="o">=</span> <span class="s2">&#34;projects.my-project-name&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="n">buildInputs</span> <span class="o">=</span> <span class="k">with</span> <span class="n">pkgs</span><span class="p">;</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">    <span class="n">bashInteractive</span>
</span></span><span class="line"><span class="cl">    <span class="n">nodePkgs</span><span class="o">.</span><span class="n">nodejs-18_x</span>
</span></span><span class="line"><span class="cl">  <span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Note the new nodePkgs variable that imports a tar file of the commit in question from github and is then used to prefix the reference to nodejs-18_x.
This is how we can now be sure that we will always get node 18.4.0 when we instantiate this nix-shell.</p>
<h2 id="using-yarn-as-the-package-manager">Using yarn as the package manager</h2>
<p>Now as a bonus let&rsquo;s see how we can use yarn with our project and ensure it is referencing the correct version of node.
Normally you would just add the package reference <code>yarn</code> into the <code>buildInputs</code> list, but we need to tell it to use the exact version of node that our project specifies.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="p">{</span> <span class="n">pkgs</span> <span class="o">?</span> <span class="kn">import</span> <span class="sr">&lt;nixpkgs&gt;</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl"><span class="p">}:</span>
</span></span><span class="line"><span class="cl"><span class="k">let</span>
</span></span><span class="line"><span class="cl">  <span class="c1"># node 18.14.0</span>
</span></span><span class="line"><span class="cl">  <span class="n">nodePkgs</span> <span class="o">=</span> <span class="kn">import</span> <span class="p">(</span><span class="nb">fetchTarball</span> <span class="s2">&#34;https://github.com/NixOS/nixpkgs/archive/55070e598e0e03d1d116c49b9eff322ef07c6ac6.tar.gz&#34;</span><span class="p">)</span> <span class="p">{</span> <span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="k">in</span>
</span></span><span class="line"><span class="cl"><span class="n">pkgs</span><span class="o">.</span><span class="n">mkShell</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">name</span> <span class="o">=</span> <span class="s2">&#34;projects.my-project-name&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="n">buildInputs</span> <span class="o">=</span> <span class="k">with</span> <span class="n">pkgs</span><span class="p">;</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">    <span class="n">bashInteractive</span>
</span></span><span class="line"><span class="cl">    <span class="n">nodePkgs</span><span class="o">.</span><span class="n">nodejs-18_x</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="n">yarn</span><span class="o">.</span><span class="n">override</span> <span class="p">{</span> <span class="n">nodejs</span> <span class="o">=</span> <span class="n">nodePkgs</span><span class="o">.</span><span class="n">nodejs-18_x</span><span class="p">;</span> <span class="p">})</span>
</span></span><span class="line"><span class="cl">  <span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>This installs yarn and passes an override through to it that specifies the correct version of node for yarn to reference.</p>
<h2 id="putting-bin-from-node_modules-into-path">Putting .bin from node_modules into $PATH</h2>
<p>Speaking of node dependencies; we can also put the <code>node_modules/.bin</code> directory on the path to make it easier to run and reference scripts installed by our npm/yarn dependencies.
This can be achieved by adding a <code>shellHook</code> to the nix-shell file that is written in bash/shell and will be executed right before the new shell is handed to the user.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="p">{</span> <span class="n">pkgs</span> <span class="o">?</span> <span class="kn">import</span> <span class="sr">&lt;nixpkgs&gt;</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl"><span class="p">}:</span>
</span></span><span class="line"><span class="cl"><span class="k">let</span>
</span></span><span class="line"><span class="cl">  <span class="c1"># node 18.14.0</span>
</span></span><span class="line"><span class="cl">  <span class="n">nodePkgs</span> <span class="o">=</span> <span class="kn">import</span> <span class="p">(</span><span class="nb">fetchTarball</span> <span class="s2">&#34;https://github.com/NixOS/nixpkgs/archive/55070e598e0e03d1d116c49b9eff322ef07c6ac6.tar.gz&#34;</span><span class="p">)</span> <span class="p">{</span> <span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="k">in</span>
</span></span><span class="line"><span class="cl"><span class="n">pkgs</span><span class="o">.</span><span class="n">mkShell</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">name</span> <span class="o">=</span> <span class="s2">&#34;projects.my-project-name&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="n">buildInputs</span> <span class="o">=</span> <span class="k">with</span> <span class="n">pkgs</span><span class="p">;</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">    <span class="n">bashInteractive</span>
</span></span><span class="line"><span class="cl">    <span class="n">nodePkgs</span><span class="o">.</span><span class="n">nodejs-18_x</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="n">yarn</span><span class="o">.</span><span class="n">override</span> <span class="p">{</span> <span class="n">nodejs</span> <span class="o">=</span> <span class="n">nodePkgs</span><span class="o">.</span><span class="n">nodejs-18_x</span><span class="p">;</span> <span class="p">})</span>
</span></span><span class="line"><span class="cl">  <span class="p">];</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="n">shellHook</span> <span class="o">=</span> <span class="s1">&#39;&#39;
</span></span></span><span class="line"><span class="cl"><span class="s1">    export PATH=&#34;$PWD/node_modules/.bin/:$PATH&#34;
</span></span></span><span class="line"><span class="cl"><span class="s1">  &#39;&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Of course you could run any code here or add any path to your <code>$PATH</code>.</p>
<h2 id="pinning-all-the-things">Pinning all the things</h2>
<p>You can also pin the overall packages import so that you always get the same version of bash or any other package that are being imported from <code>pkgs</code>.
This is done by replacing the <code>&lt;nixpkgs&gt;</code> token with a <code>fetchTarball</code> that takes a SHA hash from nixpkgs just like the <code>nodePkgs</code> pinning we did earlier.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nix" data-lang="nix"><span class="line"><span class="cl"><span class="p">{</span> <span class="n">pkgs</span> <span class="o">?</span> <span class="kn">import</span> <span class="p">(</span><span class="nb">fetchTarball</span> <span class="s2">&#34;https://github.com/NixOS/nixpkgs/archive/e0629618b4b419a47e2c8a3cab223e2a7f3a8f97.tar.gz&#34;</span><span class="p">)</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl"><span class="p">}:</span>
</span></span><span class="line"><span class="cl"><span class="k">let</span>
</span></span><span class="line"><span class="cl">  <span class="c1"># node 18.14.0</span>
</span></span><span class="line"><span class="cl">  <span class="n">nodePkgs</span> <span class="o">=</span> <span class="kn">import</span> <span class="p">(</span><span class="nb">fetchTarball</span> <span class="s2">&#34;https://github.com/NixOS/nixpkgs/archive/55070e598e0e03d1d116c49b9eff322ef07c6ac6.tar.gz&#34;</span><span class="p">)</span> <span class="p">{</span> <span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="k">in</span>
</span></span><span class="line"><span class="cl"><span class="n">pkgs</span><span class="o">.</span><span class="n">mkShell</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">name</span> <span class="o">=</span> <span class="s2">&#34;projects.my-project-name&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="n">buildInputs</span> <span class="o">=</span> <span class="k">with</span> <span class="n">pkgs</span><span class="p">;</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">    <span class="n">bashInteractive</span>
</span></span><span class="line"><span class="cl">    <span class="n">nodePkgs</span><span class="o">.</span><span class="n">nodejs-18_x</span>
</span></span><span class="line"><span class="cl">  <span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>A good place to find the latest safe hash for the various branches of nixpkgs a good place to start is <a href="https://status.nixos.org/" title="Nix Channel Status">status.nixos.org</a> that shows the build status for each of them.
Generally, you will want to either grab the latests stable version, which is <code>nixpkgs-23.11</code> at the time of writing, or the latest unstable with <code>nixpkgs-stable</code>.</p>
<h2 id="conclusion">Conclusion</h2>
<p>So, there are a few tricks to make using a nix-shell a little easier and more specific.
In another post I will describe how I combine this with direnv so that the shell is automatically instantiate for me when I change directories.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="nix" label="nix"/><category scheme="taxonomy:Tags" term="nix-shell" label="nix-shell"/><category scheme="taxonomy:Tags" term="node" label="node"/></entry><entry xml:base="yow-2023-brisbane"><title type="html">YOW! 2023 conference highlights</title><link href="https://www.simonholywell.com/post/yow-2023-brisbane/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/duty-free-with-trs-for-australians/?utm_source=atom_feed" rel="related" type="text/html" title="Duty-free with TRS for Australian residents"/><link href="https://www.simonholywell.com/post/docker-cross-compilation/?utm_source=atom_feed" rel="related" type="text/html" title="Docker cross-compilation"/><link href="https://www.simonholywell.com/post/diy-hybrid-valve-amplifier/?utm_source=atom_feed" rel="related" type="text/html" title="DIY hybrid valve headphone amplifier (SSMH)"/><link href="https://www.simonholywell.com/post/windows-10-shortcuts/?utm_source=atom_feed" rel="related" type="text/html" title="Windows 10 shortcuts"/><link href="https://www.simonholywell.com/post/jest-date-mocking/?utm_source=atom_feed" rel="related" type="text/html" title="Jest Date mocking"/><id>https://www.simonholywell.com/post/yow-2023-brisbane/</id><author><name>Simon Holywell</name></author><published>2023-12-06T13:08:12+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Highlights from the YOW! 2023 conference in Brisbane. This blog post covers engaging talks on topics ranging from creating a programming language for children to real-world applications of WebAssembly. Gain valuable insights from speakers like Felienne Hermans, Chanuki Illushka Seresinhe, Frank Yu, Dylan Beattie, Katie Bell, and Brooklyn Zelenka. Delve into the future of technology, deterministic execution, local-first software, and more.</summary><content type="html"><![CDATA[<p>Over the last two days I was fortunate enough to attend the <a href="https://yowcon.com/brisbane-2023/schedule?date=2023-12-04&amp;video=false" title="YOW! 2023 (Brisbane) Schedule">YOW! 2023</a> conference in Brisbane.
It took the form of three tracks of talks over the two days with an opening keynote each morning.
Here are some of the talks that stood out too me from the event and my thoughts on the topics.</p>
<h2 id="hedy-creating-a-programming-language-for-everyone">Hedy: Creating a programming language for everyone</h2>
<p><a href="https://www.felienne.com/" title="The personal website of Felienne Hermans">Felienne Hermans</a> was telling the story of the creation of an education tool that makes it easier for children to learn to programme.
As I was taking my own children to school on this morning I missed the beginning of this talk and caught it from about half-way through.
However, what I did see was a very interesting look at the intersection of education and programming.</p>
<p>When a new user is given <a href="https://www.hedycode.com/" title="Textual programming for the classroom">Hedy</a> to work through they are given tasks that look like natural language and then slowly build the syntax up to be fully fledged Python.
It is also possible to programme in many different languages including non-latin and right to left languages to make it even easier for newer programmers to learn.
Now they can learn the language without needing to learn bits of English at the same time.</p>
<p>You can see an older version of the talk on <a href="https://www.youtube.com/watch?v=ztdxlkmxpIQ" title="Teaching Kids to Program with Hedy: A Gradual Programming Language • Felienne Hermans • GOTO 2022">YouTube from GOTO 2022</a> too.</p>
<h2 id="deep-learning-computer-vision">Deep learning computer vision</h2>
<p><a href="https://twitter.com/thoughtsymmetry" title="Twitter profile of Chanuki Illushka Seresinhe, PhD">Chanuki Illushka Seresinhe</a> has been working on some interesting things using computer vision to determine if a given photography contains beauty or not as her passion project.
Working at Zoopla she has used computer vision to assess photos of properties to inform value and detect if the renovations have been performed.</p>
<p>The understanding around what is a beautiful place and how it can be mapped and used to inform the creation of better public spaces was the more interesting aspect of the talk to me.
One idea I particularly liked was having an app that could give you a suggested route to a given destination using the most scenic path possible.</p>
<p>She has co-founded a Community Interest Company in the United Kingdom to continue this work called <a href="https://beautifulplaces.ai/" title="Beautiful Places">Beautiful Places</a>.</p>
<p>There is a condensed version of <a href="https://www.youtube.com/watch?v=XdorkkSyR_U" title="AI UK: Spotlight - AI to understand beautiful places and our wellbeing, Chanuki Illushka Seresinhe">this talk</a> from the Turing Institute two years ago.</p>
<h2 id="deterministic-execution-to-scale-and-simplify">Deterministic execution to scale and simplify</h2>
<p><a href="https://www.linkedin.com/in/thisfrankyu/" title="LinkedIn profile of Frank Yu">Frank Yu</a> works at Coinbase and works on engineering problems that require low latency in the trading exchange.
This talk spoke to making systems deterministic such that consistency between regions can be guaranteed.
Essentially, you can send the same message to a service (or a collection of services) and the result will be the same.</p>
<p>The main thrust of the talk was saving money on transfer by computing smaller deterministic messages multiple times - they idea being that compute is cheap and network is expensive.</p>
<p>There is a video of a <a href="https://www.youtube.com/watch?v=Z8KB6yNWsQw" title="Leveraging Determinism - Frank Yu - QCon London 2023">similar talk</a> Frank gave at QCon London 2023.</p>
<h2 id="tipping-points-in-technology">Tipping points in Technology</h2>
<p><a href="https://dylanbeattie.net/" title="Personal website of Dylan Beattie">Dylan Beattie</a> took us through an entertaining discussion of what the future could look like through the lens of previous technological scares.
When something new comes along (such as AI) then it is natural for some to be concerned or predict wild outcomes.
It could be the case that AI takes all our jobs, but currently it is being used to produce things such as books and code that need a lot of human intervention for them to produce useful content.</p>
<p>There doesn&rsquo;t seem to be a video of this talk out there anywhere at this point, but the git related song, <a href="https://www.youtube.com/watch?v=S9Do2p4PwtE" title="re:bass - If git was music, what would it sound like?">re:bass</a>, that Dylan created and played as an introduction is on <a href="https://www.youtube.com/watch?v=S9Do2p4PwtE" title="re:bass - If git was music, what would it sound like?">YouTube</a>.</p>
<h2 id="real-world-uses-for-webassembly">Real world uses for WebAssembly</h2>
<p><a href="https://katiebell.net/" title="Personal website of Katie Bell">Katie Bell</a> spent the talk discussing how WebAssembly can be used to create a safe execution target for arbitrary code on the server and browser/client.</p>
<p>She illustrated how this can work best using the example of Shopify that use it encapsulate user code within the checkout flow so they can ensure third-party code (plugins or APIs) do not slow down the checkout process.
She also covered other technologies for isolated execution such as docker/containers with and without gVisor and V8 Isolates for Node.js.
CloudFlare use V8 Isolates at edge to reduce the time a function takes to start up.</p>
<p>Using a <a href="https://katiebell.net/snippy" title="Create a Rock-Paper-Scissors bot">rock, paper, scissors tournament application</a> she demonstrated live in her talk how users could submit and execute code on her server.
You can either upload a WebAssembly .wasm file or enter Python code directly into a code editor on the page to create a bot that will accept some input and return either rock, paper or scissors.
It is then entered into a knockout tournament with other people&rsquo;s bots to see who comes out on top.</p>
<h2 id="local-first-software">Local first software</h2>
<p><a href="https://twitter.com/expede" title="Twitter profile of Brooklyn Zelenka">Brooklyn Zelenka</a> discussed the work her team has been doing to bring about a local first form of computing.
This is in contrast to the current paradigm of putting everything on the cloud and having the cloud as the single source of truth like Google Docs etc.</p>
<p>The main idea is tha things should work locally first and also give the user control over their data.
This is built upon deterministic units of work that are signed.</p>
<p>There is an <a href="https://www.youtube.com/watch?v=Kr3B3sXh_VA" title="Seamless Services for an Open World - Brooklyn Zelenka">older version of this talk</a> available on YouTube.</p>
<h2 id="theres-no-such-thing-as-plain-text">There&rsquo;s no such thing as plain text</h2>
<p><a href="https://dylanbeattie.net/" title="Personal website of Dylan Beattie">Dylan Beattie</a> gave a humorous look at just what constitutes text and how it is represented by computers. There is a <a href="https://www.youtube.com/watch?v=hI-eAg3hlcM" title="There's No Such Thing As Plain Text by Dylan Beattie">video of this talk</a> from Devoxx in the UK.</p>
<h2 id="in-summary">In summary</h2>
<p>These were some of the standout talks I attended at YOW! 2023.
While not every talk was directly relevant to my work, the conference provided interesting insights, prompting me to delve deeper into some of the ideas.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="conference" label="conference"/></entry><entry xml:base="duty-free-with-trs-for-australians"><title type="html">Duty-free with TRS for Australian residents</title><link href="https://www.simonholywell.com/post/duty-free-with-trs-for-australians/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/docker-cross-compilation/?utm_source=atom_feed" rel="related" type="text/html" title="Docker cross-compilation"/><link href="https://www.simonholywell.com/post/diy-hybrid-valve-amplifier/?utm_source=atom_feed" rel="related" type="text/html" title="DIY hybrid valve headphone amplifier (SSMH)"/><link href="https://www.simonholywell.com/post/windows-10-shortcuts/?utm_source=atom_feed" rel="related" type="text/html" title="Windows 10 shortcuts"/><link href="https://www.simonholywell.com/post/jest-date-mocking/?utm_source=atom_feed" rel="related" type="text/html" title="Jest Date mocking"/><link href="https://www.simonholywell.com/post/yarn-npm-wsl/?utm_source=atom_feed" rel="related" type="text/html" title="Yarn and NPM on WSL"/><id>https://www.simonholywell.com/post/duty-free-with-trs-for-australians/</id><author><name>Simon Holywell</name></author><published>2023-12-05T14:52:58+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>In a departure from common international practices, Australia allows both residents and travellers duty-free purchases under the Tourist Refund Scheme. Buy the goods, get an invoice and you can claim the duty back on the purchase as you depart. Even if you plan to return to Australia with the purchased goods, you can still claim back the tax.</summary><content type="html"><![CDATA[<h2 id="introduction">Introduction</h2>
<p>In a departure from common international practices, Australia allows both residents and travellers duty-free purchases under the <a href="https://www.abf.gov.au/entering-and-leaving-australia/tourist-refund-scheme" title="Tourist Refund Scheme (TRS)">Tourist Refund Scheme (TRS)</a>.
Even if you plan to return to Australia with the purchased goods, you can still claim back the tax.</p>
<p>I dropped my phone before a recent overseas trip and so I claimed back the duty on its replacement when I travelled.
This made the phone slightly cheaper to purchase outright and somewhat softened the blow of breaking a 9-month-old phone.</p>
<p>When travelling overseas it is possible to claim back the tax on purchases made within Australia totalling $300 or more including GST using the Tourist Refund Scheme (TRS).
With an invoice and an international boarding pass you can claim the tax back even if you have already opened the packaging or started using the item.</p>
<p>This post recounts my latest TRS experience, but keep in mind that rules and regulations can change, so it&rsquo;s advisable to check with <a href="https://www.abf.gov.au/entering-and-leaving-australia/tourist-refund-scheme" title="Tourist Refund Scheme (TRS)">Australian Border Force (ABF)</a> beforehand.</p>
<h2 id="what-you-need-to-make-a-claim">What you need to make a claim</h2>
<p>You must purchase the goods within 60 days of departure, obtain a tax invoice and spend at least $300 including GST.
It is possible to buy the goods in multiple transactions so long as the total of all invoices for each retailer is $300 or more.</p>
<p>You could buy three different items from JB HiFi on three different invoices so long as all the ABNs matched across all three invoices.</p>
<p>&ldquo;You cannot claim on goods wholly or partially consumed in Australia such as food, drinks, health supplements and perfumes&rdquo; (<a href="https://www.abf.gov.au/entering-and-leaving-australia/tourist-refund-scheme" title="Tourist Refund Scheme (TRS)">Tourist Refund Scheme: Common Questions</a>). This also only works for goods purchased in Australia from an Australian business.</p>
<p>You should make sure that you have:</p>
<ul>
<li>the article/goods you are claiming for (you can even use it beforehand)</li>
<li>passport</li>
<li>boarding pass/proof of international travel</li>
<li>original invoice (in good condition) with
<ul>
<li>an <a href="https://business.gov.au/registrations/register-for-an-australian-business-number-abn" title="Australian Business Number (ABN)">ABN</a>, retailer name and address</li>
<li>your name (and only your name) as it appears in your passport</li>
<li>description of the goods</li>
<li>the amount of GST paid</li>
<li>the date of the purchase</li>
</ul>
</li>
</ul>
<p>For more details on this you should check the <a href="https://www.abf.gov.au/entering-and-leaving-australia/tourist-refund-scheme" title="Tourist Refund Scheme (TRS)">Australian Border Force TRS page</a> and the associated <a href="https://www.abf.gov.au/entering-and-leaving-australia/tourist-refund-scheme/trs-common-questions" title="Tourist Refund Scheme Common Questions">Common Questions page</a>.</p>
<p>I bought a phone and used it for over a week before flying out and claiming the duty on it.
Importantly, just the phone was required at claim time - you do not need the original packaging - just the item you are claiming on so &ldquo;long as the officer can verify the goods against the corresponding tax invoice when the TRS claim is processed&rdquo; (<a href="https://www.abf.gov.au/entering-and-leaving-australia/tourist-refund-scheme/trs-common-questions" title="Tourist Refund Scheme Common Questions">TRS Common Questions</a>).</p>
<p>In some cases it is possible to put the goods in your checked luggage at the airport or where they must be handled as dangerous goods, but it is best to have them with you at the time of the claim.
This way the border agent can sight the goods and verify them against your invoices.
It has been a source of <a href="https://www.abf.gov.au/newsroom-subsite/Pages/Two-charged-over-alleged-duty-free-goods-scam.aspx" title="Two charged over alleged duty free goods scam">spurious claims</a> and <a href="https://www.sbs.com.au/news/article/over-500-million-lost-as-australians-rort-tourist-gst-refund-scheme/c1otlj0fl">fraud</a> in the past so having it handy to show them is a good idea.</p>
<h2 id="how-much-will-you-get-back">How much will you get back</h2>
<p>Before making a purchase you can calculate the amount that you will get back by taking the total price and dividing that by 11 (assuming <a href="https://www.ato.gov.au/businesses-and-organisations/gst-excise-and-indirect-taxes/gst/how-gst-works" title="ATO: How GST works">GST</a> is still at the current rate of 10%).
For example, with a purchase amount of $1,600 it would be a refund of $145.45 ($1,600 / 11 = $145.45).</p>
<p>There is also a <a href="https://moneysmart.gov.au/work-and-tax/gst-calculator" title="GST calculator on the Moneysmart website">GST calculator</a> on the Australian government Moneysmart financial advice website.</p>
<p>After the purchase you can refer to the GST amount indicated on the invoice for the product to determine how much you stand to claim back.</p>
<h2 id="how-to-claim">How to claim</h2>
<p>On the day of departure you need to find the TRS desk at the airport with time to spare as all claims need to be processed no later than 30 minutes before your flight.
Depending on your luck there can be long queues for the TRS service so it is a good idea to complete this step as soon as you have cleared security.</p>
<p>It is best to fill out the <a href="https://www.abf.gov.au/entering-and-leaving-australia/tourist-refund-scheme/use-our-trs-apps" title="Tourist Refund Scheme: claim using their apps">claims online</a> beforehand and you might be able to use a dedicated queue, which could well be quicker.
This is especially true where you have multiple invoices.
If you don&rsquo;t and they are busy then they may ask you to step out of line, complete the claim online and then return to the back of the queue.</p>
<p>I only had one and they processed it at the desk, but he reminded me to use their phone apps or the website in future.
He also asked me to show him the phone I had bought.
This was simply a visual check and he did not even hold the phone let alone check the <a href="https://en.wikipedia.org/wiki/International_Mobile_Equipment_Identity" title="IMEI (International Mobile Equipment Identity)">IMEI</a> number against the invoice.</p>
<p>The staff you are claiming from here are Australian Border Force officers - in fact I saw the same officer that processed my claim checking passports on my return to Australia.</p>
<p>Keep the receipt you are issued for the refund by the officer in case you need it upon your return to Australia.
I just tucked it into my Australian passport so I would have it handy at arrivals.</p>
<h2 id="when-you-return">When you return</h2>
<p>If you bought the items as gifts for family overseas and the items are not returning with you then the usual border process applies, but if you do bring the items back into the country with you then you might need to declare them.</p>
<p>On the <a href="https://www.abf.gov.au/entering-and-leaving-australia/crossing-the-border/at-the-border/incoming-passenger-card-(ipc)" title="Incoming Passenger Card (IPC)">Incoming Passenger Card (IPC)</a> you must declare that you have goods that you purchased tax-free in Australia if the total of all goods you are returning with is over $900.
That is all goods, which means those purchased during the trip and those you claimed under TRS at the point of departure.
At the time of writing this is completed on the first page of the card as question 3 under &ldquo;Are you bringing into Australia:&rdquo;.</p>
<p>Don&rsquo;t forget that this is effectively statutory declaration/affidavit and the penalties for falsify or incorrectly completing it can be high.
It is definitely cheaper to declare and pay back any GST owing than to get caught mis-declaring and cop a fine.</p>
<p>As you pass through the border control desks at the airport you will be asked why you have declared and you need to tell them you made a TRS claim.
I simply said that I had claimed for a phone on departure and the border officer directed me to the exit.
That was it.
I did not need to pay any tax back or, in this case, even show the goods in question on return.</p>
<p>If you do get stopped and they check the value of the goods then it is important to know that you cannot bring more than <a href="https://www.abf.gov.au/entering-and-leaving-australia/duty-free" title="Australian Border Force: Duty free">$900 of general goods into the country</a> duty free as an adult and $450 as a child.</p>
<h2 id="pooling-your-duty-free-allowance-with-others">Pooling your duty-free allowance with others</h2>
<p>When travelling with family you can pool your goods allowance so for two adults travelling together that is $1,800 for example.
This is where a family is defined as:</p>
<blockquote>
<p>A family includes a person and his or her de facto partner (including same-sex couples) and any of their children under 18 years of age; or a husband and wife, and any of their children.</p>
</blockquote>
<h2 id="paying-back-the-duty">Paying back the duty</h2>
<p>If you have claimed over your allowance then you may have to pay back the GST that you claimed through the Tourist Refund Scheme on arrival in Australia.</p>
<p><a href="https://forums.whirlpool.net.au/archive/713473" title="TRS claims discussed on Whirlpool">Anecdotal evidence</a> suggests that unless you&rsquo;re a regular customer or otherwise flagged for high value items that, generally, the border officers will allow you through without checking too thoroughly.
That is not to say they won&rsquo;t check and you should be prepared to pay back the GST if you&rsquo;ve brought in more than the allowance.</p>
<p>It should be noted that despite what forum users might write to the contrary there is in fact no consideration for depreciation on the items when they return.
You will pay back the GST amount that you claimed on the item.</p>
<p>If the item is over the allowance then you will pay back all the GST on that item or items exceeding the allowance.
You cannot just pay back the GST on the amount that exceeds the duty-free allowance.</p>
<p>So in the case of a single person with a phone that cost $1,500 including GST originally ($1,363.64 excluding GST) they would pay back the full GST amount of $136.36 because the total excluding GST exceeds $900.
They could not just pay back the GST amount on the portion of the price over $900 and they would need to pay the whole GST amount.
However, if the item was $990 including GST ($900 excluding GST) then on return you would not need to pay or declare (so long as it was the only duty-free item you had in your possession) because at the time of importation it is deemed to be $900 for tax purposes.</p>
<p>In my case I had pooled my allowance with my partner and the phone was well within that combined duty-free allowance should they have checked.</p>
<h2 id="fly-safe">Fly safe</h2>
<p>Of course, it goes without saying, that I am not a border agent or a specialist in tax matters so you should <a href="https://www.abf.gov.au/entering-and-leaving-australia/tourist-refund-scheme" title="Tourist Refund Scheme (TRS)">verify everything beforehand</a> and <a href="https://www.abf.gov.au/entering-and-leaving-australia/duty-free" title="Australian Border Force: Duty free">make your own decisions</a>.</p>
<p>Thats it!
Have a great flight and enjoy the little extra bit of spending money for your holiday.</p>
]]></content><category scheme="taxonomy:Categories" term="travel" label="Travel"/><category scheme="taxonomy:Tags" term="travel" label="travel"/><category scheme="taxonomy:Tags" term="tax" label="tax"/><category scheme="taxonomy:Tags" term="gst" label="gst"/></entry><entry xml:base="docker-cross-compilation"><title type="html">Docker cross-compilation</title><link href="https://www.simonholywell.com/post/docker-cross-compilation/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/diy-hybrid-valve-amplifier/?utm_source=atom_feed" rel="related" type="text/html" title="DIY hybrid valve headphone amplifier (SSMH)"/><link href="https://www.simonholywell.com/post/windows-10-shortcuts/?utm_source=atom_feed" rel="related" type="text/html" title="Windows 10 shortcuts"/><link href="https://www.simonholywell.com/post/jest-date-mocking/?utm_source=atom_feed" rel="related" type="text/html" title="Jest Date mocking"/><link href="https://www.simonholywell.com/post/yarn-npm-wsl/?utm_source=atom_feed" rel="related" type="text/html" title="Yarn and NPM on WSL"/><link href="https://www.simonholywell.com/post/making-rope-working-fids/?utm_source=atom_feed" rel="related" type="text/html" title="Making rope working fids"/><id>https://www.simonholywell.com/post/docker-cross-compilation/</id><author><name>Simon Holywell</name></author><published>2023-11-17T17:11:58+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Explore the advantages of cross-compiling in Docker whilst working through a specific case involving a Node.js project using pkg, aiming for a Linux ARM64 architecture in the Docker build.</summary><content type="html"><![CDATA[<p>Every so often it can be really helpful to cross compile a docker image or stage in a multi-stage build.
This is especially useful where the programming language you are using supports cross-platforms builds or the tooling you are using for compilation provides good support for it.</p>
<p>Recently, I had this need when I was attempting to create build of a project written in node using pkg.
Although I did not end up going this route in the end, I think the principal is interesting enough to talk about.</p>
<p>No matter the underlying platform I wanted to ensure I was getting a Linux ARM64 architecture during the docker build.
You can use the same technique to build on other architectures and even more than one providing that the image you have chosen supports them.</p>
<p>Here I am using the official <a href="https://hub.docker.com/_/node/" title="Official node image on Docker Hub">node image</a> and it currently supports <code>amd64</code>, <code>arm32v6</code>, <code>arm32v7</code>, <code>arm64v8</code>, <code>ppc64le</code> and <code>s390x</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Dockerfile" data-lang="Dockerfile"><span class="line"><span class="cl"><span class="k">FROM</span><span class="s"> --platform=linux/amd64 node:18 as build</span><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span><span class="k">RUN</span> yarn install --frozen-lockfile<span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span><span class="k">RUN</span> npx pkg ./index.js<span class="err">
</span></span></span></code></pre></div><p>Note the inclusion of the <code>--platform=linux/amd64</code> argument to the <code>FROM</code> directive in the Dockerfile.</p>
<p>For more information the docker documentation has a <a href="https://docs.docker.com/build/building/multi-platform/" title="Multi-platform images">helpful page</a> that covers this functionality in more depth.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="docker" label="docker"/><category scheme="taxonomy:Tags" term="node" label="node"/></entry><entry xml:base="diy-hybrid-valve-amplifier"><title type="html">DIY hybrid valve headphone amplifier (SSMH)</title><link href="https://www.simonholywell.com/post/diy-hybrid-valve-amplifier/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/windows-10-shortcuts/?utm_source=atom_feed" rel="related" type="text/html" title="Windows 10 shortcuts"/><link href="https://www.simonholywell.com/post/jest-date-mocking/?utm_source=atom_feed" rel="related" type="text/html" title="Jest Date mocking"/><link href="https://www.simonholywell.com/post/yarn-npm-wsl/?utm_source=atom_feed" rel="related" type="text/html" title="Yarn and NPM on WSL"/><link href="https://www.simonholywell.com/post/making-rope-working-fids/?utm_source=atom_feed" rel="related" type="text/html" title="Making rope working fids"/><link href="https://www.simonholywell.com/post/testing-typescript-types/?utm_source=atom_feed" rel="related" type="text/html" title="Testing TypeScript types"/><id>https://www.simonholywell.com/post/diy-hybrid-valve-amplifier/</id><author><name>Simon Holywell</name></author><published>2022-02-12T23:36:39+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>I made some circuit diagrams for the various versions of the Starving Student Millet Hybrid amplifier, which is a tube/valve headphone amplifier you can build yourself relatively easily for fun.</summary><content type="html"><![CDATA[<p>A number of years ago I made my own 12AU7 version of the <a href="http://pmillett.com/starving.htm" title="SSMH homepage">Starving Student Millet Hybrid</a> headphone amplifier.
When the designs were first published using a 19J6 tube it was relatively easy to find them, but in recent years this has become much harder.
To workaround this a number of designs using various other valves have been posted on forums.</p>
<p>Trawling through hundreds of pages of posts to find the details was tiresome and as I enjoyed the project I wanted to give back to the community.
So, two years ago I created schematics of the variations and <a href="https://github.com/treffynnon/ssmh" title="SSMH schematics and variations">published them to GitHub</a>.</p>
<p>I used KiCad to create the diagrams and published both the source files and rendered schematics.
You can <a href="https://github.com/treffynnon/ssmh" title="SSMH schematics and variations">download the variations and diagrams from GitHub</a>.
Alternatively, you can <a href="https://github.com/treffynnon/ssmh/archive/refs/heads/master.zip" title="SSMH schematics and variations as a zip file">download the lot as a zip file</a>.</p>
<p><img src="amp.jpg" alt="My SSMH amplifier" title="My 12AU7 SSMH amplifier"></p>
]]></content><category scheme="taxonomy:Categories" term="electronics" label="Electronics"/><category scheme="taxonomy:Tags" term="ssmh" label="ssmh"/><category scheme="taxonomy:Tags" term="starving-student-millet-hybrid" label="starving student millet hybrid"/><category scheme="taxonomy:Tags" term="hybrid-amplifier" label="hybrid amplifier"/><category scheme="taxonomy:Tags" term="headphone-amplifier" label="headphone amplifier"/></entry><entry xml:base="windows-10-shortcuts"><title type="html">Windows 10 shortcuts</title><link href="https://www.simonholywell.com/post/windows-10-shortcuts/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2010/04/agavi-on-the-auzre-platform/?utm_source=atom_feed" rel="related" type="text/html" title="Agavi: Agavi on the Azure Platform"/><link href="https://www.simonholywell.com/post/2009/04/samba-file-share-over-ssh-tunnel/?utm_source=atom_feed" rel="related" type="text/html" title="Samba File Share Over SSH Tunnel"/><link href="https://www.simonholywell.com/post/2009/02/a-good-windows-development-environment-and-ubuntu-virtua/?utm_source=atom_feed" rel="related" type="text/html" title="A Good Windows Development Environment and Ubuntu Virtualbox"/><link href="https://www.simonholywell.com/post/2009/01/linux-to-windows-server-migrating-and-securing-your-cron/?utm_source=atom_feed" rel="related" type="text/html" title="Linux to Windows Server - Migrating and securing your crontab"/><link href="https://www.simonholywell.com/post/2008/06/windows-cron-jobs-using-schtasks-or-at/?utm_source=atom_feed" rel="related" type="text/html" title="Windows Cron Jobs using Scheduled Tasks"/><id>https://www.simonholywell.com/post/windows-10-shortcuts/</id><author><name>Simon Holywell</name></author><published>2020-11-14T13:59:23+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Here are some of the window management shortcuts that I have discovered and found very useful having moved to working on a Windows 10 machine.</summary><content type="html"><![CDATA[<p>Recently, I have moved from a MacBook Pro to a Dell XPS running Windows 10 with Window&rsquo;s Subsystem for Linux (WSL2) for my main workstation.
This means learning new software and therefore keyboard shortcuts.</p>
<p>Here are some of the window management shortcuts that I have discovered and found very useful.</p>
<p>To cycle through the three window states (Minimized, Restore and Maximized) for a given window/application:</p>
<pre tabindex="0"><code>Win + Ctrl + Up arrow
Win + Ctrl + Down arrow
</code></pre><p>Force a window to a SnapZone (Windows 10 ships with a 50% split on each monitor so this shortcut will push an application into one):</p>
<pre tabindex="0"><code>Win + Left arrow
Win + Right arrow
</code></pre><p>Move a window to another physical monitor:</p>
<pre tabindex="0"><code>Win + Shift + Left arrow
Win + Shift + Right arrow
</code></pre><p>Jump to another virtual desktop/workspace:</p>
<pre tabindex="0"><code>Win + Ctrl + Left arrow
Win + Ctrl + Right arrow
</code></pre><p>Give a virtual desktop/workspace a vanity name:</p>
<pre tabindex="0"><code>Win + Ctrl + R
</code></pre><p>Move a window to another virtual desktop/workspace:</p>
<pre tabindex="0"><code>Win + Alt + Left arrow
Win + Alt + Right arrow
</code></pre><p>To open an application As Administrator you can hold down <code>Ctrl</code> + <code>Shift</code> whilst pressing <code>Enter</code>. The UAC dialogue will show, press <code>Right arrow</code> to move to the confirm button and press <code>Enter</code> again.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="windows" label="windows"/></entry><entry xml:base="jest-date-mocking"><title type="html">Jest Date mocking</title><link href="https://www.simonholywell.com/post/jest-date-mocking/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/testing-typescript-types/?utm_source=atom_feed" rel="related" type="text/html" title="Testing TypeScript types"/><link href="https://www.simonholywell.com/post/advanced-typescript-types/?utm_source=atom_feed" rel="related" type="text/html" title="Advanced TypeScript types"/><link href="https://www.simonholywell.com/post/typescript-constructor-type/?utm_source=atom_feed" rel="related" type="text/html" title="TypeScript constructors and generic types"/><link href="https://www.simonholywell.com/post/2013/11/conditionally-loaded-responsive-content/?utm_source=atom_feed" rel="related" type="text/html" title="Conditionally loaded responsive content on the client side"/><link href="https://www.simonholywell.com/post/2010/08/firefox-radio-buttons/?utm_source=atom_feed" rel="related" type="text/html" title=""/><id>https://www.simonholywell.com/post/jest-date-mocking/</id><author><name>Simon Holywell</name></author><published>2020-09-10T17:22:23+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>The release of Jest 26 brought a new timer faking interface, which now supports Date mocks. I couldn&amp;rsquo;t readily find any documentation for this feature so, here is how I used in a project recently.</summary><content type="html"><![CDATA[<p>The release of <a href="https://jestjs.io/blog/2020/05/05/jest-26#new-fake-timers" title="Release announcement blog post for Jest 26">Jest 26</a> brought a new timer faking interface, which now supports Date mocks.
I couldn&rsquo;t readily find any documentation for this feature so, here is how I used in a project recently.</p>
<p>If you are not already running Jest 26 then upgrade and if you&rsquo;re using TypeScript don&rsquo;t forget to update the <code>@types</code> package at the same time.</p>
<p>First, you need to enable the new timer handling in your test file as it is currently behind a feature flag.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="nx">jest</span><span class="p">.</span><span class="nx">useFakeTimers</span><span class="p">(</span><span class="s2">&#34;modern&#34;</span><span class="p">);</span>
</span></span></code></pre></div><p>When Jest 27 is released then it should be the default - you&rsquo;ll still need to enable fake timers of course!
At that point you should be able to get away with the following:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="nx">jest</span><span class="p">.</span><span class="nx">useFakeTimers</span><span class="p">();</span>
</span></span></code></pre></div><p>Now to mock the <code>Date</code> in the tests I used the <code>jest.setSystemTime()</code> function.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="nx">jest</span><span class="p">.</span><span class="nx">setSystemTime</span><span class="p">(</span><span class="k">new</span> <span class="nb">Date</span><span class="p">(</span><span class="s2">&#34;2012-10-10&#34;</span><span class="p">));</span> <span class="c1">// a Date object
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">jest</span><span class="p">.</span><span class="nx">setSystemTime</span><span class="p">(</span><span class="mi">1349852318000</span><span class="p">);</span> <span class="c1">// same date as a unix time in milliseconds
</span></span></span></code></pre></div><p>Any call to <code>new Date()</code> or <code>Date.now()</code> will now return the hardcoded time we set above.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="nx">it</span><span class="p">(</span><span class="s2">&#34;should return the hardcoded date&#34;</span><span class="p">,</span> <span class="p">()</span> <span class="o">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">jest</span><span class="p">.</span><span class="nx">setSystemTime</span><span class="p">(</span><span class="mi">1349852318268</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="nx">expect</span><span class="p">(</span><span class="k">new</span> <span class="nb">Date</span><span class="p">().</span><span class="nx">valueOf</span><span class="p">()).</span><span class="nx">toBe</span><span class="p">(</span><span class="mi">1349852318268</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><p>This will affect any code that uses <code>Date</code> that is called after you&rsquo;ve set the time - either in the test file itself or in the subject code that is under test (your application code for example).</p>
<p>You can still get to the real time in the test if you need it with <code>jest.getRealSystemTime()</code>.
Here is an example test that you can try out in Jest that shows this in action.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="nx">it</span><span class="p">(</span><span class="s2">&#34;should return the hardcoded date&#34;</span><span class="p">,</span> <span class="p">()</span> <span class="o">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">jest</span><span class="p">.</span><span class="nx">setSystemTime</span><span class="p">(</span><span class="mi">1349852318268</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="nx">expect</span><span class="p">(</span><span class="k">new</span> <span class="nb">Date</span><span class="p">().</span><span class="nx">valueOf</span><span class="p">()).</span><span class="nx">toBe</span><span class="p">(</span><span class="mi">1349852318268</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="nx">expect</span><span class="p">(</span><span class="nx">jest</span><span class="p">.</span><span class="nx">getRealSystemTime</span><span class="p">().</span><span class="nx">valueOf</span><span class="p">()).</span><span class="nx">not</span><span class="p">.</span><span class="nx">toBe</span><span class="p">(</span><span class="mi">1349852318268</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><p>You can also remove the mocking entirely by calling <code>jest.useRealTimers()</code>.
This is something you might like to do in a <code>afterEach()</code> function perhaps.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="javascript" label="javascript"/><category scheme="taxonomy:Tags" term="typescript" label="typescript"/></entry><entry xml:base="yarn-npm-wsl"><title type="html">Yarn and NPM on WSL</title><link href="https://www.simonholywell.com/post/yarn-npm-wsl/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/making-rope-working-fids/?utm_source=atom_feed" rel="related" type="text/html" title="Making rope working fids"/><link href="https://www.simonholywell.com/post/testing-typescript-types/?utm_source=atom_feed" rel="related" type="text/html" title="Testing TypeScript types"/><link href="https://www.simonholywell.com/post/advanced-typescript-types/?utm_source=atom_feed" rel="related" type="text/html" title="Advanced TypeScript types"/><link href="https://www.simonholywell.com/post/typescript-constructor-type/?utm_source=atom_feed" rel="related" type="text/html" title="TypeScript constructors and generic types"/><link href="https://www.simonholywell.com/post/the-lambda-calculus-for-developers/?utm_source=atom_feed" rel="related" type="text/html" title="The lambda calculus for developers"/><id>https://www.simonholywell.com/post/yarn-npm-wsl/</id><author><name>Simon Holywell</name></author><published>2020-07-30T17:18:31+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Old versions of WSL can lead to issues with file system permissions with Node. Upgrading the version of WSL can solve this issue for you.</summary><content type="html"><![CDATA[<p>If you are running Node in Windows Subsystem for Linux then you may come across errors like the following when running <code>yarn</code> or <code>npm install</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-plain" data-lang="plain"><span class="line"><span class="cl">EPERM: operation not permitted, copyfile &#39;/home/simon/.cache/yarn/v6/npm-@babel-code-frame-7.10.4-168da1a36e90da68ae8d49c0f1b48c7c6249213a-integrity/node_modules/@babel/code-frame/package.json&#39; -&gt; &#39;/mnt/c/Users/simon/Documents/projects/project/node_modules/@babel/code-frame/package.json&#39;
</span></span></code></pre></div><p>These errors are likely being triggered because you need to upgrade the version of WSL that you are running.
To verify the version you can list the installed distros.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">wsl.exe -l -v
</span></span></code></pre></div><p>You can drop the <code>.exe</code> part of the command if you&rsquo;re using PowerShell or Command Prompt, but you don&rsquo;t have to.
It is only neccessary when you&rsquo;re in a WSL bash prompt.</p>
<p>If the distribution you are using has a version of 1 then you can upgrade it - make sure your replace <code>Ubuntu-20.04</code> with the name of the distribution you&rsquo;re using.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">wsl.exe --set-version Ubuntu-20.04 <span class="m">2</span>
</span></span></code></pre></div><p>To ensure that any further distributions use WSL2 you can also update the default installation version:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">wsl.exe --set-default-version <span class="m">2</span>
</span></span></code></pre></div><p>Finally, when you listed the versions (<code>wsl.exe -l -v</code>) you may have noticed there was an asterisk (<code>*</code>) beside one distribution - this indicates that it is the default distribution.
You can change this to your preferred distribution (again change the distribution name to match the distribution you are using).</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">wsl.exe --set-default Ubuntu-20.04
</span></span></code></pre></div>]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="wsl" label="wsl"/><category scheme="taxonomy:Tags" term="yarn" label="yarn"/><category scheme="taxonomy:Tags" term="npm" label="npm"/></entry><entry xml:base="making-rope-working-fids"><title type="html">Making rope working fids</title><link href="https://www.simonholywell.com/post/making-rope-working-fids/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/testing-typescript-types/?utm_source=atom_feed" rel="related" type="text/html" title="Testing TypeScript types"/><link href="https://www.simonholywell.com/post/advanced-typescript-types/?utm_source=atom_feed" rel="related" type="text/html" title="Advanced TypeScript types"/><link href="https://www.simonholywell.com/post/typescript-constructor-type/?utm_source=atom_feed" rel="related" type="text/html" title="TypeScript constructors and generic types"/><link href="https://www.simonholywell.com/post/the-lambda-calculus-for-developers/?utm_source=atom_feed" rel="related" type="text/html" title="The lambda calculus for developers"/><link href="https://www.simonholywell.com/post/2017/09/search-and-replace-with-confirmation-in-bash/?utm_source=atom_feed" rel="related" type="text/html" title="Search and replace with confirmation in Bash"/><id>https://www.simonholywell.com/post/making-rope-working-fids/</id><author><name>Simon Holywell</name></author><published>2020-06-14T18:11:44+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Rope working fids make it easier to splice ropes, but they can be expensive to buy for a small DIY project. Here are some ideas of how to make your own fids and the required dimensions of each fid size.</summary><content type="html"><![CDATA[<p>If you want to splice ropes then a common tool is the <a href="https://amzn.to/3htlNwU">&ldquo;Selma&rdquo; fid</a>.
Essentially, it is a metal tube with a blunt point at one end.
There are other styles but this is the most common.</p>
<p>Rope is loaded into the rear of a fid and the pointed tip is used to work into and through rope.
In this way it can be used to splice rope much like a needle is used to stitch fabric.</p>
<p>You&rsquo;ll see that a lot of rope-work tutorials use fids and, crucially, fid lengths to describe the various techniques.
For limited hobbyist use <a href="https://amzn.to/2BXx6gz">fids are expensive</a> to purchase and I wanted to avoid the expenditure whilst teaching myself rope splicing.</p>
<p>A common work around is to buy metal knitting needles, cut them down to size and shape the rear to hold rope.
The trouble is finding the correct length can be difficult so I&rsquo;ve written this quick article to refer back to later.</p>
<p>You can find the appropriate fid length by taking the rope diameter and multiplying it by twenty-one (21).
The fid diameter is three-quarters (3/4) of the rope&rsquo;s diameter.
Finally, the short fid mark is made at three-quarters (3/4) of the fid&rsquo;s overall length from the pointed tip.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-plain" data-lang="plain"><span class="line"><span class="cl">   fid length
</span></span><span class="line"><span class="cl">|--------------|   = 21 x rope diameter
</span></span><span class="line"><span class="cl">&lt;==========|====
</span></span><span class="line"><span class="cl">           |---|   = 1/4 of fid length
</span></span><span class="line"><span class="cl">           `-&gt; short fid mark
</span></span></code></pre></div><p>So, if we&rsquo;re working with 10mm diameter rope (most rock climbing rope is some where between 10mm and 13mm):</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-plain" data-lang="plain"><span class="line"><span class="cl">Length:
</span></span><span class="line"><span class="cl">  21 x 10    = 210
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Diameter:
</span></span><span class="line"><span class="cl">  3/4 of 10, which is the same as
</span></span><span class="line"><span class="cl">  0.75 x 10  = 7.5
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Short fid mark:
</span></span><span class="line"><span class="cl">  3/4 of 210, which is the same as
</span></span><span class="line"><span class="cl">  0.75 x 210 = 157.5
</span></span></code></pre></div><p>The following measurements are all given in millimetres.</p>
<table>
<thead>
<tr>
<th>Rope diameter</th>
<th>Fid length</th>
<th>Fid diameter</th>
<th>Short fid mark</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>21</td>
<td>0.75</td>
<td>15.75</td>
</tr>
<tr>
<td>2</td>
<td>42</td>
<td>1.5</td>
<td>31.5</td>
</tr>
<tr>
<td>3</td>
<td>63</td>
<td>2.25</td>
<td>47.25</td>
</tr>
<tr>
<td>4</td>
<td>84</td>
<td>3</td>
<td>63</td>
</tr>
<tr>
<td>5</td>
<td>105</td>
<td>3.75</td>
<td>78.75</td>
</tr>
<tr>
<td>6</td>
<td>126</td>
<td>4.5</td>
<td>94.5</td>
</tr>
<tr>
<td>7</td>
<td>147</td>
<td>5.25</td>
<td>110.25</td>
</tr>
<tr>
<td>8</td>
<td>168</td>
<td>6</td>
<td>126</td>
</tr>
<tr>
<td>9</td>
<td>189</td>
<td>6.75</td>
<td>141.75</td>
</tr>
<tr>
<td>10</td>
<td>210</td>
<td>7.5</td>
<td>157.5</td>
</tr>
<tr>
<td>11</td>
<td>231</td>
<td>8.25</td>
<td>173.25</td>
</tr>
<tr>
<td>12</td>
<td>252</td>
<td>9</td>
<td>189</td>
</tr>
<tr>
<td>13</td>
<td>273</td>
<td>9.75</td>
<td>204.75</td>
</tr>
<tr>
<td>14</td>
<td>294</td>
<td>10.5</td>
<td>220.5</td>
</tr>
<tr>
<td>15</td>
<td>315</td>
<td>11.25</td>
<td>236.25</td>
</tr>
</tbody>
</table>
<p>That should be all the information you need to start making fids of your own.
You&rsquo;ll probably also need a pusher to force the fid through the rope.
This is a handle with a sturdy length of metal wire protruding from it.
When a fid gets stuck; the pusher can be used to exert force on the rear of the fid.</p>
<p>Where even this struggles you can use a loop of wire to pull the rope through with pliers instead of pushing it.
There are commercially available options here called <a href="https://amzn.to/2UFAIdS">needles</a> and the <a href="https://amzn.to/2C7t3yv">D-Splicer</a>.</p>
]]></content><category scheme="taxonomy:Tags" term="rope" label="rope"/><category scheme="taxonomy:Tags" term="diy" label="diy"/></entry><entry xml:base="testing-typescript-types"><title type="html">Testing TypeScript types</title><link href="https://www.simonholywell.com/post/testing-typescript-types/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/advanced-typescript-types/?utm_source=atom_feed" rel="related" type="text/html" title="Advanced TypeScript types"/><link href="https://www.simonholywell.com/post/typescript-constructor-type/?utm_source=atom_feed" rel="related" type="text/html" title="TypeScript constructors and generic types"/><link href="https://www.simonholywell.com/post/2013/11/conditionally-loaded-responsive-content/?utm_source=atom_feed" rel="related" type="text/html" title="Conditionally loaded responsive content on the client side"/><link href="https://www.simonholywell.com/post/2010/08/firefox-radio-buttons/?utm_source=atom_feed" rel="related" type="text/html" title=""/><link href="https://www.simonholywell.com/post/2010/04/jquery-ui-datepicker-in-dialogue/?utm_source=atom_feed" rel="related" type="text/html" title="jQuery UI Datepicker appearing below Dialog"/><id>https://www.simonholywell.com/post/testing-typescript-types/</id><author><name>Simon Holywell</name></author><published>2019-07-14T22:40:52+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>To make the construction and maintenance of more advanced types easier it can be helpful to write some tests that ensure their correct function. This sounds a little easier than it turns out to be.
As part of the ecosystem for TypeScript Microsoft have written and released the dtslint tool. It can be used to link and compile TypeScript types for static analysis and mostly serves to keep the @types/* packages in line.</summary><content type="html"><![CDATA[<p>To make the construction and maintenance of more advanced types easier it can be helpful to write
some tests that ensure their correct function. This sounds a little easier than it turns out to be.</p>
<p>As part of the ecosystem for TypeScript Microsoft have written and released the <a href="https://github.com/Microsoft/dtslint">dtslint</a>
tool. It can be used to link and compile TypeScript types for static analysis and mostly serves to
keep the <code>@types/*</code> packages in line.</p>
<p>Firstly, install the dependencies that we will need to test the types.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">npm install --save-dev dtslint conditional-type-checks
</span></span></code></pre></div><p>Then in the directory you wish to write your tests (the examples in this article use a directory
<code>./typings/__tests__</code> for this) - create a new file <code>index.d.ts</code> with the following contents:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="c1">// TypeScript Version: 3.3
</span></span></span><span class="line"><span class="cl"><span class="c1">// see https://github.com/Microsoft/dtslint#specify-a-typescript-version for more information
</span></span></span></code></pre></div><p>The first line lets dtslint know which TypeScript version you would like to test your types against.</p>
<p>In that same directory you will also need to include a <code>tsconfig.json</code> file like the following:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="c1">// this additional tsconfig is required by dtslint
</span></span></span><span class="line"><span class="cl"><span class="c1">// see: https://github.com/Microsoft/dtslint#typestsconfigjson
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;compilerOptions&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;module&#34;</span><span class="p">:</span> <span class="s2">&#34;commonjs&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;lib&#34;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&#34;es6&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;noImplicitAny&#34;</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;noImplicitThis&#34;</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;strictNullChecks&#34;</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;strictFunctionTypes&#34;</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;noEmit&#34;</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// If the library is an external module (uses `export`), this allows your test file to import &#34;mylib&#34; instead of &#34;./index&#34;.
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="c1">// If the library is global (cannot be imported via `import` or `require`), leave this out.
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="nt">&#34;baseUrl&#34;</span><span class="p">:</span> <span class="s2">&#34;.&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Finally, <code>dtslint</code> needs to be added to the configuration for tslint in the <code>tslint.json</code>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;extends&#34;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&#34;dtslint/dtslint.json&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;rules&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;no-useless-files&#34;</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;no-relative-import-in-test&#34;</span><span class="p">:</span> <span class="kc">false</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>You should now have a directory structure that looks something like the following:</p>
<pre tabindex="0"><code>typings
  `-- __tests__
    `-- index.d.ts
    `-- tsconfig.json
    `-- tslint.json
</code></pre><p>Now in your package.json file you can add a script to run the <code>dtslint</code> testing.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl">  <span class="s2">&#34;ts:dtslint&#34;</span><span class="err">:</span> <span class="s2">&#34;dtslint ./typings/__tests__&#34;</span><span class="err">,</span>
</span></span></code></pre></div><p>To make the next few steps easier to follow we&rsquo;ll quickly write out a new TypeScript type
in <code>./typings</code> - without this we wouldn&rsquo;t actually have anything to test! So, let&rsquo;s write
an implementation of the <code>Omit</code> type that now comes with the TypeScript standard library.</p>
<p>It uses both <code>Pick</code> and <code>Exclude</code>, which are also included with TypeScript. If they are new
to you then you might like to read my previous article
<a href="https://www.simonholywell.com/post/advanced-typescript-types/"><em>Advanced TypeScript Types</em></a> to get an introduction first.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="cm">/**
</span></span></span><span class="line"><span class="cl"><span class="cm"> * Remove all keys listed in K from the object T
</span></span></span><span class="line"><span class="cl"><span class="cm"> *
</span></span></span><span class="line"><span class="cl"><span class="cm"> * @example type MyType = Omit&lt;{ a: &#39;1&#39;; b: &#39;2&#39;; c: &#39;3&#39; }, &#39;a&#39; | &#39;b&#39;&gt;  // { c: &#39;3&#39; }
</span></span></span><span class="line"><span class="cl"><span class="cm"> */</span>
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="kr">type</span> <span class="nx">Omit</span><span class="p">&lt;</span><span class="nt">T</span> <span class="na">extends</span> <span class="na">object</span><span class="err">,</span> <span class="na">K</span> <span class="na">extends</span> <span class="na">keyof</span> <span class="na">T</span><span class="p">&gt;</span> <span class="o">=</span> <span class="nx">Pick</span><span class="o">&lt;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">T</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">Exclude</span><span class="p">&lt;</span><span class="nt">keyof</span> <span class="na">T</span><span class="err">,</span> <span class="na">K</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="o">&gt;</span><span class="p">;</span>
</span></span></code></pre></div><p>Now you are ready to write some tests for the types you have defined. <code>dtslint</code> uses the
<code>$ExpectType</code> annotation to state the type of the type expression on the next line.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="c1">// $ExpectType Pick&lt;{ a: &#34;1&#34;; b: &#34;2&#34;; c: &#34;3&#34;; }, &#34;c&#34;&gt;
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kr">type</span> <span class="nx">Test_01_Omit</span> <span class="o">=</span> <span class="nx">Omit</span><span class="o">&lt;</span><span class="p">{</span> <span class="nx">a</span><span class="o">:</span> <span class="s2">&#34;1&#34;</span><span class="p">;</span> <span class="nx">b</span><span class="o">:</span> <span class="s2">&#34;2&#34;</span><span class="p">;</span> <span class="nx">c</span><span class="o">:</span> <span class="s2">&#34;3&#34;</span> <span class="p">},</span> <span class="s2">&#34;a&#34;</span> <span class="o">|</span> <span class="s2">&#34;b&#34;</span><span class="o">&gt;</span><span class="p">;</span>
</span></span></code></pre></div><p><code>dtslint</code> will now evaluate the <code>Test_01_Omit</code> expression and determine the resultant type
to compare it against the type you&rsquo;ve specified with <code>$ExpectType</code>. If you&rsquo;re anticipating
your type to result in a type error then this can be asserted with <code>$ExpectError</code>. These
are documented in the <a href="https://github.com/microsoft/dtslint#write-tests">README</a> for the
<code>dtslint</code> project.</p>
<p>Next up we can use some of the assertion types from the <code>conditional-type-checks</code> package
we installed earlier to run some additional unit style tests of the type.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="kr">type</span> <span class="nx">Test_02_Omit</span> <span class="o">=</span>
</span></span><span class="line"><span class="cl">  <span class="o">|</span> <span class="nx">AssertTrue</span><span class="p">&lt;</span><span class="nt">IsExact</span><span class="err">&lt;</span><span class="na">Test_01_Omit</span><span class="err">,</span> <span class="p">{</span> <span class="na">c</span><span class="err">:</span> <span class="err">&#34;</span><span class="na">3</span><span class="err">&#34;</span> <span class="p">}&gt;</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="o">|</span> <span class="nx">AssertFalse</span><span class="p">&lt;</span><span class="nt">Has</span><span class="err">&lt;</span><span class="na">Test_01_Omit</span><span class="err">,</span> <span class="p">{</span> <span class="na">a</span><span class="err">:</span> <span class="err">&#34;</span><span class="na">1</span><span class="err">&#34;;</span> <span class="na">b</span><span class="err">:</span> <span class="err">&#34;</span><span class="na">2</span><span class="err">&#34;</span> <span class="p">}&gt;</span><span class="o">&gt;</span><span class="p">;</span>
</span></span></code></pre></div><p>Here the assertions state that the final evaluated expression only has one key <code>c</code> and does
not have the keys <code>a</code> or <code>b</code>. There are more conditional types that you can employ documented
in the <a href="https://github.com/dsherret/conditional-type-checks#type-checks">project README</a>.</p>
<p>Using both of these projects you can test the more advanced types that your projects employ to
ensure their continued success against various TypeScript versions.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="typescript" label="typescript"/><category scheme="taxonomy:Tags" term="javascript" label="javascript"/><category scheme="taxonomy:Tags" term="types" label="types"/></entry><entry xml:base="advanced-typescript-types"><title type="html">Advanced TypeScript types</title><link href="https://www.simonholywell.com/post/advanced-typescript-types/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/typescript-constructor-type/?utm_source=atom_feed" rel="related" type="text/html" title="TypeScript constructors and generic types"/><link href="https://www.simonholywell.com/post/2013/11/conditionally-loaded-responsive-content/?utm_source=atom_feed" rel="related" type="text/html" title="Conditionally loaded responsive content on the client side"/><link href="https://www.simonholywell.com/post/2010/08/firefox-radio-buttons/?utm_source=atom_feed" rel="related" type="text/html" title=""/><link href="https://www.simonholywell.com/post/2010/04/jquery-ui-datepicker-in-dialogue/?utm_source=atom_feed" rel="related" type="text/html" title="jQuery UI Datepicker appearing below Dialog"/><link href="https://www.simonholywell.com/post/the-lambda-calculus-for-developers/?utm_source=atom_feed" rel="related" type="text/html" title="The lambda calculus for developers"/><id>https://www.simonholywell.com/post/advanced-typescript-types/</id><author><name>Simon Holywell</name></author><published>2019-06-25T13:02:23+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>As TypeScript applications get more complex so do the types required to describe it. There are a number of built-in types that can be used for this purpose or combined to create more specialised types.
What I term modifying types such as Partial and Required are included in the language and I will quickly cover these first to warm up for the deeper types we&amp;rsquo;ll address later.
This article will quickly move on to focus on the slightly more advanced types beginning with Extract.</summary><content type="html"><![CDATA[<p>As TypeScript applications get more complex so do the types required to describe it. There are a number
of built-in types that can be used for this purpose or combined to create more specialised types.</p>
<p>What I term modifying types such as <code>Partial</code> and <code>Required</code> are included in the language and I will quickly
cover these first to warm up for the deeper types we&rsquo;ll address later.</p>
<p>This article will quickly move on to focus on the slightly more advanced types beginning with <code>Extract</code>. You
can see the source of the various types by looking at the <a href="https://github.com/microsoft/TypeScript/blob/master/lib/lib.es5.d.ts" title="TypeScript source code for lib.es5.d.ts">lib.es5.d.ts</a> declaration file inside
TypeScript.</p>
<h2 id="partial">Partial</h2>
<p>This generic type takes a single argument, an object type, and returns a new type where all the properties
are defined as optional.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="kr">interface</span> <span class="nx">UserRecord</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">name</span>: <span class="kt">string</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">age</span>: <span class="kt">number</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">type</span> <span class="nx">User</span> <span class="o">=</span> <span class="nx">Partial</span><span class="p">&lt;</span><span class="nt">UserRecord</span><span class="p">&gt;;</span>
</span></span></code></pre></div><p>With the application of the <code>Partial</code> type TypeScript will interpret <code>User</code> as the following type where
all properties are now optional.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="kr">type</span> <span class="nx">User</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">name?</span>: <span class="kt">string</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">age?</span>: <span class="kt">number</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div><p>You can also get a little creative and keep some properties required when applying partial.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="kr">type</span> <span class="nx">User</span> <span class="o">=</span> <span class="nx">Partial</span><span class="p">&lt;</span><span class="nt">UserRecord</span><span class="p">&gt;</span> <span class="o">&amp;</span> <span class="p">{</span> <span class="nx">name</span>: <span class="kt">UserRecord</span><span class="p">[</span><span class="s2">&#34;name&#34;</span><span class="p">]</span> <span class="p">};</span>
</span></span></code></pre></div><p>Whilst this works and the <code>name</code> property is now mandatory there are easier ways to do this that will
become apparent further into this article.</p>
<h2 id="required">Required</h2>
<p>Much like partial this type takes a single argument of an object type and returns a new type where all the
properties are required.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="kr">interface</span> <span class="nx">ComputerRecord</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">clockSpeed?</span>: <span class="kt">number</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">ram?</span>: <span class="kt">number</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="kr">type</span> <span class="nx">Computer</span> <span class="o">=</span> <span class="nx">Required</span><span class="p">&lt;</span><span class="nt">ComputerRecord</span><span class="p">&gt;;</span>
</span></span></code></pre></div><p>Creates a new type with the following form when interpreted by TypeScript.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="kr">type</span> <span class="nx">Computer</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">clockSpeed</span>: <span class="kt">number</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">ram</span>: <span class="kt">number</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div><h2 id="readonly">Readonly</h2>
<p>Pretty much what it says on the tin; this type marks all the properties of an object type as readonly.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="kr">interface</span> <span class="nx">CarRecord</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">make</span>: <span class="kt">string</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">seats?</span>: <span class="kt">number</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="kr">type</span> <span class="nx">Car</span> <span class="o">=</span> <span class="nx">Readonly</span><span class="p">&lt;</span><span class="nt">CarRecord</span><span class="p">&gt;;</span>
</span></span></code></pre></div><p>Revealing a new TypeScript type that takes the following shape.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="kr">type</span> <span class="nx">Car</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">readonly</span> <span class="nx">make</span>: <span class="kt">string</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="kr">readonly</span> <span class="nx">seats?</span>: <span class="kt">number</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div><h2 id="record">Record</h2>
<p>This type is a little different to the three types that we&rsquo;ve already reviewed so far; it takes two
arguments. A union of keys and a type. With this information TypeScript will construct a new type that
includes each of these keys set to the supplied type.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="kr">type</span> <span class="nx">Building</span> <span class="o">=</span> <span class="nx">Record</span><span class="o">&lt;</span><span class="s2">&#34;streetNumber&#34;</span> <span class="o">|</span> <span class="s2">&#34;floors&#34;</span> <span class="o">|</span> <span class="s2">&#34;bedrooms&#34;</span><span class="p">,</span> <span class="kt">number</span><span class="o">&gt;</span><span class="p">;</span>
</span></span></code></pre></div><p>Which TypeScript will expand into the following type when it is interpreted.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="kr">type</span> <span class="nx">Building</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">streetNumber</span>: <span class="kt">number</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">floors</span>: <span class="kt">number</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">bedrooms</span>: <span class="kt">number</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div><p>Again, you can get a little creative with this type and do some things like this.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="kr">type</span> <span class="nx">Building</span> <span class="o">=</span> <span class="nx">Partial</span><span class="p">&lt;</span><span class="nt">Record</span><span class="err">&lt;&#34;</span><span class="na">streetNumber</span><span class="err">&#34;</span> <span class="err">|</span> <span class="err">&#34;</span><span class="na">floors</span><span class="err">&#34;</span> <span class="err">|</span> <span class="err">&#34;</span><span class="na">bedrooms</span><span class="err">&#34;,</span> <span class="na">number</span><span class="p">&gt;</span><span class="o">&gt;</span><span class="p">;</span>
</span></span></code></pre></div><p>Will create a type when interpreted that looks a lot like what you might write as:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="kr">type</span> <span class="nx">Building</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">streetNumber?</span>: <span class="kt">number</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">floors?</span>: <span class="kt">number</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">bedrooms?</span>: <span class="kt">number</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div><p>Another neat trick is to use <code>Record</code> to create types that include properties of multiple types.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="kr">type</span> <span class="nx">Plant</span> <span class="o">=</span> <span class="nx">Record</span><span class="o">&lt;</span><span class="s2">&#34;name&#34;</span> <span class="o">|</span> <span class="s2">&#34;family&#34;</span><span class="p">,</span> <span class="kt">string</span><span class="o">&gt;</span> <span class="o">&amp;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">Record</span><span class="o">&lt;</span><span class="s2">&#34;height&#34;</span> <span class="o">|</span> <span class="s2">&#34;age&#34;</span><span class="p">,</span> <span class="kt">number</span><span class="o">&gt;</span><span class="p">;</span>
</span></span></code></pre></div><p>That will create a type that will be interpreted into the following:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="kr">type</span> <span class="nx">Plant</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">name</span>: <span class="kt">string</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">family</span>: <span class="kt">string</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">height</span>: <span class="kt">number</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">age</span>: <span class="kt">number</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div><h2 id="extract-better-known-as-intersection">Extract (better known as intersection)</h2>
<p>Set notation: A∩B</p>
<p><img src="optim_drawing_extract.svg" alt="Extract venn diagram: includes a and b, but excludes x and z" title="Set A – B: includes a &amp; b, but excludes x and z"></p>
<p>Items that exist in both the first and second arguments to the type are kept, but unique items from
either side are dropped. This type essentially fills the role of an intersection between two types.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="kr">type</span> <span class="nx">T1</span> <span class="o">=</span> <span class="nx">Extract</span><span class="o">&lt;</span><span class="s2">&#34;a&#34;</span> <span class="o">|</span> <span class="s2">&#34;b&#34;</span> <span class="o">|</span> <span class="s2">&#34;x&#34;</span><span class="p">,</span> <span class="s2">&#34;a&#34;</span> <span class="o">|</span> <span class="s2">&#34;b&#34;</span> <span class="o">|</span> <span class="s2">&#34;z&#34;</span><span class="o">&gt;</span><span class="p">;</span> <span class="c1">// &#39;a&#39; | &#39;b&#39;
</span></span></span></code></pre></div><p>Describing the same operation in TypeScript code this type could be written using the in-built
<code>Array.prototype.filter()</code> function.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">t1</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&#34;a&#34;</span><span class="p">,</span> <span class="s2">&#34;b&#34;</span><span class="p">,</span> <span class="s2">&#34;x&#34;</span><span class="p">].</span><span class="nx">filter</span><span class="p">((</span><span class="nx">x</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">[</span><span class="s2">&#34;a&#34;</span><span class="p">,</span> <span class="s2">&#34;b&#34;</span><span class="p">,</span> <span class="s2">&#34;z&#34;</span><span class="p">].</span><span class="nx">includes</span><span class="p">(</span><span class="nx">x</span><span class="p">));</span> <span class="c1">// [&#39;a&#39;, &#39;b&#39;]
</span></span></span></code></pre></div><p>If you have a two union types and you want to the find the intersection then <code>Extract</code> is very useful.</p>
<h2 id="exclude-better-known-as-difference">Exclude (better known as difference)</h2>
<p>Set notation: A – B</p>
<p><img src="optim_drawing_exclude.svg" alt="Exclude venn diagram: includes x, but excludes a, b and z" title="Set A∩B: includes x, but excludes a, b and z"></p>
<p>Calculates the difference between two types (important to note that this is not the symmetrical difference).
Everything that exists in the first argument excluding all items that appear in the second argument will be
included in the resultant type.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="c1">// keep everything from the left excluding any from the right
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kr">type</span> <span class="nx">T2</span> <span class="o">=</span> <span class="nx">Exclude</span><span class="o">&lt;</span><span class="s2">&#34;a&#34;</span> <span class="o">|</span> <span class="s2">&#34;b&#34;</span> <span class="o">|</span> <span class="s2">&#34;x&#34;</span><span class="p">,</span> <span class="s2">&#34;a&#34;</span> <span class="o">|</span> <span class="s2">&#34;b&#34;</span> <span class="o">|</span> <span class="s2">&#34;z&#34;</span><span class="o">&gt;</span><span class="p">;</span> <span class="c1">// &#39;x&#39;
</span></span></span></code></pre></div><p>This can also be described by the following TypeScript implementation code.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">t2</span> <span class="o">=</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;a&#39;</span><span class="p">,</span> <span class="s1">&#39;b&#39;</span><span class="p">,</span> <span class="s1">&#39;x&#39;</span><span class="p">].</span><span class="nx">filter</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">  <span class="nx">x</span> <span class="o">=&gt;</span> <span class="o">!</span><span class="p">([</span><span class="s1">&#39;a&#39;</span><span class="p">,</span> <span class="s1">&#39;b&#39;</span><span class="p">,</span> <span class="s1">&#39;z&#39;</span><span class="p">].</span><span class="nx">includes</span><span class="p">(</span><span class="nx">x</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span> <span class="c1">// [&#39;x&#39;]
</span></span></span></code></pre></div><p>Exclude is used to narrow union types back down again. I am including the following code as a demonstration,
but it is not production ready code and in some ways takes the form of pseudocode.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="kr">enum</span> <span class="nx">ConfigType</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">INI</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">JSON</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">TOML</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">interface</span> <span class="nx">ConfigObject</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">name</span>: <span class="kt">string</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">port</span>: <span class="kt">number</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="kr">type</span> <span class="nx">JSONConfig</span> <span class="o">=</span> <span class="kt">string</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">type</span> <span class="nx">TOMLConfig</span> <span class="o">=</span> <span class="kt">string</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">type</span> <span class="nx">INIConfig</span> <span class="o">=</span> <span class="kt">string</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">type</span> <span class="nx">ENVConfig</span> <span class="o">=</span> <span class="nx">ConfigObject</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">type</span> <span class="nx">Config</span> <span class="o">=</span> <span class="nx">JSONConfig</span> <span class="o">|</span> <span class="nx">TOMLConfig</span> <span class="o">|</span> <span class="nx">INIConfig</span> <span class="o">|</span> <span class="nx">ENVConfig</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">type</span> <span class="nx">UnparsedConfig</span> <span class="o">=</span> <span class="nx">Exclude</span><span class="p">&lt;</span><span class="nt">Config</span><span class="err">,</span> <span class="na">ENVConfig</span> <span class="err">|</span> <span class="na">ConfigObject</span><span class="p">&gt;;</span>
</span></span><span class="line"><span class="cl"><span class="kr">type</span> <span class="nx">ParsedConfig</span> <span class="o">=</span> <span class="nx">Exclude</span><span class="p">&lt;</span><span class="nt">Config</span><span class="err">,</span> <span class="na">UnparsedConfig</span><span class="p">&gt;;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">loadJsonConfig</span><span class="p">(</span><span class="nx">cfg</span>: <span class="kt">JSONConfig</span><span class="p">)</span><span class="o">:</span> <span class="nx">ParsedConfig</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="nx">cfg</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">loadTomlConfig</span><span class="p">(</span><span class="nx">cfg</span>: <span class="kt">TOMLConfig</span><span class="p">)</span><span class="o">:</span> <span class="nx">ParsedConfig</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="nx">TOML</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="nx">cfg</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">loadIniConfig</span><span class="p">(</span><span class="nx">cfg</span>: <span class="kt">INIConfig</span><span class="p">)</span><span class="o">:</span> <span class="nx">ParsedConfig</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="nx">INI</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="nx">cfg</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">loadConfig</span><span class="p">(</span><span class="nx">cfg</span>: <span class="kt">UnparsedConfig</span><span class="p">)</span><span class="o">:</span> <span class="nx">ParsedConfig</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="p">(</span><span class="nx">isType</span><span class="p">(</span><span class="nx">ConfigType</span><span class="p">.</span><span class="nx">JSON</span><span class="p">,</span> <span class="nx">cfg</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nx">loadJsonConfig</span><span class="p">(</span><span class="nx">cfg</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nx">isType</span><span class="p">(</span><span class="nx">ConfigType</span><span class="p">.</span><span class="nx">TOML</span><span class="p">,</span> <span class="nx">cfg</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nx">loadTomlConfig</span><span class="p">(</span><span class="nx">cfg</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nx">isType</span><span class="p">(</span><span class="nx">ConfigType</span><span class="p">.</span><span class="nx">INI</span><span class="p">,</span> <span class="nx">cfg</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nx">loadIniConfig</span><span class="p">(</span><span class="nx">cfg</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h2 id="pick">Pick</h2>
<p>Set notation: A∩B</p>
<p><img src="optim_drawing_pick.svg" alt="Pick venn diagram: includes a and b, but excludes x" title="Set A – B: includes a &amp; b, but excludes x and z"></p>
<p>Similar to an intersection, but it is based on the keys defined in the first type argument. The second
argument is a list of the keys to copy into the new type.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="kr">type</span> <span class="nx">T3</span> <span class="o">=</span> <span class="nx">Pick</span><span class="o">&lt;</span><span class="p">{</span> <span class="nx">a</span>: <span class="kt">string</span><span class="p">;</span> <span class="nx">b</span>: <span class="kt">number</span><span class="p">;</span> <span class="nx">x</span>: <span class="kt">boolean</span> <span class="p">},</span> <span class="s2">&#34;a&#34;</span> <span class="o">|</span> <span class="s2">&#34;b&#34;</span><span class="o">&gt;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="c1">// { a: string, b: number }
</span></span></span></code></pre></div><p>Here is a very contrived example of a possible use for <code>Pick</code>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="kr">interface</span> <span class="nx">Config</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">host</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">uri</span>: <span class="kt">string</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="nx">port</span>: <span class="kt">number</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">};</span>
</span></span><span class="line"><span class="cl">  <span class="nx">authentication</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">oauth</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">uri</span>: <span class="kt">string</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">};</span>
</span></span><span class="line"><span class="cl">  <span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// these get config functions could be loading from the environment
</span></span></span><span class="line"><span class="cl"><span class="c1">// or different files etc in a real application. Here they are hard
</span></span></span><span class="line"><span class="cl"><span class="c1">// coded for demonstration purposes.
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kr">const</span> <span class="nx">getHostConfig</span> <span class="o">=</span> <span class="p">()</span><span class="o">:</span> <span class="nx">Pick</span><span class="p">&lt;</span><span class="nt">Config</span><span class="err">,</span> <span class="err">&#34;</span><span class="na">host</span><span class="err">&#34;</span><span class="p">&gt;</span> <span class="o">=&gt;</span> <span class="p">({</span>
</span></span><span class="line"><span class="cl">  <span class="nx">host</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">uri</span><span class="o">:</span> <span class="s2">&#34;http://example.org&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">port</span>: <span class="kt">1337</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">getAuthConfig</span> <span class="o">=</span> <span class="p">()</span><span class="o">:</span> <span class="nx">Pick</span><span class="p">&lt;</span><span class="nt">Config</span><span class="err">[&#34;</span><span class="na">authentication</span><span class="err">&#34;],</span> <span class="err">&#34;</span><span class="na">oauth</span><span class="err">&#34;</span><span class="p">&gt;</span> <span class="o">=&gt;</span> <span class="p">({</span>
</span></span><span class="line"><span class="cl">  <span class="nx">oauth</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">uri</span><span class="o">:</span> <span class="s2">&#34;http://example.org&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">main</span> <span class="o">=</span> <span class="p">(</span><span class="nx">cfg</span>: <span class="kt">Config</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// this is where you application code would probably be
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// assemble the final config object by piecing together
</span></span></span><span class="line"><span class="cl"><span class="c1">// the various parts that were loaded up from the env etc.
</span></span></span><span class="line"><span class="cl"><span class="c1">// and start the application
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">main</span><span class="p">({</span> <span class="p">...</span><span class="nx">getHostConfig</span><span class="p">(),</span> <span class="nx">authentication</span>: <span class="kt">getAuthConfig</span><span class="p">()</span> <span class="p">});</span>
</span></span></code></pre></div><h2 id="omit">Omit</h2>
<p>Set notation: A – B</p>
<p><img src="optim_drawing_omit.svg" alt="Omit venn diagram: includes x, but excludes a and b" title="Set A∩B: includes x, but excludes a, b and z"></p>
<p>Again, this type is similar to the <code>Exclude</code> type, but it takes an object type and a list of keys.
The keys indicate which properties should be dropped from the new object type.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="kr">type</span> <span class="nx">T4</span> <span class="o">=</span> <span class="nx">Omit</span><span class="o">&lt;</span><span class="p">{</span> <span class="nx">a</span>: <span class="kt">string</span><span class="p">;</span> <span class="nx">b</span>: <span class="kt">number</span><span class="p">;</span> <span class="nx">x</span>: <span class="kt">boolean</span> <span class="p">},</span> <span class="s2">&#34;a&#34;</span> <span class="o">|</span> <span class="s2">&#34;b&#34;</span><span class="o">&gt;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="c1">// { x: string }
</span></span></span></code></pre></div><p>This has recently been added to the set of types that come with TypeScript by default in 3.5,
but older code will need to implement this manually using code like the follow.</p>
<p>Notice how it builds upon two types that we&rsquo;ve already looked at - <code>Exclude</code> and <code>Pick</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="kr">export</span> <span class="kr">type</span> <span class="nx">Omit</span><span class="p">&lt;</span><span class="nt">T</span> <span class="na">extends</span> <span class="na">object</span><span class="err">,</span> <span class="na">K</span> <span class="na">extends</span> <span class="na">keyof</span> <span class="na">T</span><span class="p">&gt;</span> <span class="o">=</span> <span class="nx">Pick</span><span class="o">&lt;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">T</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">Exclude</span><span class="p">&lt;</span><span class="nt">keyof</span> <span class="na">T</span><span class="err">,</span> <span class="na">K</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="o">&gt;</span><span class="p">;</span>
</span></span></code></pre></div><p>Using the same example types as <code>Pick</code> we could have a function something like the following:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">startServer</span> <span class="o">=</span> <span class="p">(</span><span class="nx">cfg</span>: <span class="kt">Omit</span><span class="p">&lt;</span><span class="nt">Config</span><span class="err">,</span> <span class="err">&#34;</span><span class="na">authentication</span><span class="err">&#34;</span><span class="p">&gt;)</span> <span class="o">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">http</span><span class="p">.</span><span class="nx">listen</span><span class="p">(</span><span class="nx">cfg</span><span class="p">.</span><span class="nx">host</span><span class="p">.</span><span class="nx">port</span><span class="p">,</span> <span class="p">()</span> <span class="o">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;Started...&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div><h2 id="difference-symmetrical">Difference (symmetrical)</h2>
<p>Set notation: &lsquo;(A∩B) or (A∪B) - (A∩B)</p>
<p><img src="optim_drawing_difference.svg" alt="Difference venn diagram: includes x and z, but excludes a and b" title="Set '(A∩B) or (A∪B) - (A∩B): includes x and z, but excludes a and b"></p>
<p>Providing types for symmetrical difference is a little more difficult. This is where values
that are unique from both the left and right should be included in the resultant type.
Essentially this will lead to a final type that will be used in the following way.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="kr">type</span> <span class="nx">T5</span> <span class="o">=</span> <span class="nx">Difference</span><span class="o">&lt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">{</span> <span class="nx">a</span>: <span class="kt">number</span><span class="p">;</span> <span class="nx">b</span>: <span class="kt">number</span><span class="p">;</span> <span class="nx">x</span>: <span class="kt">number</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="p">{</span> <span class="nx">a</span>: <span class="kt">number</span><span class="p">;</span> <span class="nx">b</span>: <span class="kt">number</span><span class="p">;</span> <span class="nx">z</span>: <span class="kt">number</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="o">&gt;</span><span class="p">;</span> <span class="c1">// { x: number; z: number }
</span></span></span></code></pre></div><p>As I mentioned this is a fair bit more difficult than it sounds and there are a number of steps
required so hang in there.</p>
<p>To produce this we must first workout the difference between the keys in each of the input
types. We&rsquo;ll first write a key differencing type - <code>AMinusB</code>. This will take two object types
and keep all the keys of <code>A</code> that do not exist in <code>B</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="kr">export</span> <span class="kr">type</span> <span class="nx">AMinusB</span><span class="p">&lt;</span><span class="nt">A</span> <span class="na">extends</span> <span class="na">keyof</span> <span class="na">any</span><span class="err">,</span> <span class="na">B</span> <span class="na">extends</span> <span class="na">keyof</span> <span class="na">any</span><span class="p">&gt;</span> <span class="o">=</span> <span class="p">({</span>
</span></span><span class="line"><span class="cl">  <span class="p">[</span><span class="nx">P</span> <span class="k">in</span> <span class="nx">A</span><span class="p">]</span><span class="o">:</span> <span class="nx">P</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span> <span class="o">&amp;</span> <span class="p">{</span> <span class="p">[</span><span class="nx">P</span> <span class="k">in</span> <span class="nx">B</span><span class="p">]</span><span class="o">:</span> <span class="kt">never</span> <span class="p">}</span> <span class="o">&amp;</span> <span class="p">{</span> <span class="p">[</span><span class="nx">x</span>: <span class="kt">string</span><span class="p">]</span><span class="o">:</span> <span class="kt">never</span> <span class="p">})[</span><span class="nx">A</span><span class="p">];</span>
</span></span></code></pre></div><p>The set notation for this is A - B (as you would expect) and that makes this type is very similar
to one that we&rsquo;ve just explored - <code>Omit</code>. <code>AMinusB</code> is a little different in that it can take any
two objects and calculate the keys that exist in A, but not in B. Omit on the other hand dictates
that the keys it is supplied are on the object it is given.</p>
<p>To get the symmetrical difference of the keys we can execute the <code>AMinusB</code> type twice and join them
in a sum type.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="kr">export</span> <span class="kr">type</span> <span class="nx">SymmetricalKeyDiff</span><span class="p">&lt;</span><span class="nt">A</span> <span class="na">extends</span> <span class="na">object</span><span class="err">,</span> <span class="na">B</span> <span class="na">extends</span> <span class="na">object</span><span class="p">&gt;</span> <span class="o">=</span>
</span></span><span class="line"><span class="cl">  <span class="o">|</span> <span class="nx">AMinusB</span><span class="p">&lt;</span><span class="nt">keyof</span> <span class="na">A</span><span class="err">,</span> <span class="na">keyof</span> <span class="na">B</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="o">|</span> <span class="nx">AMinusB</span><span class="p">&lt;</span><span class="nt">keyof</span> <span class="na">B</span><span class="err">,</span> <span class="na">keyof</span> <span class="na">A</span><span class="p">&gt;;</span>
</span></span></code></pre></div><p>Note that the key lists are flipped between the two calls to <code>AMinusB</code> so as to get key difference
both ways - thus powering the &ldquo;symmetrical&rdquo; part of this difference type.</p>
<p>With these two key types we can now create the final differencing type that will take the keys and
apply them to an object type. Given what we&rsquo;ve already learned about the inbuilt types we know that
<code>Pick</code> takes an object type and a list of keys and will return a new object type with just the
specified properties/keys.</p>
<p>So, given <code>SymmetricalKeyDiff</code> and <code>Pick</code> we can create a symmetrical difference type. The input object
for <code>Pick</code> is the union of <code>A</code> and <code>B</code> and the list of keys is the <code>SymmetricalKeyDiff</code> of <code>A</code> and <code>B</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="kr">export</span> <span class="kr">type</span> <span class="nx">SymmetricalDiff</span><span class="p">&lt;</span><span class="nt">A</span> <span class="na">extends</span> <span class="na">object</span><span class="err">,</span> <span class="na">B</span> <span class="na">extends</span> <span class="na">object</span><span class="p">&gt;</span> <span class="o">=</span> <span class="nx">Pick</span><span class="o">&lt;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">A</span> <span class="o">&amp;</span> <span class="nx">B</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">SymmetricalKeyDiff</span><span class="p">&lt;</span><span class="nt">A</span><span class="err">,</span> <span class="na">B</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="o">&gt;</span><span class="p">;</span>
</span></span></code></pre></div><p>Putting this type into action looks something like this:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="kr">type</span> <span class="nx">T5</span> <span class="o">=</span> <span class="nx">SymmetricalDifference</span><span class="o">&lt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">{</span> <span class="nx">a</span>: <span class="kt">number</span><span class="p">;</span> <span class="nx">b</span>: <span class="kt">number</span><span class="p">;</span> <span class="nx">x</span>: <span class="kt">number</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="p">{</span> <span class="nx">a</span>: <span class="kt">number</span><span class="p">;</span> <span class="nx">b</span>: <span class="kt">number</span><span class="p">;</span> <span class="nx">z</span>: <span class="kt">string</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="o">&gt;</span><span class="p">;</span> <span class="c1">// { x: number; z: string }
</span></span></span></code></pre></div><h2 id="intersection">Intersection</h2>
<p>Using the same basic underlying types it is also possible to get the intersection of two object
types.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="kr">export</span> <span class="kr">type</span> <span class="nx">Intersection</span><span class="p">&lt;</span><span class="nt">A</span> <span class="na">extends</span> <span class="na">object</span><span class="err">,</span> <span class="na">B</span> <span class="na">extends</span> <span class="na">object</span><span class="p">&gt;</span> <span class="o">=</span> <span class="nx">Omit</span><span class="o">&lt;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">A</span> <span class="o">&amp;</span> <span class="nx">B</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">SymmetricalKeyDiff</span><span class="p">&lt;</span><span class="nt">A</span><span class="err">,</span> <span class="na">B</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="o">&gt;</span><span class="p">;</span>
</span></span></code></pre></div><p>Put into practice this type can be used in the following way:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="kr">type</span> <span class="nx">T6</span> <span class="o">=</span> <span class="nx">Intersection</span><span class="o">&lt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">{</span> <span class="nx">a</span>: <span class="kt">number</span><span class="p">;</span> <span class="nx">b</span>: <span class="kt">number</span><span class="p">;</span> <span class="nx">x</span>: <span class="kt">number</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="p">{</span> <span class="nx">a</span>: <span class="kt">number</span><span class="p">;</span> <span class="nx">b</span>: <span class="kt">number</span><span class="p">;</span> <span class="nx">z</span>: <span class="kt">string</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="o">&gt;</span><span class="p">;</span> <span class="c1">// { a: number; b:number }
</span></span></span></code></pre></div><p>So, there you have it - some reasonably complicated types defined in TypeScript. Hopefully, you&rsquo;ve
been able to follow along until the end and you get some use out of what you&rsquo;ve learnt here.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="typescript" label="typescript"/><category scheme="taxonomy:Tags" term="javascript" label="javascript"/><category scheme="taxonomy:Tags" term="types" label="types"/></entry><entry xml:base="typescript-constructor-type"><title type="html">TypeScript constructors and generic types</title><link href="https://www.simonholywell.com/post/typescript-constructor-type/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2013/11/conditionally-loaded-responsive-content/?utm_source=atom_feed" rel="related" type="text/html" title="Conditionally loaded responsive content on the client side"/><link href="https://www.simonholywell.com/post/2010/08/firefox-radio-buttons/?utm_source=atom_feed" rel="related" type="text/html" title=""/><link href="https://www.simonholywell.com/post/2010/04/jquery-ui-datepicker-in-dialogue/?utm_source=atom_feed" rel="related" type="text/html" title="jQuery UI Datepicker appearing below Dialog"/><link href="https://www.simonholywell.com/post/the-lambda-calculus-for-developers/?utm_source=atom_feed" rel="related" type="text/html" title="The lambda calculus for developers"/><link href="https://www.simonholywell.com/post/2017/09/search-and-replace-with-confirmation-in-bash/?utm_source=atom_feed" rel="related" type="text/html" title="Search and replace with confirmation in Bash"/><id>https://www.simonholywell.com/post/typescript-constructor-type/</id><author><name>Simon Holywell</name></author><published>2019-05-27T18:11:44+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>I have recently found myself needing a type for class constructors that is at once generic and tight enough to ensure a genuine constructor. This is useful in situations where you must handle a variety of classes - those that come from other libraries or applications that you cannot control.
When writing your own dependency injection container or some other generalised library you cannot know what class constructors might be passed in.</summary><content type="html"><![CDATA[<p>I have recently found myself needing a type for class constructors that is at once generic
and tight enough to ensure a genuine constructor. This is useful in situations where you must
handle a variety of classes - those that come from other libraries or applications that you
cannot control.</p>
<p>When writing your own dependency injection container or some other generalised library you
cannot know what class constructors might be passed in. The code just needs to know that
calling the constructor will lead to an instance.</p>
<p>I&rsquo;ve settled on a type that I use for this situation. Whilst the type itself will land up
being rather small, and some might say simple, it is, nevertheless not particularly obvious.</p>
<p>An example class constructor we might want to pass to other functions could be something like
this little <code>Author</code> class definition.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="kr">class</span> <span class="nx">Author</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">public</span> <span class="kr">readonly</span> <span class="nx">age</span>: <span class="kt">number</span> <span class="o">=</span> <span class="kc">NaN</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="kr">public</span> <span class="kr">readonly</span> <span class="nx">email</span>: <span class="kt">string</span> <span class="o">=</span> <span class="s2">&#34;&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="kr">public</span> <span class="kr">readonly</span> <span class="nx">name</span>: <span class="kt">string</span> <span class="o">=</span> <span class="s2">&#34;&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>When creating API endpoints it is common to accept a JSON string in the request body that
needs to be validated and, ideally where TypeScript is involved, correctly typed.
To facilitate this we might have a function that takes a JSON string and converts it
into an instance of a predetermined class.</p>
<p>This code is for demonstration and not production ready, but you could imagine it handling
requests for a REST API.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="cm">/**
</span></span></span><span class="line"><span class="cl"><span class="cm"> * Using a given JSON string construct and populate an instance of the
</span></span></span><span class="line"><span class="cl"><span class="cm"> * supplied class constructor
</span></span></span><span class="line"><span class="cl"><span class="cm"> * @param source JSON request payload string that the API receives
</span></span></span><span class="line"><span class="cl"><span class="cm"> * @param destinationConstructor a class constructor
</span></span></span><span class="line"><span class="cl"><span class="cm"> */</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">json2Instance</span> <span class="o">=</span> <span class="p">(</span><span class="nx">source</span>: <span class="kt">string</span><span class="p">,</span> <span class="nx">destinationConstructor</span>: <span class="kt">any</span><span class="p">)</span> <span class="o">=&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nb">Object</span><span class="p">.</span><span class="nx">assign</span><span class="p">(</span><span class="k">new</span> <span class="nx">destinationConstructor</span><span class="p">(),</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="nx">source</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">simon</span> <span class="o">=</span> <span class="nx">json2Instance</span><span class="p">(</span><span class="s1">&#39;{&#34;name&#34;:&#34;simon&#34;}&#39;</span><span class="p">,</span> <span class="nx">Author</span><span class="p">);</span>
</span></span></code></pre></div><p>This looks like it will work nicely, but in practice by using the <code>any</code> type on the
<code>destinationConstructor</code> the types have been broken. This prevents type checking from
working correctly, which also means that auto hinting will no longer work in developer&rsquo;s
IDEs or editors. So, we need to come up with a type for it so that <code>json2Instance()</code> allows
the type signatures to flow through.</p>
<p>Types given as <code>any</code> effectively block all benefits of using TypeScript in the first
place - there is a place for them, but that is another article entirely.</p>
<p>Looking at the types available in <a href="https://github.com/microsoft/TypeScript/blob/master/lib/lib.es5.d.ts" title="TypeScript source code for lib.es5.d.ts"><code>lib.es5.d.ts</code></a> from the TypeScript language
source code shows us what a constructor type could look like. There are types for all the
native JavaScript constructors such as <a href="https://github.com/microsoft/TypeScript/blob/00bf32ca3967b07e8663d0cd2b3e2bbf572da88b/lib/lib.es5.d.ts#L571" title="TypeScript source code for the NumberConstructor"><code>Number</code></a>, <a href="https://github.com/microsoft/TypeScript/blob/00bf32ca3967b07e8663d0cd2b3e2bbf572da88b/lib/lib.es5.d.ts#L517" title="TypeScript source code for the StringConstructor"><code>String</code></a>,
<a href="https://github.com/microsoft/TypeScript/blob/00bf32ca3967b07e8663d0cd2b3e2bbf572da88b/lib/lib.es5.d.ts#L306" title="TypeScript source code for the FunctionConstructor"><code>Function</code></a> and <a href="https://github.com/microsoft/TypeScript/blob/00bf32ca3967b07e8663d0cd2b3e2bbf572da88b/lib/lib.es5.d.ts#L152" title="TypeScript source code for the ObjectConstructor"><code>Object</code></a>.</p>
<p>Both the <code>Function</code> and <code>Object</code> constructor types have additional properties that are
possibly undesirable, so instead of using them directly or extending them we&rsquo;ll create
our own.</p>
<p>The most basic of constructor types could be defined as a function that returns an <code>Object</code>,
but this is not quite what we are after as you might see.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="kr">type</span> <span class="nx">Constructor</span> <span class="o">=</span> <span class="k">new</span> <span class="p">()</span> <span class="o">=&gt;</span> <span class="nb">Object</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">json2Instance</span> <span class="o">=</span> <span class="p">(</span><span class="nx">source</span>: <span class="kt">string</span><span class="p">,</span> <span class="nx">destinationConstructor</span>: <span class="kt">Constructor</span><span class="p">)</span> <span class="o">=&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nb">Object</span><span class="p">.</span><span class="nx">assign</span><span class="p">(</span><span class="k">new</span> <span class="nx">destinationConstructor</span><span class="p">(),</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="nx">source</span><span class="p">));</span>
</span></span></code></pre></div><p>Unfortunately, we&rsquo;re still losing the type - we know it&rsquo;s an <code>Author</code>, but this constructor
type is telling TypeScript that it is a standard or plain old JavaScript <code>Object</code>. To tighten this
up it is necessary to introduce generic types.</p>
<p>Before we move onto that though - a quick word on constructors that take arguments (<code>args</code> in the
example code). To handle constructor functions that take arguments we can make use of the spread
operator in the constructor type.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="kr">class</span> <span class="nx">AuthorWithConstructor</span> <span class="kr">extends</span> <span class="nx">Author</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">public</span> <span class="kr">readonly</span> <span class="nx">greeting</span><span class="o">!:</span> <span class="kt">string</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="kr">constructor</span><span class="p">(</span><span class="nx">name</span>: <span class="kt">string</span> <span class="o">=</span> <span class="s2">&#34;&#34;</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">this</span><span class="p">.</span><span class="nx">greeting</span> <span class="o">=</span> <span class="sb">`Top of the muffin to you, </span><span class="si">${</span><span class="nx">name</span><span class="si">}</span><span class="sb">`</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="kr">type</span> <span class="nx">Constructor</span> <span class="o">=</span> <span class="k">new</span> <span class="p">(...</span><span class="nx">args</span>: <span class="kt">any</span><span class="p">[])</span> <span class="o">=&gt;</span> <span class="nb">Object</span><span class="p">;</span>
</span></span></code></pre></div><p>This <code>Constructor</code> type is still indicating that the returned value is of type <code>Object</code>, which as
we discovered before is breaking the typings for the <code>json2Instance()</code> function. Using TypeScript&rsquo;s
generics features it is possible to correct this behaviour.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="kr">type</span> <span class="nx">Constructor</span><span class="p">&lt;</span><span class="nt">T</span><span class="p">&gt;</span> <span class="o">=</span> <span class="k">new</span> <span class="p">(...</span><span class="nx">args</span>: <span class="kt">any</span><span class="p">[])</span> <span class="o">=&gt;</span> <span class="nx">T</span><span class="p">;</span>
</span></span></code></pre></div><p>By passing in the type (<code>T</code>) as a generic type argument it is possible to state that the
return value of the constructor is of type <code>T</code>. To use this new type there are a couple of
changes to make to the <code>json2Instance()</code> function to allow for the generic to be specified.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">json2Instance</span> <span class="o">=</span> <span class="p">&lt;</span><span class="nt">T</span><span class="p">&gt;(</span>
</span></span><span class="line"><span class="cl">  <span class="nx">source</span>: <span class="kt">string</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">destinationConstructor</span>: <span class="kt">Constructor</span><span class="p">&lt;</span><span class="nt">T</span><span class="p">&gt;,</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span><span class="o">:</span> <span class="nx">T</span> <span class="o">=&gt;</span> <span class="nb">Object</span><span class="p">.</span><span class="nx">assign</span><span class="p">(</span><span class="k">new</span> <span class="nx">destinationConstructor</span><span class="p">(),</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="nx">source</span><span class="p">));</span>
</span></span></code></pre></div><p>When called the type (<code>Author</code>) now flows through as the generic <code>T</code> type.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">simon</span> <span class="o">=</span> <span class="nx">json2Instance</span><span class="p">(</span><span class="s1">&#39;{&#34;name&#34;:&#34;simon&#34;}&#39;</span><span class="p">,</span> <span class="nx">Author</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">({</span> <span class="nx">age</span>: <span class="kt">simon.age</span><span class="p">,</span> <span class="nx">nextYear</span>: <span class="kt">simon.age</span> <span class="o">+</span> <span class="mi">1</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="c1">// no type errors because it knows age is number in the addition
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="c1">// also in your IDE/editor you&#39;ll now get code completion/suggestions where you type
</span></span></span><span class="line"><span class="cl"><span class="c1">// the instance name `simon` and get a list of possible properties:
</span></span></span><span class="line"><span class="cl"><span class="c1">// simon.
</span></span></span><span class="line"><span class="cl"><span class="c1">//   |--&gt; age
</span></span></span><span class="line"><span class="cl"><span class="c1">//   |--&gt; email
</span></span></span><span class="line"><span class="cl"><span class="c1">//   |--&gt; name
</span></span></span></code></pre></div><p>So, we have solved the problem where the type of the constructor (<code>Author</code>) is known. However, it
is not always possible or desirable to know the type. Think of defining other types or interfaces that
have a constructor as a property.</p>
<p>A limited example of this in action might be to have a list of class constructors.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="kr">type</span> <span class="nx">ControllerList</span> <span class="o">=</span> <span class="nx">Constructor</span><span class="p">[];</span>
</span></span></code></pre></div><p>We do not know the class type of the constructors in the list and it is not necessary to know for our
calling code. It just needs to know it can create an instance. By providing a default for the type
argument (<code>T</code>) of <code>{}</code> we allow implementing types avoid providing a type argument that they cannot
know.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="kr">type</span> <span class="nx">Constructor</span><span class="p">&lt;</span><span class="nt">T</span> <span class="err">=</span> <span class="p">{}&gt;</span> <span class="o">=</span> <span class="k">new</span> <span class="p">(...</span><span class="nx">args</span>: <span class="kt">any</span><span class="p">[])</span> <span class="o">=&gt;</span> <span class="nx">T</span><span class="p">;</span>
</span></span></code></pre></div><p>By default the type will be a constructor that returns an object, but as before if you
specify the type argument <code>T</code> then it will use the given type.</p>
<p>It is possible to tighten up our definition a little further using the <code>extends</code> keyword so that any
<code>T</code> must have an object type - as all constructors do.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="kr">type</span> <span class="nx">Constructor</span><span class="p">&lt;</span><span class="nt">T</span> <span class="na">extends</span> <span class="p">{}</span> <span class="err">=</span> <span class="p">{}&gt;</span> <span class="o">=</span> <span class="k">new</span> <span class="p">(...</span><span class="nx">args</span>: <span class="kt">any</span><span class="p">[])</span> <span class="o">=&gt;</span> <span class="nx">T</span><span class="p">;</span>
</span></span></code></pre></div><p>And, there you have it. A constructor type that is at once flexible and restrictive.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="typescript" label="typescript"/><category scheme="taxonomy:Tags" term="javascript" label="javascript"/><category scheme="taxonomy:Tags" term="types" label="types"/></entry><entry xml:base="the-lambda-calculus-for-developers"><title type="html">The lambda calculus for developers</title><link href="https://www.simonholywell.com/post/the-lambda-calculus-for-developers/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2016/10/functional-programming-in-php-second-edition/?utm_source=atom_feed" rel="related" type="text/html" title="Functional Programming in PHP Second Edition Available Now"/><link href="https://www.simonholywell.com/post/2014/02/functional-php-talks/?utm_source=atom_feed" rel="related" type="text/html" title="Functional PHP talks"/><link href="https://www.simonholywell.com/post/2014/01/speaking-at-brightonphp-and-php-hampshire/?utm_source=atom_feed" rel="related" type="text/html" title="Speaking about Functional PHP at BrightonPHP and PHP Hampshire"/><link href="https://www.simonholywell.com/post/2017/04/php-and-immutability-part-three/?utm_source=atom_feed" rel="related" type="text/html" title="PHP and immutability: objects and generalisation - part three"/><link href="https://www.simonholywell.com/post/2017/04/php-and-immutability-part-two/?utm_source=atom_feed" rel="related" type="text/html" title="PHP and immutability: modified copies - part two"/><id>https://www.simonholywell.com/post/the-lambda-calculus-for-developers/</id><author><name>Simon Holywell</name></author><published>2019-02-17T13:12:34+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>This will be a quick introduction to the lambda calculus syntax, alpha (α) equivalence and beta (β) reduction.
What does a lambda look like? I am going to use the identity function as an example for the simplicity it provides. This can be expressed as a lambda function with the notation λx.x. It is a function that when given an argument outputs that argument as its return value. You can also have multiple arguments with a lambda like λxy.</summary><content type="html"><![CDATA[<p>This will be a quick introduction to the lambda calculus syntax, alpha (α) equivalence and beta (β) reduction.</p>
<h2 id="what-does-a-lambda-look-like">What does a lambda look like?</h2>
<p>I am going to use the identity function as an example for the simplicity it provides. This can be expressed
as a lambda function with the notation <code>λx.x</code>. It is a function that when given an argument outputs that
argument as its return value. You can also have multiple arguments with a lambda like <code>λxy.xy</code>.</p>
<p>A lambda is comprised of a head, argument and body.</p>
<p><img src="lambda.svg" alt="diagram illustrating the parts of a lambda function - head(argument).body"></p>
<p>The head of the lambda begins with the lambda character (<code>λ</code>), which indicates the start of a function. This is
immediately followed by the argument that is separated from the body of the function by a dot/period (<code>.</code>).</p>
<h2 id="applying-a-lambda">Applying a lambda</h2>
<p>The identity function can be applied to any argument passed to it. Here it is when applied to the digit two (2).</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-scheme" data-lang="scheme"><span class="line"><span class="cl"><span class="p">(</span><span class="nf">λx</span><span class="o">.</span><span class="nv">x</span><span class="p">)</span> <span class="mi">2</span>
</span></span><span class="line"><span class="cl"><span class="mi">2</span>
</span></span></code></pre></div><p>The steps to arrive at the final answer can be further broken down and illustrated.</p>
<p><img src="lambda_applied.svg" alt="the application of the identity lambda against the digit 2 as a diagram"></p>
<p>We have just completed the simplest of beta reductions. This is the process of reducing all expressions
to their normal form or smallest unit - to the point where you can do no more reduction. In this case we
can reduce all the way to a single value, but this is not always the case as you&rsquo;ll see further on.</p>
<h2 id="in-a-programming-language-you-may-already-know">In a programming language you may already know</h2>
<p>In JavaScript this would be written as</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="p">((</span><span class="nx">x</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="nx">x</span><span class="p">)(</span><span class="mi">2</span><span class="p">)(</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// OR
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="kd">function</span> <span class="p">(</span><span class="nx">x</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nx">x</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="cl"><span class="p">)(</span><span class="mi">2</span><span class="p">);</span>
</span></span></code></pre></div><p>and in PHP</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o">&lt;?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="k">function</span><span class="p">(</span><span class="nv">$x</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nv">$x</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">})(</span><span class="mi">2</span><span class="p">)</span>
</span></span></code></pre></div><p>and Python</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="p">(</span><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">x</span><span class="p">)</span> <span class="p">(</span><span class="mi">2</span><span class="p">)</span>
</span></span></code></pre></div><p>and Ruby</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="o">-&gt;</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="p">{</span> <span class="n">x</span> <span class="p">}</span><span class="o">.</span><span class="n">call</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
</span></span></code></pre></div><p>and Haskell</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-haskell" data-lang="haskell"><span class="line"><span class="cl"><span class="p">(</span><span class="nf">\</span><span class="n">x</span> <span class="ow">-&gt;</span> <span class="n">x</span><span class="p">)</span> <span class="mi">2</span>
</span></span></code></pre></div><h2 id="some-more-simple-examples">Some more simple examples</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-scheme" data-lang="scheme"><span class="line"><span class="cl"><span class="p">(</span><span class="nf">λx</span><span class="o">.</span><span class="nv">x</span><span class="p">)</span> <span class="mi">10</span>
</span></span><span class="line"><span class="cl"><span class="mi">10</span>
</span></span><span class="line"><span class="cl"><span class="nv">---</span>
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="nf">λx</span><span class="o">.</span><span class="nv">x</span> <span class="nv">*</span> <span class="mi">2</span><span class="p">)</span> <span class="mi">2</span>
</span></span><span class="line"><span class="cl"><span class="mi">4</span>
</span></span><span class="line"><span class="cl"><span class="nv">---</span>
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="nf">λx</span><span class="o">.</span><span class="mi">1</span> <span class="nv">+</span> <span class="nv">x</span><span class="p">)</span> <span class="mi">2</span>
</span></span><span class="line"><span class="cl"><span class="mi">3</span>
</span></span></code></pre></div><h2 id="free-variables">Free variables</h2>
<p>A free variable is one that is not mentioned in the head of a lambda - <code>y</code> is a free variable in
the expression <code>λx.xy</code>. This does not prevent the expression from being reduced though.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-scheme" data-lang="scheme"><span class="line"><span class="cl"><span class="p">(</span><span class="nf">λx</span><span class="o">.</span><span class="nv">xy</span><span class="p">)</span> <span class="nv">z</span>
</span></span><span class="line"><span class="cl"><span class="nv">zy</span>
</span></span></code></pre></div><p>The opposite of a free variable is a bound variable - it is bound to an argument specified in the
head of the lambda.</p>
<h2 id="higher-order">Higher order</h2>
<p>The lambda calculus can also encode higher order operations - that is lambdas that can accept lambdas
as arguments and/or return lambdas. To make it easier to keep track of this process I will use &ldquo;notes to
self&rdquo; inside square brackets (<code>[]</code>) that illustrate the value an argument was substituted with.</p>
<p>For reference here is the identity example again with the additional substitution notation.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-scheme" data-lang="scheme"><span class="line"><span class="cl"><span class="p">(</span><span class="nf">λx</span><span class="o">.</span><span class="nv">x</span><span class="p">)</span> <span class="mi">2</span>
</span></span><span class="line"><span class="cl"><span class="p">[</span> <span class="nv">x</span> <span class="nv">:=</span> <span class="mi">2</span> <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="mi">2</span>
</span></span></code></pre></div><p>Now for the first higher order lambda expression - the identity lambda applied to itself.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-scheme" data-lang="scheme"><span class="line"><span class="cl"><span class="p">(</span><span class="nf">λx</span><span class="o">.</span><span class="nv">x</span><span class="p">)</span> <span class="p">(</span><span class="nf">λy</span><span class="o">.</span><span class="nv">y</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">[</span> <span class="nv">x</span> <span class="nv">:=</span> <span class="p">(</span><span class="nf">λy</span><span class="o">.</span><span class="nv">y</span><span class="p">)</span> <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="nv">λy</span><span class="o">.</span><span class="nv">y</span>
</span></span></code></pre></div><p>This is a good time to mention that the lambda calculus is left associative during beta reduction.
We start with the leftmost expression and apply the left most argument to it. In the following
example I&rsquo;ve added an extra initial step to wrap the first reduction inside parentheses (<code>()</code>) so
as to make this association explicit</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-scheme" data-lang="scheme"><span class="line"><span class="cl"><span class="p">(</span><span class="nf">λx</span><span class="o">.</span><span class="nv">x</span><span class="p">)</span> <span class="p">(</span><span class="nf">λy</span><span class="o">.</span><span class="nv">y</span><span class="p">)</span> <span class="nv">z</span>
</span></span><span class="line"><span class="cl"><span class="p">((</span><span class="nf">λx</span><span class="o">.</span><span class="nv">x</span><span class="p">)</span> <span class="p">(</span><span class="nf">λy</span><span class="o">.</span><span class="nv">y</span><span class="p">))</span> <span class="nv">z</span>  <span class="c1">; here are those extra parentheses</span>
</span></span><span class="line"><span class="cl"><span class="p">[</span> <span class="nv">x</span> <span class="nv">:=</span> <span class="p">(</span><span class="nf">λy</span><span class="o">.</span><span class="nv">y</span><span class="p">)</span> <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="nf">λy</span><span class="o">.</span><span class="nv">y</span><span class="p">)</span> <span class="nv">z</span>
</span></span><span class="line"><span class="cl"><span class="p">[</span> <span class="nv">y</span> <span class="nv">:=</span> <span class="nv">z</span> <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="nv">z</span>
</span></span></code></pre></div><h2 id="α-equivalence">α-equivalence</h2>
<p>This refers to two different expressions that when given the same argument would return the same result. They are
functionally equivalent to each other and you could substitute one for the other.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-scheme" data-lang="scheme"><span class="line"><span class="cl"><span class="nv">λx</span><span class="o">.</span><span class="nv">x</span> <span class="nv">==</span> <span class="nv">λy</span><span class="o">.</span><span class="nv">y</span> <span class="nv">==</span> <span class="nv">λz</span><span class="o">.</span><span class="nv">z</span>
</span></span><span class="line"><span class="cl"><span class="nv">λxy</span><span class="o">.</span><span class="nv">yx</span> <span class="nv">==</span> <span class="nv">λzq</span><span class="o">.</span><span class="nv">qz</span> <span class="nv">==</span> <span class="nv">λpt</span><span class="o">.</span><span class="nv">tp</span>
</span></span></code></pre></div><p>conversely, due to different ordering in the body the following is not equivalent.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-scheme" data-lang="scheme"><span class="line"><span class="cl"><span class="nv">λxy</span><span class="o">.</span><span class="nv">xy</span> <span class="nv">!=</span> <span class="nv">λzq</span><span class="o">.</span><span class="nv">qz</span>
</span></span></code></pre></div><p>Importantly, this property gives you the opportunity to rename variables where there may be clashes in an
expression.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-scheme" data-lang="scheme"><span class="line"><span class="cl"><span class="p">(</span><span class="nf">λz</span><span class="o">.</span><span class="nv">z</span><span class="p">)</span> <span class="nv">λz</span><span class="o">.</span><span class="nv">zz</span> <span class="nv">==</span> <span class="p">(</span><span class="nf">λz</span><span class="o">.</span><span class="nv">z</span><span class="p">)</span> <span class="nv">λy</span><span class="o">.</span><span class="nv">yy</span>
</span></span></code></pre></div><p>Where there are free variables in the expression it is not possible to establish equivalence, but you can still
rename those that are bound (<code>x</code> in the following example).</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-scheme" data-lang="scheme"><span class="line"><span class="cl"><span class="nv">λx</span><span class="o">.</span><span class="nv">xz</span> <span class="nv">!=</span> <span class="nv">λx</span><span class="o">.</span><span class="nv">xz</span>
</span></span></code></pre></div><p>If you wanted to avoid a variable name collision in the aforementioned expression you could rename <code>x</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-scheme" data-lang="scheme"><span class="line"><span class="cl"><span class="nv">λx</span><span class="o">.</span><span class="nv">xz</span> <span class="nv">-&gt;</span> <span class="nv">λy</span><span class="o">.</span><span class="nv">yz</span>
</span></span></code></pre></div><h2 id="multiple-arguments-and-currying">Multiple arguments and currying</h2>
<p>The same basic reduction rules apply when dealing with lambdas that have multiple arguments, but there is
a little additional rule. Each argument is actually a lambda and they are nested - this is currying.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-scheme" data-lang="scheme"><span class="line"><span class="cl"><span class="nv">λxy</span><span class="o">.</span><span class="nv">xy</span>
</span></span></code></pre></div><p>is actually more like the following when considered in its most explicit form.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-scheme" data-lang="scheme"><span class="line"><span class="cl"><span class="nv">λx</span><span class="o">.</span><span class="p">(</span><span class="nf">λy</span><span class="o">.</span><span class="nv">xy</span><span class="p">)</span>
</span></span></code></pre></div><p>The more arguments you have the more nested lambdas you&rsquo;ll have.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-scheme" data-lang="scheme"><span class="line"><span class="cl"><span class="nv">λxyz</span><span class="o">.</span><span class="nv">xyz</span> <span class="nv">==</span> <span class="nv">λx</span><span class="o">.</span><span class="p">(</span><span class="nf">λy</span><span class="o">.</span><span class="p">(</span><span class="nf">λz</span><span class="o">.</span><span class="nv">xyz</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="nv">λxyzq</span><span class="o">.</span><span class="nv">xyzq</span> <span class="nv">==</span> <span class="nv">λx</span><span class="o">.</span><span class="p">(</span><span class="nf">λy</span><span class="o">.</span><span class="p">(</span><span class="nf">λz</span><span class="o">.</span><span class="p">(</span><span class="nf">λq</span><span class="o">.</span><span class="nv">xyzq</span><span class="p">)))</span>
</span></span></code></pre></div><p>This is to say that the first notation is shorthand for each argument being the application of a
lambda function.</p>
<p>Now for a multi-argument reduction</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-scheme" data-lang="scheme"><span class="line"><span class="cl"><span class="p">(</span><span class="nf">λxy</span><span class="o">.</span><span class="nv">xy</span><span class="p">)</span> <span class="nv">p</span> <span class="nv">t</span>
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="nf">λx</span><span class="o">.</span><span class="p">(</span><span class="nf">λy</span><span class="o">.</span><span class="nv">xy</span><span class="p">))</span> <span class="nv">p</span> <span class="nv">t</span>
</span></span><span class="line"><span class="cl"><span class="p">[</span> <span class="nv">x</span> <span class="nv">:=</span> <span class="nv">p</span> <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="nf">λy</span><span class="o">.</span><span class="nv">py</span><span class="p">)</span> <span class="nv">t</span>
</span></span><span class="line"><span class="cl"><span class="p">[</span> <span class="nv">y</span> <span class="nv">:=</span> <span class="nv">t</span> <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="nv">pt</span>
</span></span></code></pre></div><p>and again for a higher order example.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-scheme" data-lang="scheme"><span class="line"><span class="cl"><span class="p">(</span><span class="nf">λxy</span><span class="o">.</span><span class="nv">xy</span><span class="p">)</span> <span class="p">(</span><span class="nf">λz</span><span class="o">.</span><span class="nv">q</span><span class="p">)</span> <span class="mi">1</span>
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="nf">λx</span><span class="o">.</span><span class="p">(</span><span class="nf">λy</span><span class="o">.</span><span class="nv">xy</span><span class="p">))</span> <span class="p">(</span><span class="nf">λz</span><span class="o">.</span><span class="nv">q</span><span class="p">)</span> <span class="mi">1</span>
</span></span><span class="line"><span class="cl"><span class="p">[</span> <span class="nv">x</span> <span class="nv">:=</span> <span class="p">(</span><span class="nf">λz</span><span class="o">.</span><span class="nv">q</span><span class="p">)</span> <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="nf">λy</span><span class="o">.</span><span class="p">(</span><span class="nf">λz</span><span class="o">.</span><span class="nv">q</span><span class="p">)</span><span class="nv">y</span><span class="p">)</span> <span class="mi">1</span>
</span></span><span class="line"><span class="cl"><span class="p">[</span> <span class="nv">y</span> <span class="nv">:=</span> <span class="mi">1</span> <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="nf">λz</span><span class="o">.</span><span class="nv">q</span><span class="p">)</span> <span class="mi">1</span>
</span></span><span class="line"><span class="cl"><span class="p">[</span> <span class="nv">z</span> <span class="nv">:=</span> <span class="mi">1</span> <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="nv">q</span>
</span></span></code></pre></div><p>Worth noting here that the <code>z</code> is not used in the lambda body so the value <code>1</code> simply evaporates
(dropped from the expression/result).</p>
<p>It is, of course, possible to work through more complex problems like the following expression -
remembering we start with the left most expression first.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-scheme" data-lang="scheme"><span class="line"><span class="cl"><span class="p">(</span><span class="nf">λxyz</span><span class="o">.</span><span class="nv">xz</span><span class="p">(</span><span class="nf">yz</span><span class="p">))</span> <span class="p">(</span><span class="nf">λmn</span><span class="o">.</span><span class="nv">m</span><span class="p">)</span> <span class="p">(</span><span class="nf">λp</span><span class="o">.</span><span class="nv">p</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">; let&#39;s expand to indicate curried arguments</span>
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="nf">λx</span><span class="o">.</span><span class="p">(</span><span class="nf">λy</span><span class="o">.</span><span class="p">(</span><span class="nf">λz</span><span class="o">.</span><span class="nv">xz</span><span class="p">(</span><span class="nf">yz</span><span class="p">))))</span> <span class="p">(</span><span class="nf">λm</span><span class="o">.</span><span class="p">(</span><span class="nf">λn</span><span class="o">.</span><span class="nv">m</span><span class="p">))</span> <span class="p">(</span><span class="nf">λp</span><span class="o">.</span><span class="nv">p</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">[</span> <span class="nv">x</span> <span class="nv">:=</span> <span class="p">(</span><span class="nf">λm</span><span class="o">.</span><span class="p">(</span><span class="nf">λn</span><span class="o">.</span><span class="nv">m</span><span class="p">))</span> <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="nf">λy</span><span class="o">.</span><span class="p">(</span><span class="nf">λz</span><span class="o">.</span><span class="p">(</span><span class="nf">λm</span><span class="o">.</span><span class="p">(</span><span class="nf">λn</span><span class="o">.</span><span class="nv">m</span><span class="p">))</span> <span class="p">(</span><span class="nf">z</span><span class="p">)</span> <span class="p">(</span><span class="nf">yz</span><span class="p">)))</span> <span class="p">(</span><span class="nf">λp</span><span class="o">.</span><span class="nv">p</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">[</span> <span class="nv">y</span> <span class="nv">:=</span> <span class="p">(</span><span class="nf">λp</span><span class="o">.</span><span class="nv">p</span><span class="p">)</span> <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="nv">λz</span><span class="o">.</span><span class="p">(</span><span class="nf">λm</span><span class="o">.</span><span class="p">(</span><span class="nf">λn</span><span class="o">.</span><span class="nv">m</span><span class="p">))</span> <span class="p">(</span><span class="nf">z</span><span class="p">)</span> <span class="p">((</span><span class="nf">λp</span><span class="o">.</span><span class="nv">p</span><span class="p">)</span> <span class="nv">z</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">; there are no more arguments to apply but</span>
</span></span><span class="line"><span class="cl"><span class="c1">; we can still reduce internally</span>
</span></span><span class="line"><span class="cl"><span class="c1">; again we want to do the left most first</span>
</span></span><span class="line"><span class="cl"><span class="p">[</span> <span class="nv">m</span> <span class="nv">:=</span> <span class="nv">z</span> <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="nv">λz</span><span class="o">.</span><span class="p">(</span><span class="nf">λn</span><span class="o">.</span><span class="nv">z</span><span class="p">)</span> <span class="p">((</span><span class="nf">λp</span><span class="o">.</span><span class="nv">p</span><span class="p">)</span> <span class="nv">z</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">[</span> <span class="nv">n</span> <span class="nv">:=</span> <span class="p">((</span><span class="nf">λp</span><span class="o">.</span><span class="nv">p</span><span class="p">)</span> <span class="nv">z</span><span class="p">)</span> <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="c1">; as n is not used in the body it evaporates</span>
</span></span><span class="line"><span class="cl"><span class="c1">; and the lambda returns z</span>
</span></span><span class="line"><span class="cl"><span class="nv">λz</span><span class="o">.</span><span class="nv">z</span>
</span></span></code></pre></div><p>So after all that we land up with the identity function at the end.</p>
<h2 id="combinators">Combinators</h2>
<p>A lambda term with no free variables (all variables are bound), which serves to combine values.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-scheme" data-lang="scheme"><span class="line"><span class="cl"><span class="nv">λz</span><span class="o">.</span><span class="nv">z</span>
</span></span><span class="line"><span class="cl"><span class="nv">λzy</span><span class="o">.</span><span class="nv">zy</span>
</span></span><span class="line"><span class="cl"><span class="nv">λxyz</span><span class="o">.</span><span class="nv">xz</span><span class="p">(</span><span class="nf">yz</span><span class="p">)</span>
</span></span></code></pre></div><p>As opposed to those that contain free variables - in this case <code>y</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-scheme" data-lang="scheme"><span class="line"><span class="cl"><span class="nv">λz</span><span class="o">.</span><span class="nv">y</span>
</span></span><span class="line"><span class="cl"><span class="nv">λz</span><span class="o">.</span><span class="nv">xy</span>
</span></span></code></pre></div><p>There is a very famous combinator called the Y combinator that looks like this.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-scheme" data-lang="scheme"><span class="line"><span class="cl"><span class="nv">λf</span><span class="o">.</span><span class="p">(</span><span class="nf">λx</span><span class="o">.</span><span class="nv">f</span> <span class="p">(</span><span class="nf">x</span> <span class="nv">x</span><span class="p">))(</span><span class="nf">λx</span><span class="o">.</span><span class="nv">f</span> <span class="p">(</span><span class="nf">x</span> <span class="nv">x</span><span class="p">))</span>
</span></span></code></pre></div><h2 id="divergence">Divergence</h2>
<p>Not all expressions can be considered to converge because they lead to replication and the beta
reduction process never ends. Consider the Ω (Omega) divergence below.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-scheme" data-lang="scheme"><span class="line"><span class="cl"><span class="p">(</span><span class="nf">λx</span><span class="o">.</span><span class="nv">xx</span><span class="p">)</span> <span class="p">(</span><span class="nf">λy</span><span class="o">.</span><span class="nv">yy</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">[</span> <span class="nv">x</span> <span class="nv">:=</span> <span class="nv">λy</span><span class="o">.</span><span class="nv">yy</span> <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="nf">λy</span><span class="o">.</span><span class="nv">yy</span><span class="p">)</span> <span class="p">(</span><span class="nf">λy</span><span class="o">.</span><span class="nv">yy</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">[</span> <span class="nv">y</span> <span class="nv">:=</span> <span class="nv">λy</span><span class="o">.</span><span class="nv">yy</span> <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="nf">λy</span><span class="o">.</span><span class="nv">yy</span><span class="p">)</span> <span class="p">(</span><span class="nf">λy</span><span class="o">.</span><span class="nv">yy</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">; and so on forever</span>
</span></span></code></pre></div><h2 id="some-exercises-for-you">Some exercises for you</h2>
<p>The worked answers to these exercises are available after the summary.</p>
<h3 id="combinator-exercises">Combinator exercises</h3>
<p>For each of the following determine if they are combinators or not.</p>
<ol>
<li><code>λq.qq</code></li>
<li><code>λts.stp</code></li>
<li><code>λz.fg</code></li>
<li><code>λxy.yx</code></li>
<li><code>λrgf.f (ri) g</code></li>
</ol>
<h3 id="α-equivalence-exercises">α-equivalence exercises</h3>
<p>Are these terms α-equivalent?</p>
<ol>
<li><code>λz.z</code> and <code>λa.a</code></li>
<li><code>λbq.qb</code> and <code>λzt.zt</code></li>
<li><code>λz.zg</code> and <code>λp.pg</code></li>
<li><code>λb.λa.a</code> and <code>λa.λb.b</code></li>
<li><code>λd.λxy.y</code> and <code>λf.λyx.x</code></li>
</ol>
<h3 id="β-reduction-exercises">β-reduction exercises</h3>
<p>Reduce the following to their β-normal forms. It will be a lot easier if you use a pen and paper
or even a text document in your editor to work through these.</p>
<ol>
<li><code>(λa.ab) (λq.q)</code></li>
<li><code>(λf.(λg.fgg)) (λn.n) m</code></li>
<li><code>(λs.(λp.(sp) s)) (λt.q)</code></li>
<li><code>(λb.(λm.(bb) m) (λq.vq)) (λx.(λe.e))</code></li>
<li><code>λf.((λx.f (x x)) (λx.f (x x)))</code></li>
<li><code>(λq.qg) (λp.(λs.ss)) (λt.t) z</code></li>
<li><code>(λfg.gf) (λba.a) (λz.z) pq</code></li>
<li><code>(λpt.pt) (λx.xx) (λf.ff)</code></li>
<li><code>(λpt.t) g (λq.(λv.vv)) o (λu.uu) (λpf.fz)</code></li>
</ol>
<h2 id="summary">Summary</h2>
<p>Lambda expressions are:</p>
<ul>
<li>
<p>reduced from left to right</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-scheme" data-lang="scheme"><span class="line"><span class="cl"><span class="p">(</span><span class="nf">λx</span><span class="o">.</span><span class="nv">x</span><span class="p">)</span> <span class="p">(</span><span class="nf">λy</span><span class="o">.</span><span class="nv">y</span><span class="p">)</span> <span class="nv">g</span>
</span></span><span class="line"><span class="cl"><span class="p">[</span> <span class="nv">x</span> <span class="nv">:=</span> <span class="p">(</span><span class="nf">λy</span><span class="o">.</span><span class="nv">y</span><span class="p">)</span> <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="nf">λy</span><span class="o">.</span><span class="nv">y</span><span class="p">)</span> <span class="nv">g</span>
</span></span><span class="line"><span class="cl"><span class="p">[</span> <span class="nv">y</span> <span class="nv">:=</span> <span class="nv">g</span> <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="nv">g</span>
</span></span></code></pre></div></li>
<li>
<p>left associative and greedy</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-scheme" data-lang="scheme"><span class="line"><span class="cl"><span class="p">(</span><span class="nf">λx</span><span class="o">.</span><span class="nv">x</span><span class="p">)</span> <span class="p">(</span><span class="nf">λy</span><span class="o">.</span><span class="nv">y</span><span class="p">)</span> <span class="nv">g</span> <span class="nv">!=</span> <span class="p">(</span><span class="nf">λx</span><span class="o">.</span><span class="nv">x</span> <span class="nv">λy</span><span class="o">.</span><span class="nv">y</span> <span class="nv">g</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">; first expression</span>
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="nf">λx</span><span class="o">.</span><span class="nv">x</span><span class="p">)</span> <span class="p">(</span><span class="nf">λy</span><span class="o">.</span><span class="nv">y</span><span class="p">)</span> <span class="nv">g</span>
</span></span><span class="line"><span class="cl"><span class="p">[</span> <span class="nv">x</span> <span class="nv">:=</span> <span class="p">(</span><span class="nf">λy</span><span class="o">.</span><span class="nv">y</span><span class="p">)</span> <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="nf">λy</span><span class="o">.</span><span class="nv">y</span><span class="p">)</span> <span class="nv">g</span>
</span></span><span class="line"><span class="cl"><span class="p">[</span> <span class="nv">y</span> <span class="nv">:=</span> <span class="nv">g</span> <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="nv">g</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">; second expression</span>
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="nf">λx</span><span class="o">.</span><span class="nv">x</span> <span class="nv">λy</span><span class="o">.</span><span class="nv">y</span> <span class="nv">g</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="nf">λx</span><span class="o">.</span><span class="p">(</span><span class="nf">x</span><span class="p">(</span><span class="nf">λy</span><span class="o">.</span><span class="nv">y</span> <span class="nv">g</span><span class="p">)))</span>
</span></span></code></pre></div></li>
<li>
<p>applied/reduced through β-reduction to their β-normal form or point of divergence (they either
self-replicate or grow - think Y-Combinator and Ω (Omega))</p>
</li>
<li>
<p>combinators when all variables are bound to arguments (no free variables) - therefore
serving to combine values together</p>
</li>
</ul>
<h2 id="answers">Answers</h2>
<h3 id="combinator-answers">Combinator answers</h3>
<ol>
<li>Yes</li>
<li>No (<code>p</code> is free)</li>
<li>No (<code>fg</code> are free)</li>
<li>Yes</li>
<li>No (<code>i</code> is free)</li>
</ol>
<h3 id="α-equivalence-answers">α-equivalence answers</h3>
<ol>
<li>Yes</li>
<li>No</li>
<li>No</li>
<li>Yes</li>
<li>Yes</li>
</ol>
<h3 id="β-reduction-answers">β-reduction answers</h3>
<h4 id="1">1</h4>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-scheme" data-lang="scheme"><span class="line"><span class="cl"><span class="p">(</span><span class="nf">λa</span><span class="o">.</span><span class="nv">ab</span><span class="p">)</span> <span class="p">(</span><span class="nf">λq</span><span class="o">.</span><span class="nv">q</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">[</span> <span class="nv">a</span> <span class="nv">:=</span> <span class="p">(</span><span class="nf">λq</span><span class="o">.</span><span class="nv">q</span><span class="p">)</span> <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="nf">λq</span><span class="o">.</span><span class="nv">q</span><span class="p">)</span> <span class="nv">b</span>
</span></span><span class="line"><span class="cl"><span class="p">[</span> <span class="nv">q</span> <span class="nv">:=</span> <span class="nv">b</span> <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="nv">b</span>
</span></span></code></pre></div><h4 id="2">2</h4>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-scheme" data-lang="scheme"><span class="line"><span class="cl"><span class="p">(</span><span class="nf">λf</span><span class="o">.</span><span class="p">(</span><span class="nf">λg</span><span class="o">.</span><span class="nv">fgg</span><span class="p">))</span> <span class="p">(</span><span class="nf">λn</span><span class="o">.</span><span class="nv">n</span><span class="p">)</span> <span class="nv">m</span>
</span></span><span class="line"><span class="cl"><span class="p">[</span> <span class="nv">f</span> <span class="nv">:=</span> <span class="p">(</span><span class="nf">λn</span><span class="o">.</span><span class="nv">n</span><span class="p">)</span> <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="nf">λg</span><span class="o">.</span><span class="p">(</span><span class="nf">λn</span><span class="o">.</span><span class="nv">n</span><span class="p">)</span> <span class="nv">gg</span><span class="p">)</span> <span class="nv">m</span>
</span></span><span class="line"><span class="cl"><span class="p">[</span> <span class="nv">g</span> <span class="nv">:=</span> <span class="nv">m</span> <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="nf">λn</span><span class="o">.</span><span class="nv">n</span><span class="p">)</span> <span class="p">(</span><span class="nf">m</span><span class="p">)</span><span class="nv">m</span>
</span></span><span class="line"><span class="cl"><span class="p">[</span> <span class="nv">n</span> <span class="nv">:=</span> <span class="nv">m</span> <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="nv">mm</span>
</span></span></code></pre></div><h4 id="3">3</h4>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-scheme" data-lang="scheme"><span class="line"><span class="cl"><span class="p">(</span><span class="nf">λs</span><span class="o">.</span><span class="p">(</span><span class="nf">λp</span><span class="o">.</span><span class="p">(</span><span class="nf">sp</span><span class="p">)</span> <span class="nv">s</span><span class="p">))</span> <span class="p">(</span><span class="nf">λt</span><span class="o">.</span><span class="nv">q</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">[</span> <span class="nv">s</span> <span class="nv">:=</span> <span class="p">(</span><span class="nf">λt</span><span class="o">.</span><span class="nv">q</span><span class="p">)</span> <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="nf">λp</span><span class="o">.</span><span class="p">(</span><span class="nf">λt</span><span class="o">.</span><span class="nv">q</span><span class="p">)</span><span class="nv">p</span><span class="p">)</span> <span class="p">(</span><span class="nf">λt</span><span class="o">.</span><span class="nv">q</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">[</span> <span class="nv">p</span> <span class="nv">:=</span> <span class="p">(</span><span class="nf">λt</span><span class="o">.</span><span class="nv">q</span><span class="p">)</span> <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="nf">λt</span><span class="o">.</span><span class="nv">q</span><span class="p">)</span> <span class="p">(</span><span class="nf">λt</span><span class="o">.</span><span class="nv">q</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">[</span> <span class="nv">t</span> <span class="nv">:=</span> <span class="p">(</span><span class="nf">λt</span><span class="o">.</span><span class="nv">q</span><span class="p">)</span> <span class="p">]</span>  <span class="c1">; not that it matters, `t` is dropped anyway</span>
</span></span><span class="line"><span class="cl"><span class="nv">q</span>
</span></span></code></pre></div><h4 id="4">4</h4>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-scheme" data-lang="scheme"><span class="line"><span class="cl"><span class="p">(</span><span class="nf">λb</span><span class="o">.</span><span class="p">(</span><span class="nf">λm</span><span class="o">.</span><span class="p">(</span><span class="nf">bb</span><span class="p">)</span> <span class="nv">m</span><span class="p">)</span> <span class="p">(</span><span class="nf">λq</span><span class="o">.</span><span class="nv">vq</span><span class="p">))</span> <span class="p">(</span><span class="nf">λx</span><span class="o">.</span><span class="p">(</span><span class="nf">λe</span><span class="o">.</span><span class="nv">e</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="p">[</span> <span class="nv">b</span> <span class="nv">:=</span> <span class="p">(</span><span class="nf">λx</span><span class="o">.</span><span class="p">(</span><span class="nf">λe</span><span class="o">.</span><span class="nv">e</span><span class="p">))</span> <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="nf">λm</span><span class="o">.</span><span class="p">((</span><span class="nf">λx</span><span class="o">.</span><span class="p">(</span><span class="nf">λe</span><span class="o">.</span><span class="nv">e</span><span class="p">))</span> <span class="p">(</span><span class="nf">λx</span><span class="o">.</span><span class="p">(</span><span class="nf">λe</span><span class="o">.</span><span class="nv">e</span><span class="p">)))</span> <span class="nv">m</span><span class="p">)</span> <span class="p">(</span><span class="nf">λq</span><span class="o">.</span><span class="nv">vq</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">[</span> <span class="nv">m</span> <span class="nv">:=</span> <span class="p">(</span><span class="nf">λq</span><span class="o">.</span><span class="nv">vq</span><span class="p">)</span> <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="nf">λx</span><span class="o">.</span><span class="p">(</span><span class="nf">λe</span><span class="o">.</span><span class="nv">e</span><span class="p">))</span> <span class="p">(</span><span class="nf">λx</span><span class="o">.</span><span class="p">(</span><span class="nf">λe</span><span class="o">.</span><span class="nv">e</span><span class="p">))</span> <span class="p">(</span><span class="nf">λq</span><span class="o">.</span><span class="nv">vq</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">[</span> <span class="nv">x</span> <span class="nv">:=</span> <span class="p">(</span><span class="nf">λx</span><span class="o">.</span><span class="p">(</span><span class="nf">λe</span><span class="o">.</span><span class="nv">e</span><span class="p">))</span> <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="nf">λe</span><span class="o">.</span><span class="nv">e</span><span class="p">)</span> <span class="p">(</span><span class="nf">λq</span><span class="o">.</span><span class="nv">vq</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">[</span> <span class="nv">y</span> <span class="nv">:=</span> <span class="p">(</span><span class="nf">λq</span><span class="o">.</span><span class="nv">vq</span><span class="p">)</span> <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="nf">λq</span><span class="o">.</span><span class="nv">vq</span><span class="p">)</span>
</span></span></code></pre></div><h4 id="5">5</h4>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-scheme" data-lang="scheme"><span class="line"><span class="cl"><span class="nv">λf</span><span class="o">.</span><span class="p">((</span><span class="nf">λx</span><span class="o">.</span><span class="nv">f</span> <span class="p">(</span><span class="nf">x</span> <span class="nv">x</span><span class="p">))</span> <span class="p">(</span><span class="nf">λx</span><span class="o">.</span><span class="nv">f</span> <span class="p">(</span><span class="nf">x</span> <span class="nv">x</span><span class="p">)))</span>
</span></span><span class="line"><span class="cl"><span class="p">[</span> <span class="nv">x</span> <span class="nv">:=</span> <span class="p">(</span><span class="nf">λx</span><span class="o">.</span><span class="nv">f</span> <span class="p">(</span><span class="nf">x</span> <span class="nv">x</span><span class="p">))</span> <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="nv">λf</span><span class="o">.</span><span class="p">(</span><span class="nf">f</span><span class="p">((</span><span class="nf">λx</span><span class="o">.</span><span class="nv">f</span> <span class="p">(</span><span class="nf">x</span> <span class="nv">x</span><span class="p">)</span> <span class="p">(</span><span class="nf">λx</span><span class="o">.</span><span class="nv">f</span> <span class="p">(</span><span class="nf">x</span> <span class="nv">x</span><span class="p">)))))</span>
</span></span><span class="line"><span class="cl"><span class="p">[</span> <span class="nv">x</span> <span class="nv">:=</span> <span class="p">(</span><span class="nf">λx</span><span class="o">.</span><span class="nv">f</span> <span class="p">(</span><span class="nf">x</span> <span class="nv">x</span><span class="p">))</span> <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="nv">λf</span><span class="o">.</span><span class="p">(</span><span class="nf">f</span><span class="p">(</span><span class="nf">f</span><span class="p">((</span><span class="nf">λx</span><span class="o">.</span><span class="nv">f</span> <span class="p">(</span><span class="nf">x</span> <span class="nv">x</span><span class="p">)</span> <span class="p">(</span><span class="nf">λx</span><span class="o">.</span><span class="nv">f</span> <span class="p">(</span><span class="nf">x</span> <span class="nv">x</span><span class="p">))))))</span>
</span></span><span class="line"><span class="cl"><span class="p">[</span> <span class="nv">x</span> <span class="nv">:=</span> <span class="p">(</span><span class="nf">λx</span><span class="o">.</span><span class="nv">f</span> <span class="p">(</span><span class="nf">x</span> <span class="nv">x</span><span class="p">))</span> <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="nv">λf</span><span class="o">.</span><span class="p">(</span><span class="nf">f</span><span class="p">(</span><span class="nf">f</span><span class="p">(</span><span class="nf">f</span><span class="p">((</span><span class="nf">λx</span><span class="o">.</span><span class="nv">f</span> <span class="p">(</span><span class="nf">x</span> <span class="nv">x</span><span class="p">)</span> <span class="p">(</span><span class="nf">λx</span><span class="o">.</span><span class="nv">f</span> <span class="p">(</span><span class="nf">x</span> <span class="nv">x</span><span class="p">)))))))</span>
</span></span><span class="line"><span class="cl"><span class="c1">; the Y-combinator diverges and the expression actually grows!</span>
</span></span></code></pre></div><h4 id="6">6</h4>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-scheme" data-lang="scheme"><span class="line"><span class="cl"><span class="p">(</span><span class="nf">λq</span><span class="o">.</span><span class="nv">qg</span><span class="p">)</span> <span class="p">(</span><span class="nf">λp</span><span class="o">.</span><span class="p">(</span><span class="nf">λs</span><span class="o">.</span><span class="nv">ss</span><span class="p">))</span> <span class="p">(</span><span class="nf">λt</span><span class="o">.</span><span class="nv">t</span><span class="p">)</span> <span class="nv">z</span>
</span></span><span class="line"><span class="cl"><span class="p">[</span> <span class="nv">q</span> <span class="nv">:=</span> <span class="p">(</span><span class="nf">λp</span><span class="o">.</span><span class="p">(</span><span class="nf">λs</span><span class="o">.</span><span class="nv">ss</span><span class="p">))</span> <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="nf">λp</span><span class="o">.</span><span class="p">(</span><span class="nf">λs</span><span class="o">.</span><span class="nv">ss</span><span class="p">))</span> <span class="nv">g</span> <span class="p">(</span><span class="nf">λt</span><span class="o">.</span><span class="nv">t</span><span class="p">)</span> <span class="nv">z</span>
</span></span><span class="line"><span class="cl"><span class="p">[</span> <span class="nv">p</span> <span class="nv">:=</span> <span class="nv">g</span> <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="nf">λs</span><span class="o">.</span><span class="nv">ss</span><span class="p">)</span> <span class="p">(</span><span class="nf">λt</span><span class="o">.</span><span class="nv">t</span><span class="p">)</span> <span class="nv">z</span>
</span></span><span class="line"><span class="cl"><span class="p">[</span> <span class="nv">s</span> <span class="nv">:=</span> <span class="p">(</span><span class="nf">λt</span><span class="o">.</span><span class="nv">t</span><span class="p">)</span> <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="nf">λt</span><span class="o">.</span><span class="nv">t</span><span class="p">)</span> <span class="p">(</span><span class="nf">λt</span><span class="o">.</span><span class="nv">t</span><span class="p">)</span> <span class="nv">z</span>
</span></span><span class="line"><span class="cl"><span class="p">[</span> <span class="nv">t</span> <span class="nv">:=</span> <span class="p">(</span><span class="nf">λt</span><span class="o">.</span><span class="nv">t</span><span class="p">)</span> <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="nf">λt</span><span class="o">.</span><span class="nv">t</span><span class="p">)</span> <span class="nv">z</span>
</span></span><span class="line"><span class="cl"><span class="p">[</span> <span class="nv">t</span> <span class="nv">:=</span> <span class="nv">z</span> <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="nv">z</span>
</span></span></code></pre></div><h4 id="7">7</h4>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-scheme" data-lang="scheme"><span class="line"><span class="cl"><span class="p">(</span><span class="nf">λfg</span><span class="o">.</span><span class="nv">gf</span><span class="p">)</span> <span class="p">(</span><span class="nf">λba</span><span class="o">.</span><span class="nv">a</span><span class="p">)</span> <span class="p">(</span><span class="nf">λz</span><span class="o">.</span><span class="nv">z</span><span class="p">)</span> <span class="nv">pq</span>
</span></span><span class="line"><span class="cl"><span class="p">[</span> <span class="nv">f</span> <span class="nv">:=</span> <span class="p">(</span><span class="nf">λba</span><span class="o">.</span><span class="nv">a</span><span class="p">)</span> <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="nf">λg</span><span class="o">.</span><span class="nv">g</span><span class="p">(</span><span class="nf">λba</span><span class="o">.</span><span class="nv">a</span><span class="p">))</span> <span class="p">(</span><span class="nf">λz</span><span class="o">.</span><span class="nv">z</span><span class="p">)</span> <span class="nv">pq</span>
</span></span><span class="line"><span class="cl"><span class="p">[</span> <span class="nv">g</span> <span class="nv">:=</span> <span class="p">(</span><span class="nf">λz</span><span class="o">.</span><span class="nv">z</span><span class="p">)</span> <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="nf">λz</span><span class="o">.</span><span class="nv">z</span><span class="p">)</span> <span class="p">(</span><span class="nf">λba</span><span class="o">.</span><span class="nv">a</span><span class="p">)</span> <span class="nv">pq</span>
</span></span><span class="line"><span class="cl"><span class="p">[</span> <span class="nv">z</span> <span class="nv">:=</span> <span class="p">(</span><span class="nf">λba</span><span class="o">.</span><span class="nv">a</span><span class="p">)</span> <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="nf">λba</span><span class="o">.</span><span class="nv">a</span><span class="p">)</span> <span class="nv">pq</span>
</span></span><span class="line"><span class="cl"><span class="p">[</span> <span class="nv">b</span> <span class="nv">:=</span> <span class="nv">p</span> <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="nf">λa</span><span class="o">.</span><span class="nv">a</span><span class="p">)</span> <span class="nv">q</span>
</span></span><span class="line"><span class="cl"><span class="p">[</span> <span class="nv">a</span> <span class="nv">:=</span> <span class="nv">q</span> <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="nv">q</span>
</span></span></code></pre></div><h4 id="8">8</h4>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-scheme" data-lang="scheme"><span class="line"><span class="cl"><span class="p">(</span><span class="nf">λpt</span><span class="o">.</span><span class="nv">pt</span><span class="p">)</span> <span class="p">(</span><span class="nf">λx</span><span class="o">.</span><span class="nv">xx</span><span class="p">)</span> <span class="p">(</span><span class="nf">λf</span><span class="o">.</span><span class="nv">ff</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">[</span> <span class="nv">p</span> <span class="nv">:=</span> <span class="p">(</span><span class="nf">λx</span><span class="o">.</span><span class="nv">xx</span><span class="p">)</span> <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="nf">λt</span><span class="o">.</span><span class="p">(</span><span class="nf">λx</span><span class="o">.</span><span class="nv">xx</span><span class="p">)</span><span class="nv">t</span><span class="p">)</span> <span class="p">(</span><span class="nf">λf</span><span class="o">.</span><span class="nv">ff</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">[</span> <span class="nv">t</span> <span class="nv">:=</span> <span class="p">(</span><span class="nf">λf</span><span class="o">.</span><span class="nv">ff</span><span class="p">)</span> <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="nf">λx</span><span class="o">.</span><span class="nv">xx</span><span class="p">)</span> <span class="p">(</span><span class="nf">λf</span><span class="o">.</span><span class="nv">ff</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">[</span> <span class="nv">x</span> <span class="nv">:=</span> <span class="p">(</span><span class="nf">λf</span><span class="o">.</span><span class="nv">ff</span><span class="p">)</span> <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="nf">λf</span><span class="o">.</span><span class="nv">ff</span><span class="p">)</span> <span class="p">(</span><span class="nf">λf</span><span class="o">.</span><span class="nv">ff</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">; this diverges</span>
</span></span></code></pre></div><h4 id="9">9</h4>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-scheme" data-lang="scheme"><span class="line"><span class="cl"><span class="p">(</span><span class="nf">λpt</span><span class="o">.</span><span class="nv">t</span><span class="p">)</span> <span class="nv">g</span> <span class="p">(</span><span class="nf">λq</span><span class="o">.</span><span class="p">(</span><span class="nf">λv</span><span class="o">.</span><span class="nv">vv</span><span class="p">))</span> <span class="nv">o</span> <span class="p">(</span><span class="nf">λu</span><span class="o">.</span><span class="nv">uu</span><span class="p">)</span> <span class="p">(</span><span class="nf">λpf</span><span class="o">.</span><span class="nv">fz</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">[</span> <span class="nv">p</span> <span class="nv">:=</span> <span class="nv">g</span> <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="nf">λt</span><span class="o">.</span><span class="nv">t</span><span class="p">)</span> <span class="p">(</span><span class="nf">λq</span><span class="o">.</span><span class="p">(</span><span class="nf">λv</span><span class="o">.</span><span class="nv">vv</span><span class="p">))</span> <span class="nv">o</span> <span class="p">(</span><span class="nf">λu</span><span class="o">.</span><span class="nv">uu</span><span class="p">)</span> <span class="p">(</span><span class="nf">λpf</span><span class="o">.</span><span class="nv">fz</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">[</span> <span class="nv">t</span> <span class="nv">:=</span> <span class="p">(</span><span class="nf">λq</span><span class="o">.</span><span class="p">(</span><span class="nf">λv</span><span class="o">.</span><span class="nv">vv</span><span class="p">))</span> <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="nf">λq</span><span class="o">.</span><span class="p">(</span><span class="nf">λv</span><span class="o">.</span><span class="nv">vv</span><span class="p">))</span> <span class="nv">o</span> <span class="p">(</span><span class="nf">λu</span><span class="o">.</span><span class="nv">uu</span><span class="p">)</span> <span class="p">(</span><span class="nf">λpf</span><span class="o">.</span><span class="nv">fz</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">[</span> <span class="nv">q</span> <span class="nv">:=</span> <span class="mi">0</span> <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="nf">λv</span><span class="o">.</span><span class="nv">vv</span><span class="p">)</span> <span class="p">(</span><span class="nf">λu</span><span class="o">.</span><span class="nv">uu</span><span class="p">)</span> <span class="p">(</span><span class="nf">λpf</span><span class="o">.</span><span class="nv">fz</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">[</span> <span class="nv">v</span> <span class="nv">:=</span> <span class="p">(</span><span class="nf">λu</span><span class="o">.</span><span class="nv">uu</span><span class="p">)</span> <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="nf">λu</span><span class="o">.</span><span class="nv">uu</span><span class="p">)</span>  <span class="p">(</span><span class="nf">λu</span><span class="o">.</span><span class="nv">uu</span><span class="p">)</span> <span class="p">(</span><span class="nf">λpf</span><span class="o">.</span><span class="nv">fz</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">[</span> <span class="nv">u</span> <span class="nv">:=</span> <span class="p">(</span><span class="nf">λu</span><span class="o">.</span><span class="nv">uu</span><span class="p">)</span> <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="nf">λu</span><span class="o">.</span><span class="nv">uu</span><span class="p">)</span> <span class="p">(</span><span class="nf">λu</span><span class="o">.</span><span class="nv">uu</span><span class="p">)</span> <span class="p">(</span><span class="nf">λpf</span><span class="o">.</span><span class="nv">fz</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">; this diverges before it can reduce all its terms leaving `(λpf.fz)` unreachable/dangling</span>
</span></span></code></pre></div>]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="lambda-calculus" label="lambda calculus"/><category scheme="taxonomy:Tags" term="functional-programming" label="functional programming"/><category scheme="taxonomy:Tags" term="php" label="php"/><category scheme="taxonomy:Tags" term="haskell" label="haskell"/></entry><entry xml:base="search-and-replace-with-confirmation-in-bash"><title type="html">Search and replace with confirmation in Bash</title><link href="https://www.simonholywell.com/post/2017/09/search-and-replace-with-confirmation-in-bash/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2017/01/email-when-file-changes/?utm_source=atom_feed" rel="related" type="text/html" title="Email me when the file changes"/><link href="https://www.simonholywell.com/post/2015/09/scrape-site-with-wget-and-httrack/?utm_source=atom_feed" rel="related" type="text/html" title="Scraping websites with wget and httrack"/><link href="https://www.simonholywell.com/post/2015/08/image-resize-crop-bash-imagemagick/?utm_source=atom_feed" rel="related" type="text/html" title="Crop and resize images with bash and ImageMagick"/><link href="https://www.simonholywell.com/post/2012/03/netbeans-jvi-vim-bindings/?utm_source=atom_feed" rel="related" type="text/html" title="NetBeans with jVi vim bindings"/><link href="https://www.simonholywell.com/post/2017/04/php-and-immutability-part-three/?utm_source=atom_feed" rel="related" type="text/html" title="PHP and immutability: objects and generalisation - part three"/><id>https://www.simonholywell.com/post/2017/09/search-and-replace-with-confirmation-in-bash/</id><author><name>Simon Holywell</name></author><published>2017-09-12T01:18:44+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Automated search and replace can be very handy although there are occasions where a human needs to get involved on some of the decisions. If the search term isn&amp;rsquo;t unique or appears as part of other words or something like that. When this is the case you&amp;rsquo;ll want a confirm step where you can approve each replacement before it happens.
With very little work we can achieve this using a combination of vim and grep.</summary><content type="html"><![CDATA[<p>Automated search and replace can be very handy although there are occasions where a human needs to get
involved on some of the decisions. If the search term isn&rsquo;t unique or appears as part of other words or
something like that. When this is the case you&rsquo;ll want a confirm step where you can approve each
replacement before it happens.</p>
<p>With very little work we can achieve this using a combination of vim and grep. I&rsquo;ll use grep to find
the search term and return a list of affected files. Looping over each of these files I can employ a
simple vim substitution with the <code>/c</code> (confirmation) flag.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nv">FROM</span><span class="o">=</span><span class="s2">&#34;your search term here&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nv">TO</span><span class="o">=</span><span class="s2">&#34;your replacement here&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nv">FILES</span><span class="o">=</span><span class="k">$(</span>grep -rl <span class="s2">&#34;</span><span class="nv">$FROM</span><span class="s2">&#34;</span> *<span class="k">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;</span><span class="nv">$FROM</span><span class="s2"> =&gt; </span><span class="nv">$TO</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;-----------------------------------------------&#34;</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> SUBJECT_FILE in <span class="si">${</span><span class="nv">FILES</span><span class="p">//</span><span class="se">\\</span><span class="nv">n</span><span class="p">/ </span><span class="si">}</span> <span class="p">;</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">    <span class="nb">echo</span> <span class="s2">&#34;</span><span class="nv">$SUBJECT_FILE</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">    vim <span class="s2">&#34;</span><span class="nv">$SUBJECT_FILE</span><span class="s2">&#34;</span> -c <span class="s2">&#34;%s/</span><span class="nv">$FROM</span><span class="s2">/</span><span class="nv">$TO</span><span class="s2">/gc&#34;</span> -c <span class="s2">&#34;wq&#34;</span>
</span></span><span class="line"><span class="cl"><span class="k">done</span>
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;-----------------------------------------------&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;Done!&#34;</span>
</span></span></code></pre></div><p>The key this little script is the ability to pass vim a string of commands with the <code>-c</code> flag. In this
way it is simple to:</p>
<ul>
<li>open a file with vim <code>vim &quot;$SUBJECT_FILE&quot;</code></li>
<li>perform the substitution and <code>-c &quot;%s/$FROM/$TO/gc&quot;</code></li>
<li>then automatically save it before quitting <code>-c &quot;wq&quot;</code>.</li>
</ul>
<p>A simple little hack I use quite often in some of my bash scripts - most recently used to upgrade from
Bootstrap v4-alpha.2 to v4.alpha.5 in a project. Between the versions, a fair proportion of CSS class
names had been changed so these needed to be updated across the project.</p>
<p>To get the list of all the classes that need to be replaced I used nokogiri
(a Ruby HTML parsing library) command line tools. This was executed directly
against the bootstrap upgrade guide web site.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="bash" label="bash"/><category scheme="taxonomy:Tags" term="vim" label="vim"/></entry><entry xml:base="php-and-immutability-part-three"><title type="html">PHP and immutability: objects and generalisation - part three</title><link href="https://www.simonholywell.com/post/2017/04/php-and-immutability-part-three/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2017/04/php-and-immutability-part-two/?utm_source=atom_feed" rel="related" type="text/html" title="PHP and immutability: modified copies - part two"/><link href="https://www.simonholywell.com/post/2017/03/php-and-immutability/?utm_source=atom_feed" rel="related" type="text/html" title="PHP and immutability: difficulties and scalars - part one"/><link href="https://www.simonholywell.com/post/2016/11/quick-way-to-create-php-stdclass/?utm_source=atom_feed" rel="related" type="text/html" title="Quick way to create a PHP stdClass"/><link href="https://www.simonholywell.com/post/2016/10/functional-programming-in-php-second-edition/?utm_source=atom_feed" rel="related" type="text/html" title="Functional Programming in PHP Second Edition Available Now"/><link href="https://www.simonholywell.com/post/2016/10/importing-and-aliasing-php-functions/?utm_source=atom_feed" rel="related" type="text/html" title="Importing and aliasing PHP functions"/><id>https://www.simonholywell.com/post/2017/04/php-and-immutability-part-three/</id><author><name>Simon Holywell</name></author><published>2017-04-27T03:01:53+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>In the last article we learnt how to create modified copies of an immutable in PHP. This one is going to tackle an issue I have hitherto skirted around and avoided. Objects in immutable data structures.
This article is part of a series I have written on the topic of immutability in PHP code:
Part one - a discussion of caveats and a simple scalar handling immutable Part two - improve the process of creating modified copies of the immutable Part three - objects in immutable data structures and a generalised immutable implementation Also available in Русский (Russian):</summary><content type="html"><![CDATA[<p>In the <a href="/post/2017/04/php-and-immutability-part-two/" title="PHP and immutability: modified copies - part two">last article</a> we learnt how to create modified copies of an immutable in PHP. This
one is going to tackle an issue I have hitherto skirted around and avoided. Objects in immutable data structures.</p>
<blockquote>
<p>This article is part of a series I have written on the topic of immutability in PHP code:</p>
<ol>
<li><a href="/post/2017/03/php-and-immutability/" title="PHP and immutability: difficulties and scalars - part one">Part one</a> - a discussion of caveats and a simple scalar handling immutable</li>
<li><a href="/post/2017/04/php-and-immutability-part-two/" title="PHP and immutability: modified copies - part two">Part two</a> - improve the process of creating modified copies of the immutable</li>
<li><a href="/post/2017/04/php-and-immutability-part-three/" title="PHP and immutability: objects and generalisation - part three">Part three</a> - objects in immutable data structures and a generalised immutable implementation</li>
</ol>
<p>Also available in Русский (Russian):</p>
<ol>
<li><a href="http://langtoday.com/?p=735" title="PHP и неизменяемость. Часть 1">Часть 1</a> - PHP и неизменяемость. Часть 1</li>
<li><a href="http://langtoday.com/?p=804" title="PHP и неизменяемость: экземпляры, которые могут быть изменены. Часть 2">Часть 2</a> - PHP и неизменяемость: экземпляры, которые могут быть изменены. Часть 2</li>
<li><a href="http://langtoday.com/?p=1254" title="PHP и неизменяемость: объекты и обобщение. Часть 3">Часть 3</a> - PHP и неизменяемость: объекты и обобщение. Часть 3</li>
</ol>
</blockquote>
<h2 id="whats-the-problem-with-objects">What&rsquo;s the problem with objects?</h2>
<p>Objects or instances of classes are passed by reference in PHP. Any changes to the class will be
reflected in all places it is passed to. This is different to scalar values like strings, that are
passed by value instead.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="nv">$class</span> <span class="o">=</span> <span class="k">new</span> <span class="k">stdClass</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="k">function</span> <span class="nf">addItem</span><span class="p">(</span><span class="nv">$x</span><span class="p">,</span> <span class="nv">$item</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nv">$x</span><span class="o">-&gt;</span><span class="nv">$item</span> <span class="o">=</span> <span class="nv">$item</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="nx">var_dump</span><span class="p">(</span><span class="nv">$class</span><span class="p">);</span> <span class="c1">// object(stdClass)#1 (0) {}
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">addItem</span><span class="p">(</span><span class="nv">$class</span><span class="p">,</span> <span class="s1">&#39;test&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">var_dump</span><span class="p">(</span><span class="nv">$class</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="cm">/*
</span></span></span><span class="line"><span class="cl"><span class="cm">object(stdClass)#1 (1) {
</span></span></span><span class="line"><span class="cl"><span class="cm">  [&#34;test&#34;]=&gt; string(4) &#34;test&#34;
</span></span></span><span class="line"><span class="cl"><span class="cm">}
</span></span></span><span class="line"><span class="cl"><span class="cm">*/</span>
</span></span></code></pre></div><p>Here you can see a function called <code>addItem()</code> that adds a property to <code>stdClass</code> instance - this
produces a side effect. The original <code>$class</code> is also updated as it references the same value
so if we dump the variable we can see it&rsquo;s value has changed.</p>
<p>Now consider the same example with a simple scalar string where pass by value takes effect.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="nv">$string</span> <span class="o">=</span> <span class="s1">&#39;begin&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">function</span> <span class="nf">addItem</span><span class="p">(</span><span class="nv">$x</span><span class="p">,</span> <span class="nv">$item</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nv">$x</span> <span class="o">.=</span> <span class="nv">$item</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="nx">var_dump</span><span class="p">(</span><span class="nv">$string</span><span class="p">);</span> <span class="c1">// string(5) &#34;begin&#34;
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">addItem</span><span class="p">(</span><span class="nv">$string</span><span class="p">,</span> <span class="s1">&#39;end&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">var_dump</span><span class="p">(</span><span class="nv">$string</span><span class="p">);</span> <span class="c1">// string(5) &#34;begin&#34;
</span></span></span></code></pre></div><p>Here the original value remains intact because, unlike an object, there is no reference to it from
within the <code>addItem()</code> function.</p>
<p>These side effects make putting an object into an immutable data structure difficult. Someone with
access to the reference could simply change the object after the fact - thus breaking immutability.</p>
<h2 id="what-about-resources">What about resources?</h2>
<p>Turns out the same issues plague resources as well. They are just references to a resource ID so
any change to one will affect all those that also reference it. Simply moving the pointer in a
file resource would break immutability.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="nv">$f</span> <span class="o">=</span> <span class="nx">fopen</span><span class="p">(</span><span class="s1">&#39;/tmp/test.txt&#39;</span><span class="p">,</span> <span class="s1">&#39;r&#39;</span><span class="p">);</span> <span class="c1">// contains &#34;123456789&#34;
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nv">$out</span> <span class="o">=</span> <span class="nx">fread</span><span class="p">(</span><span class="nv">$f</span><span class="p">,</span> <span class="mi">3</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">var_dump</span><span class="p">(</span><span class="nv">$out</span><span class="p">);</span> <span class="c1">// string(3) &#34;123&#34;
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="nv">$out2</span> <span class="o">=</span> <span class="nx">fread</span><span class="p">(</span><span class="nv">$f</span><span class="p">,</span> <span class="mi">3</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">var_dump</span><span class="p">(</span><span class="nv">$out2</span><span class="p">);</span> <span class="c1">// string(3) &#34;456&#34;
</span></span></span></code></pre></div><p>This happens because <code>fread()</code> advances the file pointer as it reads. Even if we do <code>rewind()</code> the
pointer then it is no guarantee of getting the same value back.</p>
<p>An additional issue with resources is that they are, by their nature, not a finite thing so even if you did prevent
changes within your program you could still end up having mutations - someone updating a file
on disk for example.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="nv">$f</span> <span class="o">=</span> <span class="nx">fopen</span><span class="p">(</span><span class="s1">&#39;/dev/urandom&#39;</span><span class="p">,</span> <span class="s1">&#39;r&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nv">$out</span> <span class="o">=</span> <span class="nx">bin2hex</span><span class="p">(</span><span class="nx">fread</span><span class="p">(</span><span class="nv">$f</span><span class="p">,</span> <span class="mi">3</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"><span class="nx">var_dump</span><span class="p">(</span><span class="nv">$out</span><span class="p">);</span> <span class="c1">// string(6) &#34;82e42b&#34;
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="nx">rewind</span><span class="p">(</span><span class="nv">$f</span><span class="p">);</span> <span class="c1">// reset pointer to beginning
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nv">$out2</span> <span class="o">=</span> <span class="nx">bin2hex</span><span class="p">(</span><span class="nx">fread</span><span class="p">(</span><span class="nv">$f</span><span class="p">,</span> <span class="mi">3</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"><span class="nx">var_dump</span><span class="p">(</span><span class="nv">$out2</span><span class="p">);</span> <span class="c1">// string(6) &#34;e20c78&#34;
</span></span></span></code></pre></div><p>In between the two calls to <code>fread()</code> the data in the resource has changed through outside intervention.
A new random value has effectively been written to <code>/dev/urandom</code> meaning the dumped value changes
too even though we have rewound the pointer and used the same offset/index of <code>3</code>.</p>
<p>Note, that the use of <code>bin2hex()</code> converts the binary bytes that <code>/dev/urandom</code> produces into a hexadecimal
representation making it more legible to humans. This conversion process also increases the length
of the value as <code>�@D��N�</code> becomes <code>dd4044f5f84ed6</code> in hexadecimal notation. This is why the offset maybe <code>3</code>,
but the string that comes back is actually <code>6</code> characters long.</p>
<p>However, if your data source is not binary then you do not need to use <code>bin2hex()</code> in your code.</p>
<h2 id="what-can-we-do-to-fix-it">What can we do to fix it?</h2>
<p>In the case of resources, it is too hard to protect them from unauthorised changes so we won&rsquo;t bother.
If you need an immutable resource you&rsquo;ll have to fetch it as a scalar first and then put that into
your immutable data structure.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="nv">$f</span> <span class="o">=</span> <span class="nx">fopen</span><span class="p">(</span><span class="s1">&#39;/dev/urandom&#39;</span><span class="p">,</span> <span class="s1">&#39;r&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nv">$randomStr</span> <span class="o">=</span> <span class="nx">bin2hex</span><span class="p">(</span><span class="nx">fread</span><span class="p">(</span><span class="nv">$f</span><span class="p">,</span> <span class="mi">7</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"><span class="nx">var_dump</span><span class="p">(</span><span class="nv">$randomStr</span><span class="p">);</span> <span class="c1">// string(14) &#34;d102c7ca28b6f1&#34;
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="nx">var_dump</span><span class="p">(</span><span class="nx">substr</span><span class="p">(</span><span class="nv">$randomStr</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">3</span><span class="p">));</span> <span class="c1">// string(3) &#34;d10&#34;
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">var_dump</span><span class="p">(</span><span class="nx">substr</span><span class="p">(</span><span class="nv">$randomStr</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">3</span><span class="p">));</span> <span class="c1">// string(3) &#34;d10&#34;
</span></span></span></code></pre></div><p>As you can clearly see the value does not change between prints in this example because we are accessing
a scalar string instead of a resource directly. You could just as easily feed the <code>$randomStr</code> into the <code>Immutable</code>
definitions that are described further on.</p>
<p>In the case of objects though there is something we can do to protect the immutable from their pass by reference
nature. For simple objects you can simply clone the incoming object value when setting it in an immutable data structure.
This will create a new copy of the object with its own reference and, therefore, break the dependency on the
previous reference - the two objects are not linked by reference. Any change in one will not be reproduced in
the other.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">declare</span><span class="p">(</span><span class="nx">strict_types</span><span class="o">=</span><span class="mi">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">final</span> <span class="k">class</span> <span class="nc">Immutable</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="nv">$data</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="nv">$mutable</span> <span class="o">=</span> <span class="k">true</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="fm">__construct</span><span class="p">(</span><span class="k">stdClass</span> <span class="nv">$value</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="k">false</span> <span class="o">===</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">mutable</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">throw</span> <span class="k">new</span> <span class="nx">\BadMethodCallException</span><span class="p">(</span><span class="s1">&#39;Constructor called twice.&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">data</span> <span class="o">=</span> <span class="k">clone</span> <span class="nv">$value</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">mutable</span> <span class="o">=</span> <span class="k">false</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">get</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">data</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">$test</span> <span class="o">=</span> <span class="k">new</span> <span class="k">stdClass</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="nv">$test</span><span class="o">-&gt;</span><span class="na">data</span> <span class="o">=</span> <span class="s1">&#39;test&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">echo</span> <span class="nv">$test</span><span class="o">-&gt;</span><span class="na">data</span><span class="p">;</span> <span class="c1">// test
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="nv">$imm</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Immutable</span><span class="p">(</span><span class="nv">$test</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="k">echo</span> <span class="nv">$imm</span><span class="o">-&gt;</span><span class="na">get</span><span class="p">()</span><span class="o">-&gt;</span><span class="na">data</span><span class="p">;</span> <span class="c1">// test
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="nv">$test</span><span class="o">-&gt;</span><span class="na">data</span> <span class="o">=</span> <span class="s1">&#39;simon&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">echo</span> <span class="nv">$test</span><span class="o">-&gt;</span><span class="na">data</span><span class="p">;</span> <span class="c1">// simon
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">echo</span> <span class="nv">$imm</span><span class="o">-&gt;</span><span class="na">get</span><span class="p">()</span><span class="o">-&gt;</span><span class="na">data</span><span class="p">;</span> <span class="c1">// test
</span></span></span></code></pre></div><p>By cloning the object we have created a duplicate instance and referenced that instead from within
the <code>Immutable</code>. This means that when <code>$test</code> is later updated it does not affect the value inside
<code>$imm</code> as it is does not have the same reference as <code>$test</code>.</p>
<p>So, there it is, we are done.</p>
<h2 id="deep-nesting-though">Deep nesting though</h2>
<p>Yeah, right, not so fast! The previous example can easily be broken with one small change; provide an object for storage inside <code>$test</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="nv">$value</span> <span class="o">=</span> <span class="k">new</span> <span class="k">stdClass</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="nv">$value</span><span class="o">-&gt;</span><span class="na">data</span> <span class="o">=</span> <span class="s1">&#39;value&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">$test</span> <span class="o">=</span> <span class="k">new</span> <span class="k">stdClass</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="nv">$test</span><span class="o">-&gt;</span><span class="na">data</span> <span class="o">=</span> <span class="nv">$value</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nx">var_dump</span><span class="p">(</span><span class="nv">$test</span><span class="o">-&gt;</span><span class="na">data</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="cm">/*
</span></span></span><span class="line"><span class="cl"><span class="cm">object(stdClass)#1 (1) {
</span></span></span><span class="line"><span class="cl"><span class="cm">  [&#34;data&#34;]=&gt; string(5) &#34;value&#34;
</span></span></span><span class="line"><span class="cl"><span class="cm">}
</span></span></span><span class="line"><span class="cl"><span class="cm">*/</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">$imm</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Immutable</span><span class="p">(</span><span class="nv">$test</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">var_dump</span><span class="p">(</span><span class="nv">$imm</span><span class="o">-&gt;</span><span class="na">get</span><span class="p">()</span><span class="o">-&gt;</span><span class="na">data</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="cm">/*
</span></span></span><span class="line"><span class="cl"><span class="cm">object(stdClass)#1 (1) {
</span></span></span><span class="line"><span class="cl"><span class="cm">  [&#34;data&#34;]=&gt; string(5) &#34;value&#34;
</span></span></span><span class="line"><span class="cl"><span class="cm">}
</span></span></span><span class="line"><span class="cl"><span class="cm">*/</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// change the nested object&#39;s value to see if the immutable changes too
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nv">$value</span><span class="o">-&gt;</span><span class="na">data</span> <span class="o">=</span> <span class="s1">&#39;changed value!&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nx">var_dump</span><span class="p">(</span><span class="nv">$imm</span><span class="o">-&gt;</span><span class="na">get</span><span class="p">()</span><span class="o">-&gt;</span><span class="na">data</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="cm">/*
</span></span></span><span class="line"><span class="cl"><span class="cm">object(stdClass)#1 (1) {
</span></span></span><span class="line"><span class="cl"><span class="cm">  [&#34;data&#34;]=&gt; string(14) &#34;changed value!&#34;
</span></span></span><span class="line"><span class="cl"><span class="cm">}
</span></span></span><span class="line"><span class="cl"><span class="cm">*/</span>
</span></span></code></pre></div><p>As you would expect just because we cloned <code>$test</code> when it is set inside <code>Immutable</code> does not mean
its contents are cloned too. Unfortunately, <code>$value</code> is still referenced directly, so any subsequent updates
get reflected across all referring locations - including inside our <code>Immutable</code>.</p>
<p>The same would be true of any immutable containing an array too. You could just set one of the
array elements to be an object and change it later just like <code>$value</code> in this object example.</p>
<p>Long story short, this immutable is in fact mutable.</p>
<h2 id="immutable-deep-nesting-with-__clone">Immutable deep nesting with <code>__clone()</code></h2>
<p>You could work around the lack of protection by implementing the <code>__clone()</code> magic method in all
classes that might be put inside an immutable. You could then clone all objects stored in the class
when it, itself, is cloned. A simplified demonstration of how this could work is below.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">declare</span><span class="p">(</span><span class="nx">strict_types</span><span class="o">=</span><span class="mi">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">final</span> <span class="k">class</span> <span class="nc">Immutable</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="nv">$data</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="nv">$mutable</span> <span class="o">=</span> <span class="k">true</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="fm">__construct</span><span class="p">(</span><span class="nx">MySimpleClass</span> <span class="nv">$value</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="k">false</span> <span class="o">===</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">mutable</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">throw</span> <span class="k">new</span> <span class="nx">\BadMethodCallException</span><span class="p">(</span><span class="s1">&#39;Constructor called twice.&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">data</span> <span class="o">=</span> <span class="k">clone</span> <span class="nv">$value</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">mutable</span> <span class="o">=</span> <span class="k">false</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">get</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">data</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">MySimpleClass</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="nv">$data</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="fm">__construct</span><span class="p">(</span><span class="k">stdClass</span> <span class="nv">$value</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">data</span> <span class="o">=</span> <span class="nv">$value</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">get</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">data</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="fm">__clone</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">data</span> <span class="o">=</span> <span class="k">clone</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">data</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">$stdClass</span> <span class="o">=</span> <span class="k">new</span> <span class="k">stdClass</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="nv">$stdClass</span><span class="o">-&gt;</span><span class="na">value</span> <span class="o">=</span> <span class="s1">&#39;Hello&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nx">var_dump</span><span class="p">(</span><span class="nv">$stdClass</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="cm">/*
</span></span></span><span class="line"><span class="cl"><span class="cm">object(stdClass)#1 (1) {
</span></span></span><span class="line"><span class="cl"><span class="cm">  [&#34;value&#34;]=&gt; string(5) &#34;Hello&#34;
</span></span></span><span class="line"><span class="cl"><span class="cm">}
</span></span></span><span class="line"><span class="cl"><span class="cm">*/</span>
</span></span><span class="line"><span class="cl"><span class="nv">$toBeStored</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">MySimpleClass</span><span class="p">(</span><span class="nv">$stdClass</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">var_dump</span><span class="p">(</span><span class="nv">$toBeStored</span><span class="o">-&gt;</span><span class="na">get</span><span class="p">());</span>
</span></span><span class="line"><span class="cl"><span class="cm">/*
</span></span></span><span class="line"><span class="cl"><span class="cm">object(stdClass)#1 (1) {
</span></span></span><span class="line"><span class="cl"><span class="cm">  [&#34;value&#34;]=&gt; string(5) &#34;Hello&#34;
</span></span></span><span class="line"><span class="cl"><span class="cm">}
</span></span></span><span class="line"><span class="cl"><span class="cm">*/</span>
</span></span><span class="line"><span class="cl"><span class="nv">$imm</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Immutable</span><span class="p">(</span><span class="nv">$toBeStored</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">var_dump</span><span class="p">(</span><span class="nv">$imm</span><span class="o">-&gt;</span><span class="na">get</span><span class="p">()</span><span class="o">-&gt;</span><span class="na">get</span><span class="p">());</span>
</span></span><span class="line"><span class="cl"><span class="cm">/*
</span></span></span><span class="line"><span class="cl"><span class="cm">object(stdClass)#5 (1) {
</span></span></span><span class="line"><span class="cl"><span class="cm">  [&#34;value&#34;]=&gt; string(5) &#34;Hello&#34;
</span></span></span><span class="line"><span class="cl"><span class="cm">}
</span></span></span><span class="line"><span class="cl"><span class="cm">*/</span>
</span></span></code></pre></div><p>As you can see <code>MySimpleClass</code> is very naive to make the demonstration easier to grasp. You will also
note that the object ID jumps to 5 when the final <code>var_dump()</code> is applied - this is because <code>__clone()</code>
in <code>MySimpleClass</code> was triggered.</p>
<p>If we step through the implementation again and attempt to make a change to <code>$stdClass</code> then it might
be clearer.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="nv">$stdClass</span> <span class="o">=</span> <span class="k">new</span> <span class="k">stdClass</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="nv">$stdClass</span><span class="o">-&gt;</span><span class="na">value</span> <span class="o">=</span> <span class="s1">&#39;Hello&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nx">var_dump</span><span class="p">(</span><span class="nv">$stdClass</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="cm">/*
</span></span></span><span class="line"><span class="cl"><span class="cm">object(stdClass)#1 (1) {
</span></span></span><span class="line"><span class="cl"><span class="cm">  [&#34;value&#34;]=&gt; string(5) &#34;Hello&#34;
</span></span></span><span class="line"><span class="cl"><span class="cm">}
</span></span></span><span class="line"><span class="cl"><span class="cm">*/</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">$toBeStored</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">MySimpleClass</span><span class="p">(</span><span class="nv">$stdClass</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="c1">// we can still modify this object as the clone has not yet happened
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nv">$stdClass</span><span class="o">-&gt;</span><span class="na">data</span> <span class="o">=</span> <span class="s1">&#39;World&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nx">var_dump</span><span class="p">(</span><span class="nv">$toBeStored</span><span class="o">-&gt;</span><span class="na">get</span><span class="p">());</span>
</span></span><span class="line"><span class="cl"><span class="cm">/*
</span></span></span><span class="line"><span class="cl"><span class="cm">object(stdClass)#1 (2) {
</span></span></span><span class="line"><span class="cl"><span class="cm">  [&#34;value&#34;]=&gt; string(5) &#34;Hello&#34;
</span></span></span><span class="line"><span class="cl"><span class="cm">  [&#34;data&#34;]=&gt; string(5) &#34;World&#34;
</span></span></span><span class="line"><span class="cl"><span class="cm">}
</span></span></span><span class="line"><span class="cl"><span class="cm">*/</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// the clone will be triggered by the constructor in Immutable right here
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nv">$imm</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Immutable</span><span class="p">(</span><span class="nv">$toBeStored</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="c1">// Note that the following line returns a different object (#5 instead of #1)
</span></span></span><span class="line"><span class="cl"><span class="c1">// due to the clone operation in the Immutable constructor
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">var_dump</span><span class="p">(</span><span class="nv">$imm</span><span class="o">-&gt;</span><span class="na">get</span><span class="p">()</span><span class="o">-&gt;</span><span class="na">get</span><span class="p">());</span>
</span></span><span class="line"><span class="cl"><span class="cm">/*
</span></span></span><span class="line"><span class="cl"><span class="cm">object(stdClass)#5 (2) {
</span></span></span><span class="line"><span class="cl"><span class="cm">  [&#34;value&#34;]=&gt; string(5) &#34;Hello&#34;
</span></span></span><span class="line"><span class="cl"><span class="cm">  [&#34;data&#34;]=&gt; string(5) &#34;World&#34;
</span></span></span><span class="line"><span class="cl"><span class="cm">}
</span></span></span><span class="line"><span class="cl"><span class="cm">*/</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// the following line will not affect the Immutable wrapped data as $stdClass references
</span></span></span><span class="line"><span class="cl"><span class="c1">// the original #1 object
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nv">$stdClass</span><span class="o">-&gt;</span><span class="na">combined</span> <span class="o">=</span> <span class="nv">$stdClass</span><span class="o">-&gt;</span><span class="na">value</span> <span class="o">.</span> <span class="nv">$stdClass</span><span class="o">-&gt;</span><span class="na">data</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nx">var_dump</span><span class="p">(</span><span class="nv">$imm</span><span class="o">-&gt;</span><span class="na">get</span><span class="p">()</span><span class="o">-&gt;</span><span class="na">get</span><span class="p">());</span>
</span></span><span class="line"><span class="cl"><span class="cm">/*
</span></span></span><span class="line"><span class="cl"><span class="cm">object(stdClass)#5 (2) {
</span></span></span><span class="line"><span class="cl"><span class="cm">  [&#34;value&#34;]=&gt; string(5) &#34;Hello&#34;
</span></span></span><span class="line"><span class="cl"><span class="cm">  [&#34;data&#34;]=&gt; string(5) &#34;World&#34;
</span></span></span><span class="line"><span class="cl"><span class="cm">}
</span></span></span><span class="line"><span class="cl"><span class="cm">*/</span>
</span></span></code></pre></div><p>Unfortunately, this would require you to trust developers to actually implement this correctly and
there would be no way of accurately verifying that a <code>__clone()</code> method has been specified properly.</p>
<p>To solve this issue we must eschew quite a bit of flexibility and only allow known immutable
objects to be set inside the <code>Immutable</code>. This means that we have to recursively step down through
any arrays looking for mutable classes and rejecting them too.</p>
<h2 id="generalised-immutable-deep-nesting">Generalised immutable deep nesting</h2>
<p>For those of us who want a more stringently protected immutable we can generalise the problem by making
an immutable class that can sanitise itself. It will only allow known immutables to be set as data inside
it thereby preventing nested object state changes, which would break its immutable property.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">declare</span><span class="p">(</span><span class="nx">strict_types</span><span class="o">=</span><span class="mi">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">final</span> <span class="k">class</span> <span class="nc">Immutable</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="nv">$data</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="nv">$mutable</span> <span class="o">=</span> <span class="k">true</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="fm">__construct</span><span class="p">(</span><span class="k">array</span> <span class="nv">$args</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="k">false</span> <span class="o">===</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">mutable</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">throw</span> <span class="k">new</span> <span class="nx">\BadMethodCallException</span><span class="p">(</span><span class="s1">&#39;Constructor called twice.&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">data</span> <span class="o">=</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">sanitiseInput</span><span class="p">(</span><span class="nv">$args</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">mutable</span> <span class="o">=</span> <span class="k">false</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">getData</span><span class="p">()</span><span class="o">:</span> <span class="k">array</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">data</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">sanitiseInput</span><span class="p">(</span><span class="k">array</span> <span class="nv">$args</span><span class="p">)</span><span class="o">:</span> <span class="k">array</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nx">array_map</span><span class="p">(</span><span class="k">function</span><span class="p">(</span><span class="nv">$x</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="p">(</span><span class="nx">is_scalar</span><span class="p">(</span><span class="nv">$x</span><span class="p">))</span> <span class="k">return</span> <span class="nv">$x</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nx">is_object</span><span class="p">(</span><span class="nv">$x</span><span class="p">))</span> <span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">sanitiseObject</span><span class="p">(</span><span class="nv">$x</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nx">is_array</span><span class="p">(</span><span class="nv">$x</span><span class="p">))</span> <span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">sanitiseInput</span><span class="p">(</span><span class="nv">$x</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="k">else</span> <span class="k">throw</span> <span class="k">new</span> <span class="nx">\InvalidArgumentException</span><span class="p">(</span><span class="nx">gettype</span><span class="p">(</span><span class="nv">$x</span><span class="p">)</span> <span class="o">.</span> <span class="s1">&#39; cannot be stored in an Immutable.&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">},</span> <span class="nv">$args</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// This method prevents untrusted objects from being set using a type hint
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="c1">// in combination with the declare(strict_types=1) at the top of the file.
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="c1">// Note that it also clones the supplied object.
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="k">private</span> <span class="k">static</span> <span class="k">function</span> <span class="nf">sanitiseObject</span><span class="p">(</span><span class="nx">Immutable</span> <span class="nv">$object</span><span class="p">)</span><span class="o">:</span> <span class="nx">Immutable</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="k">clone</span> <span class="nv">$object</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="fm">__clone</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">data</span> <span class="o">=</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">sanitiseInput</span><span class="p">(</span><span class="nv">$this</span><span class="o">-&gt;</span><span class="na">data</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="fm">__unset</span><span class="p">(</span><span class="nx">string</span> <span class="nv">$id</span><span class="p">)</span><span class="o">:</span> <span class="nx">void</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="fm">__set</span><span class="p">(</span><span class="nx">string</span> <span class="nv">$id</span><span class="p">,</span> <span class="nv">$val</span><span class="p">)</span><span class="o">:</span> <span class="nx">void</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>This class can then be implemented to create immutable lists of things.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="nv">$immA</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Immutable</span><span class="p">([</span><span class="mi">1</span><span class="p">,</span> <span class="s1">&#39;unjani wena&#39;</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl"><span class="nx">var_dump</span><span class="p">(</span><span class="nv">$immA</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="cm">/*
</span></span></span><span class="line"><span class="cl"><span class="cm">object(Immutable)#1 (2) {
</span></span></span><span class="line"><span class="cl"><span class="cm">  [&#34;data&#34;:&#34;Immutable&#34;:private]=&gt; array(2) {
</span></span></span><span class="line"><span class="cl"><span class="cm">    [0]=&gt; int(1)
</span></span></span><span class="line"><span class="cl"><span class="cm">    [1]=&gt; string(11) &#34;unjani wena&#34;
</span></span></span><span class="line"><span class="cl"><span class="cm">  }
</span></span></span><span class="line"><span class="cl"><span class="cm">  [&#34;mutable&#34;:&#34;Immutable&#34;:private]=&gt; bool(false)
</span></span></span><span class="line"><span class="cl"><span class="cm">}
</span></span></span><span class="line"><span class="cl"><span class="cm">*/</span>
</span></span><span class="line"><span class="cl"><span class="nv">$immB</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Immutable</span><span class="p">([</span><span class="mi">2</span><span class="p">,</span> <span class="nv">$immA</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl"><span class="nx">var_dump</span><span class="p">(</span><span class="nv">$immB</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="cm">/*
</span></span></span><span class="line"><span class="cl"><span class="cm">object(Immutable)#2 (2) {
</span></span></span><span class="line"><span class="cl"><span class="cm">  [&#34;data&#34;:&#34;Immutable&#34;:private]=&gt; array(2) {
</span></span></span><span class="line"><span class="cl"><span class="cm">    [0]=&gt; int(2)
</span></span></span><span class="line"><span class="cl"><span class="cm">    [1]=&gt; object(Immutable)#4 (2) {
</span></span></span><span class="line"><span class="cl"><span class="cm">      [&#34;data&#34;:&#34;Immutable&#34;:private]=&gt; array(2) {
</span></span></span><span class="line"><span class="cl"><span class="cm">        [0]=&gt; int(1)
</span></span></span><span class="line"><span class="cl"><span class="cm">        [1]=&gt; string(11) &#34;unjani wena&#34;
</span></span></span><span class="line"><span class="cl"><span class="cm">      }
</span></span></span><span class="line"><span class="cl"><span class="cm">      [&#34;mutable&#34;:&#34;Immutable&#34;:private]=&gt; bool(false)
</span></span></span><span class="line"><span class="cl"><span class="cm">    }
</span></span></span><span class="line"><span class="cl"><span class="cm">  }
</span></span></span><span class="line"><span class="cl"><span class="cm">  [&#34;mutable&#34;:&#34;Immutable&#34;:private]=&gt; bool(false)
</span></span></span><span class="line"><span class="cl"><span class="cm">}
</span></span></span><span class="line"><span class="cl"><span class="cm">*/</span>
</span></span><span class="line"><span class="cl"><span class="nv">$immC</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Immutable</span><span class="p">([</span><span class="mi">2</span><span class="p">,</span> <span class="k">new</span> <span class="k">stdClass</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl"><span class="c1">// Error: Argument 1 passed to Immutable::sanitiseObject() must be an instance of Immutable,
</span></span></span><span class="line"><span class="cl"><span class="c1">// instance of stdClass given
</span></span></span></code></pre></div><p>The main new concept here is the recursive method <code>sanitiseInput()</code>, which recursively steps through the data
array cloning any objects it finds. This is completed in <code>sanitiseObject()</code> that you will also note, uses a type
hint to ensure only instances of <code>Immutable</code> can be set as values. This is how we ensure that only known immutable
objects are being set inside an <code>Immutable</code>.</p>
<p>If you need to check for more than one known immutable class then you could check in a number of ways:</p>
<ul>
<li>extend a base or abstract class when implementing them all,</li>
<li>use an interface that they all implement or</li>
<li>a simple set of <code>instanceOf</code> checks.</li>
</ul>
<p>Something like this might do it.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="sd">/**
</span></span></span><span class="line"><span class="cl"><span class="sd"> * @param Immutable|MyOtherImmutable|SomeOtherImmutable $object
</span></span></span><span class="line"><span class="cl"><span class="sd"> */</span>
</span></span><span class="line"><span class="cl"><span class="k">protected</span> <span class="k">function</span> <span class="nf">sanitiseObject</span><span class="p">(</span><span class="nv">$object</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="nx">array_filter</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="p">[</span><span class="s1">&#39;Immutable&#39;</span><span class="p">,</span> <span class="s1">&#39;MyOtherImmutable&#39;</span><span class="p">,</span> <span class="s1">&#39;SomeOtherImmutable&#39;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">        <span class="k">function</span><span class="p">(</span><span class="nv">$x</span><span class="p">)</span> <span class="k">use</span> <span class="p">(</span><span class="nv">$object</span><span class="p">)</span> <span class="p">{</span> <span class="k">return</span> <span class="nv">$object</span> <span class="nx">instanceOf</span> <span class="nv">$x</span><span class="p">;</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="k">clone</span> <span class="nv">$object</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">throw</span> <span class="k">new</span> <span class="nx">\InvalidArgumentException</span><span class="p">(</span><span class="nx">gettype</span><span class="p">(</span><span class="nv">$x</span><span class="p">)</span> <span class="o">.</span> <span class="s1">&#39; cannot be stored in an Immutable.&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Whichever way you choose or prefer is up to you of course.</p>
<p>So, that finally gives us a simple immutable structure that can store objects, scalars and arrays. You can use
the techniques discussed in the previous article (<a href="/post/2017/04/php-and-immutability-part-two/" title="PHP and immutability: modified copies - part two">part two</a>) to easily create modified copies of your new
immutable.</p>
<h2 id="using-a-generator-to-make-generalisation-easier">Using a generator to make generalisation easier</h2>
<p>The same functionality can also be written using a generator class to create the immutable data structure.
In this section though we are going to be extending the idea just a little further to add some convenience methods.</p>
<h3 id="the-data-structure">The data structure</h3>
<p>Turning to the structure itself, we are going to add a few methods that will make data access more robust in the
generalised class. To this end, it is useful to know if a value exists so we are going to add a <code>has($key)</code> method.
This will also be used by a <code>getOrElse($key, $default)</code> function to allow a default value to be provided where a
key does not already exist.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">declare</span><span class="p">(</span><span class="nx">strict_types</span><span class="o">=</span><span class="mi">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">final</span> <span class="k">class</span> <span class="nc">ImmutableData</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="nv">$data</span> <span class="o">=</span> <span class="p">[];</span>
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="k">function</span> <span class="fm">__construct</span><span class="p">()</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">static</span> <span class="k">function</span> <span class="nf">create</span><span class="p">(</span><span class="k">array</span> <span class="nv">$args</span><span class="p">)</span><span class="o">:</span> <span class="nx">ImmutableData</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$immutable</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">self</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$immutable</span><span class="o">-&gt;</span><span class="na">data</span> <span class="o">=</span> <span class="k">static</span><span class="o">::</span><span class="na">sanitiseInput</span><span class="p">(</span><span class="nv">$args</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$immutable</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">has</span><span class="p">(</span><span class="nv">$key</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nx">array_key_exists</span><span class="p">(</span><span class="nv">$key</span><span class="p">,</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">data</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">get</span><span class="p">(</span><span class="nv">$key</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">data</span><span class="p">[</span><span class="nv">$key</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">getOrElse</span><span class="p">(</span><span class="nv">$key</span><span class="p">,</span> <span class="nv">$default</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span><span class="p">(</span><span class="nv">$this</span><span class="o">-&gt;</span><span class="na">has</span><span class="p">(</span><span class="nv">$key</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">get</span><span class="p">(</span><span class="nv">$key</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$default</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">getAsArray</span><span class="p">()</span><span class="o">:</span> <span class="k">array</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">data</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">protected</span> <span class="k">static</span> <span class="k">function</span> <span class="nf">sanitiseInput</span><span class="p">(</span><span class="k">array</span> <span class="nv">$arr</span><span class="p">)</span><span class="o">:</span> <span class="k">array</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nx">array_map</span><span class="p">(</span><span class="k">function</span><span class="p">(</span><span class="nv">$x</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="p">(</span><span class="nx">is_scalar</span><span class="p">(</span><span class="nv">$x</span><span class="p">))</span> <span class="k">return</span> <span class="nv">$x</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nx">is_object</span><span class="p">(</span><span class="nv">$x</span><span class="p">))</span> <span class="k">return</span> <span class="k">static</span><span class="o">::</span><span class="na">sanitiseObject</span><span class="p">(</span><span class="nv">$x</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nx">is_array</span><span class="p">(</span><span class="nv">$x</span><span class="p">))</span> <span class="k">return</span> <span class="k">static</span><span class="o">::</span><span class="na">sanitiseInput</span><span class="p">(</span><span class="nv">$x</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="k">else</span> <span class="k">throw</span> <span class="k">new</span> <span class="nx">\InvalidArgumentException</span><span class="p">(</span><span class="nx">gettype</span><span class="p">(</span><span class="nv">$x</span><span class="p">)</span> <span class="o">.</span> <span class="s1">&#39; cannot be stored in an Immutable.&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">},</span> <span class="nv">$arr</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">protected</span> <span class="k">static</span> <span class="k">function</span> <span class="nf">sanitiseObject</span><span class="p">(</span><span class="nx">ImmutableData</span> <span class="nv">$object</span><span class="p">)</span><span class="o">:</span> <span class="nx">ImmutableData</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="k">clone</span> <span class="nv">$object</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// return a parsable text representation of the class
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="k">public</span> <span class="k">function</span> <span class="fm">__toString</span><span class="p">()</span><span class="o">:</span> <span class="nx">string</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nx">var_export</span><span class="p">(</span><span class="nv">$this</span><span class="o">-&gt;</span><span class="na">getAsArray</span><span class="p">(),</span> <span class="k">true</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// called when a var_export&#39;d class is parsed
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="k">public</span> <span class="k">function</span> <span class="fm">__set_state</span><span class="p">(</span><span class="k">array</span> <span class="nv">$args</span><span class="p">)</span><span class="o">:</span> <span class="nx">ImmutableData</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="k">static</span><span class="o">:</span><span class="nx">create</span><span class="p">(</span><span class="nv">$args</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="fm">__unset</span><span class="p">(</span><span class="nv">$a</span><span class="p">)</span><span class="o">:</span> <span class="nx">void</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="fm">__set</span><span class="p">(</span><span class="nv">$a</span><span class="p">,</span> <span class="nv">$b</span><span class="p">)</span><span class="o">:</span> <span class="nx">void</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="k">function</span> <span class="fm">__clone</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">data</span> <span class="o">=</span> <span class="k">static</span><span class="o">::</span><span class="na">sanitiseInput</span><span class="p">(</span><span class="nv">$this</span><span class="o">-&gt;</span><span class="na">data</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>This is the complete immutable structure that our generator will populate for us.</p>
<p>Unlike the last <code>Immutable</code> this one makes use of static methods and prevents access to the class constructor
by making it a private method. This skips the <code>$mutable</code> true/false dance we have been doing elsewhere. I prefer the
dance, but this serves as a nice example of another method to achieve a similar result.</p>
<p>You will notice that there are actually a few other methods in there that we have not discussed yet. There is a
<code>get($key)</code> that allows us to access a value by its key easily and <code>getAsArray()</code> has taken over the duties of
returning the complete <code>$this-&gt;data</code> array. Finally, there is a <code>toString()</code> method, which produces a PHP parsable
string representation of the stored data.</p>
<h3 id="a-generator-in-detail">A generator in detail</h3>
<p>Now onto the generator that will produce the populated instances of the <code>ImmutableData</code> class.</p>
<p>The main aim of this generator is to make it as generalised as possible - allowing a consumer to store the
widest selection of types and values as possible whilst ensuring immutability is not broken. In tandem with this
we will also add some methods to make modifying a copy of the immutable easier.</p>
<p>All the data will be stored in an array internally to easily facilitate different data shapes that may be thrown
at the <code>Immutable</code> class.</p>
<p>All data will need to be stored against a key so that it can be accessed again easily.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Immutable</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="nv">$data</span> <span class="o">=</span> <span class="p">[];</span>
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="k">function</span> <span class="fm">__construct</span><span class="p">()</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">static</span> <span class="k">function</span> <span class="nf">create</span><span class="p">()</span><span class="o">:</span> <span class="nx">self</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="k">new</span> <span class="nx">self</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">static</span> <span class="k">function</span> <span class="nf">with</span><span class="p">(</span><span class="nx">ImmutableData</span> <span class="nv">$old</span><span class="p">)</span><span class="o">:</span> <span class="nx">self</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$new</span> <span class="o">=</span> <span class="k">static</span><span class="o">::</span><span class="na">create</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$new</span><span class="o">-&gt;</span><span class="na">data</span> <span class="o">=</span> <span class="nv">$old</span><span class="o">-&gt;</span><span class="na">getAsArray</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$new</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">set</span><span class="p">(</span><span class="nx">string</span> <span class="nv">$key</span><span class="p">,</span> <span class="nv">$value</span><span class="p">)</span><span class="o">:</span> <span class="nx">self</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">setData</span><span class="p">(</span><span class="nv">$key</span><span class="p">,</span> <span class="nv">$value</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">unset</span><span class="p">(</span><span class="nv">$key</span><span class="p">)</span><span class="o">:</span> <span class="nx">self</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">unset</span><span class="p">(</span><span class="nv">$this</span><span class="o">-&gt;</span><span class="na">data</span><span class="p">[</span><span class="nv">$key</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$this</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">setIntKey</span><span class="p">(</span><span class="nx">int</span> <span class="nv">$key</span><span class="p">,</span> <span class="nv">$value</span><span class="p">)</span><span class="o">:</span> <span class="nx">self</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">setData</span><span class="p">(</span><span class="nv">$key</span><span class="p">,</span> <span class="nv">$value</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="k">function</span> <span class="nf">setData</span><span class="p">(</span><span class="nv">$key</span><span class="p">,</span> <span class="nv">$value</span><span class="p">)</span><span class="o">:</span> <span class="nx">self</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">data</span><span class="p">[</span><span class="nv">$key</span><span class="p">]</span> <span class="o">=</span> <span class="nv">$value</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$this</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">arr</span><span class="p">(</span><span class="k">array</span> <span class="nv">$arr</span><span class="p">)</span><span class="o">:</span> <span class="nx">self</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">foreach</span><span class="p">(</span><span class="nv">$arr</span> <span class="k">as</span> <span class="nv">$key</span> <span class="o">=&gt;</span> <span class="nv">$value</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="p">(</span><span class="nx">is_string</span><span class="p">(</span><span class="nv">$key</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">set</span><span class="p">(</span><span class="nv">$key</span><span class="p">,</span> <span class="nv">$value</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nx">is_int</span><span class="p">(</span><span class="nv">$key</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">setIntKey</span><span class="p">(</span><span class="nv">$key</span><span class="p">,</span> <span class="nv">$value</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$this</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">unsetArr</span><span class="p">(</span><span class="k">array</span> <span class="nv">$arr</span><span class="p">)</span><span class="o">:</span> <span class="nx">self</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">foreach</span><span class="p">(</span><span class="nv">$arr</span> <span class="k">as</span> <span class="nv">$key</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">unset</span><span class="p">(</span><span class="nv">$key</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$this</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">build</span><span class="p">()</span><span class="o">:</span> <span class="nx">ImmutableData</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nx">ImmutableData</span><span class="o">::</span><span class="na">create</span><span class="p">(</span><span class="nv">$this</span><span class="o">-&gt;</span><span class="na">data</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">getAsArray</span><span class="p">()</span><span class="o">:</span> <span class="k">array</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">data</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Again this class uses a private constructor and static method to prevent calls to the constructor. You could
use the <code>$mutable</code> true/false setup here, very easily, if you wanted to though.</p>
<h3 id="simple-usage">Simple usage</h3>
<p>These two classes can now be used to generate an immutable data structure like so.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="nv">$immX</span> <span class="o">=</span> <span class="nx">Immutable</span><span class="o">::</span><span class="na">create</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="o">-&gt;</span><span class="na">set</span><span class="p">(</span><span class="s1">&#39;test&#39;</span><span class="p">,</span> <span class="s1">&#39;a string goes here&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="o">-&gt;</span><span class="na">set</span><span class="p">(</span><span class="s1">&#39;another&#39;</span><span class="p">,</span> <span class="mi">100</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="o">-&gt;</span><span class="na">arr</span><span class="p">([</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">5</span><span class="p">,</span><span class="mi">6</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">    <span class="o">-&gt;</span><span class="na">arr</span><span class="p">([</span><span class="s1">&#39;a&#39;</span> <span class="o">=&gt;</span> <span class="mi">1</span><span class="p">,</span> <span class="s1">&#39;b&#39;</span> <span class="o">=&gt;</span> <span class="mi">2</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">    <span class="o">-&gt;</span><span class="na">build</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="k">echo</span> <span class="p">(</span><span class="nx">string</span><span class="p">)</span> <span class="nv">$immX</span><span class="p">;</span>
</span></span></code></pre></div><p>This uses the <code>__toString()</code> method to print a simple and parsable text representation.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">array</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">  <span class="s1">&#39;test&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;a string goes here&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="s1">&#39;another&#39;</span> <span class="o">=&gt;</span> <span class="mi">100</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="mi">0</span> <span class="o">=&gt;</span> <span class="mi">1</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="mi">1</span> <span class="o">=&gt;</span> <span class="mi">2</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="mi">2</span> <span class="o">=&gt;</span> <span class="mi">3</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="mi">3</span> <span class="o">=&gt;</span> <span class="mi">4</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="mi">4</span> <span class="o">=&gt;</span> <span class="mi">5</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="mi">5</span> <span class="o">=&gt;</span> <span class="mi">6</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="s1">&#39;a&#39;</span> <span class="o">=&gt;</span> <span class="mi">1</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="s1">&#39;b&#39;</span> <span class="o">=&gt;</span> <span class="mi">2</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span></code></pre></div><p>You can also put a trusted object into the immutable as well - in this case we will just use the immutable
we created earlier, <code>$immX</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="nv">$immY</span> <span class="o">=</span> <span class="nx">Immutable</span><span class="o">::</span><span class="na">create</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="o">-&gt;</span><span class="na">set</span><span class="p">(</span><span class="s1">&#39;anObject&#39;</span><span class="p">,</span> <span class="nv">$immX</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="o">-&gt;</span><span class="na">build</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="k">echo</span> <span class="p">(</span><span class="nx">string</span><span class="p">)</span> <span class="nv">$immY</span><span class="p">;</span>
</span></span></code></pre></div><p>Again, the output is parsable by the PHP engine so you will notice the slightly weird <code>__set_state()</code> magic
method call in there - you can safely ignore this and concentrate on the data itself. This magic method is
implemented in the <code>ImmutableData</code> class that we defined earlier and it merely serves to populate a class with
a set of data/state when a <code>var_export()</code> output is parsed by PHP.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">array</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">  <span class="s1">&#39;anObject&#39;</span> <span class="o">=&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">ImmutableData</span><span class="o">::</span><span class="na">__set_state</span><span class="p">(</span><span class="k">array</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">     <span class="s1">&#39;data&#39;</span> <span class="o">=&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="k">array</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">      <span class="s1">&#39;test&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;a string goes here&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="s1">&#39;another&#39;</span> <span class="o">=&gt;</span> <span class="mi">100</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="mi">0</span> <span class="o">=&gt;</span> <span class="mi">1</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="mi">1</span> <span class="o">=&gt;</span> <span class="mi">2</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="mi">2</span> <span class="o">=&gt;</span> <span class="mi">3</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="mi">3</span> <span class="o">=&gt;</span> <span class="mi">4</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="mi">4</span> <span class="o">=&gt;</span> <span class="mi">5</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="mi">5</span> <span class="o">=&gt;</span> <span class="mi">6</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="s1">&#39;a&#39;</span> <span class="o">=&gt;</span> <span class="mi">1</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="s1">&#39;b&#39;</span> <span class="o">=&gt;</span> <span class="mi">2</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="p">)),</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span></code></pre></div><p>So, what is the point if we cannot get our data out? Well, remember those <code>get()</code>, <code>has()</code> and <code>getOrElse()</code> methods?
They can be used to quickly and relatively easily access the stored data by key. The methods are fairly self-explanatory
so here are a few examples just to demonstrate their usage against <code>$immY</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">echo</span> <span class="nv">$immY</span><span class="o">-&gt;</span><span class="na">get</span><span class="p">(</span><span class="s1">&#39;test&#39;</span><span class="p">);</span> <span class="c1">// a string goes here
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">var_dump</span><span class="p">(</span><span class="nv">$immY</span><span class="o">-&gt;</span><span class="na">has</span><span class="p">(</span><span class="s1">&#39;test&#39;</span><span class="p">));</span> <span class="c1">// bool(true)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">var_dump</span><span class="p">(</span><span class="nv">$immY</span><span class="o">-&gt;</span><span class="na">has</span><span class="p">(</span><span class="s1">&#39;non-existent&#39;</span><span class="p">));</span> <span class="c1">// bool(false)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">echo</span> <span class="nv">$immY</span><span class="o">-&gt;</span><span class="na">getOrElse</span><span class="p">(</span><span class="s1">&#39;test&#39;</span><span class="p">,</span> <span class="s1">&#39;some default text&#39;</span><span class="p">);</span> <span class="c1">// a string goes here
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">echo</span> <span class="nv">$immY</span><span class="o">-&gt;</span><span class="na">getOrElse</span><span class="p">(</span><span class="s1">&#39;non-existent&#39;</span><span class="p">,</span> <span class="s1">&#39;some default text&#39;</span><span class="p">);</span> <span class="c1">// some default text
</span></span></span></code></pre></div><p>This should give you enough of a foundation to build additional functions like map, reduce, etc upon were
you choose to do so. You could also write methods to fetch items by their value rather than their key as well.</p>
<h3 id="modifying-copies-of-the-immutable-structure-using-the-generator">Modifying copies of the immutable structure using the generator</h3>
<p>The key to making immutables useful is allowing consumers to easily and quickly create modified copies of the
underlying data. This has been written into the generator we defined earlier and can be best described with
a few examples. Note that the <code>with()</code> static method can accept an <code>ImmutableData</code> object as its first
parameter and modification is exactly what this is for. You can then use <code>set()</code> to add or modify values.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="nv">$immZ</span> <span class="o">=</span> <span class="nx">Immutable</span><span class="o">::</span><span class="na">with</span><span class="p">(</span><span class="nv">$immY</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="o">-&gt;</span><span class="na">set</span><span class="p">(</span><span class="s1">&#39;a story&#39;</span><span class="p">,</span> <span class="s1">&#39;This is where someone should write a story&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="o">-&gt;</span><span class="na">setIntKey</span><span class="p">(</span><span class="mi">300</span><span class="p">,</span> <span class="s1">&#39;My int indexed value&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="o">-&gt;</span><span class="na">arr</span><span class="p">([</span><span class="s1">&#39;arr: int indexed&#39;</span><span class="p">,</span> <span class="s1">&#39;arr&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;arr: assoc key becomes immutable key&#39;</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">    <span class="o">-&gt;</span><span class="na">build</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="k">echo</span> <span class="p">(</span><span class="nx">string</span><span class="p">)</span> <span class="nv">$immZ</span><span class="p">;</span>
</span></span></code></pre></div><p>In the result we should see our new properties added to the stored array from <code>$immY</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">array</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">  <span class="s1">&#39;x&#39;</span> <span class="o">=&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">ImmutableData</span><span class="o">::</span><span class="na">__set_state</span><span class="p">(</span><span class="k">array</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">     <span class="s1">&#39;data&#39;</span> <span class="o">=&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="k">array</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">      <span class="s1">&#39;test&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;a string goes here&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="s1">&#39;another&#39;</span> <span class="o">=&gt;</span> <span class="mi">100</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="mi">0</span> <span class="o">=&gt;</span> <span class="mi">1</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="mi">1</span> <span class="o">=&gt;</span> <span class="mi">2</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="mi">2</span> <span class="o">=&gt;</span> <span class="mi">3</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="mi">3</span> <span class="o">=&gt;</span> <span class="mi">4</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="mi">4</span> <span class="o">=&gt;</span> <span class="mi">5</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="mi">5</span> <span class="o">=&gt;</span> <span class="mi">6</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="s1">&#39;a&#39;</span> <span class="o">=&gt;</span> <span class="mi">1</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="s1">&#39;b&#39;</span> <span class="o">=&gt;</span> <span class="mi">2</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="p">)),</span>
</span></span><span class="line"><span class="cl">  <span class="s1">&#39;a story&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;This is where someone should write a story&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="mi">300</span> <span class="o">=&gt;</span> <span class="s1">&#39;My int indexed value&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="mi">0</span> <span class="o">=&gt;</span> <span class="s1">&#39;arr: int indexed&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="s1">&#39;arr&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;arr: assoc key becomes immutable key&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span></code></pre></div><p>Of course, you can also use <code>arr()</code> or <code>setInt()</code> here in the same way too when setting new values or overwriting
existing ones. Just set a value with a key that already exists in the structure and you will overwrite it.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="nv">$throwAway</span> <span class="o">=</span> <span class="nx">Immutable</span><span class="o">::</span><span class="na">with</span><span class="p">(</span><span class="nv">$immZ</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="o">-&gt;</span><span class="na">set</span><span class="p">(</span><span class="s1">&#39;a story&#39;</span><span class="p">,</span> <span class="s1">&#39;My story begins by the slow moving waters of the meandering river.&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="o">-&gt;</span><span class="na">build</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="k">echo</span> <span class="p">(</span><span class="nx">string</span><span class="p">)</span> <span class="nv">$throwAway</span><span class="p">;</span>
</span></span></code></pre></div><p>This would result in a data structure like the following.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">array</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">  <span class="s1">&#39;x&#39;</span> <span class="o">=&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">ImmutableData</span><span class="o">::</span><span class="na">__set_state</span><span class="p">(</span><span class="k">array</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">     <span class="s1">&#39;data&#39;</span> <span class="o">=&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="k">array</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">      <span class="s1">&#39;test&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;a string goes here&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="s1">&#39;another&#39;</span> <span class="o">=&gt;</span> <span class="mi">100</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="mi">0</span> <span class="o">=&gt;</span> <span class="mi">1</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="mi">1</span> <span class="o">=&gt;</span> <span class="mi">2</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="mi">2</span> <span class="o">=&gt;</span> <span class="mi">3</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="mi">3</span> <span class="o">=&gt;</span> <span class="mi">4</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="mi">4</span> <span class="o">=&gt;</span> <span class="mi">5</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="mi">5</span> <span class="o">=&gt;</span> <span class="mi">6</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="s1">&#39;a&#39;</span> <span class="o">=&gt;</span> <span class="mi">1</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="s1">&#39;b&#39;</span> <span class="o">=&gt;</span> <span class="mi">2</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="p">)),</span>
</span></span><span class="line"><span class="cl">  <span class="s1">&#39;a story&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;My story begins by the slow moving waters of the meandering river.&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="mi">300</span> <span class="o">=&gt;</span> <span class="s1">&#39;My int indexed value&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="mi">0</span> <span class="o">=&gt;</span> <span class="s1">&#39;arr: int indexed&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="s1">&#39;arr&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;arr: assoc key becomes immutable key&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span></code></pre></div><p>It is also used to remove items from the data list quite simply too. We can either remove them one at time with
<code>unset($key)</code> or you can remove many by supplying a list to <code>unsetArr()</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="nv">$immAA</span> <span class="o">=</span> <span class="nx">Immutable</span><span class="o">::</span><span class="na">with</span><span class="p">(</span><span class="nv">$immZ</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="o">-&gt;</span><span class="na">unset</span><span class="p">(</span><span class="s1">&#39;x&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="o">-&gt;</span><span class="na">unsetArr</span><span class="p">([</span><span class="s1">&#39;a story&#39;</span><span class="p">,</span> <span class="mi">300</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">    <span class="o">-&gt;</span><span class="na">build</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="k">echo</span> <span class="p">(</span><span class="nx">string</span><span class="p">)</span> <span class="nv">$immAA</span><span class="p">;</span>
</span></span></code></pre></div><p>The execution of this results in the following modified output where a number of keys have been removed.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">array</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">  <span class="mi">0</span> <span class="o">=&gt;</span> <span class="s1">&#39;arr: int indexed&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="s1">&#39;arr&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;arr: assoc key becomes immutable key&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span></code></pre></div><p>You can <code>unset()</code>, <code>unsetArr</code>, <code>set</code>, <code>setIntKey</code> and <code>arr</code> as much as you like before calling <code>build()</code> all
in the one building chain.</p>
<h2 id="conclusion">Conclusion</h2>
<p>Now you have a generalised immutable data structure that you can store anything you like in. If you have an untrusted
object you will need store it as a string using either <code>serialize()</code> or <code>var_export()</code>. The same goes for resources
like file handles where you will need to extract value as text before storing it.</p>
<p>Apart from these two caveats though, you are relatively free to use the immutable as you see fit.</p>
<blockquote>
<p>This article is part of a series I have written on the topic of immutability in PHP code:</p>
<ol>
<li><a href="/post/2017/03/php-and-immutability/" title="PHP and immutability: difficulties and scalars - part one">Part one</a> - a discussion of caveats and a simple scalar handling immutable</li>
<li><a href="/post/2017/04/php-and-immutability-part-two/" title="PHP and immutability: modified copies - part two">Part two</a> - improve the process of creating modified copies of the immutable</li>
<li><a href="/post/2017/04/php-and-immutability-part-three/" title="PHP and immutability: objects and generalisation - part three">Part three</a> - objects in immutable data structures and a generalised immutable implementation</li>
</ol>
<p>Also available in Русский (Russian):</p>
<ol>
<li><a href="http://langtoday.com/?p=735" title="PHP и неизменяемость. Часть 1">Часть 1</a> - PHP и неизменяемость. Часть 1</li>
<li><a href="http://langtoday.com/?p=804" title="PHP и неизменяемость: экземпляры, которые могут быть изменены. Часть 2">Часть 2</a> - PHP и неизменяемость: экземпляры, которые могут быть изменены. Часть 2</li>
<li><a href="http://langtoday.com/?p=1254" title="PHP и неизменяемость: объекты и обобщение. Часть 3">Часть 3</a> - PHP и неизменяемость: объекты и обобщение. Часть 3</li>
</ol>
</blockquote>
<p>If you like this article then you might get a kick out of writing functional php code as taught in the
<a href="https://www.functionalphp.com" title="Functional Programming PHP Second Edition">Functional Programming in PHP book</a> that I wrote.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="php" label="php"/><category scheme="taxonomy:Tags" term="immutable" label="immutable"/></entry><entry xml:base="php-and-immutability-part-two"><title type="html">PHP and immutability: modified copies - part two</title><link href="https://www.simonholywell.com/post/2017/04/php-and-immutability-part-two/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2017/03/php-and-immutability/?utm_source=atom_feed" rel="related" type="text/html" title="PHP and immutability: difficulties and scalars - part one"/><link href="https://www.simonholywell.com/post/2016/11/quick-way-to-create-php-stdclass/?utm_source=atom_feed" rel="related" type="text/html" title="Quick way to create a PHP stdClass"/><link href="https://www.simonholywell.com/post/2016/10/functional-programming-in-php-second-edition/?utm_source=atom_feed" rel="related" type="text/html" title="Functional Programming in PHP Second Edition Available Now"/><link href="https://www.simonholywell.com/post/2016/10/importing-and-aliasing-php-functions/?utm_source=atom_feed" rel="related" type="text/html" title="Importing and aliasing PHP functions"/><link href="https://www.simonholywell.com/post/2015/08/namespace-php-functions/?utm_source=atom_feed" rel="related" type="text/html" title="Namespace PHP functions"/><id>https://www.simonholywell.com/post/2017/04/php-and-immutability-part-two/</id><author><name>Simon Holywell</name></author><published>2017-04-03T01:53:38+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>In the last article we learnt how to create an immutable data structure in PHP. There were a few issues to work through, but we got there in the end. Now onto making the immutable class more useful and easier to create modified copies. Note that these are copies and not modifications, in-place, to the original objects.
This article is part of a series I have written on the topic of immutability in PHP code:</summary><content type="html"><![CDATA[<p>In the <a href="/post/2017/03/php-and-immutability/" title="PHP and immutability: difficulties and scalars - part one">last article</a> we learnt how to create an immutable data structure in PHP. There were a few issues
to work through, but we got there in the end. Now onto making the immutable class more useful and easier
to create modified copies. Note that these are copies and not modifications, in-place, to the original objects.</p>
<blockquote>
<p>This article is part of a series I have written on the topic of immutability in PHP code:</p>
<ol>
<li><a href="/post/2017/03/php-and-immutability/" title="PHP and immutability: difficulties and scalars - part one">Part one</a> - a discussion of caveats and a simple scalar handling immutable</li>
<li><a href="/post/2017/04/php-and-immutability-part-two/" title="PHP and immutability: modified copies - part two">Part two</a> - improve the process of creating modified copies of the immutable</li>
<li><a href="/post/2017/04/php-and-immutability-part-three/" title="PHP and immutability: objects and generalisation - part three">Part three</a> - objects in immutable data structures and a generalised immutable implementation</li>
</ol>
<p>Also available in Русский (Russian):</p>
<ol>
<li><a href="http://langtoday.com/?p=735" title="PHP и неизменяемость. Часть 1">Часть 1</a> - PHP и неизменяемость. Часть 1</li>
<li><a href="http://langtoday.com/?p=804" title="PHP и неизменяемость: экземпляры, которые могут быть изменены. Часть 2">Часть 2</a> - PHP и неизменяемость: экземпляры, которые могут быть изменены. Часть 2</li>
<li><a href="http://langtoday.com/?p=1254" title="PHP и неизменяемость: объекты и обобщение. Часть 3">Часть 3</a> - PHP и неизменяемость: объекты и обобщение. Часть 3</li>
</ol>
</blockquote>
<h2 id="simple-parameter-mutations">Simple parameter mutations</h2>
<p>When you want to modify a property in an immutable object you must, by definition, create a new object and
insert the modified value into that new location. You could simply get the values from the current instance and pass them
into a new instance as you create it.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="nv">$a</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Immutable</span><span class="p">(</span><span class="s1">&#39;Test&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="k">echo</span> <span class="nv">$a</span><span class="o">-&gt;</span><span class="na">getX</span><span class="p">();</span> <span class="c1">// Test
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nv">$b</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Immutable</span><span class="p">(</span><span class="nv">$a</span><span class="o">-&gt;</span><span class="na">getX</span><span class="p">()</span> <span class="o">.</span> <span class="s1">&#39; again&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="k">echo</span> <span class="nv">$b</span><span class="o">-&gt;</span><span class="na">getX</span><span class="p">();</span> <span class="c1">// Test again
</span></span></span></code></pre></div><p>So simple. Too simple!</p>
<p>This technique works reasonably well for this small dataset, but what if we had five or ten parameters
that would have to be replayed every time? An exaggerated example to illustrate my
point follows.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="nv">$a</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Immutable</span><span class="p">(</span><span class="s1">&#39;A&#39;</span><span class="p">,</span> <span class="s1">&#39;B&#39;</span><span class="p">,</span> <span class="s1">&#39;C&#39;</span><span class="p">,</span> <span class="s1">&#39;D&#39;</span><span class="p">,</span> <span class="s1">&#39;E&#39;</span><span class="p">,</span> <span class="s1">&#39;F&#39;</span><span class="p">,</span> <span class="s1">&#39;G&#39;</span><span class="p">,</span> <span class="s1">&#39;H&#39;</span><span class="p">,</span> <span class="s1">&#39;I&#39;</span><span class="p">,</span> <span class="s1">&#39;J&#39;</span><span class="p">,</span> <span class="s1">&#39;K&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="k">echo</span> <span class="nv">$a</span><span class="o">-&gt;</span><span class="na">getK</span><span class="p">();</span> <span class="c1">// K
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nv">$b</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Immutable</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="nv">$a</span><span class="o">-&gt;</span><span class="na">getA</span><span class="p">(),</span> <span class="nv">$a</span><span class="o">-&gt;</span><span class="na">getB</span><span class="p">(),</span> <span class="nv">$a</span><span class="o">-&gt;</span><span class="na">getC</span><span class="p">(),</span> <span class="nv">$a</span><span class="o">-&gt;</span><span class="na">getD</span><span class="p">(),</span> <span class="nv">$a</span><span class="o">-&gt;</span><span class="na">getE</span><span class="p">(),</span> <span class="nv">$a</span><span class="o">-&gt;</span><span class="na">getF</span><span class="p">(),</span>
</span></span><span class="line"><span class="cl">    <span class="nv">$a</span><span class="o">-&gt;</span><span class="na">getG</span><span class="p">(),</span> <span class="nv">$a</span><span class="o">-&gt;</span><span class="na">getH</span><span class="p">(),</span> <span class="nv">$a</span><span class="o">-&gt;</span><span class="na">getI</span><span class="p">(),</span> <span class="nv">$a</span><span class="o">-&gt;</span><span class="na">getJ</span><span class="p">(),</span> <span class="nv">$a</span><span class="o">-&gt;</span><span class="na">getK</span><span class="p">()</span> <span class="o">.</span> <span class="s1">&#39; some change&#39;</span>
</span></span><span class="line"><span class="cl"><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="k">echo</span> <span class="nv">$b</span><span class="o">-&gt;</span><span class="na">getK</span><span class="p">();</span> <span class="c1">// K some change
</span></span></span></code></pre></div><p>It is certainly doable, but I, for one, am not going to be executing that every time I need to work with an
immutable instance. Certainly, not if I can avoid it.</p>
<h2 id="mutation-at-clone-time">Mutation at clone time</h2>
<p>There is a very handy quirk in PHP that we can exploit. It will allow us to create new modified copies of the
object in question.</p>
<p>Instead of mutating the object in place like you would in traditional OOP, we&rsquo;re
going to make a clone of the object and changes it&rsquo;s private properties. Yes, you read
that correctly, you can change the private properties of a class instance!</p>
<p>So you&rsquo;ve probably learnt that private means that a class property cannot be changed from outside or by other
classes overriding it. Whilst this is generally true; when we clone an object we get a fleeting opportunity
to change it&rsquo;s private properties.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="nv">$a</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Immutable</span><span class="p">(</span><span class="s1">&#39;A&#39;</span><span class="p">,</span> <span class="s1">&#39;B&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="k">echo</span> <span class="nv">$a</span><span class="o">-&gt;</span><span class="na">getB</span><span class="p">();</span> <span class="c1">// B
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nv">$b</span> <span class="o">=</span> <span class="k">clone</span> <span class="nv">$a</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nv">$b</span><span class="o">-&gt;</span><span class="na">B</span> <span class="o">=</span> <span class="s1">&#39;22&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="c1">// Fatal error: Cannot access private property Immutable::$B
</span></span></span></code></pre></div><p>Well that didn&rsquo;t work! I should&rsquo;ve said that you can only perform the clone from within a method of the
same class to be able to modify it like this.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">declare</span><span class="p">(</span><span class="nx">strict_types</span><span class="o">=</span><span class="mi">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">final</span> <span class="k">class</span> <span class="nc">Immutable</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="nv">$x</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="nv">$mutable</span> <span class="o">=</span> <span class="k">true</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="fm">__construct</span><span class="p">(</span><span class="nx">string</span> <span class="nv">$input</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="k">false</span> <span class="o">===</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">mutable</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">throw</span> <span class="k">new</span> <span class="nx">\BadMethodCallException</span><span class="p">(</span><span class="s1">&#39;Constructor called twice.&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">x</span> <span class="o">=</span> <span class="nv">$input</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">mutable</span> <span class="o">=</span> <span class="k">false</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">getX</span><span class="p">()</span><span class="o">:</span> <span class="nx">string</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">x</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">withX</span><span class="p">(</span><span class="nx">string</span> <span class="nv">$input</span><span class="p">)</span><span class="o">:</span> <span class="nx">Immutable</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$clonedClass</span> <span class="o">=</span> <span class="k">clone</span> <span class="nv">$this</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$clonedClass</span><span class="o">-&gt;</span><span class="na">x</span> <span class="o">=</span> <span class="nv">$input</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$clonedClass</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="nv">$a</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Immutable</span><span class="p">(</span><span class="s1">&#39;TEST&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="k">echo</span> <span class="nv">$a</span><span class="o">-&gt;</span><span class="na">getX</span><span class="p">();</span> <span class="c1">// TEST
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nv">$b</span> <span class="o">=</span> <span class="nv">$a</span><span class="o">-&gt;</span><span class="na">withX</span><span class="p">(</span><span class="s1">&#39;noop&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="k">echo</span> <span class="nv">$b</span><span class="o">-&gt;</span><span class="na">getX</span><span class="p">();</span> <span class="c1">// noop
</span></span></span></code></pre></div><p>In this way it becomes easier to modify a value inside an immutable - we can wrap up the <code>clone</code> and set
the right values for them. Having a shortened syntax like this really serves to help implementers work
with immutable objects.</p>
<h2 id="preventing-the-setting-of-unexpected-properties">Preventing the setting of unexpected properties</h2>
<p>There are other ways that a seemingly immutable class can be messed with too. Fortunately, these
can be stopped with a couple of PHP magic methods.</p>
<p>In PHP it is possible to add properties to a class at run time - even a <code>final</code> class. We don&rsquo;t want this
as it would change the shape of our class and therefore mean that it was mutable. The simple way to prevent this is to add an empty <code>__set()</code> magic method implementation to your class.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="fm">__set</span><span class="p">(</span><span class="nx">string</span> <span class="nv">$id</span><span class="p">,</span> <span class="nv">$val</span><span class="p">)</span><span class="o">:</span> <span class="nx">void</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span></code></pre></div><p>It is also possible to remove property values by using the <code>unset()</code> construct. We can also prevent this
using another empty magic method:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="fm">__unset</span><span class="p">(</span><span class="nx">string</span> <span class="nv">$id</span><span class="p">)</span><span class="o">:</span> <span class="nx">void</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span></code></pre></div><p>It is important to ban these. Whilst they do not allow modification of our private properties - they do allow outside agents
to change our immutable class by adding and remove their own public properties. The class would
no longer be immutable were this allowed to happen.</p>
<h2 id="merged-clone-time-mutation">Merged clone time mutation</h2>
<p>So far we&rsquo;ve seen the ability to change one property using a <code>withX</code> style method, but what if we want
to change more? Well, you could just chain the changes up with something like this.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="nv">$a</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">MyFantasyImmutable</span><span class="p">(</span><span class="s1">&#39;TEST&#39;</span><span class="p">,</span> <span class="s1">&#39;foo&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="k">echo</span> <span class="nv">$a</span><span class="o">-&gt;</span><span class="na">getX</span><span class="p">();</span> <span class="c1">// TEST
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">echo</span> <span class="nv">$a</span><span class="o">-&gt;</span><span class="na">getY</span><span class="p">();</span> <span class="c1">// foo
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nv">$b</span> <span class="o">=</span> <span class="nv">$a</span><span class="o">-&gt;</span><span class="na">withX</span><span class="p">(</span><span class="s1">&#39;noop&#39;</span><span class="p">)</span><span class="o">-&gt;</span><span class="na">withY</span><span class="p">(</span><span class="s1">&#39;bar&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="k">echo</span> <span class="nv">$b</span><span class="o">-&gt;</span><span class="na">getX</span><span class="p">();</span> <span class="c1">// noop
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">echo</span> <span class="nv">$b</span><span class="o">-&gt;</span><span class="na">getY</span><span class="p">();</span> <span class="c1">// bar
</span></span></span></code></pre></div><p>Whilst it works, there are a few things that I dislike about this approach. A throwaway instance is
created between the calls to <code>withX()</code> and <code>withY()</code>, you have to create a <code>with*()</code> function for every
property and the method chaining quickly gets irritating.</p>
<p>There is, of course, another way.</p>
<p>First, let&rsquo;s define a new immutable class with a few properties.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">declare</span><span class="p">(</span><span class="nx">strict_types</span><span class="o">=</span><span class="mi">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">final</span> <span class="k">class</span> <span class="nc">Bike</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="nv">$engineCc</span><span class="p">,</span> <span class="nv">$brakes</span><span class="p">,</span> <span class="nv">$tractionControl</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="nv">$mutable</span> <span class="o">=</span> <span class="k">true</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="fm">__construct</span><span class="p">(</span><span class="nx">int</span> <span class="nv">$engineCc</span><span class="p">,</span> <span class="nx">string</span> <span class="nv">$brakes</span><span class="p">,</span> <span class="nx">bool</span> <span class="nv">$tractionControl</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="k">false</span> <span class="o">===</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">mutable</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">throw</span> <span class="k">new</span> <span class="nx">\BadMethodCallException</span><span class="p">(</span><span class="s1">&#39;Constructor called twice.&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">engineCc</span> <span class="o">=</span> <span class="nv">$engineCc</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">brakes</span> <span class="o">=</span> <span class="nv">$brakes</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">tractionControl</span> <span class="o">=</span> <span class="nv">$tractionControl</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">mutable</span> <span class="o">=</span> <span class="k">false</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="fm">__get</span><span class="p">(</span><span class="nv">$property</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="nx">property_exists</span><span class="p">(</span><span class="nv">$this</span><span class="p">,</span> <span class="nv">$property</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="nv">$property</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="fm">__set</span><span class="p">(</span><span class="nx">string</span> <span class="nv">$id</span><span class="p">,</span> <span class="nv">$val</span><span class="p">)</span><span class="o">:</span> <span class="nx">void</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="fm">__unset</span><span class="p">(</span><span class="nx">string</span> <span class="nv">$id</span><span class="p">)</span><span class="o">:</span> <span class="nx">void</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>To keep the example shorter, I&rsquo;ve employed a small <code>__get()</code> magic method instead of writing a get
method of each property the class. You would have to write one for each ending up with functions like
<code>getEngineCc()</code>, <code>getBrakes()</code> and <code>getTractionControl()</code>. Instead you access them directly as
properties instead.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="nv">$zx9r</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Bike</span><span class="p">(</span><span class="mi">900</span><span class="p">,</span> <span class="s1">&#39;2 piston floating discs&#39;</span><span class="p">,</span> <span class="k">false</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="k">echo</span> <span class="nv">$zx9r</span><span class="o">-&gt;</span><span class="na">engineCc</span><span class="p">;</span> <span class="c1">// 900
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">echo</span> <span class="nv">$zx9r</span><span class="o">-&gt;</span><span class="na">brakes</span><span class="p">;</span> <span class="c1">// 2 piston floating discs
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="nv">$cagivaRaptor</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Bike</span><span class="p">(</span><span class="mi">1000</span><span class="p">,</span> <span class="s1">&#39;2 piston floating discs&#39;</span><span class="p">,</span> <span class="k">false</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">var_dump</span><span class="p">(</span><span class="nv">$cagivaRaptor</span><span class="o">-&gt;</span><span class="na">tractionControl</span><span class="p">);</span> <span class="c1">// bool(false)
</span></span></span></code></pre></div><p>Anyway back to the mutations! To allow for the easy manipulation of the classes properties when cloning
we can add a simple method to the class.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">with</span><span class="p">(</span><span class="k">array</span> <span class="nv">$args</span><span class="p">)</span><span class="o">:</span> <span class="nx">Bike</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$clonedClass</span> <span class="o">=</span> <span class="k">clone</span> <span class="nv">$this</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="k">foreach</span><span class="p">(</span><span class="nv">$args</span> <span class="k">as</span> <span class="nv">$property</span> <span class="o">=&gt;</span> <span class="nv">$value</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="p">(</span><span class="nx">property_exists</span><span class="p">(</span><span class="nv">$clonedClass</span><span class="p">,</span> <span class="nv">$property</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="nv">$clonedClass</span><span class="o">-&gt;</span><span class="nv">$property</span> <span class="o">=</span> <span class="nv">$value</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$clonedClass</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span></code></pre></div><p>Now when you want a new class with modifications - perhaps when you&rsquo;re releasing a new motorbike model -
you can just call <code>with()</code> and include an associative array.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="nv">$zx9r</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Bike</span><span class="p">(</span><span class="mi">900</span><span class="p">,</span> <span class="s1">&#39;Floating 2 piston&#39;</span><span class="p">,</span> <span class="k">false</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nv">$zx10r</span> <span class="o">=</span> <span class="nv">$zx9r</span><span class="o">-&gt;</span><span class="na">with</span><span class="p">([</span><span class="s1">&#39;engineCc&#39;</span> <span class="o">=&gt;</span> <span class="mi">1000</span><span class="p">,</span> <span class="s1">&#39;tractionControl&#39;</span> <span class="o">=&gt;</span> <span class="k">true</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl"><span class="k">echo</span> <span class="nv">$zx10r</span><span class="o">-&gt;</span><span class="na">engineCc</span><span class="p">;</span> <span class="c1">// 1000
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">echo</span> <span class="nv">$zx10r</span><span class="o">-&gt;</span><span class="na">brakes</span><span class="p">;</span> <span class="c1">// Floating 2 piston
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">var_dump</span><span class="p">(</span><span class="nv">$zx10r</span><span class="o">-&gt;</span><span class="na">tractionControl</span><span class="p">);</span> <span class="c1">// bool(true)
</span></span></span></code></pre></div><p>While it works OK, you may have noticed that we&rsquo;ve now effectively eliminated the ability for PHP to
type check the input. We&rsquo;re no longer populating the class via the constructor.</p>
<p>This is bad because a non-scalar value could be passed in (more on why this sucks in a future article).</p>
<p>One way we could solve this is to replace <code>with()</code> with a function that uses reflection to workout the
constructors parameter order and merge newly supplied values in.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">with</span><span class="p">(</span><span class="k">array</span> <span class="nv">$args</span><span class="p">)</span><span class="o">:</span> <span class="nx">Bike</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$reflection</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">ReflectionMethod</span><span class="p">(</span><span class="nv">$this</span><span class="p">,</span> <span class="s1">&#39;__construct&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$new_parameters</span> <span class="o">=</span> <span class="nx">array_map</span><span class="p">(</span><span class="k">function</span><span class="p">(</span><span class="nv">$param</span><span class="p">)</span> <span class="k">use</span> <span class="p">(</span><span class="nv">$args</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nv">$x</span> <span class="o">=</span> <span class="nv">$param</span><span class="o">-&gt;</span><span class="na">name</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="p">(</span><span class="nx">array_key_exists</span><span class="p">(</span><span class="nv">$x</span><span class="p">,</span> <span class="nv">$args</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">                <span class="o">?</span> <span class="nv">$args</span><span class="p">[</span><span class="nv">$x</span><span class="p">]</span> <span class="c1">// use newly supplied value
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>                <span class="o">:</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="nv">$x</span><span class="p">;</span> <span class="c1">// fallback to the current value
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="p">},</span> <span class="nv">$reflection</span><span class="o">-&gt;</span><span class="na">getParameters</span><span class="p">());</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="k">new</span> <span class="nx">self</span><span class="p">(</span><span class="o">...</span><span class="nv">$new_parameters</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span></code></pre></div><p>When the new class instance is created the newly supplied values are passed to the constructor, which
ensures that they&rsquo;re correctly type checked.</p>
<p>You would call this method in the same way as the last <code>with()</code> implementation. It does make the assumption
that the class properties will have the same name
as the constructor parameter name (<code>$this-&gt;engineCc</code> is the same as constructor parameter <code>$engineCc</code>
for example).</p>
<p>This would leave you a final <code>Bike</code> class of:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">declare</span><span class="p">(</span><span class="nx">strict_types</span><span class="o">=</span><span class="mi">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">final</span> <span class="k">class</span> <span class="nc">Bike</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="nv">$engineCc</span><span class="p">,</span> <span class="nv">$brakes</span><span class="p">,</span> <span class="nv">$tractionControl</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="nv">$mutable</span> <span class="o">=</span> <span class="k">true</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="fm">__construct</span><span class="p">(</span><span class="nx">int</span> <span class="nv">$engineCc</span><span class="p">,</span> <span class="nx">string</span> <span class="nv">$brakes</span><span class="p">,</span> <span class="nx">bool</span> <span class="nv">$tractionControl</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="k">false</span> <span class="o">===</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">mutable</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">throw</span> <span class="k">new</span> <span class="nx">\BadMethodCallException</span><span class="p">(</span><span class="s1">&#39;Constructor called twice.&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">engineCc</span> <span class="o">=</span> <span class="nv">$engineCc</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">brakes</span> <span class="o">=</span> <span class="nv">$brakes</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">tractionControl</span> <span class="o">=</span> <span class="nv">$tractionControl</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">mutable</span> <span class="o">=</span> <span class="k">false</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="fm">__get</span><span class="p">(</span><span class="nv">$property</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="nx">property_exists</span><span class="p">(</span><span class="nv">$this</span><span class="p">,</span> <span class="nv">$property</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="nv">$property</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">with</span><span class="p">(</span><span class="k">array</span> <span class="nv">$args</span><span class="p">)</span><span class="o">:</span> <span class="nx">Bike</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$reflection</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">ReflectionMethod</span><span class="p">(</span><span class="nv">$this</span><span class="p">,</span> <span class="s1">&#39;__construct&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$new_parameters</span> <span class="o">=</span> <span class="nx">array_map</span><span class="p">(</span><span class="k">function</span><span class="p">(</span><span class="nv">$param</span><span class="p">)</span> <span class="k">use</span> <span class="p">(</span><span class="nv">$args</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nv">$x</span> <span class="o">=</span> <span class="nv">$param</span><span class="o">-&gt;</span><span class="na">name</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="p">(</span><span class="nx">array_key_exists</span><span class="p">(</span><span class="nv">$x</span><span class="p">,</span> <span class="nv">$args</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">                <span class="o">?</span> <span class="nv">$args</span><span class="p">[</span><span class="nv">$x</span><span class="p">]</span> <span class="c1">// use newly supplied value
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>                <span class="o">:</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="nv">$x</span><span class="p">;</span> <span class="c1">// fallback to the current value
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="p">},</span> <span class="nv">$reflection</span><span class="o">-&gt;</span><span class="na">getParameters</span><span class="p">());</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="k">new</span> <span class="nx">self</span><span class="p">(</span><span class="o">...</span><span class="nv">$new_parameters</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="fm">__set</span><span class="p">(</span><span class="nx">string</span> <span class="nv">$id</span><span class="p">,</span> <span class="nv">$val</span><span class="p">)</span><span class="o">:</span> <span class="nx">void</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="fm">__unset</span><span class="p">(</span><span class="nx">string</span> <span class="nv">$id</span><span class="p">)</span><span class="o">:</span> <span class="nx">void</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Also bear in mind that the reflection API provided by PHP is not crazily quick so if micro-optimisations
are your thing then you&rsquo;d probably want to avoid this. If you can take the hit then the extra security
you get from the type checking is worth it.</p>
<h2 id="using-a-builder-to-generate-immutable-objects">Using a builder to generate immutable objects</h2>
<p>Another way around this particular issue with immutable objects can be to use a second class to generate the
immutable objects. This will allow you to avoid the use of the Reflection API and still give you the advantage of
type checking. A little touch of irony here as we&rsquo;ll use a mutable builder class to produce an immutable object,
but bear with me.</p>
<p>Firstly, we need to define the immutable object our builder will produce. I am removing the <code>__get()</code> magic here too
as our aim is to make it easier for our code to be analysed statically. This will help IDEs to type hint, code quality
tools to read our code and ostensibly make the code easier to follow cognitively.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">declare</span><span class="p">(</span><span class="nx">strict_types</span><span class="o">=</span><span class="mi">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">final</span> <span class="k">class</span> <span class="nc">Bike</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="nv">$engineCc</span><span class="p">,</span> <span class="nv">$brakes</span><span class="p">,</span> <span class="nv">$tractionControl</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="nv">$mutable</span> <span class="o">=</span> <span class="k">true</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="fm">__construct</span><span class="p">(</span><span class="nx">int</span> <span class="nv">$engineCc</span><span class="p">,</span> <span class="nx">string</span> <span class="nv">$brakes</span><span class="p">,</span> <span class="nx">bool</span> <span class="nv">$tractionControl</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="k">false</span> <span class="o">===</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">mutable</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">throw</span> <span class="k">new</span> <span class="nx">\BadMethodCallException</span><span class="p">(</span><span class="s1">&#39;Constructor called twice.&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">engineCc</span> <span class="o">=</span> <span class="nv">$engineCc</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">brakes</span> <span class="o">=</span> <span class="nv">$brakes</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">tractionControl</span> <span class="o">=</span> <span class="nv">$tractionControl</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">mutable</span> <span class="o">=</span> <span class="k">false</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">getEngineCc</span><span class="p">()</span><span class="o">:</span> <span class="nx">int</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">engineCc</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">getBrakes</span><span class="p">()</span><span class="o">:</span> <span class="nx">string</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">brakes</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">getTractionControl</span><span class="p">()</span><span class="o">:</span> <span class="nx">bool</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">tractionControl</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="fm">__set</span><span class="p">(</span><span class="nx">string</span> <span class="nv">$id</span><span class="p">,</span> <span class="nv">$val</span><span class="p">)</span><span class="o">:</span> <span class="nx">void</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="fm">__unset</span><span class="p">(</span><span class="nx">string</span> <span class="nv">$id</span><span class="p">)</span><span class="o">:</span> <span class="nx">void</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Now we have a simple little immutable class we can get on with the business of creating a generating class.
This new class will accept all the values we wish to store in the immutable class and return an instance of <code>Bike</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">BikeGenerator</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="nv">$engineCc</span><span class="p">,</span> <span class="nv">$brakes</span><span class="p">,</span> <span class="nv">$tractionControl</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">static</span> <span class="k">function</span> <span class="nf">create</span><span class="p">()</span><span class="o">:</span> <span class="nx">self</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="k">new</span> <span class="nx">self</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">static</span> <span class="k">function</span> <span class="nf">with</span><span class="p">(</span><span class="nx">Bike</span> <span class="nv">$oldBike</span><span class="p">)</span><span class="o">:</span> <span class="nx">self</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$generator</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">self</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$generator</span><span class="o">-&gt;</span><span class="na">setEngineCc</span><span class="p">(</span><span class="nv">$oldBike</span><span class="o">-&gt;</span><span class="na">getEngineCc</span><span class="p">());</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$generator</span><span class="o">-&gt;</span><span class="na">setBrakes</span><span class="p">(</span><span class="nv">$oldBike</span><span class="o">-&gt;</span><span class="na">getBrakes</span><span class="p">());</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$generator</span><span class="o">-&gt;</span><span class="na">setTractionControl</span><span class="p">(</span><span class="nv">$oldBike</span><span class="o">-&gt;</span><span class="na">getTractionControl</span><span class="p">());</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$generator</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">setEngineCc</span><span class="p">(</span><span class="nx">int</span> <span class="nv">$cc</span><span class="p">)</span><span class="o">:</span> <span class="nx">self</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">engineCc</span> <span class="o">=</span> <span class="nv">$cc</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$this</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">setBrakes</span><span class="p">(</span><span class="nx">string</span> <span class="nv">$brakes</span><span class="p">)</span><span class="o">:</span> <span class="nx">self</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">brakes</span> <span class="o">=</span> <span class="nv">$brakes</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$this</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">setTractionControl</span><span class="p">(</span><span class="nx">bool</span> <span class="nv">$tractionControl</span><span class="p">)</span><span class="o">:</span> <span class="nx">self</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">tractionControl</span> <span class="o">=</span> <span class="nv">$tractionControl</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$this</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">build</span><span class="p">()</span><span class="o">:</span> <span class="nx">Bike</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="k">new</span> <span class="nx">Bike</span><span class="p">(</span><span class="nv">$this</span><span class="o">-&gt;</span><span class="na">engineCc</span><span class="p">,</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">brakes</span><span class="p">,</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">tractionControl</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>The <code>BikeGenerator</code> duplicates some code of the original class and really serves as a glorified queue. We add
to the queue until we&rsquo;re happy and execute <code>build()</code> to be given a freshly populated instance of <code>Bike</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="nv">$zx9r</span> <span class="o">=</span> <span class="nx">BikeGenerator</span><span class="o">::</span><span class="na">create</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">  <span class="o">-&gt;</span><span class="na">setEngineCc</span><span class="p">(</span><span class="mi">900</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="o">-&gt;</span><span class="na">setBrakes</span><span class="p">(</span><span class="s1">&#39;2 piston floating disc&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="o">-&gt;</span><span class="na">setTractionControl</span><span class="p">(</span><span class="k">false</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="o">-&gt;</span><span class="na">build</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">echo</span> <span class="nv">$zx9r</span><span class="o">-&gt;</span><span class="na">getEngineCc</span><span class="p">();</span> <span class="c1">// 900
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">echo</span> <span class="nv">$zx10r</span><span class="o">-&gt;</span><span class="na">getBrakes</span><span class="p">();</span> <span class="c1">// 2 piston floating disc
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">var_dump</span><span class="p">(</span><span class="nv">$zx10r</span><span class="o">-&gt;</span><span class="na">getTractionControl</span><span class="p">());</span> <span class="c1">// bool(false)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="nv">$zx10r</span> <span class="o">=</span> <span class="nx">BikeGenerator</span><span class="o">::</span><span class="na">with</span><span class="p">(</span><span class="nv">$zx9r</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="o">-&gt;</span><span class="na">setEngineCc</span><span class="p">(</span><span class="mi">1000</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="o">-&gt;</span><span class="na">setBrakes</span><span class="p">(</span><span class="nv">$zx9r</span><span class="o">-&gt;</span><span class="na">getBrakes</span><span class="p">()</span> <span class="o">.</span> <span class="s1">&#39; ABS&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="o">-&gt;</span><span class="na">setTractionControl</span><span class="p">(</span><span class="k">true</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="o">-&gt;</span><span class="na">build</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">echo</span> <span class="nv">$zx10r</span><span class="o">-&gt;</span><span class="na">getEngineCc</span><span class="p">();</span> <span class="c1">// 1000
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">echo</span> <span class="nv">$zx10r</span><span class="o">-&gt;</span><span class="na">getBrakes</span><span class="p">();</span> <span class="c1">// 2 piston floating disc ABS
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">var_dump</span><span class="p">(</span><span class="nv">$zx10r</span><span class="o">-&gt;</span><span class="na">getTractionControl</span><span class="p">());</span> <span class="c1">// bool(true)
</span></span></span></code></pre></div><p>This shows a use of the builder pattern to generate a ready made immutable <code>Bike</code> instance. You can then call <code>::with()</code>
to easily create a new modified version of an existing object.</p>
<h2 id="setting-larger-amounts-of-properties">Setting larger amounts of properties</h2>
<p>There is not all that much that you can do remove the tedium of dealing with many values in an immutable with
PHP. One way to get past this is to pass in an array of values that are checked and stored in the immutable.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">declare</span><span class="p">(</span><span class="nx">strict_types</span><span class="o">=</span><span class="mi">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">final</span> <span class="k">class</span> <span class="nc">Config</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="nv">$properties</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// property =&gt; data type
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="c1">// assume no type = string
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="s1">&#39;name&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s1">&#39;version&#39;</span>   <span class="o">=&gt;</span> <span class="s1">&#39;int&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s1">&#39;released&#39;</span>  <span class="o">=&gt;</span> <span class="s1">&#39;bool&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s1">&#39;licence&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s1">&#39;private&#39;</span>   <span class="o">=&gt;</span> <span class="s1">&#39;bool&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s1">&#39;url&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s1">&#39;repo&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s1">&#39;downloads&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;int&#39;</span>
</span></span><span class="line"><span class="cl">    <span class="p">];</span>
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="nv">$data</span> <span class="o">=</span> <span class="p">[];</span>
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="nv">$mutable</span> <span class="o">=</span> <span class="k">true</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="fm">__construct</span><span class="p">(</span><span class="k">array</span> <span class="nv">$values</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="k">false</span> <span class="o">===</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">mutable</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">throw</span> <span class="k">new</span> <span class="nx">\Exception</span><span class="p">(</span><span class="s1">&#39;Constructor called twice.&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">set</span><span class="p">(</span><span class="nv">$values</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">mutable</span> <span class="o">=</span> <span class="k">false</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="fm">__get</span><span class="p">(</span><span class="nv">$property</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="nx">array_key_exists</span><span class="p">(</span><span class="nv">$property</span><span class="p">,</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">data</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">data</span><span class="p">[</span><span class="nv">$property</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="k">throw</span> <span class="k">new</span> <span class="nx">\Exception</span><span class="p">(</span><span class="s1">&#39;The property &#39;</span> <span class="o">.</span> <span class="nv">$property</span> <span class="o">.</span> <span class="s1">&#39; does not exist&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="k">function</span> <span class="nf">set</span><span class="p">(</span><span class="k">array</span> <span class="nv">$values</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">foreach</span><span class="p">(</span><span class="nv">$this</span><span class="o">-&gt;</span><span class="na">properties</span> <span class="k">as</span> <span class="nv">$prop</span> <span class="o">=&gt;</span> <span class="nv">$type</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">is_string</span><span class="p">(</span><span class="nv">$prop</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="c1">// coalesce to string for properties that don&#39;t have a type specified
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>                <span class="nv">$prop</span> <span class="o">=</span> <span class="nv">$type</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">                <span class="nv">$type</span> <span class="o">=</span> <span class="s1">&#39;string&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="p">(</span><span class="nx">array_key_exists</span><span class="p">(</span><span class="nv">$prop</span><span class="p">,</span> <span class="nv">$values</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">setValue</span><span class="p">(</span><span class="nv">$prop</span><span class="p">,</span> <span class="nv">$type</span><span class="p">,</span> <span class="nv">$values</span><span class="p">[</span><span class="nv">$prop</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="k">function</span> <span class="nf">setValue</span><span class="p">(</span><span class="nv">$prop</span><span class="p">,</span> <span class="nv">$type</span><span class="p">,</span> <span class="nv">$value</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$check</span> <span class="o">=</span> <span class="s1">&#39;is_&#39;</span> <span class="o">.</span> <span class="nv">$type</span><span class="p">;</span> <span class="c1">// eg. is_int()
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="k">if</span> <span class="p">(</span><span class="nv">$check</span><span class="p">(</span><span class="nv">$value</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">data</span><span class="p">[</span><span class="nv">$prop</span><span class="p">]</span> <span class="o">=</span> <span class="nv">$value</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">throw</span> <span class="k">new</span> <span class="nx">\InvalidArgumentException</span><span class="p">(</span><span class="s1">&#39;Incorrect type passed for the &#34;&#39;</span> <span class="o">.</span> <span class="nv">$prop</span> <span class="o">.</span> <span class="s1">&#39;&#34; property - expected &#39;</span> <span class="o">.</span> <span class="nv">$type</span> <span class="o">.</span> <span class="s1">&#39; , but got &#39;</span> <span class="o">.</span> <span class="nx">gettype</span><span class="p">(</span><span class="nv">$prop</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="fm">__set</span><span class="p">(</span><span class="nx">string</span> <span class="nv">$id</span><span class="p">,</span> <span class="nv">$val</span><span class="p">)</span><span class="o">:</span> <span class="nx">void</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="fm">__unset</span><span class="p">(</span><span class="nx">string</span> <span class="nv">$id</span><span class="p">)</span><span class="o">:</span> <span class="nx">void</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>We&rsquo;ve had to eschew the type system in favour a small custom type check defined in the <code>$properties</code> class property
and evaluated in the <code>setValue()</code> method.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="nv">$c</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Config</span><span class="p">([</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;name&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;foo&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;version&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;10&#39;</span>
</span></span><span class="line"><span class="cl"><span class="p">]);</span>
</span></span><span class="line"><span class="cl"><span class="c1">// Uncaught InvalidArgumentException: Incorrect type passed for the &#34;version&#34; property - expected int , but got string
</span></span></span></code></pre></div><p>The way that this works also makes it easy to handle optional arguments at instantiation - up until this point all arguments
have been mandatory. Here you can supply an array missing one or more properties and they simply won&rsquo;t be
set in the <code>$this-&gt;data</code> array.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="nv">$c</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Config</span><span class="p">([</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;name&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;foo&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;version&#39;</span> <span class="o">=&gt;</span> <span class="mi">10</span>
</span></span><span class="line"><span class="cl"><span class="p">]);</span>
</span></span><span class="line"><span class="cl"><span class="k">echo</span> <span class="nv">$c</span><span class="o">-&gt;</span><span class="na">name</span><span class="p">;</span> <span class="c1">// foo
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">echo</span> <span class="nv">$c</span><span class="o">-&gt;</span><span class="na">version</span><span class="p">;</span> <span class="c1">// 10
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">echo</span> <span class="nv">$c</span><span class="o">-&gt;</span><span class="na">repo</span><span class="p">;</span> <span class="c1">// Uncaught Exception: The property repo does not exist
</span></span></span></code></pre></div><p>There are further improvements that could be made here to make the class better able to handle non-existent
values, but they&rsquo;ll have to be the subject of another article.</p>
<p>Also, note that the way the <code>set()</code> method is designed means that it will silently ignore properties passed to it
that do not exist in the <code>$properties</code> class property. You may wish to change this to
throw an exception or warning depending on your use case, of course.</p>
<h2 id="merging-larger-collections-of-properties">Merging larger collections of properties</h2>
<p>It is a very simple exercise to perform a merge now that we have an array for the value store and we&rsquo;re
accepting an associative array for input. We can add the following method to the <code>Config</code> class.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">with</span><span class="p">(</span><span class="k">array</span> <span class="nv">$values</span><span class="p">)</span><span class="o">:</span> <span class="nx">Config</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="k">new</span> <span class="nx">self</span><span class="p">(</span><span class="nx">array_merge</span><span class="p">(</span><span class="nv">$this</span><span class="o">-&gt;</span><span class="na">data</span><span class="p">,</span> <span class="nv">$values</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span></code></pre></div><p>This can then be exercised with:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="nv">$c</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Config</span><span class="p">([</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;name&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;foo&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;version&#39;</span> <span class="o">=&gt;</span> <span class="mi">10</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;repo&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;github.com&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">]);</span>
</span></span><span class="line"><span class="cl"><span class="k">echo</span> <span class="nv">$c</span><span class="o">-&gt;</span><span class="na">name</span><span class="p">;</span> <span class="c1">// foo
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">echo</span> <span class="nv">$c</span><span class="o">-&gt;</span><span class="na">version</span><span class="p">;</span> <span class="c1">// 10
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">echo</span> <span class="nv">$c</span><span class="o">-&gt;</span><span class="na">repo</span><span class="p">;</span> <span class="c1">// github.com
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="nv">$c2</span> <span class="o">=</span> <span class="nv">$c</span><span class="o">-&gt;</span><span class="na">with</span><span class="p">([</span><span class="s1">&#39;name&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;bar&#39;</span><span class="p">,</span> <span class="s1">&#39;version&#39;</span> <span class="o">=&gt;</span> <span class="mi">12</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl"><span class="k">echo</span> <span class="nv">$c2</span><span class="o">-&gt;</span><span class="na">name</span><span class="p">;</span> <span class="c1">// bar
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">echo</span> <span class="nv">$c2</span><span class="o">-&gt;</span><span class="na">version</span><span class="p">;</span> <span class="c1">// 12
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">echo</span> <span class="nv">$c2</span><span class="o">-&gt;</span><span class="na">repo</span><span class="p">;</span> <span class="c1">// github.com
</span></span></span></code></pre></div><p>By writing the code this way, we&rsquo;ve effectively written our own little implementation of named
parameters too. As great as that may be we&rsquo;re also losing some clarity and IDE type hinting with the inherent indirection.</p>
<p>Anyway you cut it, manipulating an immutable in PHP can get annoying pretty quickly.
There appears to be no really simple way of avoiding typing more and/or affecting the type hinting abilities of IDEs.
These are some of the techniques I&rsquo;ve used before to workaround some of the frustration, but there is definitely room for improvement.</p>
<blockquote>
<p>This article is part of a series I have written on the topic of immutability in PHP code:</p>
<ol>
<li><a href="/post/2017/03/php-and-immutability/" title="PHP and immutability: difficulties and scalars - part one">Part one</a> - a discussion of caveats and a simple scalar handling immutable</li>
<li><a href="/post/2017/04/php-and-immutability-part-two/" title="PHP and immutability: modified copies - part two">Part two</a> - improve the process of creating modified copies of the immutable</li>
<li><a href="/post/2017/04/php-and-immutability-part-three/" title="PHP and immutability: objects and generalisation - part three">Part three</a> - objects in immutable data structures and a generalised immutable implementation</li>
</ol>
<p>Also available in Русский (Russian):</p>
<ol>
<li><a href="http://langtoday.com/?p=735" title="PHP и неизменяемость. Часть 1">Часть 1</a> - PHP и неизменяемость. Часть 1</li>
<li><a href="http://langtoday.com/?p=804" title="PHP и неизменяемость: экземпляры, которые могут быть изменены. Часть 2">Часть 2</a> - PHP и неизменяемость: экземпляры, которые могут быть изменены. Часть 2</li>
<li><a href="http://langtoday.com/?p=1254" title="PHP и неизменяемость: объекты и обобщение. Часть 3">Часть 3</a> - PHP и неизменяемость: объекты и обобщение. Часть 3</li>
</ol>
</blockquote>
<p>If you like this article then you might get a kick out of writing functional php code as taught in the
<a href="https://www.functionalphp.com" title="Functional Programming PHP Second Edition">Functional Programming in PHP book</a> that I wrote.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="php" label="php"/><category scheme="taxonomy:Tags" term="immutable" label="immutable"/></entry><entry xml:base="php-and-immutability"><title type="html">PHP and immutability: difficulties and scalars - part one</title><link href="https://www.simonholywell.com/post/2017/03/php-and-immutability/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2016/11/quick-way-to-create-php-stdclass/?utm_source=atom_feed" rel="related" type="text/html" title="Quick way to create a PHP stdClass"/><link href="https://www.simonholywell.com/post/2016/10/functional-programming-in-php-second-edition/?utm_source=atom_feed" rel="related" type="text/html" title="Functional Programming in PHP Second Edition Available Now"/><link href="https://www.simonholywell.com/post/2016/10/importing-and-aliasing-php-functions/?utm_source=atom_feed" rel="related" type="text/html" title="Importing and aliasing PHP functions"/><link href="https://www.simonholywell.com/post/2015/08/namespace-php-functions/?utm_source=atom_feed" rel="related" type="text/html" title="Namespace PHP functions"/><link href="https://www.simonholywell.com/post/2015/07/sql-style-guide/?utm_source=atom_feed" rel="related" type="text/html" title="SQL style guide"/><id>https://www.simonholywell.com/post/2017/03/php-and-immutability/</id><author><name>Simon Holywell</name></author><published>2017-03-16T17:07:26+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Being a weakly typed dynamic language, PHP has not really had the concept of immutability built into it. We&amp;rsquo;ve seen the venerable define() and CONSTANTS of course, but they&amp;rsquo;re limited. Whilst PHP does ship with an immutable class as part of it&amp;rsquo;s standard library, DateTimeImmutable, there is no immediately obvious method to create custom immutable objects.
This article is part of a series I have written on the topic of immutability in PHP code:</summary><content type="html"><![CDATA[<p>Being a weakly typed dynamic language, PHP has not really had the concept of immutability
built into it. We&rsquo;ve seen the venerable <code>define()</code> and CONSTANTS of course, but they&rsquo;re limited.
Whilst PHP does ship with an immutable class as part of it&rsquo;s standard library, <code>DateTimeImmutable</code>,
there is no immediately obvious method to create custom immutable objects.</p>
<blockquote>
<p>This article is part of a series I have written on the topic of immutability in PHP code:</p>
<ol>
<li><a href="/post/2017/03/php-and-immutability/" title="PHP and immutability: difficulties and scalars - part one">Part one</a> - a discussion of caveats and a simple scalar handling immutable</li>
<li><a href="/post/2017/04/php-and-immutability-part-two/" title="PHP and immutability: modified copies - part two">Part two</a> - improve the process of creating modified copies of the immutable</li>
<li><a href="/post/2017/04/php-and-immutability-part-three/" title="PHP and immutability: objects and generalisation - part three">Part three</a> - objects in immutable data structures and a generalised immutable implementation</li>
</ol>
<p>Also available in Русский (Russian):</p>
<ol>
<li><a href="http://langtoday.com/?p=735" title="PHP и неизменяемость. Часть 1">Часть 1</a> - PHP и неизменяемость. Часть 1</li>
<li><a href="http://langtoday.com/?p=804" title="PHP и неизменяемость: экземпляры, которые могут быть изменены. Часть 2">Часть 2</a> - PHP и неизменяемость: экземпляры, которые могут быть изменены. Часть 2</li>
<li><a href="http://langtoday.com/?p=1254" title="PHP и неизменяемость: объекты и обобщение. Часть 3">Часть 3</a> - PHP и неизменяемость: объекты и обобщение. Часть 3</li>
</ol>
</blockquote>
<h2 id="constants">Constants</h2>
<p>The only immutable data store available in PHP is constants, which are set with <code>define()</code> or
the <code>const</code> keyword on a PHP class. There is one important difference between the two options
though.</p>
<p>Class constants (<code>const</code>) are set when the code is written and cannot be changed at runtime.
This property makes them PHP&rsquo;s most immutable user defined structure. If you wanted to set a different value conditionally or set a value from another variable you&rsquo;re out of luck.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Immutable</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">const</span> <span class="no">TRICK</span> <span class="o">=</span> <span class="s1">&#39;kickflip&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="fm">__construct</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">echo</span> <span class="k">static</span><span class="o">::</span><span class="na">TRICK</span><span class="p">;</span>     <span class="c1">// kickflip
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="k">static</span><span class="o">::</span><span class="na">TRICK</span> <span class="o">=</span> <span class="s1">&#39;HHHH&#39;</span><span class="p">;</span> <span class="c1">// Parse error unexpected &#39;=&#39;
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="k">new</span> <span class="nx">Immutable</span><span class="p">();</span>
</span></span></code></pre></div><p>Traditional constants, set with <code>define()</code>, can be initialised conditionally and be built from other
variables - once set though, they are immutable.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="nv">$skater</span> <span class="o">=</span> <span class="s1">&#39;Mullen&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="p">(</span><span class="nv">$skater</span> <span class="o">===</span> <span class="s1">&#39;Mullen&#39;</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">define</span><span class="p">(</span><span class="s1">&#39;TRICK&#39;</span><span class="p">,</span> <span class="nv">$skater</span> <span class="o">.</span> <span class="s1">&#39; created the flatground Ollie&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nv">$skater</span> <span class="o">===</span> <span class="s1">&#39;Hawk&#39;</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">define</span><span class="p">(</span><span class="s1">&#39;TRICK&#39;</span><span class="p">,</span> <span class="nv">$skater</span> <span class="o">.</span> <span class="s1">&#39; invented the Kickflip McTwist&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="k">echo</span> <span class="nx">TRICK</span><span class="p">;</span> <span class="c1">// Mullen created the flatground Ollie
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">define</span><span class="p">(</span><span class="s1">&#39;TRICK&#39;</span><span class="p">,</span> <span class="s1">&#39;nothing&#39;</span><span class="p">);</span> <span class="c1">// Notice: Constant TRICK already defined
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">echo</span> <span class="nx">TRICK</span><span class="p">;</span> <span class="c1">// Mullen created the flatground Ollie;
</span></span></span></code></pre></div><p>As you can see, if you try to modify the constant then you&rsquo;ll get a PHP notice - the value though
will remain unchanged. You can check if a constant is already defined with the function <code>defined()</code> -
note the extra <code>d</code>!</p>
<p>So, that works well for simple scalars. If you want to store any kind of array structure as an
immutable though you&rsquo;ll have to use a class constant or be disappointed by any version of PHP
before PHP 7.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="nx">define</span><span class="p">(</span><span class="s1">&#39;TRICKS&#39;</span><span class="p">,</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;Ollie&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;Darkslide&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;Heelflip&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;Nollie&#39;</span>
</span></span><span class="line"><span class="cl"><span class="p">]);</span>
</span></span><span class="line"><span class="cl"><span class="c1">// Warning: Constants may only evaluate to scalar values
</span></span></span></code></pre></div><p>If you&rsquo;re feeling smug and running PHP7 then, well, I have some bad news - arrays work, sure, but
objects not so much!</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="nx">define</span><span class="p">(</span><span class="s1">&#39;TRICKS&#39;</span><span class="p">,</span> <span class="k">new</span> <span class="k">stdClass</span><span class="p">());</span>
</span></span><span class="line"><span class="cl"><span class="c1">// Warning: Constants may only evaluate to scalar values or arrays
</span></span></span></code></pre></div><p>There are other reasons that you probably don&rsquo;t want a constant anyway.</p>
<p>In the case of class constants we&rsquo;ve seen how limited they are with their requirement to be set before
runtime. You get a some scoping though with them bound to the class definition in question.</p>
<p>Traditional constants are defined globally. Is that really what you want? Surely you&rsquo;d rather have a
proper variable that you can pass around between functions and that adheres to PHP&rsquo;s scoping rules.</p>
<p>Both of these methods result in weird syntax usage, where a far simpler variable syntax would be more
appropriate and likely expected.</p>
<h2 id="custom-immutable-classes">Custom immutable classes</h2>
<p>It is possible to write your own immutables using some simple and sneaky PHP techniques though. We&rsquo;re
going to use a simplistic data requirement to make the examples in this article easier to follow. I&rsquo;ll be
using professional skateboarders and the tricks that they brought to the world.</p>
<p>First up, is a simple immutable PHP class that accepts it&rsquo;s values as parameters to the constructor. I
have called the class <code>Immutable</code>, but this is probably a bad idea in non-trivial code as it may become a
reserved word in the future. Right now though it has absolutely no significance beyond being a nice name
to give the class.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Immutable</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="nv">$skater</span><span class="p">,</span> <span class="nv">$trick</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="fm">__construct</span><span class="p">(</span><span class="nv">$skater</span><span class="p">,</span> <span class="nv">$trick</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">skater</span> <span class="o">=</span> <span class="nv">$skater</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">trick</span> <span class="o">=</span> <span class="nv">$trick</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">getSkater</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">skater</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">getTrick</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">trick</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>By using private class properties here we have ensured that the values cannot be changed by code outside
of the <code>Immutable</code> class definition.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="nv">$x</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Immutable</span><span class="p">(</span><span class="s1">&#39;Hawk&#39;</span><span class="p">,</span> <span class="s1">&#39;Frontside 540&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="k">echo</span> <span class="nv">$x</span><span class="o">-&gt;</span><span class="na">skater</span> <span class="o">=</span> <span class="s1">&#39;Mullen&#39;</span><span class="p">;</span> <span class="c1">// Fatal error: Cannot access private property Immutable::$skater
</span></span></span></code></pre></div><p>To allow external access the values bound up into an <code>Immutable</code> object is simply a case of writing a
public method that returns the required value. In our example here we have two class properties we want
access to so I have added <code>getSkater()</code> to get the skater&rsquo;s name and <code>getTrick()</code> to get the name of the
trick they invented.</p>
<p>This gives you a very simple immutable class that once initialised cannot be changed externally.</p>
<h2 id="avoiding-mutations">Avoiding mutations</h2>
<p>It is
important that no methods are added to <code>Immutable</code> that will allow values inside the class to be mutated.
Obviously you do not want to be writing <code>public</code> methods into the class like <code>setSkater()</code> or <code>setTrick()</code>
as these would allow an implementer to mutate our mutable class.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Immutable</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="o">...</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// WRONG: don&#39;t do this!
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="k">public</span> <span class="k">function</span> <span class="nf">setSkater</span><span class="p">(</span><span class="nv">$skater</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">skater</span> <span class="o">=</span> <span class="nv">$skater</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="o">...</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="nv">$x</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Immutable</span><span class="p">(</span><span class="s1">&#39;Mullen&#39;</span><span class="p">,</span> <span class="s1">&#39;50-50 Sidewinder&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="k">echo</span> <span class="nv">$x</span><span class="o">-&gt;</span><span class="na">getSkater</span><span class="p">();</span> <span class="c1">// Mullen
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nv">$x</span><span class="o">-&gt;</span><span class="na">setSkater</span><span class="p">(</span><span class="s1">&#39;Hawk&#39;</span><span class="p">);</span> <span class="c1">// Argh! No! You&#39;re MUTATING!
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">echo</span> <span class="nv">$x</span><span class="o">-&gt;</span><span class="na">getSkater</span><span class="p">();</span> <span class="c1">// Hawk
</span></span></span></code></pre></div><p>Now we have a working example and understanding of an immutable object in PHP it&rsquo;s time to declare that
there are a couple of other pit falls here though too. Sorry! You didn&rsquo;t really expect it to be that easy
did you?</p>
<h2 id="stopping-circumventions">Stopping circumventions</h2>
<p>A lot of people out there don&rsquo;t like immutability as much as you and I. They&rsquo;ll do everything in their
power to circumvent our very specifically designed immutable objects.</p>
<h3 id="overriding-the-immutable-variable">Overriding the immutable variable</h3>
<p>The easiest way to get around
intended immutability in PHP is simply to override the variable the immutable instance is assigned to.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="nv">$a</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Immutable</span><span class="p">(</span><span class="s1">&#39;Mullen&#39;</span><span class="p">,</span> <span class="s1">&#39;Casper slide&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nv">$a</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">TrickRecord</span><span class="p">(</span><span class="s1">&#39;Mullen&#39;</span><span class="p">,</span> <span class="s1">&#39;Airwalk&#39;</span><span class="p">);</span>
</span></span></code></pre></div><p>When the code is run <code>$a</code> will be silently overridden by a <code>new TrickRecord</code> instead of throwing an error as
we would hope. This is a symptom of PHP&rsquo;s history and the intended behaviour. Of course being a naughty
developer you can be sure they&rsquo;ve not made <code>TrickRecord</code> immutable!</p>
<p>As of writing there is no way to prevent this from happening in PHP. As we know from before objects can&rsquo;t
be assigned to a constant (only scalars and in PHP 7 arrays). In JavaScript we now have the <code>const</code> keyword
that would prevent this from happening, but no such luck in PHP.</p>
<p>The only way that you might be able to prevent this is to use type hints everywhere that you expect an
<code>Immutable</code> to be passed in, but as we&rsquo;ll see there are ways around this too!</p>
<h3 id="multiple-calls-to-the-constructor">Multiple calls to the constructor</h3>
<p>Another simple way of frustrating the immutable is to simply call the constructor again with different
parameters.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="nv">$x</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Immutable</span><span class="p">(</span><span class="s1">&#39;Hawk&#39;</span><span class="p">,</span> <span class="s1">&#39;Frontside 540&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="k">echo</span> <span class="nv">$x</span><span class="o">-&gt;</span><span class="na">getSkater</span><span class="p">();</span> <span class="c1">// Hawk
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nv">$x</span><span class="o">-&gt;</span><span class="na">__construct</span><span class="p">(</span><span class="s1">&#39;Song&#39;</span><span class="p">,</span> <span class="s1">&#39;Frontside 540&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="k">echo</span> <span class="nv">$x</span><span class="o">-&gt;</span><span class="na">getSkater</span><span class="p">();</span> <span class="c1">// Song
</span></span></span></code></pre></div><p>Obviously, this is a pain and highly undesirable. Luckily, we can work around this problem by including
a flag in our class to prevent mutations. I&rsquo;d just like to mention here that Daewon Song is a great
skater - it&rsquo;s just that he didn&rsquo;t invent the frontside 540 so we cannot allow it.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Immutable</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="nv">$skater</span><span class="p">,</span> <span class="nv">$trick</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="nv">$mutable</span> <span class="o">=</span> <span class="k">true</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="fm">__construct</span><span class="p">(</span><span class="nv">$skater</span><span class="p">,</span> <span class="nv">$trick</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="k">false</span> <span class="o">===</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">mutable</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">throw</span> <span class="k">new</span> <span class="nx">\BadMethodCallException</span><span class="p">(</span><span class="s1">&#39;Constructor called twice.&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">skater</span> <span class="o">=</span> <span class="nv">$skater</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">trick</span> <span class="o">=</span> <span class="nv">$trick</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">mutable</span> <span class="o">=</span> <span class="k">false</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">getSkater</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">skater</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">getTrick</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">trick</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>With this change multiple calls to the constructor will not be allowed and throw a fatal exception.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="nv">$x</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Immutable</span><span class="p">(</span><span class="s1">&#39;Hawk&#39;</span><span class="p">,</span> <span class="s1">&#39;Frontside 540&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="k">echo</span> <span class="nv">$x</span><span class="o">-&gt;</span><span class="na">getSkater</span><span class="p">();</span> <span class="c1">// Hawk
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nv">$x</span><span class="o">-&gt;</span><span class="na">__construct</span><span class="p">(</span><span class="s1">&#39;Song&#39;</span><span class="p">,</span> <span class="s1">&#39;Darkslide&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="c1">// Fatal error: Uncaught BadMethodCallException: Constructor called twice.
</span></span></span></code></pre></div><h3 id="extending-the-immutable-class">Extending the Immutable class</h3>
<p>It is also possible for a developer to write a class that extends our <code>Immutable</code>. This would allow them
to overload our constructor with their own.</p>
<p>Once they have their own constructor they can assign <code>$skater</code> and <code>$trick</code> to their own public class
properties. This breaks the immutability of the class as public properties can be changed. Similarly
they could add new methods to set the value of their properties too.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">NaughtyDev</span> <span class="k">extends</span> <span class="nx">Immutable</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="nv">$mySkater</span><span class="p">,</span> <span class="nv">$myTrick</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="fm">__construct</span><span class="p">(</span><span class="nv">$skater</span><span class="p">,</span> <span class="nv">$trick</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">mySkater</span> <span class="o">=</span> <span class="nv">$skater</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">myTrick</span> <span class="o">=</span> <span class="nv">$trick</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">setTrick</span><span class="p">(</span><span class="nv">$trick</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">myTrick</span> <span class="o">=</span> <span class="nv">$trick</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>As <code>NaughtyDev</code> extends <code>Immutable</code> any type checking done on an instance will pass. Here a sneaky
developer is passing us an instance of <code>NaughtyDev</code> where our code wants an <code>Immutable</code>, but we&rsquo;re
none the wiser.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="nv">$x</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">NaughtyDev</span><span class="p">(</span><span class="s1">&#39;Hawk&#39;</span><span class="p">,</span> <span class="s1">&#39;900&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nv">$x</span> <span class="nx">instanceof</span> <span class="nx">Immutable</span><span class="p">;</span> <span class="c1">// true
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="k">function</span> <span class="nf">onlyGiveMeAnImmutable</span><span class="p">(</span><span class="nx">Immutable</span> <span class="nv">$z</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nv">$z</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="nx">onlyGiveMeAnImmutable</span><span class="p">(</span><span class="nv">$x</span><span class="p">);</span> <span class="c1">// does not throw a type error
</span></span></span></code></pre></div><p>It is all perfectly valid code and the expected behaviour of PHP. We&rsquo;re doing something strange by
insisting on an immutable. So that&rsquo;s a fun little caveat to the whole process.</p>
<p>There is a way around this one with PHP&rsquo;s <code>final</code> keyword though. Final tells the parser that the class
in question is complete and must not be extended with other functionality.</p>
<p>With one small change to our <code>Immutable</code> class we can prevent this attack on the
immutable.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">final</span> <span class="k">class</span> <span class="nc">Immutable</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="nv">$skater</span><span class="p">,</span> <span class="nv">$trick</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="nv">$mutable</span> <span class="o">=</span> <span class="k">true</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="fm">__construct</span><span class="p">(</span><span class="nv">$skater</span><span class="p">,</span> <span class="nv">$trick</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="k">false</span> <span class="o">===</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">mutable</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">throw</span> <span class="k">new</span> <span class="nx">\BadMethodCallException</span><span class="p">(</span><span class="s1">&#39;Constructor called twice.&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">skater</span> <span class="o">=</span> <span class="nv">$skater</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">trick</span> <span class="o">=</span> <span class="nv">$trick</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">mutable</span> <span class="o">=</span> <span class="k">false</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">getSkater</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">skater</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">getTrick</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">trick</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">NaughtyDev</span> <span class="k">extends</span> <span class="nx">Immutable</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="c1">// Fatal error: Class NaughtyDev may not inherit from final class (Immutable)
</span></span></span></code></pre></div><p>So now we know that we need a class that is declared <code>final</code> and uses private properties to store our
data. It is important to ensure that no methods in <code>Immutable</code> allow changes to any values after the
class is instantiated.</p>
<h2 id="finally-a-more-complete-example">Finally, a more complete example</h2>
<p>To finish off let&rsquo;s go through a final working example of an immutable object in PHP. In this example
PHP 7 type hinting has been added as well.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">declare</span><span class="p">(</span><span class="nx">strict_types</span><span class="o">=</span><span class="mi">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">final</span> <span class="k">class</span> <span class="nc">SkateboardTrick</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="nv">$inventor</span><span class="p">,</span> <span class="nv">$trickName</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="nv">$mutable</span> <span class="o">=</span> <span class="k">true</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="fm">__construct</span><span class="p">(</span><span class="nx">string</span> <span class="nv">$skater</span><span class="p">,</span> <span class="nx">string</span> <span class="nv">$trick</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="k">false</span> <span class="o">===</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">mutable</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">throw</span> <span class="k">new</span> <span class="nx">\BadMethodCallException</span><span class="p">(</span><span class="s1">&#39;Constructor called twice.&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">inventor</span> <span class="o">=</span> <span class="nv">$skater</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">trickName</span> <span class="o">=</span> <span class="nv">$trick</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">mutable</span> <span class="o">=</span> <span class="k">false</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">getInventor</span><span class="p">()</span><span class="o">:</span> <span class="nx">string</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">inventor</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">getTrickName</span><span class="p">()</span><span class="o">:</span> <span class="nx">string</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">trickName</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>The strict type declaration and the use of function argument hinting further fortifies the immutable
class. We don&rsquo;t unexpectedly get given an object for instance. This would be bad because that object
could be altered elsewhere, which would change the contents of our immutable - bad! More on this in
a later article.</p>
<h2 id="conclusion">Conclusion</h2>
<p>The methods and properties defined in the <code>final</code> class <code>SkateboardTrick</code> ensure that the object is
immutable and cannot be extended. This is, of course, our goal.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="nv">$x</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">SkateboardTrick</span><span class="p">(</span><span class="s1">&#39;Mullen&#39;</span><span class="p">,</span> <span class="s1">&#39;540 Shove-it&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="k">echo</span> <span class="nv">$x</span><span class="o">-&gt;</span><span class="na">getInventor</span><span class="p">();</span> <span class="c1">// Mullen
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">echo</span> <span class="nv">$x</span><span class="o">-&gt;</span><span class="na">getTrickName</span><span class="p">();</span> <span class="c1">// 540 Shove-it
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="nv">$x</span><span class="o">-&gt;</span><span class="na">inventor</span> <span class="o">=</span> <span class="s1">&#39;Hawk&#39;</span><span class="p">;</span> <span class="c1">// Fatal error: Cannot access private property SkateboardTrick::$inventor
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="nv">$x</span><span class="o">-&gt;</span><span class="na">__construct</span><span class="p">(</span><span class="s1">&#39;Hawk&#39;</span><span class="p">,</span> <span class="nv">$x</span><span class="o">-&gt;</span><span class="na">getTrickName</span><span class="p">());</span>
</span></span><span class="line"><span class="cl"><span class="c1">// Fatal error: Uncaught BadMethodCallException: Constructor called twice.
</span></span></span></code></pre></div><p>This means that if you need to alter a value in <code>SkateboardTrick</code> you&rsquo;ll have to create a new instance
with the modified values.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="nv">$x</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">SkateboardTrick</span><span class="p">(</span><span class="s1">&#39;Mullen&#39;</span><span class="p">,</span> <span class="s1">&#39;Ollie&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="k">echo</span> <span class="nv">$x</span><span class="o">-&gt;</span><span class="na">getInventor</span><span class="p">();</span> <span class="c1">// Mullen
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">echo</span> <span class="nv">$x</span><span class="o">-&gt;</span><span class="na">getTrickName</span><span class="p">();</span> <span class="c1">// Ollie
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="nv">$z</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">SkateboardTrick</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="nv">$x</span><span class="o">-&gt;</span><span class="na">getInventor</span><span class="p">(),</span>
</span></span><span class="line"><span class="cl">    <span class="nv">$x</span><span class="o">-&gt;</span><span class="na">getTrickName</span><span class="p">()</span> <span class="o">.</span> <span class="s1">&#39; fingerflip&#39;</span>
</span></span><span class="line"><span class="cl"><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="k">echo</span> <span class="nv">$z</span><span class="o">-&gt;</span><span class="na">getInventor</span><span class="p">();</span> <span class="c1">// Mullen
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">echo</span> <span class="nv">$z</span><span class="o">-&gt;</span><span class="na">getTrickName</span><span class="p">();</span> <span class="c1">// Ollie fingerflip
</span></span></span></code></pre></div><p>In my <a href="/post/2017/04/php-and-immutability-part-two/" title="PHP and immutability: modified copies - part two">next article</a> I will cover how we can optimise the process of creating new instances with
modified information contained within them. They&rsquo;ll still be immutable of course, just with a
little more sugar to make things a touch easier.</p>
<blockquote>
<p>This article is part of a series I have written on the topic of immutability in PHP code:</p>
<ol>
<li><a href="/post/2017/03/php-and-immutability/" title="PHP and immutability: difficulties and scalars - part one">Part one</a> - a discussion of caveats and a simple scalar handling immutable</li>
<li><a href="/post/2017/04/php-and-immutability-part-two/" title="PHP and immutability: modified copies - part two">Part two</a> - improve the process of creating modified copies of the immutable</li>
<li><a href="/post/2017/04/php-and-immutability-part-three/" title="PHP and immutability: objects and generalisation - part three">Part three</a> - objects in immutable data structures and a generalised immutable implementation</li>
</ol>
<p>Also available in Русский (Russian):</p>
<ol>
<li><a href="http://langtoday.com/?p=735" title="PHP и неизменяемость. Часть 1">Часть 1</a> - PHP и неизменяемость. Часть 1</li>
<li><a href="http://langtoday.com/?p=804" title="PHP и неизменяемость: экземпляры, которые могут быть изменены. Часть 2">Часть 2</a> - PHP и неизменяемость: экземпляры, которые могут быть изменены. Часть 2</li>
<li><a href="http://langtoday.com/?p=1254" title="PHP и неизменяемость: объекты и обобщение. Часть 3">Часть 3</a> - PHP и неизменяемость: объекты и обобщение. Часть 3</li>
</ol>
</blockquote>
<p>If you like this article then you might get a kick out of writing functional php code as taught in the
<a href="https://www.functionalphp.com" title="Functional Programming PHP Second Edition">Functional Programming in PHP book</a> that I wrote.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="php" label="php"/><category scheme="taxonomy:Tags" term="immutable" label="immutable"/></entry><entry xml:base="mysql-alter-column-in-all-databases"><title type="html">Alter a MySQL column in all databases</title><link href="https://www.simonholywell.com/post/2017/03/mysql-alter-column-in-all-databases/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2015/07/sql-style-guide/?utm_source=atom_feed" rel="related" type="text/html" title="SQL style guide"/><link href="https://www.simonholywell.com/post/2016/12/sql-style-guide-misconceptions/?utm_source=atom_feed" rel="related" type="text/html" title="SQL style guide misconceptions"/><link href="https://www.simonholywell.com/post/2016/10/install-pgmodeler-ubuntu/?utm_source=atom_feed" rel="related" type="text/html" title="Installing pgmodeler on Ubuntu"/><link href="https://www.simonholywell.com/post/2012/01/mysql-udf-install-error-function-already-exists/?utm_source=atom_feed" rel="related" type="text/html" title="Installing a MySQL UDF errors with Function already exists"/><link href="https://www.simonholywell.com/post/2008/03/mysql-to-ms-sql-sql-server/?utm_source=atom_feed" rel="related" type="text/html" title="MySQL to MS SQL (SQL Server)"/><id>https://www.simonholywell.com/post/2017/03/mysql-alter-column-in-all-databases/</id><author><name>Simon Holywell</name></author><published>2017-03-01T12:41:26+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>When you have a series of applications all running the same database structure it can be annoying to roll out schema updates across all the databases. If you&amp;rsquo;ve got migrations then great - script their deployment, but when you&amp;rsquo;re dealing with an old legacy application you probably don&amp;rsquo;t have the luxury.
I was firmly in the latter class of devops when working on a project a couple of years ago so I wrote a handy little snippet of SQL to help me out.</summary><content type="html"><![CDATA[<p>When you have a series of applications all running the same database structure it can be
annoying to roll out schema updates across all the databases. If you&rsquo;ve got migrations
then great - script their deployment, but when you&rsquo;re dealing with an old legacy application
you probably don&rsquo;t have the luxury.</p>
<p>I was firmly in the latter class of devops when working on a project a couple of years ago
so I wrote a handy little snippet of SQL to help me out. It allowed me to automatically
assemble an <code>ALTER TABLE</code> query for MySQL - it&rsquo;s gonna be a hack in case you&rsquo;d not already
guessed.</p>
<p>It is MySQL specific so to make it portable across MySQL installations I have used backticks to
escape identifiers rather than the double quotes I advocate in the <a href="http://www.sqlstyle.guide" title="SQL style guide by Simon Holywell">SQL style guide</a>. tl;dr:
double quotes as escape is not enabled in MySQL by default.</p>
<p>This query hinges on the <code>information_schema</code> tables and the <code>GROUP_CONCAT</code> functionality provided
in MySQL, which will allow us to create one big query file in tandem with <code>OUTFILE</code>.</p>
<p>So without further ado here is the SQL code:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">SET</span><span class="w"> </span><span class="k">SESSION</span><span class="w"> </span><span class="n">group_concat_max_len</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1000000</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">SELECT</span><span class="w"> </span><span class="o">`</span><span class="n">query</span><span class="o">`</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="k">FROM</span><span class="w"> </span><span class="p">(</span><span class="k">SELECT</span><span class="w"> </span><span class="n">GROUP_CONCAT</span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">                   </span><span class="n">CONCAT</span><span class="p">(</span><span class="s1">&#39;ALTER TABLE `&#39;</span><span class="p">,</span><span class="w"> </span><span class="o">`</span><span class="n">isc</span><span class="o">`</span><span class="p">.</span><span class="o">`</span><span class="n">table_schema</span><span class="o">`</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;`.`&#39;</span><span class="p">,</span><span class="w"> </span><span class="o">`</span><span class="n">isc</span><span class="o">`</span><span class="p">.</span><span class="o">`</span><span class="k">table_name</span><span class="o">`</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;` ALTER `&#39;</span><span class="p">,</span><span class="w"> </span><span class="o">`</span><span class="n">isc</span><span class="o">`</span><span class="p">.</span><span class="o">`</span><span class="k">column_name</span><span class="o">`</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;` DROP DEFAULT;&#39;</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;\n&#39;</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">                   </span><span class="n">CONCAT</span><span class="p">(</span><span class="s1">&#39;ALTER TABLE `&#39;</span><span class="p">,</span><span class="w"> </span><span class="o">`</span><span class="n">isc</span><span class="o">`</span><span class="p">.</span><span class="o">`</span><span class="n">table_schema</span><span class="o">`</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;`.`&#39;</span><span class="p">,</span><span class="w"> </span><span class="o">`</span><span class="n">isc</span><span class="o">`</span><span class="p">.</span><span class="o">`</span><span class="k">table_name</span><span class="o">`</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;` CHANGE COLUMN `&#39;</span><span class="p">,</span><span class="w"> </span><span class="o">`</span><span class="n">isc</span><span class="o">`</span><span class="p">.</span><span class="o">`</span><span class="k">column_name</span><span class="o">`</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;` `&#39;</span><span class="p">,</span><span class="w"> </span><span class="o">`</span><span class="n">isc</span><span class="o">`</span><span class="p">.</span><span class="o">`</span><span class="k">column_name</span><span class="o">`</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;` VARCHAR(300) NOT NULL;&#39;</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">                   </span><span class="n">SEPARATOR</span><span class="w"> </span><span class="s1">&#39;\n&#39;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">               </span><span class="p">)</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="o">`</span><span class="n">query</span><span class="o">`</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">               </span><span class="mi">1</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="o">`</span><span class="n">groupbyme</span><span class="o">`</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="k">FROM</span><span class="w"> </span><span class="o">`</span><span class="n">information_schema</span><span class="o">`</span><span class="p">.</span><span class="o">`</span><span class="n">columns</span><span class="o">`</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="o">`</span><span class="n">isc</span><span class="o">`</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">         </span><span class="k">WHERE</span><span class="w"> </span><span class="o">`</span><span class="n">isc</span><span class="o">`</span><span class="p">.</span><span class="o">`</span><span class="n">table_schema</span><span class="o">`</span><span class="w"> </span><span class="k">NOT</span><span class="w"> </span><span class="k">IN</span><span class="w"> </span><span class="p">(</span><span class="s1">&#39;information_schema&#39;</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;mysql&#39;</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;performance_schema&#39;</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">           </span><span class="k">AND</span><span class="w"> </span><span class="o">`</span><span class="n">isc</span><span class="o">`</span><span class="p">.</span><span class="o">`</span><span class="k">table_name</span><span class="o">`</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;users&#39;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">           </span><span class="k">AND</span><span class="w"> </span><span class="o">`</span><span class="n">isc</span><span class="o">`</span><span class="p">.</span><span class="o">`</span><span class="k">column_name</span><span class="o">`</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;ipAddress&#39;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">         </span><span class="k">GROUP</span><span class="w"> </span><span class="k">BY</span><span class="w"> </span><span class="o">`</span><span class="n">groupbyme</span><span class="o">`</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">       </span><span class="p">)</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="n">T</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">   </span><span class="k">INTO</span><span class="w"> </span><span class="n">OUTFILE</span><span class="w"> </span><span class="s1">&#39;/tmp/alter_table.sql&#39;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">       </span><span class="n">FIELDS</span><span class="w"> </span><span class="n">TERMINATED</span><span class="w"> </span><span class="k">BY</span><span class="w"> </span><span class="s1">&#39;\n&#39;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">       </span><span class="n">OPTIONALLY</span><span class="w"> </span><span class="n">ENCLOSED</span><span class="w"> </span><span class="k">BY</span><span class="w"> </span><span class="s1">&#39;&#39;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">       </span><span class="n">ESCAPED</span><span class="w"> </span><span class="k">BY</span><span class="w"> </span><span class="s1">&#39;&#39;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">       </span><span class="n">LINES</span><span class="w"> </span><span class="n">TERMINATED</span><span class="w"> </span><span class="k">BY</span><span class="w"> </span><span class="s1">&#39;\n&#39;</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div><p>Great, you say, but what does it do? Well here is a brief breakdown of its constituent components.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">SET</span><span class="w"> </span><span class="k">SESSION</span><span class="w"> </span><span class="n">group_concat_max_len</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1000000</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div><p>By default MySQL has a much smaller <code>GROUP_CONCAT</code> maximum length and as we could be operating on a
lot of tables (meaning many results to concatenate) we need to up this default for our particular query.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="o">`</span><span class="n">query</span><span class="o">`</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="k">FROM</span><span class="w"> </span><span class="p">(</span><span class="k">SELECT</span><span class="w"> </span><span class="n">GROUP_CONCAT</span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">                   </span><span class="n">CONCAT</span><span class="p">(</span><span class="s1">&#39;ALTER TABLE `&#39;</span><span class="p">,</span><span class="w"> </span><span class="o">`</span><span class="n">isc</span><span class="o">`</span><span class="p">.</span><span class="o">`</span><span class="n">table_schema</span><span class="o">`</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;`.`&#39;</span><span class="p">,</span><span class="w"> </span><span class="o">`</span><span class="n">isc</span><span class="o">`</span><span class="p">.</span><span class="o">`</span><span class="k">table_name</span><span class="o">`</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;` ALTER `&#39;</span><span class="p">,</span><span class="w"> </span><span class="o">`</span><span class="n">isc</span><span class="o">`</span><span class="p">.</span><span class="o">`</span><span class="k">column_name</span><span class="o">`</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;` DROP DEFAULT;&#39;</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;\n&#39;</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">                   </span><span class="n">CONCAT</span><span class="p">(</span><span class="s1">&#39;ALTER TABLE `&#39;</span><span class="p">,</span><span class="w"> </span><span class="o">`</span><span class="n">isc</span><span class="o">`</span><span class="p">.</span><span class="o">`</span><span class="n">table_schema</span><span class="o">`</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;`.`&#39;</span><span class="p">,</span><span class="w"> </span><span class="o">`</span><span class="n">isc</span><span class="o">`</span><span class="p">.</span><span class="o">`</span><span class="k">table_name</span><span class="o">`</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;` CHANGE COLUMN `&#39;</span><span class="p">,</span><span class="w"> </span><span class="o">`</span><span class="n">isc</span><span class="o">`</span><span class="p">.</span><span class="o">`</span><span class="k">column_name</span><span class="o">`</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;` `&#39;</span><span class="p">,</span><span class="w"> </span><span class="o">`</span><span class="n">isc</span><span class="o">`</span><span class="p">.</span><span class="o">`</span><span class="k">column_name</span><span class="o">`</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;` VARCHAR(300) NOT NULL;&#39;</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">                   </span><span class="n">SEPARATOR</span><span class="w"> </span><span class="s1">&#39;\n&#39;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">               </span><span class="p">)</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="o">`</span><span class="n">query</span><span class="o">`</span><span class="w">
</span></span></span></code></pre></div><p>Here <code>GROUP_CONCAT</code> concatenates the results of the queries together separated by a newline character <code>\n</code>.
Inside there are two <code>CONCAT</code> statements that are building two <code>ALTER TABLE</code> queries. The first removes a
<code>DEFAULT</code> declaration from a column and the second changes column to be a <code>VARCHAR</code> of 300 characters in
length.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="w">               </span><span class="mi">1</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="o">`</span><span class="n">groupbyme</span><span class="o">`</span><span class="w">
</span></span></span></code></pre></div><p>This simply creates a column that whole lot can easily be grouped by as every row is ascribed the same value
of <code>1</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="w">         </span><span class="k">WHERE</span><span class="w"> </span><span class="o">`</span><span class="n">isc</span><span class="o">`</span><span class="p">.</span><span class="o">`</span><span class="n">table_schema</span><span class="o">`</span><span class="w"> </span><span class="k">NOT</span><span class="w"> </span><span class="k">IN</span><span class="w"> </span><span class="p">(</span><span class="s1">&#39;information_schema&#39;</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;mysql&#39;</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;performance_schema&#39;</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">           </span><span class="k">AND</span><span class="w"> </span><span class="o">`</span><span class="n">isc</span><span class="o">`</span><span class="p">.</span><span class="o">`</span><span class="k">table_name</span><span class="o">`</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;users&#39;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">           </span><span class="k">AND</span><span class="w"> </span><span class="o">`</span><span class="n">isc</span><span class="o">`</span><span class="p">.</span><span class="o">`</span><span class="k">column_name</span><span class="o">`</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;ipAddress&#39;</span><span class="w">
</span></span></span></code></pre></div><p>We don&rsquo;t want to accidentally perform actions against the <code>information_schema</code> or other internal MySQL
tables so we exclude them here. To ensure we only operate on the correct table we then specify its name
and the relevant column name. This way we can be sure that the DB has our target table name in it and
that the target table has our target column name in it.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="w">         </span><span class="k">GROUP</span><span class="w"> </span><span class="k">BY</span><span class="w"> </span><span class="o">`</span><span class="n">groupbyme</span><span class="o">`</span><span class="w">
</span></span></span></code></pre></div><p>This refers to the simple column we setup earlier - it meant all rows had a value of <code>1</code> allowing
the results to be easily grouped.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="w">       </span><span class="p">)</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="n">T</span><span class="w">
</span></span></span></code></pre></div><p>After all that the result must be set against an alias so for no particular reason I chose <code>T</code> here.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="w">   </span><span class="k">INTO</span><span class="w"> </span><span class="n">OUTFILE</span><span class="w"> </span><span class="s1">&#39;/tmp/alter_table.sql&#39;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">       </span><span class="n">FIELDS</span><span class="w"> </span><span class="n">TERMINATED</span><span class="w"> </span><span class="k">BY</span><span class="w"> </span><span class="s1">&#39;\n&#39;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">       </span><span class="n">OPTIONALLY</span><span class="w"> </span><span class="n">ENCLOSED</span><span class="w"> </span><span class="k">BY</span><span class="w"> </span><span class="s1">&#39;&#39;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">       </span><span class="n">ESCAPED</span><span class="w"> </span><span class="k">BY</span><span class="w"> </span><span class="s1">&#39;&#39;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">       </span><span class="n">LINES</span><span class="w"> </span><span class="n">TERMINATED</span><span class="w"> </span><span class="k">BY</span><span class="w"> </span><span class="s1">&#39;\n&#39;</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div><p>Finally, the results are written to a file on disk with a few custom options. Importantly, the field
are prevented from being enclosed or escaped - if these were left enabled then MySQL would break our
query output by escaping new lines.</p>
<p>Now all you have to do is run contents of the file we just created and the <code>ALTER TABLE</code> queries will
be executed against your database.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="sql" label="sql"/><category scheme="taxonomy:Tags" term="mysql" label="mysql"/></entry><entry xml:base="email-when-file-changes"><title type="html">Email me when the file changes</title><link href="https://www.simonholywell.com/post/2017/01/email-when-file-changes/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2015/09/scrape-site-with-wget-and-httrack/?utm_source=atom_feed" rel="related" type="text/html" title="Scraping websites with wget and httrack"/><link href="https://www.simonholywell.com/post/2015/08/image-resize-crop-bash-imagemagick/?utm_source=atom_feed" rel="related" type="text/html" title="Crop and resize images with bash and ImageMagick"/><link href="https://www.simonholywell.com/post/2009/01/linux-to-windows-server-migrating-and-securing-your-cron/?utm_source=atom_feed" rel="related" type="text/html" title="Linux to Windows Server - Migrating and securing your crontab"/><link href="https://www.simonholywell.com/post/2016/10/install-pgmodeler-ubuntu/?utm_source=atom_feed" rel="related" type="text/html" title="Installing pgmodeler on Ubuntu"/><link href="https://www.simonholywell.com/post/2016/02/intelligent-vagrant-and-ansible-files/?utm_source=atom_feed" rel="related" type="text/html" title="Intelligent Vagrant and Ansible files"/><id>https://www.simonholywell.com/post/2017/01/email-when-file-changes/</id><author><name>Simon Holywell</name></author><published>2017-01-25T16:00:55+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>It is important to ensure that Google does not index sites whilst they are still on a staging environment, but you cannot lock it down completely - how would your clients proof it? So I run a simple global rewrite rule in Apache that redirects all requests for robots.txt to a central disallow all response. This works great and Google appears to honour the rule as one would hope.
What happens though when something about that central file changes?</summary><content type="html"><![CDATA[<p>It is important to ensure that Google does not index sites whilst they are still
on a staging environment, but you cannot lock it down completely - how would your
clients proof it? So I run a simple global rewrite rule in Apache that redirects
all requests for robots.txt to a central disallow all response. This works great
and Google appears to honour the rule as one would hope.</p>
<p>What happens though when something about that central file changes? One fateful
night it so happened to occur on an old server I manage. Someone had altered the
file and replaced it with an allow all rule. A site from the server started to
appear in Google&rsquo;s listings and thankfully it was picked up quickly, banned through
Google webmaster tools and the original robots.txt put in place to protect against
future indexing.</p>
<p>This left me needing a quick and dirty little monitoring script to keep an eye on
the file. It really didn&rsquo;t need to be anything crazy - just email me when the file
changes so I can investigate what or whom changed it - tell them to desist - and
revert it&rsquo;s contents.</p>
<p>To do this I employed <code>sha512sum</code> and <code>mail</code> inside a simple <code>cron</code> job that would
regularly compare the file&rsquo;s hash against the known good hash. If the hashes do not
match then the script will email a short message to let me know to check into it.</p>
<p>Now of course you could just use the cron job to revert the contents automatically,
but I wanted to look into why it was happening first. If you&rsquo;re really worried you
could of course replace the contents of the file and then email yourself. In this
case it wasn&rsquo;t so important.</p>
<p>There are plenty of command line tools to help you get a hash for a file - handy
when you&rsquo;ve downloaded something and you want to verify the integrity of file.
It used to be common for open source projects to list hashes beside their downloads
before GitHub. Anyway there are a number of choices with increasing length and
therefore less collision prone (two different files creating the same hash):</p>
<ul>
<li><code>md5sum</code></li>
<li><code>sha1sum</code></li>
<li><code>sha256sum</code></li>
<li><code>sha512sum</code></li>
</ul>
<p>By default they&rsquo;ll spit out the hash(es) onto the command line (STDOUT), but we&rsquo;re going
to redirect them to a file so we can refer to them later.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sha512sum robots.txt index.html &gt; cron_sums.txt
</span></span></code></pre></div><p>This will create a text file containing two hash values that we can use to later
verify against the files in question. If you, later, take another hash of the files and it
doesn&rsquo;t match the one in <code>cron_sums.txt</code> then that file has changed. There is a
handy switch you can pass to <code>sha512sum</code> that makes this process much easier.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sha512sum --status -c cron_sums.txt
</span></span></code></pre></div><p>The above command&rsquo;s exit status code can be used to generate a human readable message
using a simple <code>||</code> (or) operator on the command line.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sha512sum --status -c cron_sums.txt <span class="o">&amp;&amp;</span> <span class="nb">echo</span> <span class="s2">&#34;Success&#34;</span> <span class="o">||</span> <span class="nb">echo</span> <span class="s2">&#34;Failed&#34;</span>
</span></span></code></pre></div><p>The above command is pretty self explanatory so I won&rsquo;t bother working through it
and I&rsquo;ll move onto sending the email instead. This will be done by using the
venerable <code>mail</code> command.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sha512sum --status -c cron_sums.txt <span class="o">&amp;&amp;</span> <span class="nb">echo</span> <span class="s2">&#34;Success&#34;</span> <span class="o">||</span> <span class="nb">echo</span> <span class="s2">&#34;Failed&#34;</span> <span class="p">|</span> mail -s <span class="s2">&#34;File hashes didn&#39;t match&#34;</span> example@example.co.zw
</span></span></code></pre></div><p>Here the output messages are piped to mail and dutifully sent through to your inbox.
This works, but I&rsquo;d like to only be disturbed when it goes wrong - I don&rsquo;t care if
it succeeds. To do this we&rsquo;ll pipe the success output to the <code>/dev/null</code> blackhole.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sha512sum --status -c cron_sums.txt <span class="o">&amp;&amp;</span> <span class="nb">echo</span> <span class="s2">&#34;Success&#34;</span> &gt; /dev/null <span class="o">||</span> <span class="nb">echo</span> <span class="s2">&#34;Failed&#34;</span> <span class="p">|</span> mail -s <span class="s2">&#34;File hashes didn&#39;t match&#34;</span> example@example.co.zw
</span></span></code></pre></div><p>So we&rsquo;ve worked out the bash command we want cron to run for us every minute of
the day. Let&rsquo;s tell cron about it! Execute <code>crontab -e</code> on the command line to
open the crontab in your default editor.</p>
<p>Now add the following cron job to the file.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">*   *   *   *   *    /usr/bin/sha512sum --status -c cron_sums.txt <span class="o">&amp;&amp;</span> <span class="nb">echo</span> <span class="s2">&#34;Success&#34;</span> &gt; /dev/null <span class="o">||</span> <span class="nb">echo</span> <span class="s2">&#34;Failed&#34;</span> <span class="p">|</span> mail -s <span class="s2">&#34;File hashes didn&#39;t match&#34;</span> example@example.co.zw
</span></span></code></pre></div><p>It is worth noting that the paths in the <code>cron_sums.txt</code> file are all relative so
you may need to change into the directory containing the files you want to check
before running the <code>sha512sum</code> command from cron. Also cron will run in the user&rsquo;s
home directory by default.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">*   *   *   *   *    <span class="nb">cd</span> /var/www<span class="p">;</span> /usr/bin/sha512sum --status -c cron_sums.txt <span class="o">&amp;&amp;</span> <span class="nb">echo</span> <span class="s2">&#34;Success&#34;</span> &gt; /dev/null <span class="o">||</span> <span class="nb">echo</span> <span class="s2">&#34;Failed&#34;</span> <span class="p">|</span> mail -s <span class="s2">&#34;File hashes didn&#39;t match&#34;</span> example@example.co.zw
</span></span></code></pre></div><p>It isn&rsquo;t pretty and it certainly doesn&rsquo;t scale (although you could email a
list/forwarding group), but it does serve as a quick and dirty fix to warn
you of file inconsistency.</p>
<p>As a bonus; to automatically revert the file as well you could add the following
to the crontab.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">*   *   *   *   *    <span class="nb">cd</span> /var/www<span class="p">;</span> /usr/bin/sha512sum --status -c cron_sums.txt <span class="o">&amp;&amp;</span> <span class="nb">echo</span> <span class="s2">&#34;Success&#34;</span> &gt; /dev/null <span class="o">||</span> <span class="nb">echo</span> <span class="s2">&#34;Failed&#34;</span> <span class="p">|</span> mail -s <span class="s2">&#34;File hashes didn&#39;t match&#34;</span> example@example.co.zw <span class="o">&amp;&amp;</span> <span class="nb">echo</span> <span class="s2">&#34;Disallow: All&#34;</span> &gt; robots.txt
</span></span></code></pre></div><p>Whilst this is a very simple one-liner example you could of course use the same
principles to write a simple little bash script that would be triggered by failure
instead.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">*   *   *   *   *    <span class="nb">cd</span> /var/www<span class="p">;</span> /usr/bin/sha512sum --status -c cron_sums.txt <span class="o">&amp;&amp;</span> <span class="nb">echo</span> <span class="s2">&#34;Success&#34;</span> &gt; /dev/null <span class="o">||</span> /usr/scripts/files_changed.sh
</span></span></code></pre></div>]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="email" label="email"/><category scheme="taxonomy:Tags" term="cron" label="cron"/><category scheme="taxonomy:Tags" term="bash" label="bash"/><category scheme="taxonomy:Tags" term="file-system" label="file system"/><category scheme="taxonomy:Tags" term="linux" label="linux"/></entry><entry xml:base="sql-style-guide-misconceptions"><title type="html">SQL style guide misconceptions</title><link href="https://www.simonholywell.com/post/2016/12/sql-style-guide-misconceptions/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2016/10/install-pgmodeler-ubuntu/?utm_source=atom_feed" rel="related" type="text/html" title="Installing pgmodeler on Ubuntu"/><link href="https://www.simonholywell.com/post/2015/07/sql-style-guide/?utm_source=atom_feed" rel="related" type="text/html" title="SQL style guide"/><link href="https://www.simonholywell.com/post/2008/03/mysql-to-ms-sql-sql-server/?utm_source=atom_feed" rel="related" type="text/html" title="MySQL to MS SQL (SQL Server)"/><link href="https://www.simonholywell.com/post/2016/11/quick-way-to-create-php-stdclass/?utm_source=atom_feed" rel="related" type="text/html" title="Quick way to create a PHP stdClass"/><link href="https://www.simonholywell.com/post/2016/10/functional-programming-in-php-second-edition/?utm_source=atom_feed" rel="related" type="text/html" title="Functional Programming in PHP Second Edition Available Now"/><id>https://www.simonholywell.com/post/2016/12/sql-style-guide-misconceptions/</id><author><name>Simon Holywell</name></author><published>2016-12-09T16:42:42+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Many people have read, reviewed and even implemented the SQL style guide that I wrote. This is great, but there have also been a number of commonly held misconceptions or incorrect readings of the points made in the guide. I have decided to address some of the more common ones via a blog post that will, hopefully, clarify the situation.
Basics A lot of people seem to have a very weird understanding of the basic terms used in the guide so here is what I mean when I say &amp;lsquo;Avoid&amp;rsquo; and &amp;lsquo;Try&amp;rsquo;:</summary><content type="html"><![CDATA[<p>Many people have read, reviewed and even implemented the <a href="http://www.sqlstyle.guide" title="SQL style guide by Simon Holywell">SQL style guide</a> that I wrote. This
is great, but there have also been a number of commonly held misconceptions or incorrect readings
of the points made in the guide. I have decided to address some of the more common ones via a
blog post that will, hopefully, clarify the situation.</p>
<h2 id="basics">Basics</h2>
<p>A lot of people seem to have a very weird understanding of the basic terms used in the guide so
here is what I mean when I say <a href="https://www.collinsdictionary.com/dictionary/english/avoid" title="Collins dictionary definition of 'Avoid'">&lsquo;Avoid&rsquo;</a> and <a href="https://www.collinsdictionary.com/dictionary/english/try" title="Collins dictionary definition of 'Try'">&lsquo;Try&rsquo;</a>:</p>
<blockquote>
<p>In this context I mean that where it does not make sense (for performance, readability, etc reasons)
then don&rsquo;t follow the guide. Follow it where possible and be mindful that when you deviate you&rsquo;re
adding to tech debt.</p>
</blockquote>
<p>I wrote the guide for people to employ with their brains engaged and not just to blindly follow it.
It is just a guide at the end of the day and not the law! You may have an exception that the guide
says to avoid - try to, but if you can&rsquo;t then you can&rsquo;t. Document it and highlight why the problem
has been introduced to the application and move on.</p>
<h2 id="comma-positioning">Comma positioning</h2>
<p>So many people took issue with this - they desperately wanted commas before terms. I like
to stick to reading conventions as much as possible as it makes code far more legible to me. In
the English language, a comma separated list always places the comma immediately after a term.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="n">manufacturer</span><span class="p">,</span><span class="w"> </span><span class="n">model</span><span class="p">,</span><span class="w"> </span><span class="n">engine_size</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="k">FROM</span><span class="w"> </span><span class="n">motorbikes</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div><p>Note that commenting out the <code>engine_size</code> column here would cause a SQL parser error because there
would be a dangling comma left after the <code>model</code> column.</p>
<p>Many people, when coding SQL, like to place the comma at the beginning of a term as they seem to think
it makes it easier to comment out parts of a query.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="n">manufacturer</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">       </span><span class="p">,</span><span class="w"> </span><span class="n">model</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">       </span><span class="p">,</span><span class="w"> </span><span class="n">engine_size</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="k">FROM</span><span class="w"> </span><span class="n">motorbikes</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div><p>There&rsquo;s no way of being polite here - this looks hideous, weird and totally unconventional in a bad way.
A proponent of this style would contend that they can now easily comment out the <code>engine_size</code> or
<code>model</code> column if they needed to.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="n">manufacturer</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">       </span><span class="p">,</span><span class="w"> </span><span class="n">model</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">       </span><span class="c1">-- , engine_size
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="w">  </span><span class="k">FROM</span><span class="w"> </span><span class="n">motorbikes</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div><p>The query still works, yay! This MUST be better. Well until you try to comment out <code>manufacturer</code> and
realise all you&rsquo;ve succeeded in doing is moving the problem to the other end of the list!</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="c1">-- manufacturer
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="w">       </span><span class="p">,</span><span class="w"> </span><span class="n">model</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">       </span><span class="p">,</span><span class="w"> </span><span class="n">engine_size</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="k">FROM</span><span class="w"> </span><span class="n">motorbikes</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div><p>Boom! A big SQL parser error because of the stray comma left in front of the <code>model</code> column. You&rsquo;d
be asking the parser to run the following broken SQL code:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="p">,</span><span class="w"> </span><span class="n">model</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">       </span><span class="p">,</span><span class="w"> </span><span class="n">engine_size</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="k">FROM</span><span class="w"> </span><span class="n">motorbikes</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div><p>See what I mean now?</p>
<p>So just stick to the English language convention for legible queries and your query will be just
as easy to comment out anyway.</p>
<h2 id="object-oriented-oop">Object oriented (OOP)</h2>
<p>This is one of my favourite rules but has apparently left quite a few people scratching their
heads. Given its importance, it makes sense to cover it briefly here.</p>
<blockquote>
<p>Object oriented design principles do not effectively translate to relational database
designs—avoid this pitfall</p>
<p>&ndash; <a href="http://www.sqlstyle.guide/#designs-to-avoid">Designs to avoid</a></p>
</blockquote>
<p>Fortunately, this is pretty simple and shouldn&rsquo;t require too much explaining, but it is a very
an important aspect of the guide and should not be ignored.</p>
<p>In its most simplified form, I am trying to say that you should not design your database with
the schema (table structure) dictated by the application level code objects that access it.
Do you use an ORM? So what, who cares? Your database certainly shouldn&rsquo;t!</p>
<p>The database&rsquo;s primary concern should be with the most efficient storage of data in a relational
structure that emphasises normalisation. You can choose to ignore this, but you need to know
that you&rsquo;ve just introduced a pungent smell into your application.</p>
<p>This desire to allow OOP thinking infect the database layer is known by the snappy title
&ldquo;Object-relational impedance mismatch&rdquo; and there is a nice <a href="https://en.m.wikipedia.org/wiki/Object-relational_impedance_mismatch" title="Object-relational impedance mismatch">Wikipedia article</a> of the same
name that goes into far more detail on this topic.</p>
<h2 id="id-columns-and-surrogate-keys"><code>id</code> columns and surrogate keys</h2>
<p>Another fun topic that has been bashed to death when discussing the <a href="http://www.sqlstyle.guide" title="SQL style guide by Simon Holywell">SQL style guide</a> is the banning
of surrogate keys. You do not need them in most cases as better keys often exist in the data already.</p>
<p>Of course, like I mentioned before, you can use them at your own peril - we&rsquo;re discussing a guide
here - not the law.</p>
<p>So if you choose to use an ORM that requires them then use them! I have made recommendations for
best practice, but you&rsquo;re free to disregard them. Just because I think that&rsquo;s foolish doesn&rsquo;t mean
that it is wrong for you or your project. Make your own choices - you&rsquo;ve been warned, however.</p>
<h2 id="avoiding-vendorproprietary-functions">Avoiding vendor/proprietary functions</h2>
<p>Many readers have struggled with the recommendation to only use standard SQL in the erroneously
believing that the sole reason for this is to promote SQL portability between engines. What about
ease of reading for other developers, reducing complexity and portability of you - the developer?</p>
<p>Why you would willingly choose a proprietary solution when a standard SQL method already exists is
beyond me. I really do fail to see the problem that readers have here with this recommendation. You&rsquo;re
introducing complexity where it is unnecessary.</p>
<p>One reader was so incensed by this simple rule that they felt unable to continue reading the guide.
This, of course, made me giggle at the absurdity of such a stance.</p>
<blockquote>
<p>UPDATE 19/11/2024: 8 years on and this is still something that I see developers taking issue with on Hacker News.
So, I figured I would expound upon the ideas here in a new article: <a href="/post/a-note-on-code-portability" title="A note on code portability">A note on code portability</a>.</p>
</blockquote>
<h2 id="joins-over-the-river">Joins over the river</h2>
<p>Another point of contention is the style of putting table joins on the other side of the river (east).
There have been a few readers that find this interrupts their reading flow or they don&rsquo;t like the way
it makes the whole query look.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="n">r</span><span class="p">.</span><span class="n">last_name</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="k">FROM</span><span class="w"> </span><span class="n">riders</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="n">r</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">       </span><span class="k">INNER</span><span class="w"> </span><span class="k">JOIN</span><span class="w"> </span><span class="n">bikes</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="n">b</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">       </span><span class="k">ON</span><span class="w"> </span><span class="n">r</span><span class="p">.</span><span class="n">bike_vin_num</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">b</span><span class="p">.</span><span class="n">vin_num</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="k">AND</span><span class="w"> </span><span class="n">b</span><span class="p">.</span><span class="n">engines</span><span class="w"> </span><span class="o">&gt;</span><span class="w"> </span><span class="mi">2</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">       </span><span class="k">INNER</span><span class="w"> </span><span class="k">JOIN</span><span class="w"> </span><span class="n">crew</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="k">c</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">       </span><span class="k">ON</span><span class="w"> </span><span class="n">r</span><span class="p">.</span><span class="n">crew_chief_last_name</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">c</span><span class="p">.</span><span class="n">last_name</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="k">AND</span><span class="w"> </span><span class="k">c</span><span class="p">.</span><span class="n">chief</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;Y&#39;</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div><p>Here are a few reasons for this style of join layout:</p>
<ol>
<li>The join is an addition to the <code>FROM</code> clause so it makes logical sense for it to exist grouped
under it</li>
<li>It provides a nice clean way of specifying join conditions (eg. <code>AND b.engines &gt; 2</code>)</li>
<li>They&rsquo;re an alteration or operation of the <code>FROM</code> clause</li>
<li>Join syntax doesn&rsquo;t play nicely with the river either</li>
</ol>
<p>Simple.</p>
<h2 id="i-really-dislike-x-and-y">I really dislike X and Y</h2>
<p>That&rsquo;s perfectly understandable and precisely why I made it so easy to fork the guide. The core of the
guide is even a separate <a href="https://raw.githubusercontent.com/treffynnon/sqlstyle.guide/gh-pages/_includes/sqlstyle.guide.md" title="SQL style guide as Markdown">Markdown file</a> you can drop into a project repository and start editing
it.</p>
<p>The whole idea of the guide is that it gives you a nice set of defaults to work from and a nicely
formatted output. You can enjoy these even with a completely different set of guidelines.</p>
<h2 id="where-is-the-justification">Where is the justification?</h2>
<p>It beggars belief how many readers claim to have read the guide and yet I still get messages asking for
justifications. At the very top, the introductory paragraph clearly states that <a href="https://www.amazon.com/gp/product/0120887975/ref=as_li_ss_tl?ie=UTF8&amp;linkCode=ll1&amp;tag=treffynnon-20&amp;linkId=9c88eac8cd420e979675c815771313d5" title="SQL Programming Style - Joe Celko">Celko&rsquo;s book</a>
is the place to find in-depth discussion of each point. Discussions of justification have no place in
a style guide anyway.</p>
<p>So that is where you&rsquo;ll find all the justification you could need. <a href="https://www.amazon.com/gp/product/0120887975/ref=as_li_ss_tl?ie=UTF8&amp;linkCode=ll1&amp;tag=treffynnon-20&amp;linkId=9c88eac8cd420e979675c815771313d5" title="SQL Programming Style - Joe Celko">Buy it!</a></p>
<h2 id="who-do-you-think-you-are-telling-me-what-to-do">Who do you think you are telling me what to do?</h2>
<p>Interestingly, some readers have laboured under the misapprehension that this guide is somehow the
law. Far from it, as the name guide suggests these are suggestions or guidelines. Right at the top
of the guide, there is a clear link to where it can be forked to suit your tastes. Use it as a handy
base and hack away at it!</p>
<h2 id="conclusion">Conclusion</h2>
<p>So the guide has been controversial, but that is just fine. You don&rsquo;t have to like it or agree with
it. All I&rsquo;d hoped for was that it might get you thinking about standards in your projects and talking
about well-formed SQL. If it was adopted by some then all the better of course.</p>
<p>An impetus if you will.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="sql" label="sql"/><category scheme="taxonomy:Tags" term="sqlstyleguide" label="sqlstyleguide"/></entry><entry xml:base="quick-way-to-create-php-stdclass"><title type="html">Quick way to create a PHP stdClass</title><link href="https://www.simonholywell.com/post/2016/11/quick-way-to-create-php-stdclass/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2016/10/functional-programming-in-php-second-edition/?utm_source=atom_feed" rel="related" type="text/html" title="Functional Programming in PHP Second Edition Available Now"/><link href="https://www.simonholywell.com/post/2016/10/importing-and-aliasing-php-functions/?utm_source=atom_feed" rel="related" type="text/html" title="Importing and aliasing PHP functions"/><link href="https://www.simonholywell.com/post/2015/08/namespace-php-functions/?utm_source=atom_feed" rel="related" type="text/html" title="Namespace PHP functions"/><link href="https://www.simonholywell.com/post/2015/07/sql-style-guide/?utm_source=atom_feed" rel="related" type="text/html" title="SQL style guide"/><link href="https://www.simonholywell.com/post/2015/07/international-php-dates-with-intl/?utm_source=atom_feed" rel="related" type="text/html" title="International PHP dates with intl"/><id>https://www.simonholywell.com/post/2016/11/quick-way-to-create-php-stdclass/</id><author><name>Simon Holywell</name></author><published>2016-11-16T10:39:51+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>A very short and simple trick for creating new stdClass objects without having to set every property individually. This is akin to JavaScript&amp;rsquo;s object notation, but not quite as elegant.
Creating a new object in JavaScript looks like the following example.
const x = { a: &amp;#34;test&amp;#34;, b: &amp;#34;test2&amp;#34;, c: &amp;#34;test3&amp;#34;, }; With PHP it is possible to use type casting to convert a simple array into a stdClass object which gives you a similar looking syntax although there is a little more typing required.</summary><content type="html"><![CDATA[<p>A very short and simple trick for creating new <code>stdClass</code> objects without having to
set every property individually. This is akin to JavaScript&rsquo;s object notation, but not
quite as elegant.</p>
<p>Creating a new object in JavaScript looks like the following example.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">x</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">a</span><span class="o">:</span> <span class="s2">&#34;test&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">b</span><span class="o">:</span> <span class="s2">&#34;test2&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">c</span><span class="o">:</span> <span class="s2">&#34;test3&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div><p>With PHP it is possible to use type casting to convert a simple array into a <code>stdClass</code>
object which gives you a similar looking syntax although there is a little more typing
required.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="nv">$x</span> <span class="o">=</span> <span class="p">(</span><span class="nx">object</span><span class="p">)</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;test&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;test2&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;test3&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="nx">var_dump</span><span class="p">(</span><span class="nv">$x</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="cm">/*
</span></span></span><span class="line"><span class="cl"><span class="cm">object(stdClass)#1 (3) {
</span></span></span><span class="line"><span class="cl"><span class="cm">  [0]=&gt;
</span></span></span><span class="line"><span class="cl"><span class="cm">  string(4) &#34;test&#34;
</span></span></span><span class="line"><span class="cl"><span class="cm">  [1]=&gt;
</span></span></span><span class="line"><span class="cl"><span class="cm">  string(5) &#34;test2&#34;
</span></span></span><span class="line"><span class="cl"><span class="cm">  [2]=&gt;
</span></span></span><span class="line"><span class="cl"><span class="cm">  string(5) &#34;test3&#34;
</span></span></span><span class="line"><span class="cl"><span class="cm">}
</span></span></span><span class="line"><span class="cl"><span class="cm">*/</span>
</span></span></code></pre></div><p>Note the type casting with <code>(object)</code> just before the array definition - this is what
does the work of converting the simple array definition into a <code>stdClass</code> object.</p>
<p>Of course you&rsquo;re going to want named properties too and handily casting an
associative array does just that.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="nv">$x</span> <span class="o">=</span> <span class="p">(</span><span class="nx">object</span><span class="p">)</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;a&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;test&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;b&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;test2&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;c&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;test3&#39;</span>
</span></span><span class="line"><span class="cl"><span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="nx">var_dump</span><span class="p">(</span><span class="nv">$x</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="cm">/*
</span></span></span><span class="line"><span class="cl"><span class="cm">object(stdClass)#1 (3) {
</span></span></span><span class="line"><span class="cl"><span class="cm">  [&#34;a&#34;]=&gt;
</span></span></span><span class="line"><span class="cl"><span class="cm">  string(4) &#34;test&#34;
</span></span></span><span class="line"><span class="cl"><span class="cm">  [&#34;b&#34;]=&gt;
</span></span></span><span class="line"><span class="cl"><span class="cm">  string(5) &#34;test2&#34;
</span></span></span><span class="line"><span class="cl"><span class="cm">  [&#34;c&#34;]=&gt;
</span></span></span><span class="line"><span class="cl"><span class="cm">  string(5) &#34;test3&#34;
</span></span></span><span class="line"><span class="cl"><span class="cm">}
</span></span></span><span class="line"><span class="cl"><span class="cm">*/</span>
</span></span></code></pre></div><p>What happens if you have two array indexes with the same key though? Obviously you
cannot have two class properties with the same name so one would presume an error. Well
being that this is PHP you may not be surprised to see the following.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="nv">$x</span> <span class="o">=</span> <span class="p">(</span><span class="nx">object</span><span class="p">)</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;a&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;test&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;b&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;test2&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;c&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;test3&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;a&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;wipeout&#39;</span>
</span></span><span class="line"><span class="cl"><span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="nx">var_dump</span><span class="p">(</span><span class="nv">$x</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="cm">/*
</span></span></span><span class="line"><span class="cl"><span class="cm">object(stdClass)#1 (3) {
</span></span></span><span class="line"><span class="cl"><span class="cm">  [&#34;a&#34;]=&gt;
</span></span></span><span class="line"><span class="cl"><span class="cm">  string(7) &#34;wipeout&#34;
</span></span></span><span class="line"><span class="cl"><span class="cm">  [&#34;b&#34;]=&gt;
</span></span></span><span class="line"><span class="cl"><span class="cm">  string(5) &#34;test2&#34;
</span></span></span><span class="line"><span class="cl"><span class="cm">  [&#34;c&#34;]=&gt;
</span></span></span><span class="line"><span class="cl"><span class="cm">  string(5) &#34;test3&#34;
</span></span></span><span class="line"><span class="cl"><span class="cm">}
</span></span></span><span class="line"><span class="cl"><span class="cm">*/</span>
</span></span></code></pre></div><p>There is no great big crash. PHP simply overwrites the property value (<code>$x-&gt;a</code> in this
case) with the last value of key <code>a</code> in the array. This is why <code>$x-&gt;a</code> is set to
<code>wipeout</code> and not <code>test</code>.</p>
<p>Also note here that the order of the properties in the <code>stdClass</code> might not be what you
were expecting either. Perhaps you were expecting <code>$x-&gt;a</code> to be last, but no <code>$x-&gt;a</code>
comes first because <code>'a' =&gt; 'test'</code> is set against the <code>stdClass</code> and it is then
overwritten (rather than replaced) by the later definition <code>'a' =&gt; 'wipeout'</code>.</p>
<p>Well there you have it - a very simple way of getting yourself a new <code>stdClass</code> with your
desired properties set.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="php" label="php"/><category scheme="taxonomy:Tags" term="stdclass" label="stdclass"/></entry><entry xml:base="functional-programming-in-php-second-edition"><title type="html">Functional Programming in PHP Second Edition Available Now</title><link href="https://www.simonholywell.com/post/2016/10/functional-programming-in-php-second-edition/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2015/05/2015-05-18-memoization-or-function-cache/?utm_source=atom_feed" rel="related" type="text/html" title="Memoization or function cache"/><link href="https://www.simonholywell.com/post/2014/08/functional-programming-in-php-the-book/?utm_source=atom_feed" rel="related" type="text/html" title="Functional Programming in PHP - The book"/><link href="https://www.simonholywell.com/post/2014/02/functional-php-talks/?utm_source=atom_feed" rel="related" type="text/html" title="Functional PHP talks"/><link href="https://www.simonholywell.com/post/2014/01/speaking-at-brightonphp-and-php-hampshire/?utm_source=atom_feed" rel="related" type="text/html" title="Speaking about Functional PHP at BrightonPHP and PHP Hampshire"/><link href="https://www.simonholywell.com/post/2016/10/importing-and-aliasing-php-functions/?utm_source=atom_feed" rel="related" type="text/html" title="Importing and aliasing PHP functions"/><id>https://www.simonholywell.com/post/2016/10/functional-programming-in-php-second-edition/</id><author><name>Simon Holywell</name></author><published>2016-10-27T09:17:55+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>It is with great pleasure that I announce the second edition of the Functional Programming in PHP book that I have been working on. There is twice the content of the first edition of the book as well as updates for PHP 7 and Facebook&amp;rsquo;s HHVM (HipHop Virtual Machine).
There are now more functional techniques and patterns included with pipelines, pattern matching and flat maps among them. I have added a section of the book dedicated to the handy syntax and functionality that HHVM can provide functional programmers with.</summary><content type="html"><![CDATA[<p>It is with great pleasure that I announce the <a href="http://www.functionalphp.com/#buy?utm_source=Blog&amp;utm_medium=Link&amp;utm_campaign=Book%202ndEd%20article&amp;utm_content=second%20edition" title="Functional Programming in PHP Second Edition">second edition</a> of the
<a href="http://www.functionalphp.com/#buy?utm_source=Blog&amp;utm_medium=Link&amp;utm_campaign=Book%202ndEd%20article&amp;utm_content=second%20edition2" title="Functional Programming in PHP Second Edition">Functional Programming in PHP book</a> that I have been working on. There is twice
the content of the first edition of the book as well as updates for PHP 7 and Facebook&rsquo;s
HHVM (HipHop Virtual Machine).</p>
<p>There are now more functional techniques and patterns included with pipelines, pattern
matching and flat maps among them. I have added a section of the book dedicated to the
handy syntax and functionality that HHVM can provide functional programmers with.</p>
<p>In addition I have, of course, listened to reader feedback and gone into a lot more detail
about functions themselves, type signatures and their use, functional programming history
and provided more examples of functional code in use. There is also a glossary of terms
and appendices on libraries, REPLs and the frequently requested guide to using the UTF-8
ellipsis effectively in various editors.</p>
<p>On top of all that the book has been completely reorganised into a more logical structure
with a better chapter breakdown.</p>
<p>So if you&rsquo;re the kind of programmer who likes clean and easy to test code resulting in less
bugs this is the PHP book for you. Even if functional programming isn&rsquo;t really your thing
all the techniques in the book will help you to become a better object oriented or procedural
programmer.</p>
<p>To get your copy head on over to the <a href="http://www.functionalphp.com/#buy?utm_source=Blog&amp;utm_medium=Link&amp;utm_campaign=Book%202ndEd%20article&amp;utm_content=books%20website" title="Functional Programming in PHP Second Edition">books website</a>
for purchase links.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="php" label="php"/><category scheme="taxonomy:Tags" term="functional-programming" label="functional programming"/><category scheme="taxonomy:Tags" term="book" label="book"/><category scheme="taxonomy:Tags" term="second-edition" label="second edition"/></entry><entry xml:base="importing-and-aliasing-php-functions"><title type="html">Importing and aliasing PHP functions</title><link href="https://www.simonholywell.com/post/2016/10/importing-and-aliasing-php-functions/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2015/08/namespace-php-functions/?utm_source=atom_feed" rel="related" type="text/html" title="Namespace PHP functions"/><link href="https://www.simonholywell.com/post/2015/07/sql-style-guide/?utm_source=atom_feed" rel="related" type="text/html" title="SQL style guide"/><link href="https://www.simonholywell.com/post/2015/07/international-php-dates-with-intl/?utm_source=atom_feed" rel="related" type="text/html" title="International PHP dates with intl"/><link href="https://www.simonholywell.com/post/2015/07/php-date-setlocale-localisation/?utm_source=atom_feed" rel="related" type="text/html" title="PHP date localisation with setlocale"/><link href="https://www.simonholywell.com/post/2015/06/parallel-benchmark-many-urls-with-apachebench/?utm_source=atom_feed" rel="related" type="text/html" title="Simultaneously benchmark many URLs with ApacheBench and GNU parallel"/><id>https://www.simonholywell.com/post/2016/10/importing-and-aliasing-php-functions/</id><author><name>Simon Holywell</name></author><published>2016-10-18T14:50:26+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>As a follow on to my short post about namespaces and functions from a year ago I thought it would be worth covering importing a specific function and aliasing functions via namespace operators too. This has been possible since PHP 5.6, but there is a nice addition in PHP 7 I&amp;rsquo;ll cover towards the end.
In the previous article I demonstrated how you can namespace functions and use them, but as a refresher; you can enclose functions within a namespace just like a class.</summary><content type="html"><![CDATA[<p>As a follow on to my short post about <a href="https://www.simonholywell.com/post/2015/08/namespace-php-functions/">namespaces and functions</a> from
a year ago I thought it would be worth covering importing a specific function and aliasing
functions via namespace operators too. This has been possible since PHP 5.6, but there is
a nice addition in PHP 7 I&rsquo;ll cover towards the end.</p>
<p>In the previous article I demonstrated how you can namespace functions and <code>use</code> them, but
as a refresher; you can enclose functions within a namespace just like a class. In the
following example there is a function setup in the <code>MyProject\MyModule</code> namespace first, which
is subsequently called by code inside the root namespace (<code>namespace { }</code>).</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">namespace</span> <span class="nx">MyProject\MyModule</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">function</span> <span class="nf">get_nice_superlative_for_me_please</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="s1">&#39;gorgeous&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">namespace</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">use</span> <span class="nx">MyProject\MyModule</span> <span class="k">as</span> <span class="nx">M</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">echo</span> <span class="s2">&#34;You&#39;re &#34;</span> <span class="o">.</span> <span class="nx">M\get_nice_superlative_for_me_please</span><span class="p">()</span> <span class="o">.</span> <span class="s1">&#39; today&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// You&#39;re gorgeous today
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span></code></pre></div><p>Hopefully this is all pretty straight forward and clear to follow. Now onto the <code>use</code> keyword and
how it can be implemented to import a specific function.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">namespace</span> <span class="nx">MyProject\MyModule</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">function</span> <span class="nf">get_nice_superlative_for_me_please</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="s1">&#39;gorgeous&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">namespace</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">use</span> <span class="k">function</span> <span class="nf">MyProject\MyModule\get_nice_superlative_for_me_please</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">echo</span> <span class="s2">&#34;You&#39;re &#34;</span> <span class="o">.</span> <span class="nx">get_nice_superlative_for_me_please</span><span class="p">()</span> <span class="o">.</span> <span class="s1">&#39; today&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// You&#39;re gorgeous today
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span></code></pre></div><p>Note the <code>use function</code> construct here instead of the usual straight forward <code>use</code> that you&rsquo;d
normally see when importing a PHP namespace. This imports just the specified function for use
in the current scope.</p>
<p>So, my example function name sure is a little ungainly and a bit of a chore to type with it&rsquo;s
long name. For the sake of demonstration let&rsquo;s assume that we can&rsquo;t change the function name,
but we still want it to be shorter in our current scope. To do this we can use the familiar <code>as</code>
keyword used in namespace aliasing.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">namespace</span> <span class="nx">MyProject\MyModule</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">function</span> <span class="nf">get_nice_superlative_for_me_please</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="s1">&#39;gorgeous&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">namespace</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">use</span> <span class="k">function</span> <span class="nf">MyProject\MyModule\get_nice_superlative_for_me_please</span> <span class="k">as</span> <span class="nx">compliment</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">echo</span> <span class="s2">&#34;You&#39;re &#34;</span> <span class="o">.</span> <span class="nx">compliment</span><span class="p">()</span> <span class="o">.</span> <span class="s1">&#39; today&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// You&#39;re gorgeous today
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span></code></pre></div><p>As we did earlier we&rsquo;ve gone with <code>use function</code> to show that we&rsquo;re importing and later
aliasing a particular function. This is also works for functions in the root or same
namespace as each other.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">use</span> <span class="k">function</span> <span class="nf">get_nice_superlative_for_me_please</span> <span class="k">as</span> <span class="nx">compliment</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">function</span> <span class="nf">get_nice_superlative_for_me_please</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="s1">&#39;gorgeous&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">echo</span> <span class="s2">&#34;You&#39;re &#34;</span> <span class="o">.</span> <span class="nx">compliment</span><span class="p">()</span> <span class="o">.</span> <span class="s1">&#39; today&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="c1">// You&#39;re gorgeous today
</span></span></span></code></pre></div><p>Now if you&rsquo;re running PHP 7 you can do a another little trick with the namespace operators.
If you want to include multiple specific functions in the current scope you can use the new braced
grouping syntax.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">namespace</span> <span class="nx">MyProject\MyModule</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">function</span> <span class="nf">get_nice_superlative_for_me_please</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="s1">&#39;gorgeous&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">function</span> <span class="nf">verb</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="s1">&#39;looking&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">function</span> <span class="nf">when</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="s1">&#39;today&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">namespace</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">use</span> <span class="k">function</span> <span class="nf">MyProject\MyModule\</span><span class="p">{</span><span class="nx">verb</span><span class="p">,</span><span class="nx">when</span><span class="p">};</span>
</span></span><span class="line"><span class="cl">    <span class="k">use</span> <span class="k">function</span> <span class="nf">MyProject\MyModule\get_nice_superlative_for_me_please</span> <span class="k">as</span> <span class="nx">compliment</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">echo</span> <span class="s2">&#34;You&#39;re &#34;</span> <span class="o">.</span> <span class="nx">verb</span><span class="p">()</span> <span class="o">.</span> <span class="s1">&#39; &#39;</span> <span class="o">.</span> <span class="nx">compliment</span><span class="p">()</span> <span class="o">.</span> <span class="s1">&#39; &#39;</span> <span class="o">.</span> <span class="nx">when</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// You&#39;re looking gorgeous today
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span></code></pre></div><p>Here you can see group syntax (<code>{verb,when}</code>) and function aliasing that we saw earlier working together
to create the expected text output.</p>
<p>Unfortunately, you cannot alias and group import in the one hit as you would generate a parse error
(<code>syntax error, unexpected 'as' (T_AS), expecting ';'</code>) with code like the following example:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">namespace</span> <span class="nx">MyProject\MyModule</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">function</span> <span class="nf">get_nice_superlative_for_me_please</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="s1">&#39;gorgeous&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">function</span> <span class="nf">when</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="s1">&#39;today&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">function</span> <span class="nf">verb</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="s1">&#39;looking&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">namespace</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">use</span> <span class="k">function</span> <span class="nf">MyProject\MyModule\</span><span class="p">{</span><span class="nx">verb</span><span class="p">,</span><span class="nx">when</span><span class="p">}</span> <span class="k">as</span> <span class="p">{</span><span class="nx">v</span><span class="p">,</span><span class="nx">w</span><span class="p">};</span>
</span></span><span class="line"><span class="cl">    <span class="k">use</span> <span class="k">function</span> <span class="nf">MyProject\MyModule\get_nice_superlative_for_me_please</span> <span class="k">as</span> <span class="nx">compliment</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">echo</span> <span class="s2">&#34;You&#39;re &#34;</span> <span class="o">.</span> <span class="nx">v</span><span class="p">()</span> <span class="o">.</span> <span class="s1">&#39; &#39;</span> <span class="o">.</span> <span class="nx">compliment</span><span class="p">()</span> <span class="o">.</span> <span class="s1">&#39; &#39;</span> <span class="o">.</span> <span class="nx">w</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>So more recent additions to PHP give namespaces more power than previously discussed with
the ability to import a specific function being the highlight.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="php" label="php"/><category scheme="taxonomy:Tags" term="namespace" label="namespace"/><category scheme="taxonomy:Tags" term="functions" label="functions"/><category scheme="taxonomy:Tags" term="alias" label="alias"/><category scheme="taxonomy:Tags" term="import" label="import"/></entry><entry xml:base="install-pgmodeler-ubuntu"><title type="html">Installing pgmodeler on Ubuntu</title><link href="https://www.simonholywell.com/post/2016/10/install-pgmodeler-ubuntu/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2013/03/install-netbeans-scala-ubuntu/?utm_source=atom_feed" rel="related" type="text/html" title="Install Netbeans and Scala on Ubuntu"/><link href="https://www.simonholywell.com/post/2011/04/ssh-agent-not-storing-unencrypted-key/?utm_source=atom_feed" rel="related" type="text/html" title="Why won't ssh-agent save my unencrypted key for later use?"/><link href="https://www.simonholywell.com/post/2010/08/php-ssdeep-fuzzy-hashing-php-extension/?utm_source=atom_feed" rel="related" type="text/html" title="php_ssdeep Fuzzy Hashing PHP Extension"/><link href="https://www.simonholywell.com/post/2010/08/php-wrapper-for-linux-at-command/?utm_source=atom_feed" rel="related" type="text/html" title="A PHP wrapper for the unix at command"/><link href="https://www.simonholywell.com/post/2010/08/linux-batch-remove-extension/?utm_source=atom_feed" rel="related" type="text/html" title="Batch remove extensions in Ubuntu"/><id>https://www.simonholywell.com/post/2016/10/install-pgmodeler-ubuntu/</id><author><name>Simon Holywell</name></author><published>2016-10-18T12:41:26+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Pgmodeler is a handy tool for designing databases with an ERD style interface specifically aimed at the PostgreSQL community. It can come in a couple of different ways, but I am going to covering the self build process here. So if you want to learn how to build and install pgmodeler read on!
To be able to build anything you&amp;rsquo;ll need to install the tools from Ubuntu&amp;rsquo;s repositories.
sudo apt-get install gcc libxml2-dev postgresql The first dependency you will need to install is the from QT5 UI toolkit.</summary><content type="html"><![CDATA[<p>Pgmodeler is a handy tool for designing databases with an ERD style interface
specifically aimed at the PostgreSQL community. It can come in a couple of different
ways, but I am going to covering the self build process here. So if you want to
learn how to build and install pgmodeler read on!</p>
<p>To be able to build anything you&rsquo;ll need to install the tools from Ubuntu&rsquo;s repositories.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo apt-get install gcc libxml2-dev postgresql
</span></span></code></pre></div><p>The first dependency you will need to install is the from QT5 UI toolkit.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo add-apt-repository ppa:ubuntu-sdk-team/ppa <span class="o">&amp;&amp;</span> sudo apt-get update <span class="o">&amp;&amp;</span> sudo apt-get dist-upgrade <span class="o">&amp;&amp;</span> sudo apt-get install ubuntu-sdk
</span></span></code></pre></div><p>Next up you&rsquo;ll need to install <code>libpq</code>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo apt-get install libpq-dev
</span></span></code></pre></div><p>To ensure that QT is installed correctly verify that you get similar responses to
me from the following commands:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">pkg-config libpq --cflags --libs
</span></span><span class="line"><span class="cl"><span class="c1"># -I/usr/include -L/usr/lib64/libpq.so</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">pkg-config libxml-2.0 --cflags --libs
</span></span><span class="line"><span class="cl"><span class="c1"># -I/usr/include/libxml2 -lxml2</span>
</span></span></code></pre></div><p>If you do not the there is a little manual intervention that you&rsquo;ll need to perform
by creating the <code>/usr/lib/pkgconfig/libpq.pc</code> manually. It should contain code of
the following block.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nv">prefix</span><span class="o">=</span>/usr
</span></span><span class="line"><span class="cl"><span class="nv">libdir</span><span class="o">=</span><span class="si">${</span><span class="nv">prefix</span><span class="si">}</span>/lib/postgresql/<span class="o">[</span>VERSION<span class="o">]</span>/lib
</span></span><span class="line"><span class="cl"><span class="nv">includedir</span><span class="o">=</span><span class="si">${</span><span class="nv">prefix</span><span class="si">}</span>/include/postgresql
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Name: LibPQ
</span></span><span class="line"><span class="cl">Version: 5.0.0
</span></span><span class="line"><span class="cl">Description: PostgreSQL client library
</span></span><span class="line"><span class="cl">Requires:
</span></span><span class="line"><span class="cl">Libs: -L<span class="si">${</span><span class="nv">libdir</span><span class="si">}</span>/libpq.so -lpq
</span></span><span class="line"><span class="cl">Cflags: -I<span class="si">${</span><span class="nv">includedir</span><span class="si">}</span>
</span></span></code></pre></div><p>So that is all the dependencies taken care of and we can move onto building and
installing the actual binary itself.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">qmake pgmodeler.pro
</span></span><span class="line"><span class="cl">make
</span></span><span class="line"><span class="cl">sudo make install
</span></span></code></pre></div><p>The binary is now in the build directory so we can call it from there after passing
it a few options with a start-up script.</p>
<p>Move into the build directory and create <code>start-pgmodeler.sh</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">cd</span> build
</span></span><span class="line"><span class="cl">vim start-pgmodeler.sh
</span></span></code></pre></div><p>In the start-up file we want to add the following lines of bash script.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1">#/bin/bash</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Specify here the full path to the pgmodeler&#39;s root directory</span>
</span></span><span class="line"><span class="cl"><span class="nb">export</span> <span class="nv">PGMODELER_ROOT</span><span class="o">=</span><span class="s2">&#34;.&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">export</span> <span class="nv">PGMODELER_CONF_DIR</span><span class="o">=</span><span class="s2">&#34;</span><span class="nv">$PGMODELER_ROOT</span><span class="s2">/conf&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nb">export</span> <span class="nv">PGMODELER_SCHEMAS_DIR</span><span class="o">=</span><span class="s2">&#34;</span><span class="nv">$PGMODELER_ROOT</span><span class="s2">/schemas&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nb">export</span> <span class="nv">PGMODELER_LANG_DIR</span><span class="o">=</span><span class="s2">&#34;</span><span class="nv">$PGMODELER_ROOT</span><span class="s2">/lang&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nb">export</span> <span class="nv">PGMODELER_TMP_DIR</span><span class="o">=</span><span class="s2">&#34;</span><span class="nv">$PGMODELER_ROOT</span><span class="s2">/tmp&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nb">export</span> <span class="nv">PGMODELER_PLUGINS_DIR</span><span class="o">=</span><span class="s2">&#34;</span><span class="nv">$PGMODELER_ROOT</span><span class="s2">/plugins&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nb">export</span> <span class="nv">PGMODELER_CHANDLER_PATH</span><span class="o">=</span><span class="s2">&#34;</span><span class="nv">$PGMODELER_ROOT</span><span class="s2">/pgmodeler-ch&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nb">export</span> <span class="nv">LD_LIBRARY_PATH</span><span class="o">=</span><span class="nv">$LD_LIBRARY_PATH</span>:<span class="s2">&#34;</span><span class="nv">$PGMODELER_ROOT</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nb">export</span> <span class="nv">PATH</span><span class="o">=</span><span class="nv">$PATH</span>:<span class="nv">$PGMODELER_ROOT</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Running pgModeler</span>
</span></span><span class="line"><span class="cl">pgmodeler
</span></span></code></pre></div><p>After writing that file and quitting <code>vim</code> you need to set the files executable
bit using chmod.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">chmod +x start-pdmodeler.sh
</span></span></code></pre></div><p>You can now run <code>pgmodeler</code> by calling the <code>start-pgmodeler.sh</code> shell script on
the command line.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">./start-pdmodeler.sh
</span></span></code></pre></div><p>After the application starts itself you will be greeted by the nice QT interface
of <code>pgmodeler</code>. You&rsquo;re done!</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="sql" label="sql"/><category scheme="taxonomy:Tags" term="postgresql" label="postgresql"/><category scheme="taxonomy:Tags" term="pgmodeler" label="pgmodeler"/><category scheme="taxonomy:Tags" term="ubuntu" label="ubuntu"/><category scheme="taxonomy:Tags" term="linux" label="linux"/></entry><entry xml:base="tamiya-manta-ray"><title type="html">Tamiya Manta Ray</title><link href="https://www.simonholywell.com/post/2016/09/tamiya-manta-ray/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2016/09/brisbane/?utm_source=atom_feed" rel="related" type="text/html" title="Brisbane"/><link href="https://www.simonholywell.com/post/2016/02/intelligent-vagrant-and-ansible-files/?utm_source=atom_feed" rel="related" type="text/html" title="Intelligent Vagrant and Ansible files"/><link href="https://www.simonholywell.com/post/2015/09/scrape-site-with-wget-and-httrack/?utm_source=atom_feed" rel="related" type="text/html" title="Scraping websites with wget and httrack"/><link href="https://www.simonholywell.com/post/2015/08/image-resize-crop-bash-imagemagick/?utm_source=atom_feed" rel="related" type="text/html" title="Crop and resize images with bash and ImageMagick"/><link href="https://www.simonholywell.com/post/2015/08/namespace-php-functions/?utm_source=atom_feed" rel="related" type="text/html" title="Namespace PHP functions"/><id>https://www.simonholywell.com/post/2016/09/tamiya-manta-ray/</id><author><name>Simon Holywell</name></author><published>2016-09-13T10:20:11+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>I&amp;rsquo;ve finally found some time to look at my old remote control car again - I was so happy when I bought it as a kid nearly twenty years ago. I&amp;rsquo;ve still got the original nickel cadmium battery (all 1300mAh!) and charger so I charged it up expecting that there&amp;rsquo;d be little to no response from the car. Amazingly the kids and I got about 5 minutes of full throttle action out of it before it slowed to a halt.</summary><content type="html"><![CDATA[<p>I&rsquo;ve finally found some time to look at my old remote control car again - I was so happy when
I bought it as a kid nearly twenty years ago. I&rsquo;ve still got the original nickel cadmium
battery (all 1300mAh!) and charger so I charged it up expecting that there&rsquo;d be little
to no response from the car. Amazingly the kids and I got about 5 minutes of full throttle
action out of it before it slowed to a halt.</p>
<p>As I picked it up and the wheels spun, winding down the last of the charge in the old battery,
I noticed that it was quite a bit noisier than I remembered as a kid. Especially from around
the rear differential area so I figured some grease was required. Naturally, I looked around online
for stories from others who&rsquo;d resurrected their old cars and surprisingly there was a lot of
information out there.</p>
<p>Most of it in quite difficult to find tidbits that are spread out across many different
online forum threads. So I&rsquo;ve assembled all the information I found useful here for my own
reference and yours too.</p>
<h2 id="parts-compatible-models">Parts compatible models</h2>
<p>The Manta Ray (58087 and the later 58360 re-release) it would seem is a much loved car both back
then and now. It was part of the first wave of modern 4WD Tamiya remote control cars and was the
first to carry chassis designation of DF01. There were other DF01 cars including the Blazing Star,
Top Force, Top Force Evolution, Dirt Thrasher and Terra Conqueror.</p>
<p>Later Tamiya made a number of other rally (such as the Lancia Delta Integrale) and road cars
(including the Nissan Skyline) that shared many of the same parts and chassis as the DF01 cars.
These later cars were designated as, first, the TA01 and then later the TA02.</p>
<p>Some parts on the later cars are considered to be stronger or better designed so most
of the people rebuilding will replace broken or worn parts on a DF01 with parts for the TA01
or TA02 chassis. Being rally/road cars though there are a couple of differences and deviations:</p>
<ul>
<li>the suspension strut towers (front and back) are shorter than the buggy</li>
<li>in sympathy the struts themselves are shorter</li>
<li>with that the body mount pins are in different positions too.</li>
</ul>
<p>It is important to note that parts from the DF02 or DF03 are completely different to the DF01,
TA01 or TA02 so you can&rsquo;t use them in your Manta Ray. Some people have mentioned that you can
use the wheels from a DF03 on the DF01 as they&rsquo;re both compatible with 12mm hex wheels - the
advantage of swapping here is that you can use newer (read better) tyres in the new 2.2 profile.</p>
<p>Also, note that the re-re-release and Quick Drive version of the Manta Ray is also incompatible -
you can tell these easily as they&rsquo;ve got little impact wheels on either end of the front bumper
and/or are smaller.</p>
<h2 id="replacement-parts">Replacement parts</h2>
<p>As mentioned there are a number of common parts between the DF01 and the later TA01 or TA02. After
reading around I noted down the parts that people were having issues with or those that regularly
break and ordered the recommended Tamiya part numbers.</p>
<ul>
<li><a href="http://amzn.to/2ceiYgT">Tamiya 50197</a> Snap pin set - my model was missing a few securing the
body - there are after market alternatives too</li>
<li><a href="http://amzn.to/2cGIo8f">Tamiya 50478</a> TA01/TA02 Skyline rear drive/gear case - a weak point
on the original so I wanted a spare and apparently these are an improved design</li>
<li><a href="http://amzn.to/2cGHtoA">Tamiya 50602</a> Bevel gear differential set - can be worn so I got these
as spares (you&rsquo;ll probably want two - one for the front and one for the rear)</li>
<li><a href="http://amzn.to/2ctyjw6">Tamiya 50541</a> TA01/TA02 4WD rally car front drive/gear case - another
weak point like the rear</li>
<li><a href="http://amzn.to/2bXVoJI">Tamiya 50529</a> TA01/TA02 4WD plastic gear set - replace the aluminium
gears with a stronger, improved plastic gear set designed for the later cars</li>
</ul>
<p>I may refer to the above part numbers later in the article, but these should give you a go to
list of compatible part. These parts are relatively easy to find on Amazon, eBay and rcMart.</p>
<h2 id="upgradehop-up-parts">Upgrade/Hop-Up parts</h2>
<p>The upgrade parts for the DF01 are all but impossible to find - Tamiya called these Hop-Up parts.
There are some companies like Fibre-Lyte, Carson, GPM and Yeah Racing that do provide some after
market parts for the TA01 and TA02 so you can use some of those.</p>
<p>If you can find them then the following Tamiya parts are highly prized:</p>
<ul>
<li>Tamiya 53079 Stainless steel prop shaft for Manta Ray</li>
<li>Tamiya 53099 FRP double deck chassis plate set</li>
<li>Tamiya 53100 Top Force double deck carbon graphite chassis plate set</li>
<li><a href="http://amzn.to/2bXVS2n">Tamiya 53070</a> Manta Ray/TA01 ball diff set</li>
<li>Tamiya 53071 Manta Ray/TA01 torque splitter set</li>
<li>Tamiya 53164 Hollow carbon gearshaft set</li>
<li>Tamiya 53073 Bearing set for the Manta Ray</li>
</ul>
<p>Some of the more desirable after market parts include:</p>
<ul>
<li>Fibre-Lyte TOP 01 &amp; TOP 02 chassis set (you&rsquo;ll need to choose the straps to pair with it based on
the battery pack you intend to use - you&rsquo;ll also need two of each strap)</li>
<li>Fibre-Lyte TOP 03 front strut tower/mount</li>
<li>Fibre-Lyte TOP 04 rear strut tower/mount</li>
<li>GPM TA1012 front gear case cover - this is good to have as the suspension arms connect to it and this upgrade
will strengthen the front end in case of a crash</li>
<li>GPM TA1025 prop shaft or main shaft</li>
<li>Yeah Racing TA01-027BU rear gear case cover</li>
</ul>
<p>Most of the Tamiya parts a really hard to find and cost exorbitantly large stacks of cash. It&rsquo;s not
uncommon for a chassis to be above $200USD or the bearing set to be in excess of $140USD.
Thankfully there are after market parts that can fill this void and make upgrades to the Manta
Ray affordable.</p>
<h2 id="bearing-set">Bearing set</h2>
<p>To help reduce the wear on moving parts it is recommended that one of the first and most valuable
upgrades you could do to the car is to replace all bushings with ball bearings. Due to exposure to
dirt (being a buggy rather than a street car) it is recommended to go with a plastic/PFTE/nylon
shielded sealed ball bearing as opposed to the slightly cheaper metal shielded variety.</p>
<p>You&rsquo;ll need 22 bearings made up of:</p>
<ul>
<li>6x 1150 bearings (5 x 8 x 2.5mm)</li>
<li>16x 850 bearings (5 x 11 x 4mm)</li>
</ul>
<p>These can be bought as kits (look for TA01 kits) or you can use the bearing numbers/dimensions to
buy them individually from a bearing or hobby shop.</p>
<p>Manufacturers of kits include:</p>
<ul>
<li>Tamiya 53073 - rare as hens teeth</li>
<li><a href="http://amzn.to/2ctzrQB">Acer Racing ceramic bearings</a></li>
<li><a href="http://amzn.to/2cHHPhv">Alicenter Bearings</a></li>
<li>Yeah Racing YB0018B</li>
<li><a href="http://amzn.to/2ctySWG">Fast Eddy 769173950092</a></li>
<li><a href="http://amzn.to/2cGIbCf">VXB Ball Bearings Kit177096</a></li>
<li><a href="http://amzn.to/2c2k4PC">Boca Bearing #55-145</a>, #55-145GS, #55-145C-YZ, #55-145C-YS and #55-145C-YU in
ascending order of price</li>
</ul>
<p>If you&rsquo;re going to be installing a more powerful motor then you really should install the bearing kit
beforehand.</p>
<h2 id="propeller-shaft-or-main-shaft">Propeller shaft or main shaft</h2>
<p>By far and away the easiest method of getting a new prop shaft (sometimes known as a main shaft) is
to buy a <a href="http://amzn.to/2chQgig">Yeah Racing (TA01-134BU)</a> after market alloy one. Some people using fast
brushless motors have reported shearing the dog bones off the end of shafts like this. I am not sure how
much abuse they were giving them, but it might be worth the extra dollars up front to get a more sturdy
GPM (TA1025) or Tamiya Hop-Up (53079) part if you intend to go crazy brushless.</p>
<p>Whilst the next one is not a Hop-Up, but it is more substantial than the wire prop shaft that comes
by default in many of the DF01s you can use the Top Force shaft apparently, which is Tamiya 3485025
(also X10185). As they were standard with a few models they can be easier to come by one eBay - bear
in mind you may need the shaft, two circlips and the end cups. Jury is out on that one as I&rsquo;ve also
read some people have had success with the standard prop shaft cups.</p>
<p>The standard Manta Ray prop, should you need it, is even cheaper and easier to get as it is not
desirable - look for Tamiya 3485039 - sometimes derisively known as the twisted coat hanger in RC
forums.</p>
<p>If you&rsquo;re installing a more powerful motor then this is definitely a sensible upgrade to make to
ensure the power is being expended to the wheels and not in deforming the prop shaft!</p>
<h2 id="esc-electronic-speed-controller">ESC (Electronic Speed Controller)</h2>
<p>Most Manta Rays weren&rsquo;t fitted with an ESC but with an MSC (Motorised/Manual Speed Controller) and
these aren&rsquo;t really up to modern batteries or motors - quickly burning out. On top of that they&rsquo;re
less efficient and heavier than even the cheapest of ESCs.</p>
<p>You can swap in a new ESC very easily as they will plug right into the radio receiver already in your
car so you don&rsquo;t need to change your radio equipment. The connectors for the motor will probably also
be compatible, but there may be some soldering required.</p>
<p>Interestingly you&rsquo;ll also no longer need the additional power wire that runs from the MSC to the radio
receiver. The ESC will power the radio receiver via it&rsquo;s one control/power cable triptych.</p>
<p>I just went with the simplest and cheapest ESC I could find that had some positive reviews. A Hobby
King X-Car 45, which is simple, small and suitable for brushed motors and up to a 2S LiPo battery -
perfect!</p>
<p>If you want something waterproof or just that bit better then I&rsquo;ve not seen any bad words
said about the <a href="http://amzn.to/2ctyLKU">Hobbywing QuicRun WP 1060 Brushed</a> or it&rsquo;s rebadged clone
the <a href="http://amzn.to/2c2lpWu">Yeah Racing Tritronic (ESC-1060WP)</a>.</p>
<p>As I am not running a brushless motor or ever intending to in this car I&rsquo;ve not looked into brushless
ESCs, but you need to ensure the ESC you select is specifically for a brushless motor if you intend to
run one. You cannot, generally, use a brushed ESC with a brushless motor and vice versa so make sure you
check carefully if you intend to do so - you&rsquo;ll probably be able to tell by the crazy price you&rsquo;re paying!</p>
<p>So if you plan to go to high capacity LiPo or NiMH batteries it is important that you look into
replacing that MSC with a nice new ESC. In the case of a LiPo this is especially true as you&rsquo;ll see
in the batteries section.</p>
<h2 id="batteries-and-charging">Batteries and charging</h2>
<p>Battery technology has really moved on since the Manta Ray was released along with its low capacity
NiCd batteries (1300mAh!). The next step up from a NiCd is probably a NiMH battery, which is an
improvement in terms of capacity and charge time. You can handle this pretty much like you would your
NiCd pack from the past and they come in a similar form factor - round cells in a shrink plastic wrap.</p>
<p>They can be a bit of pain like the old NiCds though in that they do end up suffering from the memory
effect over time and they display voltage sag during use. Another aspect to consider is whether your old
charger can charge a NiMH battery properly.</p>
<p>After looking at these options I decided that as I needed to upgrade the charger and I wanted to run an
ESC anyway I might as well go for a LiPo battery pack and enjoy the longer and more consistent power
delivery. The cost difference between a LiPo an NiMH battery also appeared to be negligible for a
similar capacity.</p>
<p>Some anecdotal evidence suggested that the greater output of a modern NiMH battery would be enough to
burn out the MSC pretty quickly as well anyway so I saw no point in keeping the old technology.</p>
<p>It is important that LiPo batteries are not discharged too far so you&rsquo;ll want to select an ESC that is
designed to cut-out/off when the battery voltage drops - most LiPo compatible ones will provide this
feature.</p>
<p>Charging a multi-cell LiPo battery is different to a NiMH or NiCd as the cells need to be balanced so
it is best to get a charger that can do this for you. I went with a tried and trusted iMax B6 charger
that can do up to 60W and 5A. As you shouldn&rsquo;t charge at greater than 1C and the battery I intended to
buy was 4200mAh a 5A charger should be more than enough.</p>
<p>The C rating is something that I found confusing at first, but it essentially means charge rate so if
your battery capacity is 4200mAh then 1C would be 4200mA or 4.2A and 2C would be 8400mA or 8.4A. This
can apply to charge and discharge rates - usually a batteries charge rate is lower than it&rsquo;s discharge
rate. This means it will take longer to charge than it will to be discharged - presuming it is discharged
at its maximum rate.</p>
<p>You&rsquo;ll also need to be a little more careful with your LiPo batteries as they can catch fire if they&rsquo;re
incorrectly charged or damaged. Most people recommend charging them in a fireproof container like a sealed
metal tin or a specialist LiPo charging bag. It is recommended that you only charge them on a solid
non-flammable surface like concrete to further minimise any risk.</p>
<p>Now choosing a LiPo for your DF01/TA01 chassis cars isn&rsquo;t as easy as you&rsquo;d think. To reduce the chance
of damaging the battery it is recommended that cars use the hard case packs - given their position in
the buggy they could come into contact with something during a crash or hard landing. Most hard packs
have a rectangular profile so they simply won&rsquo;t fit into the chassis oval shaped battery receptacle.</p>
<p>So you&rsquo;ll be looking for what are known as car stick packs or hardcase stick packs to use in your car.
Choose a 2S pack (means that there are 2 cells in the battery) - 3S will not be the right shape for the
Manta Ray or other DF01s.</p>
<p>I went with a <a href="http://amzn.to/2c2kR2N">Turnigy nano-tech 4200mAh 2S (NC4200.2S2P.4)</a> LiPo battery that
claimed to fit the Manta Ray chassis, but it doesn&rsquo;t, I discovered, without some modification to enlarge
the ovalised shape in my chassis. Others have claimed to get a good fit from the following batteries, but
they weren&rsquo;t available to me when I was buying mine:</p>
<ul>
<li><a href="http://amzn.to/2c3yrWw">Speed Energy SE-4800/30/TP 7.4v 4800mAh 30C 2S</a></li>
<li>Core RC CR158 7.4v 4000mAh 20C 2S</li>
<li>Core RC CR293 7.4v 4000mAh 30C 2S</li>
<li>Jamara #141390 7.4v 5000mAh 30C 2S</li>
<li>Gens ace #8 7.4v 4000mAh 25C 2S</li>
<li>Intellect IP2500 7.4v 2500mAh</li>
<li>Intellect IP4000 7.4v 4000mAh</li>
<li>Hyperion G3 SWIFT HP-SW20-4000CP-2S Classic Pack 4000mAh 7.4v 20C 2S</li>
</ul>
<p>I also took the opportunity to change the old Tamiya battery connector over to a
<a href="http://amzn.to/2cGLklz">Deans connector</a>, which has a larger contact area for better power transmission and
they&rsquo;re easier to use. They were marketed as <a href="http://amzn.to/2cHJHqv">T connectors</a> by the shop I bought them
from, but they&rsquo;re the same as the <a href="http://amzn.to/2c2mm0X">Deans</a> as far as I can tell.</p>
<h2 id="motor-and-pinion-gears">Motor and pinion gears</h2>
<p>With the standard motor (silver can) you probably want a 19 tooth or (19T) steel pinion gear - the more
powerful the motor you run the fewer teeth you&rsquo;ll want say a 16T. Confusingly, motors are also rated in
terms of T except in this case it stands for turns. So a 9T motor will be faster than a 21T motor. For
a hot, but still brushed motor consider something like a <a href="http://amzn.to/2bXYvRJ">17T motor</a> with a
<a href="http://amzn.to/2ctBnbx">19T pinion</a>. You&rsquo;ll want to be looking for 540 sized motors as replacements.</p>
<p>This steel pinion gear should be 0.6 pitch and there are at least two manufacturers currently making
them Robinson Racing (USA) or RW Racing (UK). Their part numbers are simple and you can adjust the
last two numbers to the number of teeth you want.</p>
<ul>
<li><a href="http://amzn.to/2ctBnbx">Robinson Racing RRP1119</a></li>
<li>RW Racing ARW0600-19</li>
</ul>
<p>Many people have gone with the newer brushless motors to get top speed out of their models such as 9T
motor paired with a 16T pinion gear. You will need a brushless specific ESC too, but I&rsquo;ll cover that
later. So back to pinions 16T would be:</p>
<ul>
<li><a href="http://amzn.to/2cGL9q2">Robinson Racing RRP1116</a></li>
<li>RW Racing ARW0600-16</li>
</ul>
<p>Another good upgrade is to replace the plastic motor mount with a metal one for increased strength. There
is evidence that the plastic mount can deform or crack allowing the motor pinion gear to move around
and crash into the gearbox destroying the gears. A number of people mentioned that they preferred the
mounts that had fixed posts like the Yeah Racing one rather than those with screw on posts like the GPM.</p>
<p>It was also noted that some cheaper eBay versions don&rsquo;t have one post shorter than the other like
they should to match the factory plastic one. I ended up going for the Yeah Racing one based on recommendations
although I was initially attracted to the GPMs heat sink style design - it has screw on posts. Whilst looking
I found the following mounts available:</p>
<ul>
<li>Tamiya 53142</li>
<li><a href="http://amzn.to/2c2mca1">Yeah Racing TA02-013BU</a></li>
<li>GPM TA1002</li>
<li>Pargu MS0104</li>
</ul>
<p>If you do decide to fit a more powerful motor then ensure you install an aluminium motor mount, a set of
bearings, a compatible ESC and a more substantial prop shaft as well. These are considered the basic
essentials before introducing more power to the DF01/TA01/TA02 chassis. You should also upgrade the
gear set to the <a href="http://amzn.to/2cHLvjb">Tamiya 50529</a> and use one of the pinion steel pinion gears
discussed above.</p>
<p>Obviously the faster you go the harder you impact when you crash so maybe sticking the fastest motor
the chassis can handle into a 20-30 year old RC car isn&rsquo;t the best idea&hellip;</p>
<h2 id="wheels-and-tyres">Wheels and tyres</h2>
<p>You&rsquo;re going to be looking for <a href="http://amzn.to/2bXXv00">12mm hex drive off road buggy wheels</a>.</p>
<p>The wheels from a Tamiya DF-03 Dark Impact look good on the Manta Ray with the advantage that you can use newer
(read better) tyres (2.2 profile) than the Manta wheels. You&rsquo;d need both front (Tamiya 10440209) and rear
(Tamiya 10440210) wheels with tyres:</p>
<ul>
<li><a href="http://amzn.to/2chSj6d">Tamiya 54185</a> (front) and <a href="http://amzn.to/2bXXpWh">Tamiya 54186</a> (rear)</li>
<li><a href="http://amzn.to/2ctAPCE">Tamiya 51240</a> (front) and Tamiya 51241 (rear)</li>
<li><a href="http://amzn.to/2cen4FB">Tamiya 53878</a> (front) and Tamiya 53879 (rear)</li>
</ul>
<p>to match.</p>
<p>Other cheaper options also abound on eBay, but fitting may be more hit and miss with diameter, offset
and interior space within the wheel for the axle stub/wheel hub.</p>
<h2 id="suspension">Suspension</h2>
<p>You can use pretty much any remote control car alloy strut that is between <a href="http://amzn.to/2bXX59W">95mm</a>
and <a href="http://amzn.to/2bXX06f">100mm</a> long. I&rsquo;ve not bothered looking into this so far as my dampers are in
really good condition luckily. There are Tamiya rebuild kits available, but they seem very difficult to come
across.</p>
<p>If mine do need replacement then I think I&rsquo;d be looking for some <a href="http://amzn.to/2cHLFav">generic aluminium dampers</a>
that are the correct length to suit the car. This looks to be an easier and cheaper way of fixing the suspension
than buying replacement Tamiya parts - plus they look better than the yellow originals!</p>
<h2 id="conclusion">Conclusion</h2>
<p>It is also worth pointing out here that some people have spent an awful lot of money improving their
cars or replacing bits with up-spec parts. One build I saw was over $1k AUD and another around the
$700 USD mark - so you can go nuts with aluminium, carbon and titanium. Set yourself a budget as all the
tiny parts at $15-20 each very quickly add up too.</p>
<p>A few of the most hopped up cars I found whilst looking for information:</p>
<ul>
<li><a href="http://tamiyabase.com/forum/forum/32-vintage-tamiya-custom-builds/802-vintage-manta-ray-customisation-quest.html">Edou&rsquo;s Manta Ray</a></li>
<li><a href="http://www.tamiyaclub.com/showroom_model.asp?cid=85254&amp;sid=20319">TA-Mark&rsquo;s Blazing Star</a></li>
<li><a href="http://www.tamiyaclub.com/forum/index.php?/topic/31350-top-force-evolution-beyond-build-chronicles/">djmcnz&rsquo;s Top Force</a></li>
<li><a href="http://www.tamiyaclub.com/forum/index.php?/topic/68061-rebirth-of-a-58100-top-force-my-2-year-forum-anniversary-project/&amp;page=1">Percymon&rsquo;s Top Force</a></li>
</ul>
<p>Some other places to get parts excluding the obvious:</p>
<ul>
<li><a href="http://twokeysrcparts.com.au">Twokey&rsquo;s RC Parts</a> - Australia</li>
<li><a href="http://jasons-store.highwire.com">Jason&rsquo;s RC Store</a> - Japan (cheap international postage)</li>
<li><a href="http://www.rcmart.com">rcMart</a> - Hong Kong (cheap parts - reasonable postage)</li>
<li><a href="http://www.asiatees.com">Asiatees</a> - Hong Kong</li>
<li><a href="http://www.stellamodels.net">Stella Models</a> - Hong Kong</li>
<li><a href="http://www.goldstarstockists.net">Goldstar Stockists</a> - Tamiya parts UK</li>
<li><a href="http://www.hobbyking.com">Hobby King</a> - (Australia, US, Hong Kong and UK warehouses)</li>
<li><a href="http://www.fusionhobbies.com">Fusion Hobbies</a> - UK</li>
<li><a href="http://www.modelsport.co.uk">Modelsport</a> - UK</li>
</ul>
]]></content><category scheme="taxonomy:Categories" term="motors" label="Motors"/><category scheme="taxonomy:Tags" term="tamiya" label="tamiya"/><category scheme="taxonomy:Tags" term="manta-ray" label="manta ray"/><category scheme="taxonomy:Tags" term="remote-control-car" label="remote control car"/><category scheme="taxonomy:Tags" term="rc-car" label="rc car"/></entry><entry xml:base="brisbane"><title type="html">Brisbane</title><link href="https://www.simonholywell.com/post/2016/09/brisbane/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2016/02/intelligent-vagrant-and-ansible-files/?utm_source=atom_feed" rel="related" type="text/html" title="Intelligent Vagrant and Ansible files"/><link href="https://www.simonholywell.com/post/2015/09/scrape-site-with-wget-and-httrack/?utm_source=atom_feed" rel="related" type="text/html" title="Scraping websites with wget and httrack"/><link href="https://www.simonholywell.com/post/2015/08/image-resize-crop-bash-imagemagick/?utm_source=atom_feed" rel="related" type="text/html" title="Crop and resize images with bash and ImageMagick"/><link href="https://www.simonholywell.com/post/2015/08/namespace-php-functions/?utm_source=atom_feed" rel="related" type="text/html" title="Namespace PHP functions"/><link href="https://www.simonholywell.com/post/2015/07/sql-style-guide/?utm_source=atom_feed" rel="related" type="text/html" title="SQL style guide"/><id>https://www.simonholywell.com/post/2016/09/brisbane/</id><author><name>Simon Holywell</name></author><published>2016-09-02T10:20:11+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Way back in 2007 I arrived in London, England ready to start a new chapter of my life working in the big city. I&amp;rsquo;d left a good job at a web agency in Melbourne - one of the world&amp;rsquo;s most livable cities - to experience the financial capital of Europe.
It was a fantastic time and so much happened I could write a novel, but here are a few highlights.</summary><content type="html"><![CDATA[<p>Way back in 2007 I arrived in London, England ready to start a new chapter of my life working in the big city. I&rsquo;d left a good job at a web agency in Melbourne - one of the world&rsquo;s most livable cities - to experience the financial capital of Europe.</p>
<p>It was a fantastic time and so much happened I could write a novel, but here are a few highlights.</p>
<p>During my time in England I met my now wife and decided to move to the south coast. Soon after she completed her degree we wed at the extravagant <a href="http://brightonmuseums.org.uk/royalpavilion/">Royal Pavilion</a> in Brighton.</p>
<p>On the way to a brief sojourn in Auckland, New Zealand we travelled through Europe by train and car before honeymooning in Phuket, Thailand.</p>
<p>Soon after flying back to England and setting up in Worthing (near Brighton) we welcomed the first of two children into the world. During this time we travelled to Zimbabwe where I met my wife&rsquo;s parents for the first time.</p>
<p>We had our second child and bought our first house on a street in Worthing and did a little DIY.</p>
<p>Throughout this time I took up roles with a number of companies that finally culminated in becoming Technical Director at <a href="http://www.emosaic.co.uk">Mosaic Digital</a> in Brighton.</p>
<p>Oh and yeah I wrote a book on <a href="http://www.functionalphp.com">Functional Programming in PHP</a>.</p>
<p>After nearly nine years in the United Kingdom it was time to say goodbye and try something new. So for various reasons we decided to move to Brisbane in Australia.</p>
<p>We came via a motorcycle track day at Donington, a long weekend in Bruges, Belgium and a second wedding/vowal renewal at <a href="http://www.nesbittcastle.co.zw">Nesbitt Castle</a> in Bulawayo, Zimbabwe.</p>
<p>Before leaving I&rsquo;d organised a job with a company called <a href="http://www.temando.com">Temando</a> as a Lead Developer based here in Brisbane. I now work at a company called <a href="http://www.aurion.com">Aurion</a> in Toowong as a Senior Developer primarily working with Node.js.</p>
]]></content><category scheme="taxonomy:Tags" term="moves" label="moves"/><category scheme="taxonomy:Tags" term="brisbane" label="brisbane"/><category scheme="taxonomy:Tags" term="temando" label="temando"/><category scheme="taxonomy:Tags" term="aurion" label="aurion"/></entry><entry xml:base="intelligent-vagrant-and-ansible-files"><title type="html">Intelligent Vagrant and Ansible files</title><link href="https://www.simonholywell.com/post/2016/02/intelligent-vagrant-and-ansible-files/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2015/09/scrape-site-with-wget-and-httrack/?utm_source=atom_feed" rel="related" type="text/html" title="Scraping websites with wget and httrack"/><link href="https://www.simonholywell.com/post/2015/08/image-resize-crop-bash-imagemagick/?utm_source=atom_feed" rel="related" type="text/html" title="Crop and resize images with bash and ImageMagick"/><link href="https://www.simonholywell.com/post/2015/07/php-date-setlocale-localisation/?utm_source=atom_feed" rel="related" type="text/html" title="PHP date localisation with setlocale"/><link href="https://www.simonholywell.com/post/2013/03/install-netbeans-scala-ubuntu/?utm_source=atom_feed" rel="related" type="text/html" title="Install Netbeans and Scala on Ubuntu"/><link href="https://www.simonholywell.com/post/2012/06/fish-console/?utm_source=atom_feed" rel="related" type="text/html" title="Fish Console Reborn"/><id>https://www.simonholywell.com/post/2016/02/intelligent-vagrant-and-ansible-files/</id><author><name>Simon Holywell</name></author><published>2016-02-08T12:16:56+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>I use both Vagrant and Ansible to run and provision development virtual machines for testing work locally. This provides an easy to build environment as close to production as possible that all developers can easily create from the source code repository. A simple vagrant up and the associated Ansible scripts will handle all of the configuration and package installation for the VM.
This is unbelievably handy and it really helps to reduce the kind of bugs that are difficult to track down - &amp;ldquo;it works on my machine!</summary><content type="html"><![CDATA[<p>I use both Vagrant and Ansible to run and provision development virtual machines for
testing work locally. This provides an easy to build environment as close to production
as possible that all developers can easily create from the source code repository.
A simple <code>vagrant up</code> and the associated Ansible scripts will handle all of the
configuration and package installation for the VM.</p>
<p>This is unbelievably handy and it really helps to reduce the kind of bugs that are
difficult to track down - &ldquo;it works on my machine!&rdquo;</p>
<h2 id="shared-configuration">Shared configuration</h2>
<p>Recently, though I got to thinking about how the configuration is bound up in a
rather unhelpful <code>Vagrantfile</code>, which is a Ruby script underneath in reality. The
same configuration details need for the <code>Vagrantfile</code> will likely also be required
by your provisioning scripts.</p>
<p>There are at least two ways to achieve this - each with their respective advantages
and pitfalls. You can use a central file or pass the information as arguments to
Ansible from the Vagrant provision commands. If you need to support machines that
Ansible cannot run on then you&rsquo;ll prefer the central configuration file as otherwise
you need to pass the parameters in two locations. Using a bash script to support
Windows machines is discussed further on.</p>
<h3 id="central-configuration-file">Central configuration file</h3>
<p>One way to work around this is to use a universal configuration file that both
your provisioning scripts (Ansible, etc) and the <code>Vagrantfile</code> can read. The common
thread between Ansible and Ruby (of course) is that they both parse YAML so a
central config file is going to be the ticket. I am calling this file <code>vagrant.yml</code>
and I have it sat at the same level as <code>Vagrantfile</code> in my projects.</p>
<p>In <code>vagrant.yml</code> you can have a structure like:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nn">---</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">ip_address</span><span class="p">:</span><span class="w"> </span><span class="m">192.168.33.66</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">vm_name</span><span class="p">:</span><span class="w"> </span><span class="l">example</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">server_domain</span><span class="p">:</span><span class="w"> </span><span class="l">example.dev</span><span class="w">
</span></span></span></code></pre></div><p>From the Ruby script in <code>Vagrantfile</code> it is possible to parse the <code>vagrant.yml</code>
configuration file and set the values against internal Vagrant options.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="nb">require</span> <span class="s1">&#39;yaml&#39;</span>
</span></span><span class="line"><span class="cl"><span class="n">settings</span> <span class="o">=</span> <span class="no">YAML</span><span class="o">.</span><span class="n">load_file</span> <span class="s1">&#39;vagrant.yml&#39;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="no">Vagrant</span><span class="o">.</span><span class="n">configure</span><span class="p">(</span><span class="s2">&#34;2&#34;</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">config</span><span class="o">|</span>
</span></span><span class="line"><span class="cl">  <span class="n">config</span><span class="o">.</span><span class="n">vm</span><span class="o">.</span><span class="n">network</span> <span class="ss">:private_network</span><span class="p">,</span> <span class="ss">ip</span><span class="p">:</span> <span class="n">settings</span><span class="o">[</span><span class="s1">&#39;ip_address&#39;</span><span class="o">]</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span>
</span></span></code></pre></div><p>You can also use these configuration details from Ansible project by loading it in
a <code>vars_files:</code> directive. The variables will then become available in the global
space. In the example code you can see the variables in use to define <code>servername:</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nn">---</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span>- <span class="nt">hosts</span><span class="p">:</span><span class="w"> </span><span class="l">all</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">sudo</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">vars_files</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">../vagrant.yml</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">vars/common.yml</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">vars</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">servername</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;{{ server_domain }} www.{{ server_domain }} {{ ip_address }}&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">timezone</span><span class="p">:</span><span class="w"> </span><span class="l">Europe/London</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">roles</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">init</span><span class="w">
</span></span></span></code></pre></div><p>Note that my Ansible configuration is in a subfolder hence the need to call the
shared configuration with <code>../vagrant.yml</code>.</p>
<h3 id="passed-as-arguments">Passed as arguments</h3>
<p>Another way of having shared configuration between Vagrant and Ansible is to pass
arguments from Vagrant into Ansible at provision time. This is done using the
<code>ansible</code> API in your <code>Vagrantfile</code> and specifically the <code>extra_vars</code> property.</p>
<p>The sample code below illustrates how this might look in a simple Ansible backed
Vagrant setup.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="no">Vagrant</span><span class="o">.</span><span class="n">configure</span><span class="p">(</span><span class="s2">&#34;2&#34;</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">config</span><span class="o">|</span>
</span></span><span class="line"><span class="cl">  <span class="n">ansible_inventory_dir</span> <span class="o">=</span> <span class="s2">&#34;ansible/hosts&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="n">config</span><span class="o">.</span><span class="n">vm</span><span class="o">.</span><span class="n">provision</span> <span class="s2">&#34;ansible&#34;</span> <span class="k">do</span> <span class="o">|</span><span class="n">ansible</span><span class="o">|</span>
</span></span><span class="line"><span class="cl">    <span class="n">ansible</span><span class="o">.</span><span class="n">playbook</span> <span class="o">=</span> <span class="s2">&#34;ansible/playbook.yml&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">ansible</span><span class="o">.</span><span class="n">inventory_path</span> <span class="o">=</span> <span class="s2">&#34;</span><span class="si">#{</span><span class="n">ansible_inventory_dir</span><span class="si">}</span><span class="s2">/vagrant&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">ansible</span><span class="o">.</span><span class="n">limit</span> <span class="o">=</span> <span class="s1">&#39;all&#39;</span>
</span></span><span class="line"><span class="cl">    <span class="n">ansible</span><span class="o">.</span><span class="n">extra_vars</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="ss">vm_cores</span><span class="p">:</span> <span class="n">cpus</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="ss">vm_memory</span><span class="p">:</span> <span class="n">mem</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="ss">server_domain</span><span class="p">:</span> <span class="n">servers</span><span class="o">[</span><span class="s1">&#39;server_domain&#39;</span><span class="o">]</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="ss">ip_address</span><span class="p">:</span> <span class="n">servers</span><span class="o">[</span><span class="s1">&#39;ip_address&#39;</span><span class="o">]</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="ss">additional_server_domain_aliases</span><span class="p">:</span> <span class="n">servers</span><span class="o">[</span><span class="s1">&#39;additional_server_domain_aliases&#39;</span><span class="o">]</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="ss">vm_user</span><span class="p">:</span> <span class="n">settings</span><span class="o">[</span><span class="s1">&#39;vm_user&#39;</span><span class="o">]</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span>
</span></span></code></pre></div><p>Just like the shared configuration these variables can be accessed in the global
space of Ansible.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nn">---</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span>- <span class="nt">hosts</span><span class="p">:</span><span class="w"> </span><span class="l">all</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">sudo</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">vars_files</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">vars/common.yml</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">vars</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">servername</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;{{ server_domain }} www.{{ server_domain }} {{ ip_address }}&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">timezone</span><span class="p">:</span><span class="w"> </span><span class="l">Europe/London</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">roles</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">init</span><span class="w">
</span></span></span></code></pre></div><h2 id="dynamically-create-the-ansible-inventory-file">Dynamically create the Ansible inventory file</h2>
<p>One aspect of projects that can be annoying to maintain or see committed into the
project is the Ansible inventory file. Thankfully this can easily be automated
from the <code>Vagrantfile</code> and the path dynamically set against Vagrant&rsquo;s configuration.</p>
<p>In the code below the Ansible directory is set to a variable and then Ansible is
set as the provisioning setup for Vagrant. This is all pretty much standard, but
then the code moves onto handle the actual inventory file creation.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="no">Vagrant</span><span class="o">.</span><span class="n">configure</span><span class="p">(</span><span class="s2">&#34;2&#34;</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">config</span><span class="o">|</span>
</span></span><span class="line"><span class="cl">  <span class="n">ansible_inventory_dir</span> <span class="o">=</span> <span class="s2">&#34;ansible/hosts&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="n">config</span><span class="o">.</span><span class="n">vm</span><span class="o">.</span><span class="n">provision</span> <span class="s2">&#34;ansible&#34;</span> <span class="k">do</span> <span class="o">|</span><span class="n">ansible</span><span class="o">|</span>
</span></span><span class="line"><span class="cl">    <span class="n">ansible</span><span class="o">.</span><span class="n">playbook</span> <span class="o">=</span> <span class="s2">&#34;ansible/playbook.yml&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">ansible</span><span class="o">.</span><span class="n">inventory_path</span> <span class="o">=</span> <span class="s2">&#34;</span><span class="si">#{</span><span class="n">ansible_inventory_dir</span><span class="si">}</span><span class="s2">/vagrant&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">ansible</span><span class="o">.</span><span class="n">limit</span> <span class="o">=</span> <span class="s1">&#39;all&#39;</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1"># setup the ansible inventory file</span>
</span></span><span class="line"><span class="cl">  <span class="no">Dir</span><span class="o">.</span><span class="n">mkdir</span><span class="p">(</span><span class="n">ansible_inventory_dir</span><span class="p">)</span> <span class="k">unless</span> <span class="no">Dir</span><span class="o">.</span><span class="n">exist?</span><span class="p">(</span><span class="n">ansible_inventory_dir</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="no">File</span><span class="o">.</span><span class="n">open</span><span class="p">(</span><span class="s2">&#34;</span><span class="si">#{</span><span class="n">ansible_inventory_dir</span><span class="si">}</span><span class="s2">/vagrant&#34;</span> <span class="p">,</span><span class="s1">&#39;w&#39;</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">f</span><span class="o">|</span>
</span></span><span class="line"><span class="cl">    <span class="n">f</span><span class="o">.</span><span class="n">write</span> <span class="s2">&#34;[</span><span class="si">#{</span><span class="n">settings</span><span class="o">[</span><span class="s1">&#39;vm_name&#39;</span><span class="o">]</span><span class="si">}</span><span class="s2">]</span><span class="se">\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">f</span><span class="o">.</span><span class="n">write</span> <span class="s2">&#34;</span><span class="si">#{</span><span class="n">settings</span><span class="o">[</span><span class="s1">&#39;ip_address&#39;</span><span class="o">]</span><span class="si">}</span><span class="se">\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span>
</span></span></code></pre></div><p>It simply creates the directory if it doesn&rsquo;t already exist and then opens the
inventory file for writing whereupon it puts the machine name and IP address into
the file. This is a simple way to save yourself a little work when creating new
Ansible backed Vagrant projects.</p>
<h2 id="give-the-box-all-virtual-cores-and-a-quarter-of-the-systems-memory">Give the box all virtual cores and a quarter of the systems memory</h2>
<p>Another tip I have picked up is from <a href="http://www.stefanwrobel.com/how-to-make-vagrant-performance-not-suck#toc_1">Stefan Wrobel&rsquo;s</a>
article <em>How to make Vagrant performance not suck</em>. He suggests an automatic method
for determining the number of CPU cores available on your host machine and then
giving the Vagrant box access to all of them. To further increase performance you
can also have the <code>Vagrantfile</code> calculate and assign a quarter of available host
system memory.</p>
<p>The Ruby code to perform this is reasonably self explanatory and uses command line
to establish the system resources.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="no">Vagrant</span><span class="o">.</span><span class="n">configure</span><span class="p">(</span><span class="s2">&#34;2&#34;</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">config</span><span class="o">|</span>
</span></span><span class="line"><span class="cl">  <span class="n">config</span><span class="o">.</span><span class="n">vm</span><span class="o">.</span><span class="n">provider</span> <span class="ss">:virtualbox</span> <span class="k">do</span> <span class="o">|</span><span class="n">v</span><span class="o">|</span>
</span></span><span class="line"><span class="cl">    <span class="n">v</span><span class="o">.</span><span class="n">name</span> <span class="o">=</span> <span class="n">settings</span><span class="o">[</span><span class="s1">&#39;vm_name&#39;</span><span class="o">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># taken from http://www.stefanwrobel.com/how-to-make-vagrant-performance-not-suck#toc_1</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># assigns all available CPU cores and 1/4 of the host systems memory to the vm</span>
</span></span><span class="line"><span class="cl">    <span class="n">host</span> <span class="o">=</span> <span class="no">RbConfig</span><span class="o">::</span><span class="no">CONFIG</span><span class="o">[</span><span class="s1">&#39;host_os&#39;</span><span class="o">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Give VM 1/4 system memory &amp; access to all cpu cores on the host</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">host</span> <span class="o">=~</span> <span class="sr">/darwin/</span>
</span></span><span class="line"><span class="cl">      <span class="n">cpus</span> <span class="o">=</span> <span class="sb">`sysctl -n hw.ncpu`</span><span class="o">.</span><span class="n">to_i</span>
</span></span><span class="line"><span class="cl">      <span class="c1"># sysctl returns Bytes and we need to convert to MB</span>
</span></span><span class="line"><span class="cl">      <span class="n">mem</span> <span class="o">=</span> <span class="sb">`sysctl -n hw.memsize`</span><span class="o">.</span><span class="n">to_i</span> <span class="o">/</span> <span class="mi">1024</span> <span class="o">/</span> <span class="mi">1024</span> <span class="o">/</span> <span class="mi">4</span>
</span></span><span class="line"><span class="cl">    <span class="k">elsif</span> <span class="n">host</span> <span class="o">=~</span> <span class="sr">/linux/</span>
</span></span><span class="line"><span class="cl">      <span class="n">cpus</span> <span class="o">=</span> <span class="sb">`nproc`</span><span class="o">.</span><span class="n">to_i</span>
</span></span><span class="line"><span class="cl">      <span class="c1"># meminfo shows KB and we need to convert to MB</span>
</span></span><span class="line"><span class="cl">      <span class="n">mem</span> <span class="o">=</span> <span class="sb">`grep &#39;MemTotal&#39; /proc/meminfo | sed -e &#39;s/MemTotal://&#39; -e &#39;s/ kB//&#39;`</span><span class="o">.</span><span class="n">to_i</span> <span class="o">/</span> <span class="mi">1024</span> <span class="o">/</span> <span class="mi">4</span>
</span></span><span class="line"><span class="cl">    <span class="k">else</span> <span class="c1"># sorry Windows folks, I can&#39;t help you</span>
</span></span><span class="line"><span class="cl">      <span class="n">cpus</span> <span class="o">=</span> <span class="mi">2</span>
</span></span><span class="line"><span class="cl">      <span class="n">mem</span> <span class="o">=</span> <span class="mi">1024</span>
</span></span><span class="line"><span class="cl">    <span class="k">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">v</span><span class="o">.</span><span class="n">customize</span> <span class="o">[</span><span class="s2">&#34;modifyvm&#34;</span><span class="p">,</span> <span class="ss">:id</span><span class="p">,</span> <span class="s2">&#34;--memory&#34;</span><span class="p">,</span> <span class="n">mem</span><span class="o">]</span>
</span></span><span class="line"><span class="cl">    <span class="n">v</span><span class="o">.</span><span class="n">customize</span> <span class="o">[</span><span class="s2">&#34;modifyvm&#34;</span><span class="p">,</span> <span class="ss">:id</span><span class="p">,</span> <span class="s2">&#34;--cpus&#34;</span><span class="p">,</span> <span class="n">cpus</span><span class="o">]</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span>
</span></span></code></pre></div><p>Finally, using <code>v.customize</code> the values are set against the Vagrant configuration.</p>
<h2 id="provision-without-ansible-installed">Provision without Ansible installed</h2>
<p>It is possible to provision a Vagrant box on a system that doesn&rsquo;t have Ansible
installed by using a small shell script. This is the approach that phansible.com
has taken and with some slight modification I have adopted.</p>
<p>The first step is two write some Ruby in the <code>Vagrantfile</code> that determines if Ansible
is installed in the user&rsquo;s path. If it is not then we should use the shell script
as the provisioner.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="c1"># Check to determine whether we&#39;re on a windows or linux/os-x host,</span>
</span></span><span class="line"><span class="cl"><span class="c1"># later on we use this to launch ansible in the supported way</span>
</span></span><span class="line"><span class="cl"><span class="c1"># source: https://stackoverflow.com/questions/2108727/which-in-ruby-checking-if-program-exists-in-path-from-ruby</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">which</span><span class="p">(</span><span class="n">cmd</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">exts</span> <span class="o">=</span> <span class="no">ENV</span><span class="o">[</span><span class="s1">&#39;PATHEXT&#39;</span><span class="o">]</span> <span class="p">?</span> <span class="no">ENV</span><span class="o">[</span><span class="s1">&#39;PATHEXT&#39;</span><span class="o">].</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39;;&#39;</span><span class="p">)</span> <span class="p">:</span> <span class="o">[</span><span class="s1">&#39;&#39;</span><span class="o">]</span>
</span></span><span class="line"><span class="cl">  <span class="no">ENV</span><span class="o">[</span><span class="s1">&#39;PATH&#39;</span><span class="o">].</span><span class="n">split</span><span class="p">(</span><span class="no">File</span><span class="o">::</span><span class="no">PATH_SEPARATOR</span><span class="p">)</span><span class="o">.</span><span class="n">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">path</span><span class="o">|</span>
</span></span><span class="line"><span class="cl">    <span class="n">exts</span><span class="o">.</span><span class="n">each</span> <span class="p">{</span> <span class="o">|</span><span class="n">ext</span><span class="o">|</span>
</span></span><span class="line"><span class="cl">      <span class="n">exe</span> <span class="o">=</span> <span class="no">File</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="s2">&#34;</span><span class="si">#{</span><span class="n">cmd</span><span class="si">}#{</span><span class="n">ext</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="k">return</span> <span class="n">exe</span> <span class="k">if</span> <span class="no">File</span><span class="o">.</span><span class="n">executable?</span> <span class="n">exe</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="kp">nil</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="no">Vagrant</span><span class="o">.</span><span class="n">configure</span><span class="p">(</span><span class="s2">&#34;2&#34;</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">config</span><span class="o">|</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="n">which</span><span class="p">(</span><span class="s1">&#39;ansible-playbook&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">config</span><span class="o">.</span><span class="n">vm</span><span class="o">.</span><span class="n">provision</span> <span class="s2">&#34;ansible&#34;</span> <span class="k">do</span> <span class="o">|</span><span class="n">ansible</span><span class="o">|</span>
</span></span><span class="line"><span class="cl">      <span class="n">ansible</span><span class="o">.</span><span class="n">playbook</span> <span class="o">=</span> <span class="s2">&#34;ansible/playbook.yml&#34;</span>
</span></span><span class="line"><span class="cl">      <span class="n">ansible</span><span class="o">.</span><span class="n">inventory_path</span> <span class="o">=</span> <span class="s2">&#34;</span><span class="si">#{</span><span class="n">ansible_inventory_dir</span><span class="si">}</span><span class="s2">/vagrant&#34;</span>
</span></span><span class="line"><span class="cl">      <span class="n">ansible</span><span class="o">.</span><span class="n">limit</span> <span class="o">=</span> <span class="s1">&#39;all&#39;</span>
</span></span><span class="line"><span class="cl">    <span class="k">end</span>
</span></span><span class="line"><span class="cl">  <span class="k">else</span>
</span></span><span class="line"><span class="cl">    <span class="n">config</span><span class="o">.</span><span class="n">vm</span><span class="o">.</span><span class="n">provision</span> <span class="ss">:shell</span><span class="p">,</span> <span class="ss">path</span><span class="p">:</span> <span class="s2">&#34;ansible/windows.sh&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span>
</span></span></code></pre></div><p>This shell script will handle the base setup of the box before Ansible can run -
so installing Ansible dependencies, then Ansible, setup SSH keys, link the Ansible
inventory and finally running the playbook locally on the box. This script targets
Ubuntu/Debian Vagrant boxes, but it could be adapted for other POSIX systems.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="cp">#!/usr/bin/env bash
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>sudo apt-get update
</span></span><span class="line"><span class="cl">sudo apt-get install -y python-software-properties
</span></span><span class="line"><span class="cl">sudo add-apt-repository -y ppa:ansible/ansible
</span></span><span class="line"><span class="cl">sudo apt-get update
</span></span><span class="line"><span class="cl">sudo apt-get install -y ansible
</span></span><span class="line"><span class="cl">cp /vagrant/ansible/hosts/vagrant /etc/ansible/hosts -f
</span></span><span class="line"><span class="cl">chmod <span class="m">666</span> /etc/ansible/hosts
</span></span><span class="line"><span class="cl">cat /vagrant/ansible/files/authorized_keys &gt;&gt; /home/vagrant/.ssh/authorized_keys
</span></span><span class="line"><span class="cl">sudo ansible-playbook /vagrant/ansible/playbook.yml --connection<span class="o">=</span><span class="nb">local</span>
</span></span></code></pre></div><h2 id="some-non-config-related-tips">Some non-config related tips</h2>
<h3 id="handy-plugins">Handy plugins</h3>
<p>In most of the configurations I prepare I also make use of <code>vagrant-cachier</code> and
<code>vagrant-hostsupdater</code>. The former aims to prevent duplicate package downloads for
a given Vagrant box so that subsequent provisions are faster. Hostsupdater will
automatically add the IP address and host name of the project to your hosts file
so that you don&rsquo;t have to. Both of their configurations are pretty straight forward
and dealt with on their respective project pages so I won&rsquo;t duplicate effort here.</p>
<h3 id="moving-the-vagrant-and-virtualbox-vms-to-an-external-hdd">Moving the Vagrant and VirtualBox VMs to an external HDD</h3>
<p>It is rare for a computer not to contain an SSD drive of some sort these days and
they&rsquo;re often set as the primary drive for the machine. This means that both
Vagrant and Ansible will be storing their large VMs and files on your limited capacity
(unless you&rsquo;re ultra lucky) SSD. To free up space a USB 3.0 external HDD can really
help without slowing down performance too much.</p>
<p>If you&rsquo;ve already got a few boxes and/or VirtualBox VMs setup then this process can
take some time as you will be copying large files - you may want to leave it over
night rather than a cup of coffee! It is a pretty simple process though.</p>
<p>For the sake of this example I am going to assume the external HDD is mounted at
<code>/media/simon/mydrive/</code> and you&rsquo;ll need to substitute this for your drive as you
follow along.</p>
<p>The first step is to move the Vagrant home directory to a new location on your
external hard drive.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">rsync -av ~/.vagrant.d/ /media/simon/mydrive/.vagrant.d/
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s1">&#39;export VAGRANT_HOME=&#34;/media/simon/mydrive/.vagrant.d&#34;&#39;</span> &gt;&gt; ~/.bash_profile
</span></span></code></pre></div><p>We&rsquo;ve also added the new location to your <code>.bash_profile</code> so that it will automatically
available when you boot your machine.</p>
<p>With that out of the way the bulk of the copying is still to come! Open the
VirtualBox application and then in Preferences set the Default Machine Folder to
<code>/media/simon/mydrive/VirtualBox VMs</code>. Now to move your current VMs to the new
location.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">rsync -av ~/VirtualBox VMs/ /media/simon/mydrive/VirtualBox VMs/
</span></span></code></pre></div><p>The next step maybe unnecessary, but you can then re-open VirtualBox and remove
any VMs that are showing as inaccessible. To re-add them it you can simply run</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">find /media/simon/mydrive/VirtualBox VMs/ -iname *.vbox -exec vboxmanage registervm <span class="s1">&#39;{}&#39;</span> <span class="se">\;</span>
</span></span></code></pre></div><p>Finally, you can now move your actual project directories to the external harddrive
too and they&rsquo;ll use the new locations for storage and access. They could also stay
where they are as they are only small so up to you!</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="ansible" label="ansible"/><category scheme="taxonomy:Tags" term="vagrant" label="vagrant"/><category scheme="taxonomy:Tags" term="linux" label="linux"/></entry><entry xml:base="scrape-site-with-wget-and-httrack"><title type="html">Scraping websites with wget and httrack</title><link href="https://www.simonholywell.com/post/2015/09/scrape-site-with-wget-and-httrack/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2015/08/image-resize-crop-bash-imagemagick/?utm_source=atom_feed" rel="related" type="text/html" title="Crop and resize images with bash and ImageMagick"/><link href="https://www.simonholywell.com/post/2015/07/php-date-setlocale-localisation/?utm_source=atom_feed" rel="related" type="text/html" title="PHP date localisation with setlocale"/><link href="https://www.simonholywell.com/post/2013/03/install-netbeans-scala-ubuntu/?utm_source=atom_feed" rel="related" type="text/html" title="Install Netbeans and Scala on Ubuntu"/><link href="https://www.simonholywell.com/post/2012/06/fish-console/?utm_source=atom_feed" rel="related" type="text/html" title="Fish Console Reborn"/><link href="https://www.simonholywell.com/post/2011/06/linux-on-dell-inspiron-2500/?utm_source=atom_feed" rel="related" type="text/html" title="Running a sane version of Linux on a Dell Inspiron 2500"/><id>https://www.simonholywell.com/post/2015/09/scrape-site-with-wget-and-httrack/</id><author><name>Simon Holywell</name></author><published>2015-09-05T12:41:26+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Scrapes can be useful to take static backups of websites or to catalogue a site before a rebuild. If you do online courses then it can also be useful to have as much of the course material as possible locally. Another use is to download HTML only ebooks for offline reading.
There are two ways that I generally do this - one on the command line with wget and another through the GUI with httrack.</summary><content type="html"><![CDATA[<p>Scrapes can be useful to take static backups of websites or to catalogue a site
before a rebuild. If you do online courses then it can also be useful to have as
much of the course material as possible locally. Another use is to download HTML
only ebooks for offline reading.</p>
<p>There are two ways that I generally do this - one on the command line with <code>wget</code>
and another through the GUI with <a href="https://www.httrack.com/" title="HTTrack Website Copier"><code>httrack</code></a>. By far the easiest if you
want an entire site is the <code>wget</code> method so I&rsquo;ll introduce that first.</p>
<p>I like to use the following command so that a browseable local copy is created.
Two of the options that are useful to ensure this are <code>--convert-links</code> and
<code>--restrict-file-names=windows</code>. The former converts any links into local relative
URLs so that the site can be browsed locally and I am using <code>--restrict-file-names</code>
for the purpose of ensuring safe file names. This is particularly relevant when the
URLs you&rsquo;re trying to scrape <a href="http://superuser.com/questions/242597/escaping-query-strings-with-wget-mirror" title="Escaping query strings with wget --mirror">contain parameters</a>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">wget -H -r --level<span class="o">=</span><span class="m">5</span> --restrict-file-names<span class="o">=</span>windows --convert-links -e <span class="nv">robots</span><span class="o">=</span>off http://example.org
</span></span></code></pre></div><p>The rest of the options can easily be looked up on the <code>wget</code> manual page so I&rsquo;ll
leave that as an exercise for the reader to save some time.</p>
<p>For more complicated scrapes and those that require authentication in particular
<a href="https://www.httrack.com/" title="HTTrack Website Copier"><code>httrack</code></a> is very handy. You do need a GUI though and it uses Chrome
underneath to request the pages from what I can tell - at least for the WebHTTrack
software for linux. There is a Windows version (I have never used it) which seems
to have a typical Windows application interface from the screenshots on their site
so I can&rsquo;t be sure what this doing underneath.</p>
<p>The <a href="https://www.httrack.com/html/index.html" title="HTTrack Website Copier Manual">options for httrack</a> are reasonably well documented on their site, but when you
start it up it will walk you through a relatively straight forward wizard process
anyway. Once it has started you&rsquo;re able to pause and restart downloads, which is
a nice feature and it automatically fixes the URLs so the site is browseable
locally.</p>
<p>As I read on the train and complete course work I find both methods very handy -
can also be used to download the videos too!</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="wget" label="wget"/><category scheme="taxonomy:Tags" term="bash" label="bash"/><category scheme="taxonomy:Tags" term="scrape" label="scrape"/><category scheme="taxonomy:Tags" term="linux" label="linux"/><category scheme="taxonomy:Tags" term="httrack" label="httrack"/></entry><entry xml:base="image-resize-crop-bash-imagemagick"><title type="html">Crop and resize images with bash and ImageMagick</title><link href="https://www.simonholywell.com/post/2015/08/image-resize-crop-bash-imagemagick/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2015/07/php-date-setlocale-localisation/?utm_source=atom_feed" rel="related" type="text/html" title="PHP date localisation with setlocale"/><link href="https://www.simonholywell.com/post/2013/03/install-netbeans-scala-ubuntu/?utm_source=atom_feed" rel="related" type="text/html" title="Install Netbeans and Scala on Ubuntu"/><link href="https://www.simonholywell.com/post/2012/06/fish-console/?utm_source=atom_feed" rel="related" type="text/html" title="Fish Console Reborn"/><link href="https://www.simonholywell.com/post/2011/06/linux-on-dell-inspiron-2500/?utm_source=atom_feed" rel="related" type="text/html" title="Running a sane version of Linux on a Dell Inspiron 2500"/><link href="https://www.simonholywell.com/post/2011/04/ssh-agent-not-storing-unencrypted-key/?utm_source=atom_feed" rel="related" type="text/html" title="Why won't ssh-agent save my unencrypted key for later use?"/><id>https://www.simonholywell.com/post/2015/08/image-resize-crop-bash-imagemagick/</id><author><name>Simon Holywell</name></author><published>2015-08-24T11:12:26+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Not wanting to repeat myself I have written a small bash script to handle the parallel processing of the post images for this site. This involves resizing, cropping and then compressing the images ready for the web. Currently the script supports both JPEG and PNG images for all these operations.
On top of this I wanted to ensure that only recently added or modified images would be processed rather than processing the entire folder again.</summary><content type="html"><![CDATA[<p>Not wanting to repeat myself I have written a small bash script to handle the
parallel processing of the post images for this site. This involves resizing,
cropping and then compressing the images ready for the web. Currently the script
supports both JPEG and PNG images for all these operations.</p>
<p>On top of this I wanted to ensure that only recently added or modified images would
be processed rather than processing the entire folder again. There is a handy
option for <code>touch</code> that we&rsquo;ll see later that makes this process much easier.</p>
<p>So let&rsquo;s work through the bash script to slowly build it up into a working
example. The first item on the agenda is to declare the hashbang for the script.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="cp">#! /usr/bin/env bash
</span></span></span></code></pre></div><p>Here we are using <code>env</code> to locate the bash executable - this should help to make the
script more portable between systems rather than hard referencing <code>/usr/bin/bash</code>
directly. Some systems might have bash in <code>/bin/bash</code> for example and using <code>env</code>
will prevent this from breaking our script.</p>
<p>Now the script can begin in earnest by declaring a few variables to store the
width and heights we want the final images to be. A temporary file path is also
required to store the last run timestamp to prevent re-processing the same image
twice.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nv">TH_WIDTH</span><span class="o">=</span><span class="m">720</span>
</span></span><span class="line"><span class="cl"><span class="nv">TH_HEIGHT</span><span class="o">=</span><span class="m">70</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">LG_WIDTH</span><span class="o">=</span><span class="m">720</span>
</span></span><span class="line"><span class="cl"><span class="nv">LG_HEIGHT</span><span class="o">=</span><span class="m">480</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">TOUCH_FILE</span><span class="o">=</span><span class="s2">&#34;last.run.time&#34;</span>
</span></span></code></pre></div><p>Across the article I will refer to thumbnail, TH and list image interchangeably -
same goes for large, LG and post image.</p>
<p>If the touch file doesn&rsquo;t exist then we need to create it and specify the timestamp
to use as it&rsquo;s default. As I am tracking the entire project in git the last git
commit date will do for the default date. This will prevent any already committed
in images from being run again.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="k">if</span> <span class="o">[</span> ! -f <span class="s2">&#34;</span><span class="nv">$TOUCHFILE</span><span class="s2">&#34;</span> <span class="o">]</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># http://stackoverflow.com/a/19812608/461813</span>
</span></span><span class="line"><span class="cl">    <span class="nv">LAST_COMMIT_TIMESTAMP</span><span class="o">=</span><span class="k">$(</span>git show -s --format<span class="o">=</span>%ct<span class="k">)</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># http://unix.stackexchange.com/a/36765/10219</span>
</span></span><span class="line"><span class="cl">    touch -d <span class="s2">&#34;@</span><span class="nv">$LAST_COMMIT_TIMESTAMP</span><span class="s2">&#34;</span> <span class="s2">&#34;</span><span class="nv">$TOUCHFILE</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl"><span class="k">fi</span>
</span></span></code></pre></div><p>There is one slight caveat here - if you clone the git repository then all the
files will have a modification time of the clone date and not their original
resize date. Therefore the resizing will be run against all images on initial
clone. This is not an issue for me as I will rarely clone the repo - if it is for
you then you could get the latest modification time across all the files and use
that instead.</p>
<p>All of the images we wish to resize are stored in a directory called <code>src</code> so we
need to find all the files in there that have a more recent modification time
than the touch file. <code>find</code> has a handy switch <code>-newer</code> that will allow us to
easily locate them.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nv">FILES</span><span class="o">=</span><span class="k">$(</span>find src -newer <span class="s2">&#34;</span><span class="nv">$TOUCHFILE</span><span class="s2">&#34;</span> -iname <span class="s1">&#39;*.jpg&#39;</span> -or -newer <span class="s2">&#34;</span><span class="nv">$TOUCHFILE</span><span class="s2">&#34;</span> -iname <span class="s1">&#39;*.png&#39;</span><span class="k">)</span>
</span></span></code></pre></div><p>This will find all files that are newer than the touch file and that have either
<code>.jpg</code> or <code>.png</code> extensions. If there are any then we want to resize and crop
them to the correct dimensions using ImageMagick&rsquo;s <code>convert</code> utility. To complicate
this we&rsquo;re also going to using GNU parallel to process the images across processors.</p>
<p>If you haven&rsquo;t used parallel before it is probably worth checking out <a href="/post/2015/06/parallel-benchmark-many-urls-with-apachebench" title="Simultaneously benchmark many URLs with ApacheBench and GNU parallel">my other post</a>
to get an idea of the syntax and opportunities it provides.</p>
<p>To test that there are some files to process we can simply test it with the <code>-n</code>
switch.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="k">if</span> <span class="o">[</span> -n <span class="s2">&#34;</span><span class="nv">$FILES</span><span class="s2">&#34;</span> <span class="o">]</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># process the large images</span>
</span></span><span class="line"><span class="cl">    parallel -j8 convert <span class="s2">&#34;{}&#34;</span> -strip -resize <span class="s2">&#34;</span><span class="si">${</span><span class="nv">LG_WIDTH</span><span class="si">}</span><span class="s2">x</span><span class="si">${</span><span class="nv">LG_HEIGHT</span><span class="si">}</span><span class="s2">^&#34;</span> -gravity center -crop <span class="s2">&#34;</span><span class="si">${</span><span class="nv">LG_WIDTH</span><span class="si">}</span><span class="s2">x</span><span class="si">${</span><span class="nv">LG_HEIGHT</span><span class="si">}</span><span class="s2">+0+0&#34;</span> -filter catrom <span class="s2">&#34;t_post/{/}&#34;</span> ::: <span class="nv">$FILES</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># process the image slices</span>
</span></span><span class="line"><span class="cl">    parallel -j8 convert <span class="s2">&#34;t_post/{/}&#34;</span> -gravity center -crop <span class="s2">&#34;</span><span class="si">${</span><span class="nv">TH_WIDTH</span><span class="si">}</span><span class="s2">x</span><span class="si">${</span><span class="nv">TH_HEIGHT</span><span class="si">}</span><span class="s2">+0+0&#34;</span> -filter catrom -extent <span class="s2">&#34;</span><span class="si">${</span><span class="nv">TH_WIDTH</span><span class="si">}</span><span class="s2">x</span><span class="si">${</span><span class="nv">TH_HEIGHT</span><span class="si">}</span><span class="s2">&#34;</span> +repage <span class="s2">&#34;t_list/{/}&#34;</span> ::: <span class="nv">$FILES</span>
</span></span><span class="line"><span class="cl"><span class="k">fi</span>
</span></span></code></pre></div><p>The cropping and resizing particulars can be researched in the ImageMagick manual
so I won&rsquo;t spend too much time covering it here. Note that the parallel utility
uses the same syntax (pretty much) as <code>xargs</code> where the file names are passed into
<code>convert</code> - as detailed in <a href="/post/2015/06/parallel-benchmark-many-urls-with-apachebench" title="Simultaneously benchmark many URLs with ApacheBench and GNU parallel">my previous post</a>. Also note how <code>$FILES</code>
is passed into the <code>parallel</code> command as an argument after the special <code>:::</code> blockade.</p>
<p>So in the first call to <code>parallel</code> you can see <code>{}</code> being used - that is the file
name/path as it is passed back from <code>find</code> without modification. You&rsquo;ll see it used
else where with <code>{/}</code>, which will be the same as <code>{}</code> except that it strips the
preceeding path from the argument before printing it (eg. <code>/var/www/index.html</code>
becomes <code>index.html</code>). You can also strip the extension from the argument with
<code>{.}</code> giving <code>/var/www/index</code> when fed <code>/var/www/index.html</code>. Finally you can
also combine the two; <code>{./}</code> produces <code>index</code> when given the same.</p>
<p>As the thumbnail quality is less important than the actual large image I have cheated
a little performed the second crop and resize on the large image rather re-cutting
from the <code>src</code>. This has two purposes; it is quicker to process a smaller image and
it means the image is already at the correct width.</p>
<p>So now we have resized and cropped both our large and thumbnail image - it is time
to compress them. Before we get into that however now is a good time to go over
the required dependencies and how to install them. I have wrapped them all up into
installation bash script you can use at the end of this of article too.</p>
<p>Handily some of the requirements can be obtained from Ubuntu/Debians&rsquo;s repositories.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo apt-get install imagemagick optipng advancecomp parallel
</span></span></code></pre></div><p>This gives you the ImageMagick package to do the resizing and cropping, two PNG
optimisation tools and GNU parallel to handle the multi-processor usage.</p>
<p>Compressing JPEGs nicely takes a little more work as we must manually compile the
dependencies here - not at all hard I promise! To facilitate compilation we need
to install some build tools from the repositories.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo apt-get install build-essential autoconf pkg-config nasm libtool git
</span></span></code></pre></div><p>With these in place we can turn our attention to <a href="https://github.com/mozilla/mozjpeg"><code>mozjpeg</code></a>
which sits under our final library <a href="https://github.com/danielgtaylor/jpeg-archive"><code>jpeg-archive</code></a>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">git clone https://github.com/mozilla/mozjpeg.git
</span></span><span class="line"><span class="cl"><span class="nb">cd</span> mozjpeg
</span></span><span class="line"><span class="cl">autoreconf -fiv
</span></span><span class="line"><span class="cl">./configure --with-jpeg8
</span></span><span class="line"><span class="cl">make
</span></span><span class="line"><span class="cl">sudo make install
</span></span><span class="line"><span class="cl"><span class="nb">cd</span> -
</span></span></code></pre></div><p>Now that has been built and installed it is possible to <code>jpeg-archive</code> up and running
with another simple build script.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">git clone https://github.com/danielgtaylor/jpeg-archive.git
</span></span><span class="line"><span class="cl"><span class="nb">cd</span> jpeg-archive
</span></span><span class="line"><span class="cl">git checkout 2.1.1
</span></span><span class="line"><span class="cl">make
</span></span><span class="line"><span class="cl">sudo make install
</span></span><span class="line"><span class="cl"><span class="nb">cd</span> -
</span></span></code></pre></div><p>After the dependencies are available we can get on with process of compressing
the resized and cropped image files. It is essential that different file types are
handled differently here. You cannot compress a PNG with the same tools as a JPEG
and vice versa. Additionally I want to compress the thumbnail/list images more than
the large/post images.</p>
<p>Let&rsquo;s begin with handling the JPEG results first.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nv">JPOST_FILES</span><span class="o">=</span><span class="k">$(</span>find t_post -newer <span class="s2">&#34;</span><span class="nv">$TOUCHFILE</span><span class="s2">&#34;</span> -iname <span class="s1">&#39;*.jpg&#39;</span><span class="k">)</span>
</span></span><span class="line"><span class="cl"><span class="nv">JLIST_FILES</span><span class="o">=</span><span class="k">$(</span>find t_list -newer <span class="s2">&#34;</span><span class="nv">$TOUCHFILE</span><span class="s2">&#34;</span> -iname <span class="s1">&#39;*.jpg&#39;</span><span class="k">)</span>
</span></span></code></pre></div><p>The next step is to loop over these results in parallel and apply the compression
tools we installed earlier.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="k">if</span> <span class="o">[</span> -n <span class="s2">&#34;</span><span class="nv">$JPOST_FILES</span><span class="s2">&#34;</span> <span class="o">]</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">    parallel -j8 jpeg-recompress --method smallfry --quality medium --min <span class="m">60</span> <span class="s2">&#34;{}&#34;</span> <span class="s2">&#34;{}&#34;</span> ::: <span class="nv">$JPOST_FILES</span>
</span></span><span class="line"><span class="cl"><span class="k">fi</span>
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="o">[</span> -n <span class="s2">&#34;</span><span class="nv">$JLIST_FILES</span><span class="s2">&#34;</span> <span class="o">]</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">    parallel -j8 jpeg-recompress --method smallfry --quality low --min <span class="m">50</span> <span class="s2">&#34;{}&#34;</span> <span class="s2">&#34;{}&#34;</span> ::: <span class="nv">$JLIST_FILES</span>
</span></span><span class="line"><span class="cl"><span class="k">fi</span>
</span></span></code></pre></div><p>From the <code>jpeg-archive</code> suite the above code is <code>jpeg-recompress</code> to perform the
compression using the so called smallfry algorithm/technique. As you can see the
thumnail/list and large/post images are handled separately and the options passed
to the list <code>jpeg-recompress</code> are far more severe.</p>
<p>PNGs are simpler, because they&rsquo;ve not got the same level of compression options.
We&rsquo;re going to use a PNG optimiser followed by a compressor/reducer (GZIP underneath
essentially).</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nv">PNG_FILES</span><span class="o">=</span><span class="k">$(</span>find t_post t_list -newer <span class="s2">&#34;</span><span class="nv">$TOUCHFILE</span><span class="s2">&#34;</span> -iname <span class="s1">&#39;*.png&#39;</span><span class="k">)</span>
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="o">[</span> -n <span class="s2">&#34;</span><span class="nv">$PNG_FILES</span><span class="s2">&#34;</span> <span class="o">]</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">    parallel -j8 optipng -o <span class="m">3</span> -fix <span class="s2">&#34;{}&#34;</span> -out <span class="s2">&#34;{}&#34;</span> ::: <span class="nv">$PNG_FILES</span>
</span></span><span class="line"><span class="cl">    parallel -j8 advdef --shrink-extra -z <span class="s2">&#34;{}&#34;</span> ::: <span class="nv">$PNG_FILES</span>
</span></span><span class="line"><span class="cl"><span class="k">fi</span>
</span></span></code></pre></div><p>Together these two utilities will shave something like 10% or so off of a PNG image
in my limited experience with 10 or so images.</p>
<p>With all the actual operations now complete it just remains to update the <code>last.run.time</code>
file to prevent the same images being run over twice.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">touch <span class="s2">&#34;</span><span class="nv">$TOUCHFILE</span><span class="s2">&#34;</span>
</span></span></code></pre></div><p>Simple! So, yes, it took some work to get here, but you&rsquo;ve now got repeatable and
efficient image manipulation with a small and easily modified bash script.</p>
<p>To make it easier to copy and paste and verify your final result the full installation
and resize scripts are included below.</p>
<h2 id="resizesh">resize.sh</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="cp">#! /usr/bin/env bash
</span></span></span><span class="line"><span class="cl"><span class="cp"></span><span class="nv">LG_WIDTH</span><span class="o">=</span><span class="m">720</span>
</span></span><span class="line"><span class="cl"><span class="nv">LG_HEIGHT</span><span class="o">=</span><span class="m">480</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">TH_WIDTH</span><span class="o">=</span><span class="m">720</span>
</span></span><span class="line"><span class="cl"><span class="nv">TH_HEIGHT</span><span class="o">=</span><span class="m">70</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">TOUCHFILE</span><span class="o">=</span><span class="s2">&#34;last.run.time&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="o">[</span> ! -f <span class="s2">&#34;</span><span class="nv">$TOUCHFILE</span><span class="s2">&#34;</span> <span class="o">]</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># http://stackoverflow.com/a/19812608/461813</span>
</span></span><span class="line"><span class="cl">    <span class="nv">LAST_COMMIT_TIMESTAMP</span><span class="o">=</span><span class="k">$(</span>git show -s --format<span class="o">=</span>%ct<span class="k">)</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># http://unix.stackexchange.com/a/36765/10219</span>
</span></span><span class="line"><span class="cl">    touch -d <span class="s2">&#34;@</span><span class="nv">$LAST_COMMIT_TIMESTAMP</span><span class="s2">&#34;</span> <span class="s2">&#34;</span><span class="nv">$TOUCHFILE</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl"><span class="k">fi</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;Resizing in post images&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nv">FILES</span><span class="o">=</span><span class="k">$(</span>find src -newer <span class="s2">&#34;</span><span class="nv">$TOUCHFILE</span><span class="s2">&#34;</span> -iname <span class="s1">&#39;*.jpg&#39;</span> -or -newer <span class="s2">&#34;</span><span class="nv">$TOUCHFILE</span><span class="s2">&#34;</span> -iname <span class="s1">&#39;*.png&#39;</span><span class="k">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="o">[</span> -n <span class="s2">&#34;</span><span class="nv">$FILES</span><span class="s2">&#34;</span> <span class="o">]</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># process the large images</span>
</span></span><span class="line"><span class="cl">    parallel -j8 convert <span class="s2">&#34;{}&#34;</span> -strip -resize <span class="s2">&#34;</span><span class="si">${</span><span class="nv">LG_WIDTH</span><span class="si">}</span><span class="s2">x</span><span class="si">${</span><span class="nv">LG_HEIGHT</span><span class="si">}</span><span class="s2">^&#34;</span> -gravity center -crop <span class="s2">&#34;</span><span class="si">${</span><span class="nv">LG_WIDTH</span><span class="si">}</span><span class="s2">x</span><span class="si">${</span><span class="nv">LG_HEIGHT</span><span class="si">}</span><span class="s2">+0+0&#34;</span> -filter catrom <span class="s2">&#34;t_post/{/}&#34;</span> ::: <span class="nv">$FILES</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># process the image slices</span>
</span></span><span class="line"><span class="cl">    parallel -j8 convert <span class="s2">&#34;t_post/{/}&#34;</span> -gravity center -crop <span class="s2">&#34;</span><span class="si">${</span><span class="nv">TH_WIDTH</span><span class="si">}</span><span class="s2">x</span><span class="si">${</span><span class="nv">TH_HEIGHT</span><span class="si">}</span><span class="s2">+0+0&#34;</span> -filter catrom -extent <span class="s2">&#34;</span><span class="si">${</span><span class="nv">TH_WIDTH</span><span class="si">}</span><span class="s2">x</span><span class="si">${</span><span class="nv">TH_HEIGHT</span><span class="si">}</span><span class="s2">&#34;</span> +repage <span class="s2">&#34;t_list/{/}&#34;</span> ::: <span class="nv">$FILES</span>
</span></span><span class="line"><span class="cl"><span class="k">fi</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># compress jpg images</span>
</span></span><span class="line"><span class="cl"><span class="nv">JPOST_FILES</span><span class="o">=</span><span class="k">$(</span>find t_post -newer <span class="s2">&#34;</span><span class="nv">$TOUCHFILE</span><span class="s2">&#34;</span> -iname <span class="s1">&#39;*.jpg&#39;</span><span class="k">)</span>
</span></span><span class="line"><span class="cl"><span class="nv">JLIST_FILES</span><span class="o">=</span><span class="k">$(</span>find t_list -newer <span class="s2">&#34;</span><span class="nv">$TOUCHFILE</span><span class="s2">&#34;</span> -iname <span class="s1">&#39;*.jpg&#39;</span><span class="k">)</span>
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="o">[</span> -n <span class="s2">&#34;</span><span class="nv">$JPOST_FILES</span><span class="s2">&#34;</span> <span class="o">]</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">    parallel -j8 jpeg-recompress --method smallfry --quality medium --min <span class="m">60</span> <span class="s2">&#34;{}&#34;</span> <span class="s2">&#34;{}&#34;</span> ::: <span class="nv">$JPOST_FILES</span>
</span></span><span class="line"><span class="cl"><span class="k">fi</span>
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="o">[</span> -n <span class="s2">&#34;</span><span class="nv">$JLIST_FILES</span><span class="s2">&#34;</span> <span class="o">]</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">    parallel -j8 jpeg-recompress --method smallfry --quality low --min <span class="m">50</span> <span class="s2">&#34;{}&#34;</span> <span class="s2">&#34;{}&#34;</span> ::: <span class="nv">$JLIST_FILES</span>
</span></span><span class="line"><span class="cl"><span class="k">fi</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># compress png images</span>
</span></span><span class="line"><span class="cl"><span class="nv">PNG_FILES</span><span class="o">=</span><span class="k">$(</span>find t_post t_list -newer <span class="s2">&#34;</span><span class="nv">$TOUCHFILE</span><span class="s2">&#34;</span> -iname <span class="s1">&#39;*.png&#39;</span><span class="k">)</span>
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="o">[</span> -n <span class="s2">&#34;</span><span class="nv">$PNG_FILES</span><span class="s2">&#34;</span> <span class="o">]</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">    parallel -j8 optipng -o <span class="m">3</span> -fix <span class="s2">&#34;{}&#34;</span> -out <span class="s2">&#34;{}&#34;</span> ::: <span class="nv">$PNG_FILES</span>
</span></span><span class="line"><span class="cl">    parallel -j8 advdef --shrink-extra -z <span class="s2">&#34;{}&#34;</span> ::: <span class="nv">$PNG_FILES</span>
</span></span><span class="line"><span class="cl"><span class="k">fi</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34; &#34;</span>
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;Completed resize operation&#34;</span>
</span></span><span class="line"><span class="cl">touch <span class="s2">&#34;</span><span class="nv">$TOUCHFILE</span><span class="s2">&#34;</span>
</span></span></code></pre></div><h2 id="installsh">install.sh</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;Installing imagemagick&#34;</span>
</span></span><span class="line"><span class="cl">sudo apt-get install imagemagick
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34; &#34;</span>
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;Installing optipng and advdef&#34;</span>
</span></span><span class="line"><span class="cl">sudo apt-get install optipng advancecomp
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34; &#34;</span>
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;Installing gnu parallel&#34;</span>
</span></span><span class="line"><span class="cl">sudo apt-get install parallel
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34; &#34;</span>
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;Installing mozjpeg&#34;</span>
</span></span><span class="line"><span class="cl">sudo apt-get install build-essential autoconf pkg-config nasm libtool
</span></span><span class="line"><span class="cl">git clone https://github.com/mozilla/mozjpeg.git
</span></span><span class="line"><span class="cl"><span class="nb">cd</span> mozjpeg
</span></span><span class="line"><span class="cl">autoreconf -fiv
</span></span><span class="line"><span class="cl">./configure --with-jpeg8
</span></span><span class="line"><span class="cl">make
</span></span><span class="line"><span class="cl">sudo make install
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">cd</span> -
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34; &#34;</span>
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;Installing jpeg-archive&#34;</span>
</span></span><span class="line"><span class="cl">git clone https://github.com/danielgtaylor/jpeg-archive.git
</span></span><span class="line"><span class="cl"><span class="nb">cd</span> jpeg-archive
</span></span><span class="line"><span class="cl">git checkout 2.1.1
</span></span><span class="line"><span class="cl">make
</span></span><span class="line"><span class="cl">sudo make install
</span></span></code></pre></div>]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="image" label="image"/><category scheme="taxonomy:Tags" term="bash" label="bash"/><category scheme="taxonomy:Tags" term="imagemagick" label="imagemagick"/><category scheme="taxonomy:Tags" term="linux" label="linux"/></entry><entry xml:base="namespace-php-functions"><title type="html">Namespace PHP functions</title><link href="https://www.simonholywell.com/post/2015/08/namespace-php-functions/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2015/06/parallel-benchmark-many-urls-with-apachebench/?utm_source=atom_feed" rel="related" type="text/html" title="Simultaneously benchmark many URLs with ApacheBench and GNU parallel"/><link href="https://www.simonholywell.com/post/2015/07/sql-style-guide/?utm_source=atom_feed" rel="related" type="text/html" title="SQL style guide"/><link href="https://www.simonholywell.com/post/2015/07/international-php-dates-with-intl/?utm_source=atom_feed" rel="related" type="text/html" title="International PHP dates with intl"/><link href="https://www.simonholywell.com/post/2015/07/php-date-setlocale-localisation/?utm_source=atom_feed" rel="related" type="text/html" title="PHP date localisation with setlocale"/><link href="https://www.simonholywell.com/post/2015/05/2015-05-18-memoization-or-function-cache/?utm_source=atom_feed" rel="related" type="text/html" title="Memoization or function cache"/><id>https://www.simonholywell.com/post/2015/08/namespace-php-functions/</id><author><name>Simon Holywell</name></author><published>2015-08-10T12:41:26+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>With the release of PHP 5.3 namespaces became a reality in PHP and they&amp;rsquo;ve made so much possible including better autoloading. The majority of the time you&amp;rsquo;ll be used to seeing them at the top of each class file. They can also be used to namespace functions however.
A standard PHP namespace declaration would look similar to the following at the top of a class file.
namespace Treffynnon\Html; class Tag { // .</summary><content type="html"><![CDATA[<p>With the release of PHP 5.3 namespaces became a reality in PHP and they&rsquo;ve made
so much possible including better autoloading. The majority of the time you&rsquo;ll be
used to seeing them at the top of each class file. They can also be used
to namespace functions however.</p>
<p>A standard PHP namespace declaration would look similar to the following at the
top of a class file.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">namespace</span> <span class="nx">Treffynnon\Html</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Tag</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// ...
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span></code></pre></div><p>In this scheme you should not have multiple namespaces in the same file - generally
frowned upon anyway as class files should really only include the one class
declaration.</p>
<p>Namespaces can actually wrap code - rather than just being declared at the
top of files. There is an <a href="http://php.net/manual/en/language.namespaces.definitionmultiple.php#example-266">unbracketed syntax</a> too, but I don&rsquo;t like it so I am
not going to use it here. I much prefer the clear boundaries of the wrapping
braces and some indentation.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">namespace</span> <span class="nx">Treffynnon\Html</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">function</span> <span class="nf">get</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="s1">&#39;&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>You can also have multiple namespaces in the same file this way although I would
not recommend this in practice much like I don&rsquo;t like multiple classes in the same
PHP file.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">namespace</span> <span class="nx">Treffynnon\Html</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">function</span> <span class="nf">get</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="s1">&#39;&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">namespace</span> <span class="nx">Treffynnon\Utils</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">function</span> <span class="nf">get</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="s1">&#39;&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>If you want to dip back into the global namespace you can do so by specifying a
namespace without an explicit name.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">namespace</span> <span class="nx">Treffynnon\Html</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">function</span> <span class="nf">get</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="s1">&#39;&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">namespace</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">function</span> <span class="nf">get</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="s1">&#39;&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>I have found this especially helpful in Drupal or Wordpress where you have hook
functions that get called from/in the global namespace. These functions can be
treated as entry points with the bulk of the actual code inside a module specific
namespace.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">namespace</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">use</span> <span class="nx">MyProject\MyModule</span> <span class="k">as</span> <span class="nx">M</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">function</span> <span class="nf">my_module_menu</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nx">M\get_menu</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">namespace</span> <span class="nx">MyProject\MyModule</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">function</span> <span class="nf">get_menu</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">            <span class="c1">// some Drupal menu implementation goes here
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="p">];</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>This is a bit of a flimsy example, but you can see how it can be used to isolate
your code from the huge global space of Drupal. It is more helpful with hooks that
change the page or node and in the case of data a view. Wordpress is similar in
this regard so I won&rsquo;t go into more detail.</p>
<p>I have written an addendum to this post that covers <a href="https://www.simonholywell.com/post/2016/10/importing-and-aliasing-php-functions/">importing and aliasing functions</a> with
PHP&rsquo;s namespace keywords (<code>use</code> and <code>as</code>).</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="php" label="php"/><category scheme="taxonomy:Tags" term="namespace" label="namespace"/><category scheme="taxonomy:Tags" term="functions" label="functions"/><category scheme="taxonomy:Tags" term="drupal" label="Drupal"/><category scheme="taxonomy:Tags" term="wordpress" label="Wordpress"/></entry><entry xml:base="sql-style-guide"><title type="html">SQL style guide</title><link href="https://www.simonholywell.com/post/2015/07/sql-style-guide/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2015/07/international-php-dates-with-intl/?utm_source=atom_feed" rel="related" type="text/html" title="International PHP dates with intl"/><link href="https://www.simonholywell.com/post/2015/07/php-date-setlocale-localisation/?utm_source=atom_feed" rel="related" type="text/html" title="PHP date localisation with setlocale"/><link href="https://www.simonholywell.com/post/2015/06/parallel-benchmark-many-urls-with-apachebench/?utm_source=atom_feed" rel="related" type="text/html" title="Simultaneously benchmark many URLs with ApacheBench and GNU parallel"/><link href="https://www.simonholywell.com/post/2015/05/2015-05-18-memoization-or-function-cache/?utm_source=atom_feed" rel="related" type="text/html" title="Memoization or function cache"/><link href="https://www.simonholywell.com/post/2015/04/php-function-objects/?utm_source=atom_feed" rel="related" type="text/html" title="PHP Function Objects"/><id>https://www.simonholywell.com/post/2015/07/sql-style-guide/</id><author><name>Simon Holywell</name></author><published>2015-07-24T12:41:26+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>When you&amp;rsquo;re working in a team you need ways to easily share and denote good style and taste. This is true of your primary programming language with PEP8 for Python and PSRs 1 &amp;amp; 2 for PHP being well known. There is probably even a style guide for HTML and CSS set out at your company. So why should SQL miss out on the party?
I have written a style guide for SQL to promote a consistent code style ensuring legible and maintainable projects - sqlstyle.</summary><content type="html"><![CDATA[<p>When you&rsquo;re working in a team you need ways to easily share and denote good style
and taste. This is true of your primary programming language with
<a href="https://www.python.org/dev/peps/pep-0008/">PEP8</a> for Python and PSRs
<a href="http://www.php-fig.org/psr/psr-1/">1</a> &amp; <a href="http://www.php-fig.org/psr/psr-2/">2</a>
for PHP being well known. There is probably even a style guide for
<a href="http://codeguide.co/">HTML and CSS</a> set out at your company. So why should SQL
miss out on the party?</p>
<p>I have written a style guide for SQL to promote a consistent code style ensuring
legible and maintainable projects - <a href="http://www.sqlstyle.guide">sqlstyle.guide</a>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="n">a</span><span class="p">.</span><span class="n">title</span><span class="p">,</span><span class="w"> </span><span class="n">a</span><span class="p">.</span><span class="n">release_date</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="k">FROM</span><span class="w"> </span><span class="n">albums</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="n">a</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">WHERE</span><span class="w"> </span><span class="n">a</span><span class="p">.</span><span class="n">title</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;Charcoal Lane&#39;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="k">OR</span><span class="w"> </span><span class="n">a</span><span class="p">.</span><span class="n">title</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;The New Danger&#39;</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div><p>There are so many variant SQL styles that projects and people use which can make
code difficult to easily read. Looking over various questions on Stackoverflow
(on of which was mine!) I noticed that there were elements of good style that were
shared by most examples.</p>
<p>I figured it was time that SQL had a concise and easy to read style guide that could
easily be adopted and/or modified for bespoke requirements.</p>
<p>It is trivial to apply this style to your projects now or going forward. In the
case of PHP you could have some code like the following.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="nv">$year</span> <span class="o">=</span> <span class="nx">filter_input</span><span class="p">(</span><span class="nx">INPUT_GET</span><span class="p">,</span> <span class="s1">&#39;year&#39;</span><span class="p">,</span> <span class="nx">FILTER_SANITIZE_NUMBER_INT</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nv">$db</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">PDO</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;mysql:host=localhost;dbname=testdb;charset=utf8&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;username&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;password&#39;</span>
</span></span><span class="line"><span class="cl"><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nv">$statement</span> <span class="o">=</span> <span class="nv">$db</span><span class="o">-&gt;</span><span class="na">prepare</span><span class="p">(</span><span class="s2">&#34;
</span></span></span><span class="line"><span class="cl"><span class="s2">SELECT r.last_name,
</span></span></span><span class="line"><span class="cl"><span class="s2">       (SELECT MAX(YEAR(championship_date))
</span></span></span><span class="line"><span class="cl"><span class="s2">          FROM champions AS c
</span></span></span><span class="line"><span class="cl"><span class="s2">         WHERE c.last_name = r.last_name
</span></span></span><span class="line"><span class="cl"><span class="s2">           AND c.confirmed = &#39;Y&#39;) AS last_championship_year
</span></span></span><span class="line"><span class="cl"><span class="s2">  FROM riders AS r
</span></span></span><span class="line"><span class="cl"><span class="s2"> WHERE r.last_name IN
</span></span></span><span class="line"><span class="cl"><span class="s2">       (SELECT c.last_name
</span></span></span><span class="line"><span class="cl"><span class="s2">          FROM champions AS c
</span></span></span><span class="line"><span class="cl"><span class="s2">         WHERE YEAR(championship_date) &gt; :year
</span></span></span><span class="line"><span class="cl"><span class="s2">           AND c.confirmed = &#39;Y&#39;);
</span></span></span><span class="line"><span class="cl"><span class="s2">&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nv">$statement</span><span class="o">-&gt;</span><span class="na">bindParam</span><span class="p">(</span><span class="s1">&#39;:year&#39;</span><span class="p">,</span> <span class="nv">$year</span><span class="p">,</span> <span class="nx">PDO</span><span class="o">::</span><span class="na">PARAM_INT</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nv">$statement</span><span class="o">-&gt;</span><span class="na">execute</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="nv">$rows</span> <span class="o">=</span> <span class="nv">$statement</span><span class="o">-&gt;</span><span class="na">fetchAll</span><span class="p">(</span><span class="nx">PDO</span><span class="o">::</span><span class="na">FETCH_ASSOC</span><span class="p">);</span>
</span></span></code></pre></div><p>To produce the guide I settled upon using GitHub Pages, Jekyll and Markdown sources.
This means it is very easy to make <a href="https://github.com/treffynnon/sqlstyle.guide/fork">forks</a>,
open <a href="https://github.com/treffynnon/sqlstyle.guide/issues">issues</a> and
<a href="https://github.com/treffynnon/sqlstyle.guide/pulls/">pull requests</a> as GitHub Pages
will handle the hosting and site build process. It is released under the <a href="http://creativecommons.org/licenses/by-sa/4.0/">Creative
Commons Attribution-ShareAlike 4.0 International License</a>.</p>
<p>The style in this guide is explicitly designed to be compatible with Joe Celko&rsquo;s
book <a href="https://www.amazon.com/gp/product/0120887975/ref=as_li_ss_tl?ie=UTF8&amp;linkCode=ll1&amp;tag=treffynnon-20&amp;linkId=9c88eac8cd420e979675c815771313d5" title="Joe Celko's SQL Programming Style (The Morgan Kaufmann Series in Data Management Systems)">SQL Programming Style</a> so that teams who have already read that book
will find the guide easy to adopt.</p>
<p>To read the guide you can simply visit <a href="http://www.sqlstyle.guide">sqlstyle.guide</a>
and to access the sources you can find the <a href="https://github.com/treffynnon/sqlstyle.guide">repository on GitHub</a>.</p>
<p>If you like the guide please consider sharing it with your team and via twitter - thanks!</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="sql" label="sql"/><category scheme="taxonomy:Tags" term="php" label="php"/><category scheme="taxonomy:Tags" term="mysql" label="mysql"/><category scheme="taxonomy:Tags" term="sql-style-guide" label="sql style guide"/><category scheme="taxonomy:Tags" term="style-guide" label="style guide"/></entry><entry xml:base="international-php-dates-with-intl"><title type="html">International PHP dates with intl</title><link href="https://www.simonholywell.com/post/2015/07/international-php-dates-with-intl/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2015/07/php-date-setlocale-localisation/?utm_source=atom_feed" rel="related" type="text/html" title="PHP date localisation with setlocale"/><link href="https://www.simonholywell.com/post/2014/01/add-a-duration-or-interval-to-a-date/?utm_source=atom_feed" rel="related" type="text/html" title="Add a duration or interval to a date"/><link href="https://www.simonholywell.com/post/2013/12/convert-utc-to-local-time/?utm_source=atom_feed" rel="related" type="text/html" title="Convert UTC/GMT or any time zone to local time in PHP"/><link href="https://www.simonholywell.com/post/2015/06/parallel-benchmark-many-urls-with-apachebench/?utm_source=atom_feed" rel="related" type="text/html" title="Simultaneously benchmark many URLs with ApacheBench and GNU parallel"/><link href="https://www.simonholywell.com/post/2015/05/2015-05-18-memoization-or-function-cache/?utm_source=atom_feed" rel="related" type="text/html" title="Memoization or function cache"/><id>https://www.simonholywell.com/post/2015/07/international-php-dates-with-intl/</id><author><name>Simon Holywell</name></author><published>2015-07-21T15:33:51+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>I wrote about localising dates (and other data) in a recent blog post, but unfortunately there were some shortcomings where time zones were concerned. As I alluded to in that post there is a way around this via the Intl extension that exposes a simple API to format DateTime instances.
Thankfully this follow up post will be quite short as the setup is very simple for those of you on Ubuntu/Debian you can use the repositories.</summary><content type="html"><![CDATA[<p>I wrote about localising dates (and other data) in a <a href="/post/2015/07/php-date-setlocale-localisation/" title="PHP date localisation with setlocale by Simon Holywell">recent blog post</a>,
but unfortunately there were some shortcomings where time zones were concerned.
As I alluded to in that post there is a way around this via the <code>Intl</code> extension
that exposes a simple API to format <code>DateTime</code> instances.</p>
<p>Thankfully this follow up post will be quite short as the setup is very simple
for those of you on Ubuntu/Debian you can use the repositories.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo apt-get install php5-intl
</span></span></code></pre></div><p>For other distributions you can use PECL to install <code>Intl</code> after building the
dependencies - <a href="http://site.icu-project.org/" title="ICU - International Components for Unicode">icu</a> (on Redhat this is as simple as
<code>yum install libicu libicu-devel.x86_64</code>).</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">pecl install intl
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;extension=intl.so&#34;</span> &gt;&gt; /etc/php.ini
</span></span></code></pre></div><p>Don&rsquo;t forget to restart your webserver (eg. Apache) to make the new extension
available to PHP.</p>
<p>Now it is installed you can use the extension to format dates in code.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="nv">$DateTime</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">DateTime</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="nv">$IntlDateFormatter</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">IntlDateFormatter</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;es_ES&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">IntlDateFormatter</span><span class="o">::</span><span class="na">FULL</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">IntlDateFormatter</span><span class="o">::</span><span class="na">FULL</span>
</span></span><span class="line"><span class="cl"><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="k">echo</span> <span class="nv">$IntlDateFormatter</span><span class="o">-&gt;</span><span class="na">format</span><span class="p">(</span><span class="nv">$DateTime</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="c1">// martes, 21 de julio de 2015, 14:11:11 (Hora de verano británica)
</span></span></span></code></pre></div><p>In this example I am telling the <code>IntlDateFormatter</code> that I want to use the
Spanish locale (<code>es_ES</code>) to print out the full date and time. By changing the
constants you can alter the format of the date that will be printed.</p>
<p>So if you just want the time you could create a formatter in the following manner.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="nv">$DateTime</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">DateTime</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="nv">$IntlDateFormatter</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">IntlDateFormatter</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;es_ES&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">IntlDateFormatter</span><span class="o">::</span><span class="na">NONE</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">IntlDateFormatter</span><span class="o">::</span><span class="na">FULL</span>
</span></span><span class="line"><span class="cl"><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="k">echo</span> <span class="nv">$IntlDateFormatter</span><span class="o">-&gt;</span><span class="na">format</span><span class="p">(</span><span class="nv">$DateTime</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="c1">// 14:15:04 (Hora de verano británica)
</span></span></span></code></pre></div><p>There are a few constants that can be passed into both the second (date) and
third (time) parameters of the <code>IntlDateFormatter</code> constructor to change output
format.</p>
<ul>
<li><code>IntlDateFormatter::NONE</code> - exclude this element from display</li>
<li><code>IntlDateFormatter::SHORT</code> - shortest format (22/07/2007)</li>
<li><code>IntlDateFormatter::MEDIUM</code> - abbreviated format (Jul 22, 2007)</li>
<li><code>IntlDateFormatter::LONG</code> - unabbreviated format (July 22, 2007)</li>
<li><code>IntlDateFormatter::FULL</code> - full date information</li>
</ul>
<p>Another example using the long format with the Spanish locale:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="nv">$DateTime</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">DateTime</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="nv">$IntlDateFormatter</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">IntlDateFormatter</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;es_ES&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">IntlDateFormatter</span><span class="o">::</span><span class="na">LONG</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">IntlDateFormatter</span><span class="o">::</span><span class="na">LONG</span>
</span></span><span class="line"><span class="cl"><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="k">echo</span> <span class="nv">$IntlDateFormatter</span><span class="o">-&gt;</span><span class="na">format</span><span class="p">(</span><span class="nv">$DateTime</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="c1">// 21 de julio de 2015, 14:25:41 GMT+1
</span></span></span></code></pre></div><p>So now you have seen how to change the format of the date we can look at the
timezone aspect of the equation. Normally it uses the default PHP timezone, but
this can be specified as the fourth parameter of the <code>IntlDateFormatter</code> constructor.
You can pass in an instance of <code>DateTimeZone</code> or <code>IntlTimeZone</code> or a timezone
string such as <code>Europe/London</code> or <code>GMT+10</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="nv">$DateTime</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">DateTime</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="nv">$IntlDateFormatter</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">IntlDateFormatter</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;es_ES&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">IntlDateFormatter</span><span class="o">::</span><span class="na">FULL</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">IntlDateFormatter</span><span class="o">::</span><span class="na">FULL</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;Australia/Yancowinna&#39;</span>
</span></span><span class="line"><span class="cl"><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="k">echo</span> <span class="nv">$IntlDateFormatter</span><span class="o">-&gt;</span><span class="na">format</span><span class="p">(</span><span class="nv">$DateTime</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="c1">// martes, 21 de julio de 2015, 23:03:30 (Hora estándar de Australia central)
</span></span></span></code></pre></div><p>Incidentally, you can also pass other values into the <code>format()</code> method too and not
just an instance of <code>DateTime</code>. You can also pass an <code>IntlCalendar</code> instance, the
number of seconds since the Unix epoch (01/01/1970 00:00:00) or a an array compatible
with <a href="http://php.net/manual/en/function.localtime.php" title="PHP manual: localtime"><code>localtime()</code></a>.</p>
<p>By default <code>Intl</code> uses the <a href="https://en.wikipedia.org/wiki/Gregorian_calendar" title="Gregorian Calendar on Wikipedia">Gregorian calendar</a> but it can also make use
of other calendars by specifying a fifth parameter in the calls to <code>IntlDateFormatter</code>
constructor. So by default the previous example would include a calendar specification
like the following.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="nv">$DateTime</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">DateTime</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="nv">$IntlDateFormatter</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">IntlDateFormatter</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;es_ES&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">IntlDateFormatter</span><span class="o">::</span><span class="na">FULL</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">IntlDateFormatter</span><span class="o">::</span><span class="na">FULL</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;Australia/Yancowinna&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">IntlDateFormatter</span><span class="o">::</span><span class="na">GREGORIAN</span>
</span></span><span class="line"><span class="cl"><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="k">echo</span> <span class="nv">$IntlDateFormatter</span><span class="o">-&gt;</span><span class="na">format</span><span class="p">(</span><span class="nv">$DateTime</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="c1">// martes, 21 de julio de 2015, 23:12:43 (Hora estándar de Australia central)
</span></span></span></code></pre></div><p>Should you wish to use another calendar it can be specified as part of the locale.
In the following example I have decided to use the <a href="https://en.wikipedia.org/wiki/Buddhist_calendar" title="Buddhist calendar on Wikipedia">Buddhist calendar</a>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="nv">$DateTime</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">DateTime</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="nv">$IntlDateFormatter</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">IntlDateFormatter</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;es_ES@calendar=buddhist&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">IntlDateFormatter</span><span class="o">::</span><span class="na">FULL</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">IntlDateFormatter</span><span class="o">::</span><span class="na">FULL</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;Australia/Yancowinna&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">IntlDateFormatter</span><span class="o">::</span><span class="na">TRADITIONAL</span>
</span></span><span class="line"><span class="cl"><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="k">echo</span> <span class="nv">$IntlDateFormatter</span><span class="o">-&gt;</span><span class="na">format</span><span class="p">(</span><span class="nv">$DateTime</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="c1">// martes, 21 de julio de 2558 BE, 23:16:08 (Hora estándar de Australia central)
</span></span></span></code></pre></div><p>Notice that I have changed the code for the locale (first parameter) to
<code>es_ES@calendar=buddhist</code> and the calendar (fifth parameter) to
<code>IntlDateFormatter::TRADITIONAL</code>. You could also use the <a href="https://en.wikipedia.org/wiki/Islamic_calendar" title="Islamic calendar on Wikipedia">Islamic calendar</a>
with:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="nv">$DateTime</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">DateTime</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="nv">$IntlDateFormatter</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">IntlDateFormatter</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;es_ES@calendar=islamic&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">IntlDateFormatter</span><span class="o">::</span><span class="na">FULL</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">IntlDateFormatter</span><span class="o">::</span><span class="na">FULL</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;Australia/Yancowinna&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">IntlDateFormatter</span><span class="o">::</span><span class="na">TRADITIONAL</span>
</span></span><span class="line"><span class="cl"><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="k">echo</span> <span class="nv">$IntlDateFormatter</span><span class="o">-&gt;</span><span class="na">format</span><span class="p">(</span><span class="nv">$DateTime</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="c1">// martes, 5 de Shawwal de 1436 AH, 23:23:10 (Hora estándar de Australia central)
</span></span></span></code></pre></div><p>The calendars <a href="http://userguide.icu-project.org/datetime/calendar" title="ICU User Guide: Calendar Classes">ICU</a> allows you to play with include:</p>
<ul>
<li>Japanese (<code>@calendar=japanese</code>)</li>
<li>Buddhist (<code>@calendar=buddhist</code>)</li>
<li>Chinese (<code>@calendar=chinese</code>)</li>
<li>Persian (<code>@calendar=persian</code>)</li>
<li>Indian (<code>@calendar=indian</code>)</li>
<li>Islamic (<code>@calendar=islamic</code>)</li>
<li>Hebrew (<code>@calendar=hebrew</code>)</li>
<li>Coptic (<code>@calendar=coptic</code>)</li>
<li>Ethiopic (<code>@calendar=ethiopic</code>)</li>
</ul>
<p>So there you have it; localised time zone aware dates with PHP on multiple calendar
types. If the provided formats suit your application then this is a simple way
to ensure your date and time information is readable in various locations and
languages.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="intl" label="intl"/><category scheme="taxonomy:Tags" term="php" label="php"/><category scheme="taxonomy:Tags" term="localisation" label="localisation"/><category scheme="taxonomy:Tags" term="date" label="date"/><category scheme="taxonomy:Tags" term="localization" label="localization"/><category scheme="taxonomy:Tags" term="datetime" label="datetime"/></entry><entry xml:base="php-date-setlocale-localisation"><title type="html">PHP date localisation with setlocale</title><link href="https://www.simonholywell.com/post/2015/07/php-date-setlocale-localisation/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2014/01/add-a-duration-or-interval-to-a-date/?utm_source=atom_feed" rel="related" type="text/html" title="Add a duration or interval to a date"/><link href="https://www.simonholywell.com/post/2013/12/convert-utc-to-local-time/?utm_source=atom_feed" rel="related" type="text/html" title="Convert UTC/GMT or any time zone to local time in PHP"/><link href="https://www.simonholywell.com/post/2010/08/php-ssdeep-fuzzy-hashing-php-extension/?utm_source=atom_feed" rel="related" type="text/html" title="php_ssdeep Fuzzy Hashing PHP Extension"/><link href="https://www.simonholywell.com/post/2010/08/php-wrapper-for-linux-at-command/?utm_source=atom_feed" rel="related" type="text/html" title="A PHP wrapper for the unix at command"/><link href="https://www.simonholywell.com/post/2015/06/parallel-benchmark-many-urls-with-apachebench/?utm_source=atom_feed" rel="related" type="text/html" title="Simultaneously benchmark many URLs with ApacheBench and GNU parallel"/><id>https://www.simonholywell.com/post/2015/07/php-date-setlocale-localisation/</id><author><name>Simon Holywell</name></author><published>2015-07-20T13:43:36+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Localising sites can be a chore, but PHP has the venerable setlocale() to use system locales. These are like templates or profiles that describe how various types of data should be displayed. Should a price have a comma or point to indicate the decimals? When printing a date should PHP output Monday or Montag?
All of these considerations are locale specific and they map to a geographical area. Various cultures have their own standards for displaying this kind of information not to mention different languages to accommodate.</summary><content type="html"><![CDATA[<p>Localising sites can be a chore, but PHP has the venerable <code>setlocale()</code> to use
system locales. These are like templates or profiles that describe how various
types of data should be displayed. Should a price have a comma or point to
indicate the decimals? When printing a date should PHP output Monday or Montag?</p>
<p>All of these considerations are locale specific and they map to a geographical
area. Various cultures have their own standards for displaying this kind of
information not to mention different languages to accommodate. This is why the
locale name first specifies the language (<code>en</code> - English) and then the geographic
location (<code>GB</code> - Great Britain).</p>
<p>The full locale name would look like <code>en_GB</code> to match <a href="http://www.loc.gov/standards/iso639-2/php/code_list.php" title="Codes for the Representation of Names of Languages">ISO639</a> and
<a href="http://www.faqs.org/rfcs/rfc1766" title="RFC1766 Tags for the Identification of Languages">RFC1766</a>.</p>
<p>To find the list of locales that your system has available you can run a simple
Linux command.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">locale -a
</span></span></code></pre></div><p>This will return a simple list of locale files; something like the following:</p>
<pre tabindex="0"><code>C
C.UTF-8
POSIX
en_AG
en_AG.utf8
en_AU.utf8
en_BW.utf8
en_CA.utf8
en_DK.utf8
en_GB.utf8
</code></pre><p>If the locale you need is not there then you will need to install it on your machine.
In my case I wanted to use a Spanish locale (<code>es_ES</code>) and as you can see from the
list above it is not currently available.</p>
<p>First check if your system can install the required locale by browsing through
the supported locales with:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">less /usr/share/i18n/SUPPORTED
</span></span></code></pre></div><p>Having spotted the locale you wish to install you can now compile it from the
sources on your machine.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo locale-gen es_ES es_ES.utf8
</span></span></code></pre></div><p>Alternatively, if you&rsquo;re on Ubuntu, you can install it from the package repository
using <code>apt-get</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo apt-get install language-pack-es
</span></span></code></pre></div><p>Where <code>es</code> at the end is the language you want to install.</p>
<p>You can now run <code>locale -a</code> again and you will see your new locale available in
the returned list. A further test you can do before moving to PHP is to run the
locale from the command line. Firstly though you need to take a note of you current
locale:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;</span><span class="nv">$LC_ALL</span><span class="s2">&#34;</span>
</span></span></code></pre></div><p>Make sure you keep the local that is printed to hand as you&rsquo;re going to want to
switch back to it later.</p>
<p>To change the default locale to <code>es_ES</code> on the command line you would first set
value of the <code>LC_ALL</code> environment variable.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">export</span> <span class="nv">LC_ALL</span><span class="o">=</span>es_ES
</span></span></code></pre></div><p>Now we can do a simple test by printing out the current month and ensuring it is
using our desired locale.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">date +B%
</span></span></code></pre></div><p>The month should have been printed out in the language of the current locale -
in my case this is Spanish so it would be <code>Julio</code>.</p>
<p>Now that is tested we can switch back to your original locale using that same
<code>export</code> method from before.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">export</span> <span class="nv">LC_ALL</span><span class="o">=</span>en_GB
</span></span></code></pre></div><p>In my case I am switching back to <code>en_GB</code>, but you will want to substitute that
for the locale you noted down earlier - you did note it down didn&rsquo;t you?</p>
<p>This is great - we&rsquo;ve now got a working locale that we can use from PHP to
localise our content. (You may need to restart the webserver if you&rsquo;re using one).</p>
<p>My concern here is to change the locale for dates (<code>LC_TIME</code>), but you can find
out the other constants by looking at the <a href="http://php.net/manual/en/function.setlocale.php" title="setlocale() PHP manual page">relevant PHP manual page</a>.
For the remainder of this article I will concentrate on the time.</p>
<p>The first thing we must do is set the locale against the time.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="nx">setlocale</span><span class="p">(</span><span class="nx">LC_TIME</span><span class="p">,</span> <span class="s1">&#39;es_ES&#39;</span><span class="p">);</span>
</span></span></code></pre></div><p>Now to actually print a date you will need to make use of the <code>strftime()</code> function
which basically wraps the <code>date</code> command we were using from the command line earlier.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">echo</span> <span class="nx">strftime</span><span class="p">(</span><span class="s1">&#39;%B&#39;</span><span class="p">);</span> <span class="c1">// junio
</span></span></span></code></pre></div><p>You should note that the defacto PHP date handling functionality does not respect
the prevailing locale like <code>strftime()</code> does.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">echo</span> <span class="nx">date</span><span class="p">(</span><span class="s1">&#39;F&#39;</span><span class="p">);</span> <span class="c1">// June
</span></span></span></code></pre></div><p>Also the same is true of PHP&rsquo;s <code>DateTime</code> classes too.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="nv">$date</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">DateTime</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="k">echo</span> <span class="nv">$date</span><span class="o">-&gt;</span><span class="na">format</span><span class="p">(</span><span class="s1">&#39;F&#39;</span><span class="p">);</span> <span class="c1">// June
</span></span></span></code></pre></div><p>One way around this is to pass the date out as a timestamp from <code>DateTime</code> and
then format it using the <code>strftime()</code> function:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="nv">$date</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">DateTime</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="k">echo</span> <span class="nx">strftime</span><span class="p">(</span><span class="s2">&#34;%B&#34;</span><span class="p">,</span> <span class="nv">$date</span><span class="o">-&gt;</span><span class="na">getTimestamp</span><span class="p">());</span> <span class="c1">// junio
</span></span></span></code></pre></div><p>This is fine, but it does mean that you&rsquo;re going to miss out on the time zone power
of the <code>DateTime</code> library and have to revert back to using <code>date_default_timezone_set</code>
to set the current time zone instead. By doing this you will miss out on the time
zone conversion trick I wrote about previously; <a href="/post/2013/12/convert-utc-to-local-time/" title="Convert UTC/GMT or any time zone to local time in PHP">Convert UTC to local time</a>.</p>
<p>Additionally <code>strftime()</code> does not support dates before the UNIX epoch
(January 1, 1970). If these caveats are not a concern the <code>setlocale()</code> can provide
a helpful way of localising the output of your PHP code.</p>
<p>Finally, there is a <a href="http://php.net/setlocale#refsect1-function.setlocale-notes" title="setlocale() multithreaded server warning">big red warning</a> on the PHP manual page for <code>setlocale()</code>
that applies to those running multithreaded servers:</p>
<blockquote>
<p><strong>Warning</strong> The locale information is maintained per process, not per thread.
If you are running PHP on a multithreaded server API like IIS, HHVM or Apache
on Windows, you may experience sudden changes in locale settings while a script
is running, though the script itself never called setlocale(). This happens due
to other scripts running in different threads of the same process at the same
time, changing the process-wide locale using setlocale().</p>
</blockquote>
<p>Another way around this is to use the Intl extension for PHP with its
<code>IntlDateFormatter</code> class, but that is <a href="/post/2015/07/international-php-dates-with-intl/" title="International PHP dates with intl by Simon Holywell">another post</a>!</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="setlocale" label="setlocale"/><category scheme="taxonomy:Tags" term="php" label="php"/><category scheme="taxonomy:Tags" term="localisation" label="localisation"/><category scheme="taxonomy:Tags" term="date" label="date"/><category scheme="taxonomy:Tags" term="localization" label="localization"/><category scheme="taxonomy:Tags" term="linux" label="linux"/></entry><entry xml:base="parallel-benchmark-many-urls-with-apachebench"><title type="html">Simultaneously benchmark many URLs with ApacheBench and GNU parallel</title><link href="https://www.simonholywell.com/post/2015/06/parallel-benchmark-many-urls-with-apachebench/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2014/02/2014-02-28-hhvm-zephir-php-benchmark/?utm_source=atom_feed" rel="related" type="text/html" title="HHVM vs Zephir vs PHP: The showdown"/><link href="https://www.simonholywell.com/post/2015/05/2015-05-18-memoization-or-function-cache/?utm_source=atom_feed" rel="related" type="text/html" title="Memoization or function cache"/><link href="https://www.simonholywell.com/post/2015/04/php-function-objects/?utm_source=atom_feed" rel="related" type="text/html" title="PHP Function Objects"/><link href="https://www.simonholywell.com/post/2014/08/functional-programming-in-php-the-book/?utm_source=atom_feed" rel="related" type="text/html" title="Functional Programming in PHP - The book"/><link href="https://www.simonholywell.com/post/2014/07/2014-07-24-three-devs-and-a-maybe-podcast/?utm_source=atom_feed" rel="related" type="text/html" title="Functional Programming on Three Devs and a Maybe"/><id>https://www.simonholywell.com/post/2015/06/parallel-benchmark-many-urls-with-apachebench/</id><author><name>Simon Holywell</name></author><published>2015-06-25T14:47:55+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Once in a while you come across situations where someone wants to know what a server can do or how many requests it can handle under a realistic load scenario. It could simply be that you want to hit a large selection of sites or even that you want to simultaneously hit a number of different pages on the same site.
In my case I am testing the performance of a Drupal multisite installation where one core set of code is shared by many sites on different URLs.</summary><content type="html"><![CDATA[<p>Once in a while you come across situations where someone wants to know what a
server can do or how many requests it can handle under a realistic load scenario.
It could simply be that you want to hit a large selection of sites or even that
you want to simultaneously hit a number of different pages on the same site.</p>
<p>In my case I am testing the performance of a <a href="https://www.drupal.org/documentation/install/multi-site">Drupal multisite</a>
installation where one core set of code is shared by many sites on different
URLs. I wanted to find out how many simultaneous requests the server would be
able to handle when key URLs in each of the sites were interacted with. In
production the respective load on each site was estimated to be approximately
the same which made it easier as I can just replicate the same scenario on each
site/URL.</p>
<p>This can be difficult to achieve as you need to simulate traffic across a number
of website URLs as many of the benchmarking tools, including ApacheBench, do not
support this. Whilst <a href="http://httpd.apache.org/docs/2.4/programs/ab.html">ApacheBench</a>
can perform concurrent requests to one URL it cannot do the same across a number
of URLs or domains.</p>
<p>A way to work around this limitation is to make use of
<a href="https://twitter.com/oletange">Ole Tange</a>&rsquo;s GNU <a href="http://www.gnu.org/software/parallel/"><code>parallel</code></a>
utility. When piped a list of arguments <code>parallel</code> will execute a command against them
concurrently (generally limited by the number of physical CPUs where on job maps
to one processor). This means you can take any crusty Linux utility that runs serially
and turn it into a concurrently executed task with minimal effort. (If you are using
<code>parallel</code> with <code>gzip</code> though you might prefer <a href="http://zlib.net/pigz/"><code>pigz</code></a> instead.) On top of that
it is also possible to farm out the parallel processing to other machines if you
have them.</p>
<p>If you are paying attention then you will probably have noticed that I just
described a rudimentary botnet. You could take a server of limited resources
offline in a DDOS (Distributed Denial of Service) style attack using the method
I am going to describe here. Please use this knowledge to interact with networks
and hardware you own though and be responsible. Of course this is not the most
efficient or practical means of performing such an attack anyway so you would be
wasting your own time as well as your targets time.</p>
<blockquote>
<p><strong>Note</strong></p>
<p>You could easily bring your own site offline or piss off your hosting provider
so do not actually execute this against a URL without being sure of the
consequences first. Basically, do not run it against your production server!</p>
</blockquote>
<p>So now I have the obligatory warning out of the way we can get on with the good
stuff.</p>
<p>If you are running Ubuntu (like me) or Debian then GNU <code>parallel</code> is really easy
to install (other distros may be easy too - I have not tested).</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo apt-get install parallel
</span></span></code></pre></div><p>In addition, if you have not already installed it, you will have to install
ApacheBench (often known simply as <code>ab</code>).</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo apt-get install apache2-utils
</span></span></code></pre></div><p>Should you have a number of servers you want to network the jobs out to then
also perform the same installation steps above on them too. If you do not install
<code>parallel</code> on the other hosts then the process will only have access to one CPU
core. It is also important to note here that <code>parallel</code> uses SSH communicate with
the other machines so you will want to setup password-less login on those
machines - I previously wrote about this in
<a href="/post/2009/01/securing-ssh-with-key-based-authentication">Securing SSH with Key Based Authentication</a>.</p>
<p>A simple ApacheBench test might be to make 100 requests with up 10 of those
occurring concurrently at any one time. This simple test should be easy for most
webservers to shrug off.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">ab -n <span class="m">100</span> -c <span class="m">10</span> <span class="s2">&#34;http://www.example.org&#34;</span>
</span></span></code></pre></div><p>You will be given a report back from ApacheBench containing all the vital stats
of the benchmark run. As you can see this gives you concurrent tests on one URL
or domain so this is where <code>parallel</code> will step into parallelize the benchmarking
process.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="o">(</span><span class="nb">echo</span> <span class="s2">&#34;http://www.example.org&#34;</span><span class="p">;</span> <span class="nb">echo</span> <span class="s2">&#34;http://www.example.com&#34;</span><span class="o">)</span> <span class="p">|</span> parallel <span class="s1">&#39;ab -n 100 -c 10 {}&#39;</span>
</span></span></code></pre></div><p>This command pipes two URLs into the <code>parallel</code> utility which then fires up a
process running <code>ab -n 100 -c 10</code> against one of the URLs. The results will be
printed to screen in the order that the jobs are completed and not necessarily
in the order the URLs are specified. This is normal and to be expected when working
with parallel implementations, but it might seem strange at first.</p>
<p>You might be wondering what the weird <code>{}</code> near the end of the command means
and why it might be needed. <code>parallel</code> uses the same syntax as <a href="http://unixhelp.ed.ac.uk/CGI/man-cgi?xargs"><code>xargs</code></a>
for handling the argument substitution in the command. In this case when the <code>ab</code>
command is run <code>parallel</code> will substitute the token <code>{}</code> for the URL it has been
passed. There are a number of other options and things you can do such as
substitution without a file extension <code>{.}</code>, which are described on the
<a href="http://www.gnu.org/software/parallel/man.html#pod">manual page</a>.</p>
<p>It is not strictly necessary in the commands we are doing here as &ldquo;&hellip;[where]
the command line contains no replacement strings then {} will be appended to the
command&hellip;&rdquo;, but I like to be explicit should I later want to add any other
arguments or options to the command.</p>
<p>If you want to maintain the order then you can simply pass <code>parallel</code> the <code>-k</code>
switch as an argument.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="o">(</span><span class="nb">echo</span> <span class="s2">&#34;http://www.example.org&#34;</span><span class="p">;</span> <span class="nb">echo</span> <span class="s2">&#34;http://www.example.com&#34;</span><span class="o">)</span> <span class="p">|</span> parallel -k <span class="s1">&#39;ab -n 100 -c 10 {}&#39;</span>
</span></span></code></pre></div><p>As this is not really important though further examples will omit this parameter
for brevity.</p>
<p>Another option you may wish to tweak is the number of jobs you want <code>parallel</code>
to run concurrently using the <code>-j</code> option. Normally this would be mapped to the
number of cores you have available on your machine (<code>-j+0</code>), but you can change
it as you see fit. The following code would be limited to just two concurrent
processes.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="o">(</span><span class="nb">echo</span> <span class="s2">&#34;http://www.example.org&#34;</span><span class="p">;</span> <span class="nb">echo</span> <span class="s2">&#34;http://www.example.com&#34;</span><span class="o">)</span> <span class="p">|</span> parallel -j2 <span class="s1">&#39;ab -n 100 -c 10 {}&#39;</span>
</span></span></code></pre></div><p>What if you have more than two URLs to test though? You could keep chaining calls
to <code>echo</code> for each one, but that would be a pain. The easiest method is to put
all your target URLs into a text file with each URL on a newline like my
<code>URLs.txt</code> file below.</p>
<pre tabindex="0"><code>http://example.org
http://www.example.net
http://tools.example.com
http://secure.example.tk/my-passwords.html
</code></pre><p>This can then easily be passed into <code>parallel</code> through the use of the <code>cat</code> utility.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">cat URLs.txt <span class="p">|</span> parallel <span class="s1">&#39;ab -c 10 -n 100 {}&#39;</span>
</span></span></code></pre></div><p>Results for all four URLs will then be printed to screen. To speed the whole thing
up we can employ other machines to handle some processing as I mentioned previously.
This can be performed with a simple list of IP addresses or hostnames provided to
<code>parallel</code> with the <code>-S</code> option. Do not forget that <code>parallel</code> communicates via
SSH so you will need to setup password-less access to each of these servers
before continuing - I previously wrote about this in
<a href="/post/2009/01/securing-ssh-with-key-based-authentication">Securing SSH with Key Based Authentication</a>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">cat URLs.txt <span class="p">|</span> parallel -S 192.168.0.215,192.168.0.99,: <span class="s1">&#39;ab -c 10 -n 100 {}&#39;</span>
</span></span></code></pre></div><p>The colon (<code>:</code>) at the end of the list specifies that I also want the job to run
on the local machine too.</p>
<p>To make the process more transparent it is also possible to get <code>parallel</code> to
generate an ETA and some server usage statistics with the <code>--eta</code> switch.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">cat URLs.txt <span class="p">|</span> parallel --eta -S 192.168.0.215,192.168.0.99,: <span class="s1">&#39;ab -c 10 -n 100 {}&#39;</span>
</span></span></code></pre></div><p>This will cause <code>parallel</code> to output some additional information breaking down
the percentage of jobs each server processed and the time it took.</p>
<pre tabindex="0"><code>ETA: 33s 8left 4.23avg  192.168.0.215:2/4/31%/14.0s  192.168.0.99:2/4/31%/10.1s  local:4/9/28%/6.2s
</code></pre><p>To increase the load on the server you can either add extra URLs to the text file
or you can adjust the options passed to <code>ab</code>. In the following example <code>-c</code> and
<code>-n</code> are increased tenfold.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">cat URLs.txt <span class="p">|</span> parallel --eta -S 192.168.0.215,192.168.0.99,: <span class="s1">&#39;ab -c 100 -n 1000 {}&#39;</span>
</span></span></code></pre></div><p>Now you have seen how <code>parallel</code> can help you perform many benchmarking requests
against many URLs using ApacheBench I will throw in a little bonus. <code>parallel</code>
can be used to run all the jobs on all the available computers so it could actually
be used to roll out a change to all machines as part of system orchestration. It
is not designed to do this, but it can! Another use might be performing a benchmark
on all machines to determine the best.</p>
<p>To make our earlier example with ApacheBench run all jobs on all available machines
it as simple as:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">cat URLs.txt <span class="p">|</span> parallel --onall --eta -S 192.168.0.215,192.168.0.99,: <span class="s1">&#39;ab -c 100 -n 1000 {}&#39;</span>
</span></span></code></pre></div><p>There is one design decision that Ole made here though; if you use <code>--onall</code> and
also specify <code>-j</code> the value passed to the latter will be used to determine the
number of machines to login into in parallel and not the number of jobs to run in
parallel. This is an important distinction that the manual describes thus:</p>
<blockquote>
<p>Run all the jobs on all computers given with <strong>-S</strong>. GNU parallel will
log into <strong>-j</strong> number of computers in parallel and run one job at a time on
the computer. The order of the jobs will not be changed, but some computers may
finish before others.</p>
</blockquote>
<p>Ole has also <a href="http://stackoverflow.com/a/20858225/461813">written about it</a> on
StackOverflow:</p>
<blockquote>
<p>You are hitting a design decision: What does -j mean when you run &ndash;onall?
The decision is that -j is the number of hosts to run on simultaneously (in
your case 2). This was done so that it would be easy to run commands serially
on a number of hosts in parallel.</p>
</blockquote>
<p>To work round it he suggests wrapping the call to <code>parallel</code> with another call
to <code>parallel</code>, which in our example would look like:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">cat URLs.txt <span class="p">|</span> parallel parallel -j2 --onall --eta -S 192.168.0.215,192.168.0.99,: <span class="s1">&#39;ab -c 100 -n 1000 {}&#39;</span>
</span></span></code></pre></div><p>There is so much more you can do with both ApacheBench and GNU parallel so you
should have a quick look over their respective manuals and resources too.</p>
<ul>
<li><a href="http://httpd.apache.org/docs/2.4/programs/ab.html">ApacheBench manual</a></li>
<li><a href="http://www.gnu.org/software/parallel/man.html">GNU parallel manual</a></li>
<li><a href="https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1">Ole&rsquo;s <code>parallel</code> tutorial videos</a></li>
<li><a href="http://davetang.org/muse/2013/11/18/using-gnu-parallel/">Dave Tang&rsquo;s <code>parallel</code> tutorial</a></li>
<li><a href="https://www.digitalocean.com/community/tutorials/how-to-use-apachebench-to-do-load-testing-on-an-ubuntu-13-10-vps">ApacheBench DigitalOcean article</a></li>
<li><a href="http://www.sitepoint.com/stress-test-php-app-apachebench/">SitePoint ApacheBench article</a></li>
</ul>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="apachebench" label="ApacheBench"/><category scheme="taxonomy:Tags" term="benchmark" label="benchmark"/><category scheme="taxonomy:Tags" term="parallel" label="parallel"/><category scheme="taxonomy:Tags" term="gnu-parallel" label="GNU parallel"/><category scheme="taxonomy:Tags" term="ddos" label="DDOS"/><category scheme="taxonomy:Tags" term="php" label="php"/><category scheme="taxonomy:Tags" term="drupal" label="Drupal"/></entry><entry xml:base=""><title type="html">Memoization or function cache</title><link href="https://www.simonholywell.com/post/2015/05/2015-05-18-memoization-or-function-cache/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2014/08/functional-programming-in-php-the-book/?utm_source=atom_feed" rel="related" type="text/html" title="Functional Programming in PHP - The book"/><link href="https://www.simonholywell.com/post/2015/04/php-function-objects/?utm_source=atom_feed" rel="related" type="text/html" title="PHP Function Objects"/><link href="https://www.simonholywell.com/post/2014/07/2014-07-24-three-devs-and-a-maybe-podcast/?utm_source=atom_feed" rel="related" type="text/html" title="Functional Programming on Three Devs and a Maybe"/><link href="https://www.simonholywell.com/post/2013/01/unicode-shortcut-in-netbeans/?utm_source=atom_feed" rel="related" type="text/html" title="Unicode shortcut in Netbeans for React/Curry"/><link href="https://www.simonholywell.com/post/2014/02/2014-02-28-hhvm-zephir-php-benchmark/?utm_source=atom_feed" rel="related" type="text/html" title="HHVM vs Zephir vs PHP: The showdown"/><id>https://www.simonholywell.com/post/2015/05/2015-05-18-memoization-or-function-cache/</id><author><name>Simon Holywell</name></author><published>2015-05-18T13:24:16+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>A little known feature of PHP&amp;rsquo;s static keyword is that it allows for memoization or function caching. This is a process whereby a functions heavy lifting can be cached so that subsequent calls are faster.
It is possible to store any value in a memoized way such as arrays or even objects. This is done without any external side effects - that is to say that the code calling the function will require no changes to support memoization.</summary><content type="html"><![CDATA[<p>A little known feature of PHP&rsquo;s static keyword is that it allows for memoization
or function caching. This is a process whereby a functions heavy lifting can be
cached so that subsequent calls are faster.</p>
<p>It is possible to store any value in a memoized way such as arrays or even objects.
This is done without any external side effects - that is to say that the code
calling the function will require no changes to support memoization.</p>
<p>This can be illustrated in the following example:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o">&lt;?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl"><span class="k">function</span> <span class="nf">get_static_rand</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">static</span> <span class="nv">$rand</span> <span class="o">=</span> <span class="k">null</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span><span class="p">(</span><span class="nx">is_null</span><span class="p">(</span><span class="nv">$rand</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$rand</span> <span class="o">=</span> <span class="nx">rand</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nv">$rand</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="k">echo</span> <span class="nx">get_static_rand</span><span class="p">();</span> <span class="c1">// 985873932
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">echo</span> <span class="nx">get_static_rand</span><span class="p">();</span> <span class="c1">// 985873932
</span></span></span></code></pre></div><p>As you can each time the function is called it will return the same value, but
just how does this work? Well let&rsquo;s run down from the top.</p>
<p>First up a static variable is declared (<code>$rand</code>) and this is the hidden secret
that performs all the magic. It causes PHP to cache the value of the variable
between calls to the function.</p>
<p>Next we set a value against the variable by calling <code>rand()</code>. Note that this
only occurs if the <code>$rand</code> variable is null. Without this check the value would
be changed on every call to <code>get_static_rand()</code>.</p>
<p>Finally <code>$rand</code> is returned. It is clear from this example that you can implement
this without changing the functions external API and in a way that subsequent calls
reference cached information.</p>
<p>In contrast the same function without memoization would look something like this:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o">&lt;?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl"><span class="k">function</span> <span class="nf">get_rand</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nx">rand</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="k">echo</span> <span class="nx">get_rand</span><span class="p">();</span> <span class="c1">// 1487005861
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">echo</span> <span class="nx">get_rand</span><span class="p">();</span> <span class="c1">// 1262820787
</span></span></span></code></pre></div><p>Here is another simple example that takes a slowish call to read a JSON encoded
data set from a local file and parses it. The file does not change between
function calls so it is an ideal candidate for memoization.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o">&lt;?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl"><span class="k">function</span> <span class="nf">get_json_index</span><span class="p">(</span><span class="nv">$index</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">static</span> <span class="nv">$json</span> <span class="o">=</span> <span class="k">null</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span><span class="p">(</span><span class="nx">is_null</span><span class="p">(</span><span class="nv">$json</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$json</span> <span class="o">=</span> <span class="nx">json_decode</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">            <span class="nx">file_get_contents</span><span class="p">(</span><span class="s1">&#39;stock_codes.json&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span><span class="p">(</span><span class="nx">array_key_exists</span><span class="p">(</span><span class="nv">$index</span><span class="p">,</span> <span class="nv">$json</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$json</span><span class="p">[</span><span class="nv">$index</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>As you can see the subsequent calls to the <code>$json</code> variable will use the
pre-chewed data.</p>
<p>This effectively eliminates multiple calls to <code>file_get_contents()</code> and
<code>json_decode()</code>. Of course in the real production code you would include more
checks before opening the file such as; does it exist? Is it actually JSON?</p>
<p>Through memoization you would remove the overhead of these checks during
subsequent calls to <code>get_json_index()</code> without the surrounding code needing to
worry about the caching strategy used.</p>
<p>Whilst I have shown examples of functions this technique can also be used in
exactly the same way on class methods not demonstrated here.</p>
<p>Although a simple technique it is very often overlooked or unknown. If you only
need to cache a value in a function for the current execution cycle (on a web
server this is one request) then there is no need to get complicated.</p>
<p>Caching mechanisms utilising NoSQL datastores such as memcached or redis or even
the venerable APC can be overkill in many cases. The caveat to bear in mind
however are that the variable is only accessible in and from the current execution
cycle.</p>
<p>On the next cycle the value will be reset and other processes will have no access
to it. So if you have many parallel workers operating on the same cache then this
is not the method for you.</p>
<p>One final example I will include involves caching a function based on its parameters.
A common place that this might be useful is when your caching database queries
that vary dependent upon the functions parameters. In this case we might like to
cache the blog posts by tag as they&rsquo;re used in a listing and in a latest posts
widget on the same page.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o">&lt;?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl"><span class="k">function</span> <span class="nf">get_blog_list</span><span class="p">(</span><span class="nv">$tag</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">static</span> <span class="nv">$_c</span> <span class="o">=</span> <span class="k">array</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="nx">array_key_exists</span><span class="p">(</span><span class="nv">$tag</span><span class="p">,</span> <span class="nv">$_c</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$_c</span><span class="p">[</span><span class="nv">$tag</span><span class="p">]</span> <span class="o">=</span> <span class="nx">get_blogs_by_tag</span><span class="p">(</span><span class="nv">$tag</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nv">$_c</span><span class="p">[</span><span class="nv">$tag</span><span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>You can probably think of a number of other ways that this simple pattern can be
used to speed up operations. Either way it is a handy technique both for functional
and object oriented programmers.</p>
<p>It is also worth a quick note, even though it is obvious, that whilst this technique will give you a faster running site it will consume more memory so don&rsquo;t go memoizing everything!</p>
<blockquote>
<p><strong>note</strong></p>
<p>If you&rsquo;re interested in more functional techniques like this then checkout my book; <a href="http://www.functionalphp.com/?utm_source=SimonHolywell.com&amp;utm_medium=Footer%20Link&amp;utm_term=You%20might%20be%20interested%20in&amp;utm_campaign=functional-book">Functional Programming in PHP</a>. A guide to advanced and powerful functional programming techniques in your favourite language.</p>
</blockquote>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="php" label="php"/><category scheme="taxonomy:Tags" term="memoization" label="memoization"/><category scheme="taxonomy:Tags" term="function-cache" label="function cache"/><category scheme="taxonomy:Tags" term="functional" label="functional"/><category scheme="taxonomy:Tags" term="functional-php" label="functional php"/><category scheme="taxonomy:Tags" term="book" label="book"/></entry><entry xml:base="php-function-objects"><title type="html">PHP Function Objects</title><link href="https://www.simonholywell.com/post/2015/04/php-function-objects/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2014/08/functional-programming-in-php-the-book/?utm_source=atom_feed" rel="related" type="text/html" title="Functional Programming in PHP - The book"/><link href="https://www.simonholywell.com/post/2014/07/2014-07-24-three-devs-and-a-maybe-podcast/?utm_source=atom_feed" rel="related" type="text/html" title="Functional Programming on Three Devs and a Maybe"/><link href="https://www.simonholywell.com/post/2013/01/unicode-shortcut-in-netbeans/?utm_source=atom_feed" rel="related" type="text/html" title="Unicode shortcut in Netbeans for React/Curry"/><link href="https://www.simonholywell.com/post/2014/02/2014-02-28-hhvm-zephir-php-benchmark/?utm_source=atom_feed" rel="related" type="text/html" title="HHVM vs Zephir vs PHP: The showdown"/><link href="https://www.simonholywell.com/post/2014/02/functional-php-talks/?utm_source=atom_feed" rel="related" type="text/html" title="Functional PHP talks"/><id>https://www.simonholywell.com/post/2015/04/php-function-objects/</id><author><name>Simon Holywell</name></author><published>2015-04-16T12:36:38+01:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>It is possible to treat a class instance as a function in PHP. Quite often this is referred to as a functor even though it should really be known as a function object. This is because functions actually serve a different role in languages that support their use.
The convenience of having a reusable function that can be overloaded and carry a context is something to weigh up against using functions or closures.</summary><content type="html"><![CDATA[<p>It is possible to treat a class instance as a function in PHP. Quite often this is referred to as a functor even though it should really be known as a function object. This is because functions actually serve a different role in languages that support their use.</p>
<p>The convenience of having a reusable function that can be overloaded and carry a context is something to weigh up against using functions or closures.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o">&lt;?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">MyFunctionObject</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">   <span class="k">public</span> <span class="k">function</span> <span class="fm">__invoke</span><span class="p">(</span><span class="nv">$name</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">       <span class="k">echo</span> <span class="s2">&#34;My name is </span><span class="si">$name</span><span class="s2">.&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">   <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="nv">$MyFunctionObject</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">MyFunctionObject</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">echo</span> <span class="nv">$MyFunctionObject</span><span class="p">(</span><span class="nx">‘Simon’</span><span class="p">);</span> <span class="c1">// My name is Simon.
</span></span></span></code></pre></div><p>The usual method for creating autoloaded functions is to create them as static methods on a class. This does work, but of course carries with it no context.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o">&lt;?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">MyStatic</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">static</span> <span class="k">function</span> <span class="nf">myName</span><span class="p">(</span><span class="nv">$name</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">echo</span> <span class="s2">&#34;My name is </span><span class="si">$name</span><span class="s2">.&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">echo</span> <span class="nx">MyStatic</span><span class="o">::</span><span class="na">myName</span><span class="p">(</span><span class="s1">&#39;Simon&#39;</span><span class="p">);</span> <span class="c1">// My name is Simon.
</span></span></span></code></pre></div><p>Coming at it from another angle you can also bind closures to class instances. This then allows you access to the classes context from within your closure. Of course you miss out on the autoloading in this case. Also it may make the code harder to read if the binding is not obvious.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o">&lt;?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">MyContextClass</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="nv">$context</span> <span class="o">=</span> <span class="s1">&#39;My name is &#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="nv">$my_function</span> <span class="o">=</span> <span class="k">new</span> <span class="k">function</span><span class="p">(</span><span class="nv">$name</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">echo</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">content</span> <span class="o">.</span> <span class="s2">&#34;</span><span class="si">$name</span><span class="s2">&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="nv">$MyContextClass</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">MyContextClass</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nv">$my_function</span><span class="o">-&gt;</span><span class="na">bindTo</span><span class="p">(</span><span class="nv">$MyContextClass</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">$my_function</span><span class="p">(</span><span class="s1">&#39;Simon&#39;</span><span class="p">);</span> <span class="c1">// My name is Simon
</span></span></span></code></pre></div><p>So as you can see a function object is a happy medium that allows you the best of both. The main thing to note is that you can only have one function per object.</p>
<p>An instance of a function can be passed into anything expecting a <code>callable</code> and it will be executed just like any other function. They also allow you to alias any function object using PHPs namespace syntax:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o">&lt;?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl"><span class="k">use</span> <span class="nx">MyFunctionObject</span> <span class="k">as</span> <span class="nx">F</span><span class="p">;</span>
</span></span></code></pre></div><p>This is a small benefit that you cannot currently get from any other method already discussed. PHP has a pending patch to make this possible with regular functions as well.</p>
<p>There are at least two downfalls of function objects however and the first of which is most annoying. You cannot currently call the function inline without creating the instance.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o">&lt;?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl"><span class="nv">$f</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">F</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">echo</span> <span class="nv">$f</span><span class="p">();</span>
</span></span></code></pre></div><p>There is currently an RFC and patch targeted at PHP 5.6 that will allow for the following syntax:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o">&lt;?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl"><span class="k">echo</span> <span class="k">new</span> <span class="nx">F</span><span class="p">();</span>
</span></span></code></pre></div><p>Additionally function objects can be frowned upon as they are not self documenting. Every <code>__invoke()</code> API can be different making predictable use difficult.</p>
<p>In my research most IDE’s are not able to give parameter hints for the function objects either. Additionally once an object is instantiated it is not clear if it is a function object or not. Without documentation it can be difficult for an implementer to know whether to call it via the function notation or to continue using an OOP So there are a number of reasons that this feature is so underused, but it certainly does have it&rsquo;s uses. Now you know about it and and how it works you may have the killer blow for that problem that has been nagging you.</p>
<blockquote>
<p><strong>note</strong></p>
<p>If you&rsquo;re interested in more functional techniques like this then checkout my book; <a href="http://www.functionalphp.com/?utm_source=SimonHolywell.com&amp;utm_medium=Footer%20Link&amp;utm_term=You%20might%20be%20interested%20in&amp;utm_campaign=functional-book">Functional Programming in PHP</a>. A guide to advanced and powerful functional programming techniques in your favourite language.</p>
</blockquote>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="php" label="php"/><category scheme="taxonomy:Tags" term="functional" label="functional"/><category scheme="taxonomy:Tags" term="functional-php" label="functional php"/><category scheme="taxonomy:Tags" term="function-objects" label="function objects"/></entry><entry xml:base="functional-programming-in-php-the-book"><title type="html">Functional Programming in PHP - The book</title><link href="https://www.simonholywell.com/post/2014/08/functional-programming-in-php-the-book/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2014/07/2014-07-24-three-devs-and-a-maybe-podcast/?utm_source=atom_feed" rel="related" type="text/html" title="Functional Programming on Three Devs and a Maybe"/><link href="https://www.simonholywell.com/post/2013/01/unicode-shortcut-in-netbeans/?utm_source=atom_feed" rel="related" type="text/html" title="Unicode shortcut in Netbeans for React/Curry"/><link href="https://www.simonholywell.com/post/2014/02/2014-02-28-hhvm-zephir-php-benchmark/?utm_source=atom_feed" rel="related" type="text/html" title="HHVM vs Zephir vs PHP: The showdown"/><link href="https://www.simonholywell.com/post/2014/02/functional-php-talks/?utm_source=atom_feed" rel="related" type="text/html" title="Functional PHP talks"/><link href="https://www.simonholywell.com/post/2014/01/speaking-at-brightonphp-and-php-hampshire/?utm_source=atom_feed" rel="related" type="text/html" title="Speaking about Functional PHP at BrightonPHP and PHP Hampshire"/><id>https://www.simonholywell.com/post/2014/08/functional-programming-in-php-the-book/</id><author><name>Simon Holywell</name></author><published>2014-08-29T11:09:23+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>After working hard on the guide to Functional Programming in PHP I am pleased to announce that it has been published by php[architect]! The book is offcially now available and you can purchase your very own copy!
If you’re a programmer who wants less bugs and easier testing then this is the functional introduction for you. Throughout the chapters I gently lead you through the various functional constructs available in and with PHP.</summary><content type="html"><![CDATA[<p>After working hard on the guide to <a href="http://www.functionalphp.com/?utm_source=Blog&amp;utm_medium=Link&amp;utm_campaign=Book%20launch%20article&amp;utm_content=Functional%20Programming%20in%20PHP">Functional Programming in PHP</a> I am pleased to announce that it has been <a href="http://www.phparch.com">published by php[architect]</a>! The book is offcially <a href="http://www.functionalphp.com/#buy?utm_source=Blog&amp;utm_medium=Link&amp;utm_campaign=Book%20launch%20article&amp;utm_content=Now%20available">now available</a> and you can purchase <a href="http://www.functionalphp.com/#buy?utm_source=Blog&amp;utm_medium=Link&amp;utm_campaign=Book%20launch%20article&amp;utm_content=Very%20own%20copy">your very own copy</a>!</p>
<p>If you’re a programmer who wants less bugs and easier testing then this is the functional introduction for you. Throughout the chapters I gently lead you through the various functional constructs available in and with PHP.</p>
<p>You will witness the power of map/reduce and the ease of composition monads can bring to your code.</p>
<p>Even if functional isn’t your bag then (as any functional aware programmer will tell you) there is much you can apply from functional to OOP code. It gives you a new and beneficial perspective on coding be it procedural or object oriented.</p>
<p>Of course functional style code and object oriented code can also co-exist in PHP just as they can in Scala. You can use a functional approach where it makes sense to you and an object oriented one where it is an advantage in PHP.</p>
<p>Functional and event driven programming are here to stay - <a href="http://www.functionalphp.com/#buy?utm_source=Blog&amp;utm_medium=Link&amp;utm_campaign=Book%20launch%20article&amp;utm_content=Buy%20the%20book%20now">buy the book now</a> and get ahead of the curve.</p>
<p>Increasingly computing power is being delivered through the use of multiple cores in CPUs, which require code that can run in parallel to fully exploit their power. Functional programming provides a way to reduce the difficulties that surround concurrent code. As computing requirements increase multi-process programming will be unavoidable - even in PHP.</p>
<p>This book provides a way for developers to gain an understanding of functional programming in their own language. Functional programming is a Turing complete methodology, which means that anything you can achieve procedural or object oriented code you can also complete in a functional style.</p>
<p>By the end you will have seen and implemented a number of core functional concepts and patterns leaving you empowered to include them in your own projects.</p>
<p>For more information please see the <a href="http://www.functionalphp.com/?utm_source=Blog&amp;utm_medium=Link&amp;utm_campaign=Book%20launch%20article&amp;utm_content=Functional%20PHP%20book">Functional PHP book</a> website or buy the book through <a href="http://www.functionalphp.com/#buy?utm_source=Blog&amp;utm_medium=Link&amp;utm_campaign=Book%20launch%20article&amp;utm_content=phparch%20link">php[architect]</a> or <a href="http://www.functionalphp.com/#buy?utm_source=Blog&amp;utm_medium=Link&amp;utm_campaign=Book%20launch%20article&amp;utm_content=Amazon%20link">Amazon</a>.</p>
]]></content><category scheme="taxonomy:Tags" term="php" label="php"/><category scheme="taxonomy:Tags" term="functional" label="functional"/><category scheme="taxonomy:Tags" term="functional-php" label="functional php"/><category scheme="taxonomy:Tags" term="book" label="book"/></entry><entry xml:base=""><title type="html">Functional Programming on Three Devs and a Maybe</title><link href="https://www.simonholywell.com/post/2014/07/2014-07-24-three-devs-and-a-maybe-podcast/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2014/02/2014-02-28-hhvm-zephir-php-benchmark/?utm_source=atom_feed" rel="related" type="text/html" title="HHVM vs Zephir vs PHP: The showdown"/><link href="https://www.simonholywell.com/post/2014/02/functional-php-talks/?utm_source=atom_feed" rel="related" type="text/html" title="Functional PHP talks"/><link href="https://www.simonholywell.com/post/2014/01/speaking-at-brightonphp-and-php-hampshire/?utm_source=atom_feed" rel="related" type="text/html" title="Speaking about Functional PHP at BrightonPHP and PHP Hampshire"/><link href="https://www.simonholywell.com/post/2014/01/add-a-duration-or-interval-to-a-date/?utm_source=atom_feed" rel="related" type="text/html" title="Add a duration or interval to a date"/><link href="https://www.simonholywell.com/post/2013/12/convert-utc-to-local-time/?utm_source=atom_feed" rel="related" type="text/html" title="Convert UTC/GMT or any time zone to local time in PHP"/><id>https://www.simonholywell.com/post/2014/07/2014-07-24-three-devs-and-a-maybe-podcast/</id><author><name>Simon Holywell</name></author><published>2014-07-24T14:11:23+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>I was recently invited to join Edd and Michael to appear on the Three Devs and a Maybe podcast to discuss function programming. The recording of our chat is now available so head on over and have a listen.
If you haven’t listened to the podcast before there are some 34 past episodes archived there as well!
note
If you are interested in finding out more about my book on functional programming in PHP or to subscribe for notification of its release please visit functionalphp.</summary><content type="html"><![CDATA[<p>I was recently invited to join Edd and Michael to appear on the <a href="http://threedevsandamaybe.com/">Three Devs and a Maybe</a> podcast to discuss function programming. The recording of our chat is now available so head on over and <a href="http://threedevsandamaybe.com/posts/functional-programming-with-simon-holywell/">have a listen</a>.</p>
<p>If you haven’t listened to the podcast before there are some 34 past episodes archived there as well!</p>
<blockquote>
<p><strong>note</strong></p>
<p>If you are interested in finding out more about my book on functional programming in PHP or to subscribe for notification of its release please visit <a href="http://www.functionalphp.com/?utm_source=simonholywell.com&amp;utm_medium=Link&amp;utm_campaign=ThreeDevsPodcastArticle">functionalphp.com</a> or follow <a href="http://twitter.com/FunctionalPHP">@FunctionalPHP</a> on Twitter.</p>
</blockquote>
]]></content><category scheme="taxonomy:Tags" term="php" label="php"/><category scheme="taxonomy:Tags" term="functional-php" label="functional php"/><category scheme="taxonomy:Tags" term="podcast" label="podcast"/><category scheme="taxonomy:Tags" term="three-devs-and-a-maybe" label="three devs and a maybe"/></entry><entry xml:base=""><title type="html">HHVM vs Zephir vs PHP: The showdown</title><link href="https://www.simonholywell.com/post/2014/02/2014-02-28-hhvm-zephir-php-benchmark/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2014/02/functional-php-talks/?utm_source=atom_feed" rel="related" type="text/html" title="Functional PHP talks"/><link href="https://www.simonholywell.com/post/2014/01/speaking-at-brightonphp-and-php-hampshire/?utm_source=atom_feed" rel="related" type="text/html" title="Speaking about Functional PHP at BrightonPHP and PHP Hampshire"/><link href="https://www.simonholywell.com/post/2014/01/add-a-duration-or-interval-to-a-date/?utm_source=atom_feed" rel="related" type="text/html" title="Add a duration or interval to a date"/><link href="https://www.simonholywell.com/post/2013/12/convert-utc-to-local-time/?utm_source=atom_feed" rel="related" type="text/html" title="Convert UTC/GMT or any time zone to local time in PHP"/><link href="https://www.simonholywell.com/post/2013/09/idiorm-and-paris-1-4-0-released/?utm_source=atom_feed" rel="related" type="text/html" title="Idiorm and Paris 1.4.0 Released"/><id>https://www.simonholywell.com/post/2014/02/2014-02-28-hhvm-zephir-php-benchmark/</id><author><name>Simon Holywell</name></author><published>2014-02-28T13:42:23+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Since its inception the slow running speed of PHP has been widely publicised and over the years there have been a number of improvements. The first Zend Engine arrived with PHP4 and delivered various performance enhancements (among other features). Each release since this time has delivered some sort of increased efficiency in one way or another.
It has become more interesting recently however with three projects looking for improvements in different ways.</summary><content type="html"><![CDATA[<p>Since its inception the slow running speed of PHP has been widely publicised and over the years there have been a number of improvements. The first Zend Engine arrived with PHP4 and delivered various performance enhancements (among other features). Each release since this time has delivered some sort of increased efficiency in one way or another.</p>
<p>It has become more interesting recently however with three projects looking for improvements in different ways. The core has adopted the Zend <a href="http://php.net/opcache">OPcache</a> for future versions of <a href="http://php.net">PHP</a>, Facebook has been working on a just in time compiler called <a href="http://www.hhvm.com">HipHop VM</a> and the team that brought us Phalcon framework have created <a href="http://zephir-lang.com">Zephir</a>.</p>
<p>All of these projects have chosen to tackle the issue of PHP’s speed via different avenues. It has therefore left one simple question - who’s making the biggest improvements? Who’s the fastest?</p>
<p>With this question in my mind I decided to do something quite ridiculous and write a simple benchmarking setup to test the various ways these projects can be employed. Yes, there is one outright winner in this particular benchmark, but it is important not to get hung up on that.</p>
<p>Like I mentioned all of these techniques are different and therefore they are likely to be a better fit for differing situations. Although winning in terms of outright speed in this particular test it may not work for you from another perspective. Each carries with it certain side effects or caveats that you’ll need to take into consideration.</p>
<p>You should take all factors into consideration and additionally bear in mind that all benchmarks are flawed. The only way to truly test it out is to use real algorithms in a production environment. By using this benchmark code I am focusing on one particular and simplified problem.</p>
<p>Of course, as in this case, it is not always reasonably possible to port a sufficiently complex and realistic problem to all benchmark targets. So it is typical to pick a trivial, but computationally intense problem that can easily be implemented in all of the benchmark subjects.</p>
<p>Now that I have addressed some of the fundamental assumptions of benchmarks; let’s meet the contenders!</p>
<h1 id="the-contenders">The contenders</h1>
<h2 id="hhvm">HHVM</h2>
<p>We’ll begin by introducing Facebook’s PHP runtime, which has been receiving a lot of attention recently. The project is interchangeably known as <a href="http://www.hhvm.com">HHVM</a>, HipHop VM and less frequently HipHop Virtual Machine.</p>
<p>Facebook originally created HipHop VM to replace HPHPc which was their PHP to C++ compiler. They also sought to speed up their application infrastructure through the use of just in time compilation. More recently they have put a lot of effort into improving compatibility with <a href="http://www.hhvm.com/blog/2813/we-are-the-98-5-and-the-16">existing PHP libraries</a> (including <a href="https://github.com/j4mie/idiorm/pull/168">Idiorm and Paris</a>).</p>
<p>This means that it is now possible to run many PHP applications directly on HHVM and take advantage of its JIT (just in time compiler) to increase the speed of code. There are still some rough edges and some aspects that will not work, but there are regular commits on the project from the core team. It would seem that eventually HHVM will become fully compatible parallel runtime for PHP code.</p>
<h2 id="php-55-and-opcache">PHP 5.5 and OPcache</h2>
<p>PHP and Zend have also been busy trying to make <a href="http://php.net">PHP</a> faster and with the advent of <a href="http://php.net/opcache">OPcache</a> they have shaved between 10% to 20% off of PHP processes. It is a modern replacement for the bytecode cache features of the <a href="http://pecl.php.net/package/APC">APC PECL extension</a>. Unlike APC it doesn’t have the userland memory key/value store and it is entirely focused on the caching and optimisation of PHP code.</p>
<p>I am not au fait with the techniques that these caches use, but reading through the available documentation I found the following high level explanation. Zend OPcache offers increased “performance by storing precompiled bytecode in shared memory” to reduce reads from disk. Additionally it will apply a number of “bytecode optimization patterns” to the code decreasing execution times.</p>
<h2 id="zephir">Zephir</h2>
<p>In a separate effort and taking a different direction the team behind the <a href="http://phalconphp.com">Phalcon</a> framework for PHP have been working on <a href="http://zephir-lang.com">Zephir</a>. Phalcon is a web application framework written in C and bound as a PHP extension with the aim of being the fastest framework for PHP. It is worth mentioning here that Phalcon certainly is not the first to take this approach with <a href="http://pecl.php.net/package/yaf">Yaf</a> existing before it’s inception.</p>
<p>With the pursuit of speed however there are usually some trade-offs and in the case of Phalcon it is difficult for PHP developers to understand the source code in the framework. This hampers adoption and also makes it difficult to encourage community contributions to the project. So they’re in the process of re-writing Phalcon on top of their own language called Zephir.</p>
<p>Zephir is a fairly simple language that is sort of a mixture of PHP and some aspects of C. When compiled Zephir converts it’s code into the lower level C underpinnings and the resulting library is installed as a PHP extension. In some ways it is a little bit like a cross between a PECL extension and Facebooks old HPHPc project.</p>
<h1 id="the-work">The work</h1>
<p>This benchmark uses the Mandelbrot Set fractal as it’s algorithm of work for no particular reason other than the fractals look pretty when compiled. It is reasonably intensive computationally and does take a little bit of time for all test subjects to complete.</p>
<p>I did not actually write most of the code that implements the Mandelbrot Set as this was already available from the <a href="http://benchmarksgame.alioth.debian.org/u64/performance.php?test=mandelbrot">The Computer Language Benchmarks Game</a> under <a href="http://benchmarksgame.alioth.debian.org/license.php">it’s BSD licence</a>.</p>
<p>All the C based tests are extended from the <a href="http://benchmarksgame.alioth.debian.org/u64q/program.php?test=mandelbrot&amp;lang=gcc&amp;id=2#sourcecode">C gcc #2</a> base programme and the PHP oriented languages (including Zephir) are based on the <a href="http://benchmarksgame.alioth.debian.org/u64q/program.php?test=mandelbrot&amp;lang=php&amp;id=1#sourcecode">PHP programme</a>.</p>
<p>I did however make a number of changes - for example the code now writes to a stream rather than directly to STDOUT and it can produce ASCII art interpretations or Portable Bitmap binary files. In these benchmarks all the programmes are set to create ASCII and print the result out to STDOUT.</p>
<p>To test out the various ways of creating faster PHP I have implemented the algorithm in the following ways:</p>
<ul>
<li>Plain C</li>
<li>Plain PHP</li>
<li>PHP Extension (just like PECL)</li>
<li>HHVM’s HACK/PHP++/PHQ</li>
<li>HHVM Extension</li>
<li>Zephir CBLOCK (C code dumped inside Zephir)</li>
<li>Zephir Optimiser (C code accessible to Zephir - kinda like an extension)</li>
<li>Plain Zephir Lang</li>
</ul>
<p>If you’re interested in finding out more about the code used to produce these sets of statistics then you can <a href="https://github.com/treffynnon/Benchmark-PHP-HHVM-Zephir">checkout the repository</a> for the code on GitHub.</p>
<h1 id="the-command-line-problem">The command line problem</h1>
<blockquote>
<p><strong>note</strong></p>
<p><a href="https://twitter.com/saramg">Sara Golemon</a> has graciously got in touch to help me cover an important caveat in the benchmarking in this article. If you didn’t already know Sara is on the HHVM team at Facebook and she has written PHP internals, extensions, <a href="http://devzone.zend.com/317/extension-writing-part-ii-parameters-arrays-and-zvals/">articles</a> and the <a href="https://www.amazon.com/Extending-Embedding-PHP-Sara-Golemon/dp/067232704X/ref=as_li_ss_tl?ie=UTF8&amp;linkCode=ll1&amp;tag=treffynnon-20&amp;linkId=095567ac7c818abbfadd2a2b2801f42c">Extending and Embedding PHP</a> book.</p>
<p>She has prepared the following section that describes some of the possible short-comings in my method of benchmarking these PHP run times.</p>
<p>tl;dr: most PHP is run in the server where start up and shutdown times do not directly affect the run times in the way they do in CLI tests like I have used.</p>
</blockquote>
<p>Every test run in this suite was executed on the command-line with a fresh process environment for each. This inherently biases the results in favor of pre-compiled solutions first, and strongly against a multi-threaded JIT based approach. In the real world, using a long-running webserver, these startup costs would disappear in the noise and we could focus solely on the per-request time.</p>
<p>In the case of PHP, the script must be recompiled to bytecode on every invocation since the bytecodes are not saved to disk. Worse, in fact, with an OpCache forcibly enabled (which it’s not normally for CLI), we must then make a second copy of those bytecodes into shared memory (shared only with ourselves) before execution can begin.</p>
<p>Similarly, in the case of HHVM, forcibly turning on the JIT incurs extra startup cost (though with a runtime benefit) since the script must be compiled from PHP to bytecode*, then from bytecode into machine code. For short-running scripts, the extra compilation time is often worse than the JIT savings, so it’s disabled from the command line by default.</p>
<p>A proper comparison of these technologies would require a warmed up multi-request environment, probably with each running as a FastCGI server using a basic fcgi client over unix socket to reduce the overhead of making the request.</p>
<p>Bottom line, these results are like most benchmarks: Only as good as the methodology.</p>
<p>* Normally HHVM caches the bytecode compilation to disk, however this test suite may be negating that due to the cache being inadvertently deleted or overwritten.</p>
<blockquote>
<p><strong>note</strong></p>
<p>If anyone wants to help to improve the tests then please submit any <a href="https://github.com/treffynnon/Benchmark-PHP-HHVM-Zephir">pull requests</a> on the GitHub project. This project was a way for me to play with all the elements and I was under no illusions that there would be potential for improvement.</p>
<p>As I tried to make clear in this article you shouldn’t take these results as imperical or even as givens. Benchmarks test isolated things and will not be directly applicable to your situation. Unless you’re calculating the Mandelbrot set then these results are but a possible indication of a trend.</p>
</blockquote>
<h1 id="the-fight">The fight</h1>
<p>So how does PHP 5.5 with OPcache compare with Facebook’s Hip Hop VM or Phalcon’s Zephir project?</p>
<p>From here on out I will be addressing this question in terms of outright speed only in terms of seconds elapsed. During the benching I did grab other statistics from the processes, but I will leave these for later discussion.</p>
<p>When actually performing the benchmarks I used a very simple system to account for variance between runs of the same code. Instead of just running each set of code once I ran them for 1, 20 and 40 iterations. This then allowed me to take an average of the results and therefore hopefully arriving at a fairer figure.</p>
<p>In addition to the tests that have already been mentioned I also tested each HHVM item with the JIT on and off with the same going for PHP and it’s OPcache.</p>
<p>The machine I am running the benchmarks on is a Intel® Core™ i3 CPU 530 @ 2.93GHz x 4 with 8GB of RAM with a installation of Linux Mint for OS. The versions of the relevant software are PHP 5.5.8, Zephir (fc08fab1e - Feb 3 2014) and HHVM (55212b92 - Jan 21 2014).</p>
<p>To time each run I simply used the Linux utility <code>time</code>, which can also gather other information such as processor load for the task and memory usage.</p>
<h1 id="the-results-are-in">The results are in</h1>
<p>To be completely honest the results are not really shocking or that different to what you would expect I imagine. Going into this testing I already an order in my mind and an idea of the orders of magnitude that might exist between the various techniques. Needless to say I was so close to right as to make this benchmark almost entirely pointless.</p>
<p>With this particular benchmark Zephir is the outright fastest, followed by HHVM and then PHP where they are all set to use optimum speed. If you would like to see all the statistics up close then you can checkout the <a href="/static/files/2014-02-28/index.html">graphs I prepared</a> using D3 or read the <a href="https://github.com/treffynnon/Benchmark-PHP-HHVM-Zephir/releases/tag/1.0.0">raw CSV data dumps</a>.</p>
<p>Based on this I would make the following loose recommendations:</p>
<ul>
<li>You need outright speed = standard PHP C extension</li>
<li>You need non-C programmers to help maintain it = Zephir Lang</li>
<li>You cannot port away from PHP but can install other runtimes = HHVM</li>
<li>Your only deployment path is PHP = setup and enable the OPcache</li>
</ul>
<p>As I mentioned previously; none of this is actually that much of a shock or a departure from the recommendations I already had in my mind. Additionally, you should of course do your own testing/benching using your specific domain model and not just take my word for it!</p>
<h1 id="the-caveats">The caveats</h1>
<p>I should point out here that Zephir lang is not as simple as it may seem and at times the syntax can make problems harder to express. I also found myself regularly having to look at the compiled C source code output to debug the operations within my code. This is something that would be difficult for someone with no prior knowledge of C or the PHP extension architecture.</p>
<p>Zephir is a nice project and it does bring with it a number of performance advantages, but I would agree with the project maintainers that it is not a general purpose language (at least not yet). For the time being it is more focused on the issues it was built to solve in the Phalcon project.</p>
<p>One of the unexpected outcomes was to be from HHVM with it’s JIT free run coming dead last. According to Facebook their HHVM without the compilation should run at the same speed as PHP. In my testing it was much much slower.</p>
<p>It is therefore worth noting here that by default HHVM does not JIT scripts when it is run from the command line. So if you do find yourself regularly running HHVM CLI scripts then don’t forget to set the appropriate flag: <code>-vEval.Jit=1</code>.</p>
<h1 id="running-your-own-benchmarks">Running your own benchmarks</h1>
<p>If you want to gather your own statistics in the same way that I have done above then you can use my code. It is all <a href="https://github.com/treffynnon/Benchmark-PHP-HHVM-Zephir">up on GitHub</a> under a liberal 3-clause BSD licence.</p>
<p>In the repository you’ll find a handy readme that goes some way to explaining how it all works and how to compile and run all the code yourself. In some of the subdirectories there are also readmes that are related solely to that technique.</p>
<p>It would be pretty easy to add your own benchmarking algorithm or test out various other techniques using the loose benching “framework” I have thrown together here.</p>
<p>Should you find any bugs or have any suggestions for improvement then please report them on the <a href="https://github.com/treffynnon/Benchmark-PHP-HHVM-Zephir/issues">repository issue tracker</a>.</p>
]]></content><category scheme="taxonomy:Tags" term="php" label="php"/><category scheme="taxonomy:Tags" term="hhvm" label="hhvm"/><category scheme="taxonomy:Tags" term="zephir" label="zephir"/><category scheme="taxonomy:Tags" term="benchmark" label="benchmark"/><category scheme="taxonomy:Tags" term="showdown" label="showdown"/></entry><entry xml:base="functional-php-talks"><title type="html">Functional PHP talks</title><link href="https://www.simonholywell.com/post/2014/02/functional-php-talks/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2014/01/speaking-at-brightonphp-and-php-hampshire/?utm_source=atom_feed" rel="related" type="text/html" title="Speaking about Functional PHP at BrightonPHP and PHP Hampshire"/><link href="https://www.simonholywell.com/post/2014/01/add-a-duration-or-interval-to-a-date/?utm_source=atom_feed" rel="related" type="text/html" title="Add a duration or interval to a date"/><link href="https://www.simonholywell.com/post/2013/12/convert-utc-to-local-time/?utm_source=atom_feed" rel="related" type="text/html" title="Convert UTC/GMT or any time zone to local time in PHP"/><link href="https://www.simonholywell.com/post/2013/09/idiorm-and-paris-1-4-0-released/?utm_source=atom_feed" rel="related" type="text/html" title="Idiorm and Paris 1.4.0 Released"/><link href="https://www.simonholywell.com/post/2013/05/improve-php-session-cookie-security/?utm_source=atom_feed" rel="related" type="text/html" title="Improve PHP session cookie security"/><id>https://www.simonholywell.com/post/2014/02/functional-php-talks/</id><author><name>Simon Holywell</name></author><published>2014-02-13T09:38:57+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>I was recently invited to speak about functional programming in PHP for both BrightonPHP and PHP Hampshire. The details of which are in a previous blog post.
If you attended either talk and you’ve yet to leave feedback then please do on the respective Joind.in pages:
Brighton PHP joind.in page PHP Hampshire joind.in page You can view the slides from the sessions on my website. I created the slides using reveal.</summary><content type="html"><![CDATA[<p>I was recently invited to speak about <a href="http://www.functionalphp.com/?utm_source=simonholywell.com&amp;utm_medium=Link&amp;utm_campaign=JanFebSumUpArticle">functional programming in PHP</a> for both <a href="http://brightonphp.org">BrightonPHP</a> and <a href="http://phphants.co.uk">PHP Hampshire</a>. The details of which are in a <a href="/post/2014/01/speaking-at-brightonphp-and-php-hampshire.html">previous blog post</a>.</p>
<p>If you attended either talk and you’ve yet to leave feedback then please do on the respective Joind.in pages:</p>
<ul>
<li><a href="https://joind.in/talk/view/10390">Brighton PHP joind.in page</a></li>
<li><a href="https://joind.in/talk/view/10400">PHP Hampshire joind.in page</a></li>
</ul>
<p>You can view the <a href="/static/slides/2014-02-12">slides from the sessions</a> on my website. I created the slides using <a href="http://lab.hakim.se/reveal-js">reveal.js</a> and my <a href="https://github.com/treffynnon/pandoc.reveal.js">pandoc boilerplate</a> project.</p>
<p>The main take-aways from the talk are:</p>
<ul>
<li>Avoid state</li>
<li>Keep things small</li>
<li>Make reusable components</li>
<li>Separate logic from data</li>
</ul>
<p>These principles apply no matter whether you’re writing in a functional style or object oriented approach. Learning functional programming is great idea even if you do not intend to use it day to day. Things you learn in a functional paradigm are directly applicable to your object oriented code too.</p>
<p>You should follow <a href="https://twitter.com/brightonphp">@BrightonPHP</a> and <a href="https://twitter.com/phphants">@PHPHants</a> to keep up to date with these meetups in the future.</p>
<p>I enjoyed presenting at both events and it was great to meet you all!</p>
<blockquote>
<p><strong>note</strong></p>
<p>If you are interested in finding out more about my book on functional programming in PHP or to subscribe for notification of its release please visit <a href="http://www.functionalphp.com/?utm_source=simonholywell.com&amp;utm_medium=Link&amp;utm_campaign=JanFebTalksArticle">functionalphp.com</a> or follow <a href="http://twitter.com/FunctionalPHP">@FunctionalPHP</a> on Twitter.</p>
</blockquote>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="phpug" label="phpug"/><category scheme="taxonomy:Tags" term="php" label="php"/><category scheme="taxonomy:Tags" term="speaking" label="speaking"/><category scheme="taxonomy:Tags" term="meetup" label="meetup"/><category scheme="taxonomy:Tags" term="functional-programming" label="functional programming"/></entry><entry xml:base="speaking-at-brightonphp-and-php-hampshire"><title type="html">Speaking about Functional PHP at BrightonPHP and PHP Hampshire</title><link href="https://www.simonholywell.com/post/2014/01/speaking-at-brightonphp-and-php-hampshire/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2014/01/add-a-duration-or-interval-to-a-date/?utm_source=atom_feed" rel="related" type="text/html" title="Add a duration or interval to a date"/><link href="https://www.simonholywell.com/post/2013/12/convert-utc-to-local-time/?utm_source=atom_feed" rel="related" type="text/html" title="Convert UTC/GMT or any time zone to local time in PHP"/><link href="https://www.simonholywell.com/post/2013/09/idiorm-and-paris-1-4-0-released/?utm_source=atom_feed" rel="related" type="text/html" title="Idiorm and Paris 1.4.0 Released"/><link href="https://www.simonholywell.com/post/2013/05/improve-php-session-cookie-security/?utm_source=atom_feed" rel="related" type="text/html" title="Improve PHP session cookie security"/><link href="https://www.simonholywell.com/post/2013/04/three-things-i-set-on-new-servers/?utm_source=atom_feed" rel="related" type="text/html" title="3 things I set on new servers"/><id>https://www.simonholywell.com/post/2014/01/speaking-at-brightonphp-and-php-hampshire/</id><author><name>Simon Holywell</name></author><published>2014-01-09T14:56:57+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>I have been invited to speak at both the upcoming meetings of BrightonPHP and PHP Hampshire about functional programming. This is off the back of the site I created for my (soon to be released) book tentatively entitled Functional Programming in PHP.
To get a better idea of what the talk will include I have prepared an abstract:
In the PHP world functions are generally sneered at due to their simplicity and perceived as an evil side effect of spaghetti code.</summary><content type="html"><![CDATA[<p>I have been invited to speak at both the upcoming meetings of <a href="http://brightonphp.org">BrightonPHP</a> and <a href="http://phphants.co.uk">PHP Hampshire</a> about functional programming. This is off the back of the site I created for my (soon to be released) book tentatively entitled <a href="http://www.functionalphp.com/?utm_source=simonholywell.com&amp;utm_medium=Link&amp;utm_campaign=JanFebTalksArticle">Functional Programming in PHP</a>.</p>
<p>To get a better idea of what the talk will include I have prepared an abstract:</p>
<blockquote>
<p>In the PHP world functions are generally sneered at due to their simplicity and perceived as an evil side effect of spaghetti code. This is not necessarily the case however as when functions are combined in a logical manner they can be very powerful.</p>
<p>In fact they can be deployed to great effect in all manner of applications to create advanced and potentially less error prone software.</p>
<p>This talk will take the form of a gentle introduction to functional programming concepts in a PHP context. It will cater to a variety of levels of knowledge. Right from those who have never heard of functional programming to coders who have been practicing aspects for years in other languages (JavaScript!) - perhaps without even knowing.</p>
<p>During my talk you’ll hear some history, functional theory (introduced gently I promise) and of course some practical examples. You definitely do not need to be a mathematician or expert/functional coder to enjoy this session.</p>
</blockquote>
<p>Both are not-for-profit PHP user groups setup on the south coast of England that organise free to attend monthly meetups.</p>
<h1 id="brighton---january">Brighton - January</h1>
<p>The <a href="https://joind.in/talk/view/10390">BrightonPHP talk</a> is first up on Monday the 20th of January 2014 at 19:00 and will be held at <a href="http://theskiff.org">The Skiff</a> in the <a href="http://northlaine.co.uk">North Laine</a> area of Brighton (easily accessible by train). To register your attendance for the evening please visit the <a href="http://lanyrd.com/2014/brightonphp-january">associated Lanyrd page</a> and there is also a <a href="https://joind.in/talk/view/10390">joind.in page</a> for the talk.</p>
<p>You should follow <a href="https://twitter.com/brightonphp">@BrightonPHP</a> to keep up to date with this meetup in the future.</p>
<h1 id="portsmouth---february">Portsmouth - February</h1>
<p>On Wednesday the 12th of February I will be <a href="http://www.eventbrite.co.uk/e/php-hampshire-february-meetup-tickets-9904055296">speaking at the PHP Hampshire</a> user group; again starting at 7pm. The group meets at the <a href="http://www.oasisthevenue.com/conference-centre">Oasis Conference Centre</a> on Arundel Street every month. You can claim your free spot by going to the <a href="http://www.eventbrite.co.uk/e/php-hampshire-february-meetup-tickets-9904055296">EventBrite page</a> for the meetup and there is also <a href="https://joind.in/talk/view/10400">another joind.in page</a> for the PHP Hampshire talk.</p>
<p>You should follow <a href="https://twitter.com/phphants">@PHPHants</a> to keep up to date with this meetup in the future.</p>
<p>I look forward to presenting at both events and hopefully I will see you there!</p>
<blockquote>
<p><strong>note</strong></p>
<p>If you are interested in finding out more about my book on functional programming in PHP or to subscribe for notification of its release please visit <a href="http://www.functionalphp.com/?utm_source=simonholywell.com&amp;utm_medium=Link&amp;utm_campaign=JanFebTalksArticle">functionalphp.com</a> or follow <a href="http://twitter.com/FunctionalPHP">@FunctionalPHP</a> on Twitter.</p>
</blockquote>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="phpug" label="phpug"/><category scheme="taxonomy:Tags" term="php" label="php"/><category scheme="taxonomy:Tags" term="speaking" label="speaking"/><category scheme="taxonomy:Tags" term="meetup" label="meetup"/><category scheme="taxonomy:Tags" term="functional-programming" label="functional programming"/></entry><entry xml:base="add-a-duration-or-interval-to-a-date"><title type="html">Add a duration or interval to a date</title><link href="https://www.simonholywell.com/post/2014/01/add-a-duration-or-interval-to-a-date/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2013/12/convert-utc-to-local-time/?utm_source=atom_feed" rel="related" type="text/html" title="Convert UTC/GMT or any time zone to local time in PHP"/><link href="https://www.simonholywell.com/post/2013/09/idiorm-and-paris-1-4-0-released/?utm_source=atom_feed" rel="related" type="text/html" title="Idiorm and Paris 1.4.0 Released"/><link href="https://www.simonholywell.com/post/2013/05/improve-php-session-cookie-security/?utm_source=atom_feed" rel="related" type="text/html" title="Improve PHP session cookie security"/><link href="https://www.simonholywell.com/post/2013/04/three-things-i-set-on-new-servers/?utm_source=atom_feed" rel="related" type="text/html" title="3 things I set on new servers"/><link href="https://www.simonholywell.com/post/2013/02/php-ssdeep-in-git/?utm_source=atom_feed" rel="related" type="text/html" title="ssdeep PHP extension in git"/><id>https://www.simonholywell.com/post/2014/01/add-a-duration-or-interval-to-a-date/</id><author><name>Simon Holywell</name></author><published>2014-01-03T15:51:13+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>In PHP you can easily add a duration to a DateTime instance in a number of ways. I will review the most common methods for completing the task starting with those available on the DateTime object itself.
If you are running PHP 5.2 then the only way to achieve this is to call the modify method. This allows you to pass in a date format, but in this case we are most interested in the relative formats.</summary><content type="html"><![CDATA[<p>In PHP you can easily add a duration to a <code>DateTime</code> instance in a number of ways. I will review the most common methods for completing the task starting with those available on the <code>DateTime</code> object itself.</p>
<p>If you are running PHP 5.2 then the only way to achieve this is to call <a href="http://www.php.net/manual/en/datetime.modify.php">the modify method</a>. This allows you to pass in a <a href="http://www.php.net/manual/en/datetime.formats.php">date format</a>, but in this case we are most interested in the <a href="http://www.php.net/manual/en/datetime.formats.relative.php">relative formats</a>.</p>
<p>So if we want to add one day to a date we would use the format <code>+1 day</code> implemented as so:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o">&lt;?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl"><span class="nv">$date</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">DateTime</span><span class="p">(</span><span class="s1">&#39;2014-01-03&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nv">$date</span><span class="o">-&gt;</span><span class="na">modify</span><span class="p">(</span><span class="s1">&#39;+1 day&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="k">echo</span> <span class="nv">$date</span><span class="o">-&gt;</span><span class="na">format</span><span class="p">(</span><span class="s1">&#39;Y-m-d&#39;</span><span class="p">);</span> <span class="c1">// 2014-01-04
</span></span></span></code></pre></div><p>PHP date and time handling was significantly improved in PHP 5.3+ to include a specific <a href="http://www.php.net/manual/en/datetime.add.php">add</a> (and <a href="http://www.php.net/manual/en/datetime.sub.php">subtract</a>) method to <code>DateTime</code>. Although instead of simply including a text format you must use a <code>DateInterval</code> to represent the duration.</p>
<p>In addition the <a href="http://www.php.net/manual/en/dateinterval.construct.php#refsect1-dateinterval.construct-parameters">format is slightly different</a> to incorporate the <a href="http://en.wikipedia.org/wiki/Iso8601#Durations">ISO 8601 duration specification</a>. All intervals should begin with a <code>P</code> (period) and include a integer representation of the interval followed by a period designator such as <code>D</code> for day.</p>
<p>This would simply be <code>P1D</code> for our 1 day time period. A more complex example would be <code>P4Y1M2D</code>, which is 2 days, 1 month and 4 years.</p>
<p>A handy addition to the format specification is the availability of <code>W</code> for weeks such as <code>P4Y1W</code>, which works out as 1 week and 4 years. You should note that <code>W</code> cannot be combined with days because <code>W</code> units get converted into days.</p>
<p>You can follow this with a <code>T</code> if you wish to include a time period. Just as with the date you include an integer for the interval period followed by a period designator.</p>
<p>Should you want to make our period 1 day and 2 hours then the format would be <code>P1DT2H</code>. To make it more interesting here is a full format <code>P4Y1M2DT1H2M3S</code> that works out as 2 days, 1 month, 4 years and 1 hour, 2 minutes and 2 seconds.</p>
<p>Of course it is also possible to only specify the time portion of the interval. This allows you to add periods of an hour or even seconds to a <code>DateTime</code> instance. Logically this is specified as <code>PT1H2M3S</code> for a interval of 1 hour, 2 minutes and 2 seconds.</p>
<p>One final note on the formatting; you must specify the units in descending order where you are using more than one period designator. Essentially this means that larger units such as years (<code>Y</code>) should come before smaller units like seconds (<code>S</code>).</p>
<p>With this in mind we can see that <code>P4YT2S</code> and <code>P4Y1D</code> are valid formats whereas <code>PT2S4Y</code> and <code>P1D4Y</code> are not.</p>
<p>It is worth pointing out here that you can use the same <a href="http://www.php.net/manual/en/datetime.formats.relative.php">relative formats</a> from the the <code>DateTime::modify()</code> method if you prefer using the <code>DateInterval::createFromDateString()</code> static method (see <a href="http://www.php.net/manual/en/dateinterval.createfromdatestring.php">PHP documentation</a>).</p>
<p>So back to the original example of adding one day to our <code>DateTime</code> instance:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o">&lt;?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl"><span class="nv">$date</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">DateTime</span><span class="p">(</span><span class="s1">&#39;2014-01-03&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nv">$date</span><span class="o">-&gt;</span><span class="na">add</span><span class="p">(</span><span class="k">new</span> <span class="nx">DateInterval</span><span class="p">(</span><span class="s1">&#39;P1D&#39;</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"><span class="k">echo</span> <span class="nv">$date</span><span class="o">-&gt;</span><span class="na">format</span><span class="p">(</span><span class="s1">&#39;Y-m-d&#39;</span><span class="p">);</span> <span class="c1">// 2014-01-04
</span></span></span></code></pre></div><p>You can also subtract intervals from <code>DateTime</code> instances as well:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o">&lt;?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl"><span class="nv">$date</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">DateTime</span><span class="p">(</span><span class="s1">&#39;2014-01-03&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nv">$date</span><span class="o">-&gt;</span><span class="na">sub</span><span class="p">(</span><span class="k">new</span> <span class="nx">DateInterval</span><span class="p">(</span><span class="s1">&#39;P1D&#39;</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"><span class="k">echo</span> <span class="nv">$date</span><span class="o">-&gt;</span><span class="na">format</span><span class="p">(</span><span class="s1">&#39;Y-m-d&#39;</span><span class="p">);</span> <span class="c1">// 2014-01-02
</span></span></span></code></pre></div><p>As you can see PHP provides a rich API for dealing with dates and times and their modification via simple instructions. It is also possible to adjust a <code>DateTime</code> instances time zone as I have previously blogged in <a href="/post/2013/12/convert-utc-to-local-time.html">Convert UTC/GMT or any time zone to local time in PHP</a>.</p>
<p>Based on this I would point out that if you are still using the older procedural API for your PHP date operations then you are missing out on a lot of the power afforded you by the languages standard library.</p>
<p>For a final tidbit I would recommend a little further reading about the <code>DateInterval::format()</code> method, which can also be handy when debugging intervals.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="php" label="php"/><category scheme="taxonomy:Tags" term="time" label="time"/><category scheme="taxonomy:Tags" term="date" label="date"/><category scheme="taxonomy:Tags" term="dateinterval" label="dateinterval"/><category scheme="taxonomy:Tags" term="datetime" label="datetime"/></entry><entry xml:base="reverse-github-pull-request"><title type="html">Reverse a git pull request on GitHub the hard way</title><link href="https://www.simonholywell.com/post/2013/12/reverse-github-pull-request/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2013/02/php-ssdeep-in-git/?utm_source=atom_feed" rel="related" type="text/html" title="ssdeep PHP extension in git"/><link href="https://www.simonholywell.com/post/2013/02/git-tag-secrets/?utm_source=atom_feed" rel="related" type="text/html" title="Git tag secrets"/><link href="https://www.simonholywell.com/post/2009/08/moving-to-git-and-setting-up-indefero-as-a-web-frontend/?utm_source=atom_feed" rel="related" type="text/html" title="Moving to git and setting up InDefero as a web frontend"/><link href="https://www.simonholywell.com/post/2009/03/using-phing-for-good-unfuddle-add-repository-and-svn-imp/?utm_source=atom_feed" rel="related" type="text/html" title="Using phing for good - Unfuddle Add Repository and SVN Import Ta…"/><link href="https://www.simonholywell.com/post/2013/12/convert-utc-to-local-time/?utm_source=atom_feed" rel="related" type="text/html" title="Convert UTC/GMT or any time zone to local time in PHP"/><id>https://www.simonholywell.com/post/2013/12/reverse-github-pull-request/</id><author><name>Simon Holywell</name></author><published>2013-12-12T11:26:17+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>As you may know I am currently the maintainer of both Idiorm and Paris; well recently I merged in what looked to be an innocuous pull request from a contributor. Unfortunately this merge had unintended consequences and basically broke the backwards compatibility of the library. Shame on me!
After waiting for a patch that would fix the problem and coming up short I decided enough was enough. So today I backed out the errant merges in both Idiorm and Paris.</summary><content type="html"><![CDATA[<p>As you may know I am currently the maintainer of both <a href="http://j4mie.github.io/idiormandparis/">Idiorm and Paris</a>; well recently I merged in what looked to be an innocuous pull request from a contributor. Unfortunately this merge had unintended consequences and basically broke the backwards compatibility of the library. Shame on me!</p>
<p>After waiting for a patch that would fix the problem and coming up short I decided enough was enough. So today I backed out the errant merges in both Idiorm and Paris.</p>
<p>Now it is important to note here that both repositories had commits and merges in their history post the introduction of this rogue pull request. In addition these changes had been out in the wild for quite some time.</p>
<p>With this in mind it would not be possible to simply amend the previous commit, rebase the changes or reset to a previous commit. These would either break the history or in the case of amend simply be impossible as HEAD had moved on.</p>
<p>To do this I used a technique that I could find little reference to online - a reverse patch application. This is actually very simple with GitHub as you can use an equally unknown feature to obtain a patch file from a pull request.</p>
<p>You can go to any commit or pull request in the GitHub web interface and append .patch onto the end of the URL. This will then spit out the full raw commit or pull request as a pull request patch file.</p>
<p>For example if you have a pull request at <a href="https://github.com/user/project/pull/123">https://github.com/user/project/pull/123</a> then you should access <a href="https://github.com/user/project/pull/123.patch">https://github.com/user/project/pull/123.patch</a> to gain access to the aforementioned patch file. So either download this via your web browser or use wget on the command line.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">wget https://github.com/user/project/pull/123.patch
</span></span></code></pre></div><p>We can now use git to reverse apply the patch:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">git apply -R 123.patch
</span></span><span class="line"><span class="cl">git status
</span></span></code></pre></div><p>You will now see that the files affected by the patch are in a modified state and you can commit them in just like you would any other commit or patch application.</p>
<p>Once committed you can push the changes to your projects GitHub project without worrying about breaking its commit history or angering other contributors! This technique can of course be used with any git patch file and not just those obtained via GitHub.</p>
<blockquote>
<p><strong>note</strong></p>
<p>This is not <strong>THE</strong> way to do this, but the hard way. This is more of a post to expose these two features as they are not so well known. You would of course usually perform this task using <code>git revert</code> with the merge commit. There are tonnes of posts out there about that though so what would be the fun in that!</p>
</blockquote>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="git" label="git"/><category scheme="taxonomy:Tags" term="github" label="github"/></entry><entry xml:base="convert-utc-to-local-time"><title type="html">Convert UTC/GMT or any time zone to local time in PHP</title><link href="https://www.simonholywell.com/post/2013/12/convert-utc-to-local-time/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2013/09/idiorm-and-paris-1-4-0-released/?utm_source=atom_feed" rel="related" type="text/html" title="Idiorm and Paris 1.4.0 Released"/><link href="https://www.simonholywell.com/post/2013/05/improve-php-session-cookie-security/?utm_source=atom_feed" rel="related" type="text/html" title="Improve PHP session cookie security"/><link href="https://www.simonholywell.com/post/2013/04/three-things-i-set-on-new-servers/?utm_source=atom_feed" rel="related" type="text/html" title="3 things I set on new servers"/><link href="https://www.simonholywell.com/post/2013/02/php-ssdeep-in-git/?utm_source=atom_feed" rel="related" type="text/html" title="ssdeep PHP extension in git"/><link href="https://www.simonholywell.com/post/2013/01/idiorm-and-paris-the-minimalist-orm/?utm_source=atom_feed" rel="related" type="text/html" title="Idiorm and Paris 1.3.0 released - the minimalist ORM and fluent query builder for PHP"/><id>https://www.simonholywell.com/post/2013/12/convert-utc-to-local-time/</id><author><name>Simon Holywell</name></author><published>2013-12-11T14:42:31+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Wrangling dates and times can be a somewhat arduous task for all programmers. One very common requirement is to convert a time from one time zone to another.
In PHP this is greatly simplified with the DateTime standard library classes and especially DateTimeZone.
For this example let us assume we have a UTC date and time string (2011-04-27 02:45) that we would like to convert to ACST (Australian Central Standard Time).</summary><content type="html"><![CDATA[<p>Wrangling dates and times can be a somewhat arduous task for all programmers. One very common requirement is to convert a time from one time zone to another.</p>
<p>In PHP this is greatly simplified with the <a href="http://php.net/manual/en/class.datetime.php">DateTime</a> standard library classes and especially <a href="http://php.net/manual/en/class.datetimezone.php">DateTimeZone</a>.</p>
<p>For this example let us assume we have a UTC date and time string (2011-04-27 02:45) that we would like to convert to ACST (Australian Central Standard Time).</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o">&lt;?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl"><span class="nv">$utc_date</span> <span class="o">=</span> <span class="nx">DateTime</span><span class="o">::</span><span class="na">createFromFormat</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;Y-m-d G:i&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;2011-04-27 02:45&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="k">new</span> <span class="nx">DateTimeZone</span><span class="p">(</span><span class="s1">&#39;UTC&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">$acst_date</span> <span class="o">=</span> <span class="k">clone</span> <span class="nv">$utc_date</span><span class="p">;</span> <span class="c1">// we don&#39;t want PHP&#39;s default pass object by reference here
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nv">$acst_date</span><span class="o">-&gt;</span><span class="na">setTimeZone</span><span class="p">(</span><span class="k">new</span> <span class="nx">DateTimeZone</span><span class="p">(</span><span class="s1">&#39;Australia/Yancowinna&#39;</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">echo</span> <span class="s1">&#39;UTC:  &#39;</span> <span class="o">.</span> <span class="nv">$utc_date</span><span class="o">-&gt;</span><span class="na">format</span><span class="p">(</span><span class="s1">&#39;Y-m-d g:i A&#39;</span><span class="p">);</span>  <span class="c1">// UTC:  2011-04-27 2:45 AM
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">echo</span> <span class="s1">&#39;ACST: &#39;</span> <span class="o">.</span> <span class="nv">$acst_date</span><span class="o">-&gt;</span><span class="na">format</span><span class="p">(</span><span class="s1">&#39;Y-m-d g:i A&#39;</span><span class="p">);</span> <span class="c1">// ACST: 2011-04-27 12:15 PM
</span></span></span></code></pre></div><p>After some experimentation between <a href="http://www.timeanddate.com/worldclock/converted.html?day=27&amp;month=4&amp;year=2011&amp;hour=8&amp;min=15&amp;sec=0&amp;p1=136&amp;p2=152">time zones that do and do not currently have DST</a> (Day Light Savings Time) I have discovered that this will take DST into account.</p>
<p>Anyway a very simple tip for moving dates around in PHP.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="php" label="php"/><category scheme="taxonomy:Tags" term="time" label="time"/><category scheme="taxonomy:Tags" term="date" label="date"/><category scheme="taxonomy:Tags" term="timezone" label="timezone"/><category scheme="taxonomy:Tags" term="datetime" label="datetime"/></entry><entry xml:base="conditionally-loaded-responsive-content"><title type="html">Conditionally loaded responsive content on the client side</title><link href="https://www.simonholywell.com/post/2013/11/conditionally-loaded-responsive-content/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2010/08/firefox-radio-buttons/?utm_source=atom_feed" rel="related" type="text/html" title=""/><link href="https://www.simonholywell.com/post/2010/04/jquery-ui-datepicker-in-dialogue/?utm_source=atom_feed" rel="related" type="text/html" title="jQuery UI Datepicker appearing below Dialog"/><link href="https://www.simonholywell.com/post/2013/09/idiorm-and-paris-1-4-0-released/?utm_source=atom_feed" rel="related" type="text/html" title="Idiorm and Paris 1.4.0 Released"/><link href="https://www.simonholywell.com/post/2013/05/improve-php-session-cookie-security/?utm_source=atom_feed" rel="related" type="text/html" title="Improve PHP session cookie security"/><link href="https://www.simonholywell.com/post/2013/04/three-things-i-set-on-new-servers/?utm_source=atom_feed" rel="related" type="text/html" title="3 things I set on new servers"/><id>https://www.simonholywell.com/post/2013/11/conditionally-loaded-responsive-content/</id><author><name>Simon Holywell</name></author><published>2013-11-21T09:55:16+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Sometimes it is helpful to entirely change chunks of markup when a certain CSS media query is triggered. This could because a certain layout will not work on smaller screen sizes or because it refers to media that you would not want a mobile to download.
Recently I had this exact problem when dealing with a site that included a grid based layout in a carousel/slider. When the browser was sized down from desktop it needed to change the number of columns in the grid.</summary><content type="html"><![CDATA[<p>Sometimes it is helpful to entirely change chunks of markup when a certain CSS media query is triggered. This could because a certain layout will not work on smaller screen sizes or because it refers to media that you would not want a mobile to download.</p>
<p>Recently I had this exact problem when dealing with a site that included a grid based layout in a carousel/slider. When the browser was sized down from desktop it needed to change the number of columns in the grid. If a column is suddenly removed from the grid then where does the content residing in it go?</p>
<p>Well in this case it would slip to the next slide in the carousel, which then means that every slide in the carousel changes as all the items are reshuffled in the respective grids. This re-gridding of the content could not realistically be performed by JavaScript on the fly.</p>
<p>To workaround this I would need to have a way to have three different versions (one for each supported responsive break point) of the carousel in the page and only show the one relevant to the current media query. Before you run off screaming, no, I did not fire up three carousels and have them waiting for instruction!</p>
<p>You can have hidden HTML/content inside your document that you then conditionally load in at the right point in time using JavaScript. Firstly, to be able to match against media query break points you will want to use <a href="https://developer.mozilla.org/en-US/docs/Web/API/Window.matchMedia">window.matchMedia</a> and if you are stuck support &lt;=IE9 you can use <a href="https://github.com/paulirish/matchMedia.js/">Paul Irish’s polyfill</a>.</p>
<p>Next up we need to hide the content that we will conditionally load. Now there are a few ways to do this, but I settled on so called JavaScript templates. They are really simple just involve one script tag surrounding the content:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;text/conditional-html&#34;</span> <span class="na">id</span><span class="o">=</span><span class="s">&#34;tablet-a-unique-reference&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="o">&lt;</span><span class="nx">p</span><span class="o">&gt;</span><span class="nx">I</span> <span class="nx">am</span> <span class="nx">a</span> <span class="nx">hidden</span> <span class="nx">block</span> <span class="k">of</span> <span class="nx">HTML</span><span class="p">.</span><span class="o">&lt;</span><span class="err">/p&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>You should note that this script tag is a little different to the ones you are probably used to writing. Instead of having a type of text/javascript they have a type of text/conditional-html. This is what causes the content to be hidden and not evaluated by JavaScript - it serves no other purpose.</p>
<p>Now let us actually go ahead and replace the content. For this demonstration I have assumed that we are moving from a desktop responsive breakpoint to a tablet one. The intial HTML loaded with the page is that of the desktop experience.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">div</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="s2">&#34;a-unique-reference&#34;</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="nx">desktop_html</span> <span class="o">=</span> <span class="nx">div</span><span class="p">.</span><span class="nx">innerHTML</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">tablet_html</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="s2">&#34;tablet-a-unique-reference&#34;</span><span class="p">).</span><span class="nx">innerHTML</span><span class="p">;</span>
</span></span></code></pre></div><p>The above code just grabs the HTML from the currently displayed <code>&lt;div&gt;</code> and also the content of the JavaScript template we setup above.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">checkAndChangeHtml</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="p">(</span><span class="nx">matchMedia</span><span class="p">(</span><span class="s2">&#34;screen and (max-width : 62.000em)&#34;</span><span class="p">).</span><span class="nx">matches</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">div</span><span class="p">.</span><span class="nx">innerHTML</span> <span class="o">=</span> <span class="nx">tablet_html</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">div</span><span class="p">.</span><span class="nx">innerHTML</span> <span class="o">=</span> <span class="nx">desktop_html</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="nb">window</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="s2">&#34;resize&#34;</span><span class="p">,</span> <span class="nx">checkAndChangeHtml</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">checkAndChangeHtml</span><span class="p">();</span> <span class="c1">// call it once on document load incase it
</span></span></span><span class="line"><span class="cl"><span class="c1">// initially loads at a lower width/on a mobile device
</span></span></span></code></pre></div><p>Now this is where the action takes place. The code adds a listener to resize event so that we can run our code when the user resizes their browser. If the width of the browser falls into our tablet media query range then the <code>div</code> has it’s content set to the tablet HTML.</p>
<p>You should wrap all the of the above in the following to ensure that the DOM is ready (supports &gt;=IE8):</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="nb">document</span><span class="p">.</span><span class="nx">onreadystatechange</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="p">(</span><span class="nb">document</span><span class="p">.</span><span class="nx">readyState</span> <span class="o">==</span> <span class="s2">&#34;interactive&#34;</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// code would go here
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div><p>Obviously if you prefer you can use jQuery to abstract away these event bindings.</p>
<p>So there you have it. A very simple way of conditionally loading content on the client side for use in responsive designs.</p>
<blockquote>
<p><strong>note</strong></p>
<p>After writing this I discovered that someone had already released something called <a href="http://responsivecomments.com/">ResponsiveComments</a> that is similar. It however uses more mark up as it wraps the hidden content in a <code>&lt;div&gt;</code> and then HTML comments (<code>&lt;!-- --&gt;</code>). I do not like this approach as it inserts block level items into your source code unlike the script tag example given here. Divs have layout and script tags do not.</p>
</blockquote>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="responsive-web-design" label="responsive web design"/><category scheme="taxonomy:Tags" term="media-queries" label="media queries"/><category scheme="taxonomy:Tags" term="rwd" label="RWD"/><category scheme="taxonomy:Tags" term="css" label="css"/><category scheme="taxonomy:Tags" term="javascript" label="javascript"/></entry><entry xml:base="idiorm-and-paris-1-4-0-released"><title type="html">Idiorm and Paris 1.4.0 Released</title><link href="https://www.simonholywell.com/post/2013/09/idiorm-and-paris-1-4-0-released/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2013/01/idiorm-and-paris-the-minimalist-orm/?utm_source=atom_feed" rel="related" type="text/html" title="Idiorm and Paris 1.3.0 released - the minimalist ORM and fluent query builder for PHP"/><link href="https://www.simonholywell.com/post/2013/05/improve-php-session-cookie-security/?utm_source=atom_feed" rel="related" type="text/html" title="Improve PHP session cookie security"/><link href="https://www.simonholywell.com/post/2013/04/three-things-i-set-on-new-servers/?utm_source=atom_feed" rel="related" type="text/html" title="3 things I set on new servers"/><link href="https://www.simonholywell.com/post/2013/02/php-ssdeep-in-git/?utm_source=atom_feed" rel="related" type="text/html" title="ssdeep PHP extension in git"/><link href="https://www.simonholywell.com/post/2013/01/unicode-shortcut-in-netbeans/?utm_source=atom_feed" rel="related" type="text/html" title="Unicode shortcut in Netbeans for React/Curry"/><id>https://www.simonholywell.com/post/2013/09/idiorm-and-paris-1-4-0-released/</id><author><name>Simon Holywell</name></author><published>2013-09-05T13:24:16+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>After a lot of work and many contributions from valued community members Idiorm and Paris versions 1.4.0 have been released into the wild. You can download them now from their respective repositories or via Composer/Packagist.
As you are probably aware from my previous posts Idiorm is a minimalist ORM that is targetted at PHP 5.2 and above. It combines a fluent query builder with a simple ORM interface to allow fast and easy access to databases over PDO.</summary><content type="html"><![CDATA[<p>After a lot of work and many contributions from valued community members <a href="https://github.com/j4mie/idiorm">Idiorm</a> and <a href="https://github.com/j4mie/paris">Paris</a> versions 1.4.0 have been released into the wild. You can download them now from their respective repositories or via <a href="https://packagist.org/packages/j4mie/">Composer/Packagist</a>.</p>
<p>As you are probably aware from <a href="/post/2013/01/idiorm-and-paris-the-minimalist-orm.html">my previous posts</a> Idiorm is a minimalist ORM that is targetted at PHP 5.2 and above. It combines a fluent query builder with a simple ORM interface to allow fast and easy access to databases over PDO. On top of this can sit Paris, if you so choose, which acts as a lightweight active record implementation to allow for more defined functionality and models. Both Idiorm and Paris have shared the same minimalist philosophy since their inception with the key aim being to provide compact and simple, but powerful code. This makes for a smaller and easier to learn set of libraries with less namespace pollution (it supports PHP 5.2 remember).</p>
<p>This lightweight and simple philosophy has been challenged along the way with requests for ever more complicated features to be added to the libraries. Unfortunately this has led to some pull requests being summarily closed over the past year or so, but for good reason. It is this very reason that has led <a href="http://www.j4mie.org">Jamie</a> and myself to decide that both Idiorm and Paris are more than feature complete at this time. So many useful features have been submitted over the years and we have been able to adopt most of them - some of them are out there as forks.</p>
<p>So what am I alluding to? Idiorm and Paris will no longer receive new features going forward. Of course bug fixes will still be maintained along with support of the libraries via the respective GitHub issue trackers. So if you find any issues please report them or better yet if you have bug fixing patches please submit them (preferably with a regression test or two).</p>
<p>Should you wish to add features to either library or raise their minimum requirement above PHP 5.2 then you are more than welcome to create your own fork for this purpose. You can, if you like, open a pull request, but it is likely to be given short shrift if I am honest.</p>
<p>Anyway with that out of the way there are a few niceties that Idiorm 1.4.0 brings with it:</p>
<ul>
<li><code>find_many()</code> now returns an associative array with the databases primary ID as the array keys</li>
<li>Calls to <code>set()</code> and <code>set_expr()</code> return <code>$this</code> allowing them to be chained</li>
<li>PSR-1 compliant camelCase methods can be mapped to the original underscore ones (PHP 5.3+ required due to <code>__callStatic()</code> usage``)</li>
<li>Add <code>get_config()</code> to access configuration values</li>
<li>Support for a logging callback function allowing usuage of any logging library</li>
<li>MS SQL <code>TOP</code> select query limit style support</li>
<li>And many smaller bug fixes</li>
</ul>
<p>Paris 1.4.0 also comes with a few new features:</p>
<ul>
<li>Ability to methods against the model class directly eg. <code>User::find_many()</code> (PHP 5.3+ required)</li>
<li><code>find_many()</code> now returns an associative array with the databases primary ID as the array keys</li>
<li>PSR-1 compliant camelCase methods can be mapped to the original underscore ones (PHP 5.3+ required due to <code>__callStatic()</code> usage``)</li>
<li>And a couple of smaller bug fixes</li>
</ul>
<p>There you have it. Idiorm and Paris have matured!</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="php" label="php"/><category scheme="taxonomy:Tags" term="idiorm" label="idiorm"/><category scheme="taxonomy:Tags" term="paris" label="paris"/></entry><entry xml:base="improve-php-session-cookie-security"><title type="html">Improve PHP session cookie security</title><link href="https://www.simonholywell.com/post/2013/05/improve-php-session-cookie-security/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2013/04/three-things-i-set-on-new-servers/?utm_source=atom_feed" rel="related" type="text/html" title="3 things I set on new servers"/><link href="https://www.simonholywell.com/post/2013/02/php-ssdeep-in-git/?utm_source=atom_feed" rel="related" type="text/html" title="ssdeep PHP extension in git"/><link href="https://www.simonholywell.com/post/2013/01/idiorm-and-paris-the-minimalist-orm/?utm_source=atom_feed" rel="related" type="text/html" title="Idiorm and Paris 1.3.0 released - the minimalist ORM and fluent query builder for PHP"/><link href="https://www.simonholywell.com/post/2013/01/unicode-shortcut-in-netbeans/?utm_source=atom_feed" rel="related" type="text/html" title="Unicode shortcut in Netbeans for React/Curry"/><link href="https://www.simonholywell.com/post/2013/01/navigator-geographic-calculations-library-for-php/?utm_source=atom_feed" rel="related" type="text/html" title="Navigator: Geographic calculation library for PHP"/><id>https://www.simonholywell.com/post/2013/05/improve-php-session-cookie-security/</id><author><name>Simon Holywell</name></author><published>2013-05-14T11:42:16+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>The security of session handling in PHP can easily be enhanced through the use of a few configuration settings and the addition of an SSL certificate. Whilst this topic has been covered numerous times before it still bears mentioning with a large number of PHP sites and servers having not implemented these features.
To prevent session hijacking through cross site scripting (XSS) you should always filter and escape all user supplied values before printing them to screen.</summary><content type="html"><![CDATA[<p>The security of session handling in PHP can easily be enhanced through the use of a few configuration settings and the addition of an SSL certificate. Whilst this topic has been covered numerous times before it still bears mentioning with a large number of PHP sites and servers having not implemented these features.</p>
<p>To prevent session hijacking through cross site scripting (XSS) you should always filter and escape all user supplied values before printing them to screen. However some bugs may slip through or a piece of legacy code might be vulnerable so it makes sense to also make use of browser protections against XSS.</p>
<p>By specifying the <a href="https://www.owasp.org/index.php/HttpOnly">HttpOnly flag</a> when setting the session cookie you can tell a users browser not to expose the cookie to client side scripting such as JavaScript. This makes it harder for an attacker to hijack the session ID and masquerade as the effected user.</p>
<p>A helpful setting has been added to the PHP configuration to automate this process this for you.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ini" data-lang="ini"><span class="line"><span class="cl"><span class="na">session.cookie_httponly</span> <span class="o">=</span> <span class="s">1</span>
</span></span></code></pre></div><p>It is also a good idea to make sure that PHP only uses cookies for sessions and disallow session ID passing as a GET parameter:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ini" data-lang="ini"><span class="line"><span class="cl"><span class="na">session.use_only_cookies</span> <span class="o">=</span> <span class="s">1</span>
</span></span></code></pre></div><p>It is important to point out that HttpOnly, whilst useful as another layer in the onion of security is not going to protect a user from other forms of XSS attack. As previously mentioned on <a href="http://www.gnucitizen.org/blog/why-httponly-wont-protect-you">GNUCitizen</a> session hijacking is often avoided by attackers as it requires getting and keeping a user in the right state in the target application. You must ensure that the rest of you application is not XSS vulnerable to prevent attackers utilising other vectors.</p>
<p>So it is just one very small step in making your PHP installation slightly more secure, but if you are not doing it then you are failing to exploit all the avenues available to you.</p>
<p>Another important way to increase the security of PHP sessions in your application is to install an <a href="http://php.net/manual/en/session.security.php">SSL certificate</a> on the web server and force all user interactions to occur over HTTPS only. This will prevent the users session ID from being transmitted in plain text to make it much harder to hijack the users session.</p>
<p>Helpfully PHP has <a href="http://www.php.net/manual/en/session.configuration.php#ini.session.cookie-secure">another ini setting</a> to assist you in ensuring session cookies are only sent over secure connections (thank you to <a href="http://www.reddit.com/r/PHP/comments/1eb232/improve_php_session_cookie_security/c9ykevt">Padraic for reminding me</a>):</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ini" data-lang="ini"><span class="line"><span class="cl"><span class="na">session.cookie_secure</span> <span class="o">=</span> <span class="s">1</span>
</span></span></code></pre></div><p>If you liked this post then you’ll probably also like <a href="/post/2013/04/three-things-i-set-on-new-servers.html">3 things I set on new servers</a> for more security tips.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="security" label="security"/><category scheme="taxonomy:Tags" term="php" label="php"/><category scheme="taxonomy:Tags" term="owasp" label="owasp"/></entry><entry xml:base="three-things-i-set-on-new-servers"><title type="html">3 things I set on new servers</title><link href="https://www.simonholywell.com/post/2013/04/three-things-i-set-on-new-servers/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2012/11/force-lowercase-urls-rewrite-php/?utm_source=atom_feed" rel="related" type="text/html" title="Force URLs to lowercase with Apache rewrite and PHP"/><link href="https://www.simonholywell.com/post/2013/02/php-ssdeep-in-git/?utm_source=atom_feed" rel="related" type="text/html" title="ssdeep PHP extension in git"/><link href="https://www.simonholywell.com/post/2013/01/idiorm-and-paris-the-minimalist-orm/?utm_source=atom_feed" rel="related" type="text/html" title="Idiorm and Paris 1.3.0 released - the minimalist ORM and fluent query builder for PHP"/><link href="https://www.simonholywell.com/post/2013/01/unicode-shortcut-in-netbeans/?utm_source=atom_feed" rel="related" type="text/html" title="Unicode shortcut in Netbeans for React/Curry"/><link href="https://www.simonholywell.com/post/2013/01/navigator-geographic-calculations-library-for-php/?utm_source=atom_feed" rel="related" type="text/html" title="Navigator: Geographic calculation library for PHP"/><id>https://www.simonholywell.com/post/2013/04/three-things-i-set-on-new-servers/</id><author><name>Simon Holywell</name></author><published>2013-04-23T13:42:16+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>There are a number of things you can do to make a server more secure whilst protecting your hosted entities and their users. Here are just three of the many things I do on every new server I commission. I hasten to add that these are not necessarily the most effective or at the top of my list - they are just that: 3 things I set on new servers.</summary><content type="html"><![CDATA[<p>There are a number of things you can do to make a server more secure whilst protecting your hosted entities and their users. Here are just three of the many things I do on every new server I commission. I hasten to add that these are not necessarily the most effective or at the top of my list - they are just that: 3 things I set on new servers.</p>
<h1 id="prevent-framing">Prevent framing</h1>
<p>One method of attempting to fool users into interacting with a website is by loading it into an iframe on the attackers page. More formally known as Clickjacking; this technique involves overlaying the iframe with a different user interface.</p>
<p>As you can imagine this makes it possible for the attacker to mask the actions of the user. They think that they are using the attacker supplied interface when in actual fact they are performing actions on the background application in the iframe.</p>
<p>There are a couple of techniques that can be employed to combat this threat and protect your users. At the server level and as javascript in the web pages themselves.</p>
<p>On the server you can set the <code>X-Frame-Options</code> header, which tells the web browser how to treat the page when it is framed. It is possible to set this header to <code>DENY</code>, which blocks all loading of the page via frames. By setting it to <code>SAMEORIGIN</code> you can relax the restrict and only allow framing by pages on the same domain.</p>
<p>On the Apache webserver this directive is set like so (on Debian/Ubuntu servers this is /etc/apache2/apache2.conf):</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-apacheconf" data-lang="apacheconf"><span class="line"><span class="cl"><span class="nb">Header</span> always append X-Frame-Options SAMEORIGIN
</span></span></code></pre></div><p>Alternatively if you are using nginx then you can implement it in the following way:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-apacheconf" data-lang="apacheconf"><span class="line"><span class="cl"><span class="nb">add_header</span> X-Frame-Options SAMEORIGIN;
</span></span></code></pre></div><p>Do not forget of course that Apache configuration changes require an Apache server reload or restart.</p>
<p>Unfortunately this header is only supported on more recent browsers with the following minimum requirements:</p>
<ul>
<li>Firefox 3.6.9</li>
<li>Chrome 4.1.249.1042</li>
<li>Internet Explorer 8</li>
<li>Opera 10.50</li>
<li>Safari 4.0</li>
</ul>
<p>In addition to the two aforementioned settings there is also <code>ALLOW-FROM</code> to whitelist a certain domain.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-apacheconf" data-lang="apacheconf"><span class="line"><span class="cl"><span class="nb">Header</span> always append X-Frame-Options ALLOW-FROM http://foo.com
</span></span></code></pre></div><p>There are at least three problems with this particular option though:</p>
<ol>
<li>It is only (currently) supported in Firefox 18 and above as it is a relatively new addition to the specification in 2012.</li>
<li>For some reason it was not foreseen that someone implementing this directive would want to list a number of domains to be allowed to frame the content so you can only specify one domain.</li>
<li>Why add a hyphen between the words when <code>SAMEORIGIN</code> does not? Maybe there is a technical reason, but from the outside it just creates an inconsistency.</li>
</ol>
<p>When any of these options are set and an invalid framing occurs Firefox will show a blank page, but Internet Explorer rather more helpfully will display an error for the user.</p>
<p>Now for legacy browsers you will need to drop back to using a JavaScript framebusting code. It goes without saying however that this can be circumvented by a potential attacker through techniques such as double framing and exploiting cross site scripting filters in some browsers.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="k">if</span> <span class="p">(</span><span class="nx">top</span> <span class="o">!=</span> <span class="nx">self</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">top</span><span class="p">.</span><span class="nx">location</span> <span class="o">=</span> <span class="nx">self</span><span class="p">.</span><span class="nx">location</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>The latest recommendation from The Open Web Application Security Project (OWASP) is to include the following code in the <code>&lt;head&gt;</code> section of your web page:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">style</span> <span class="na">id</span><span class="o">=</span><span class="s">&#34;antiClickjack&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nt">body</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">display</span><span class="p">:</span> <span class="kc">none</span> <span class="cp">!important</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">style</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;text/javascript&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="p">(</span><span class="nx">self</span> <span class="o">===</span> <span class="nx">top</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kd">var</span> <span class="nx">antiClickjack</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="s2">&#34;antiClickjack&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">antiClickjack</span><span class="p">.</span><span class="nx">parentNode</span><span class="p">.</span><span class="nx">removeChild</span><span class="p">(</span><span class="nx">antiClickjack</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">top</span><span class="p">.</span><span class="nx">location</span> <span class="o">=</span> <span class="nx">self</span><span class="p">.</span><span class="nx">location</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>This works by disabling the whole page using the CSS style at the beginning and then later on in the javascript checking to see that the page is not framed. It then removes the style from the pages HTML thereby revealing the content. If it is framed then it sets itself as the parent page.</p>
<p>It should be noted that if the user has JavaScript turned off or it does not run due to an error then they will not be able to see anything of the page.</p>
<h1 id="http-trace">HTTP TRACE</h1>
<p>Apache responds to debugging requests via the HTTP <code>TRACE</code> method with the exact request that was received. In general this does not appear harmful, but it can be used to find out information about a users request. An attacker will attempt to trick a user into making a <code>TRACE</code> request and then obtain information about session cookies or authentication from the response. The information can then be used to exploit other potential vulnerabilities such as cross site scripting.</p>
<p>It is possible to disable this helpful debug functionality in production by setting the <code>TraceEnable</code> Apache directive in the following fashion:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-apacheconf" data-lang="apacheconf"><span class="line"><span class="cl"><span class="nb">TraceEnable</span> <span class="k">Off</span>
</span></span></code></pre></div><p>Do not forget of course that Apache configuration changes require a server restart.</p>
<p>If you do not have access to the main Apache configuration then you can still block <code>TRACE</code> requests using mod_rewrite:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-apacheconf" data-lang="apacheconf"><span class="line"><span class="cl"><span class="nb">RewriteEngine</span> <span class="k">On</span>
</span></span><span class="line"><span class="cl"><span class="nb">RewriteCond</span> %{REQUEST_METHOD} ^(TRACE|TRACK)
</span></span><span class="line"><span class="cl"><span class="nb">RewriteRule</span> .* - [F]
</span></span></code></pre></div><p>You will note the addition of a rule to prevent <code>TRACK</code> requests as well, which is a similar debugging method.</p>
<p>For the nginx users out there; you have no need to worry as from version 0.5.17 all <code>TRACE</code> requests are rejected with a 405 error and it has no concept of a <code>TRACK</code> request. To debug this server you are expected to have access to the logs on disk.</p>
<h1 id="hide-your-versions">Hide your versions</h1>
<p>Another super simple, but often overlooked adjustment to make is to prevent the server from broadcasting too much information about itself. Whilst attackers maybe able to source the information in other ways the harder we make it the more likely potential attackers are to give up and move onto a softer target. It is similar to introducing yourself to someone and giving them specific details about yourself such as “I rarely lock the back window when I pop into town”.</p>
<p>Firstly, let us silence the Apache server a little. Gag it with the following configuration changes:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-apacheconf" data-lang="apacheconf"><span class="line"><span class="cl"><span class="nb">ServerSignature</span> <span class="k">Off</span>
</span></span><span class="line"><span class="cl"><span class="nb">ServerTokens</span> <span class="k">ProductOnly</span>
</span></span></code></pre></div><p>nginx servers can be muffled by setting the following directives in the configuration after installing the module:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-apacheconf" data-lang="apacheconf"><span class="line"><span class="cl"><span class="nb">server_tokens</span> <span class="k">off</span>;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># Install HttpHeadersMoreModule first for this one</span>
</span></span><span class="line"><span class="cl"><span class="nb">more_set_headers</span> &#39;Server: Nginx&#39;;
</span></span></code></pre></div><p>Secondly, PHP is also being too noisy about its presence. Put a sock in it by editing the core php.ini file (typically /etc/php5/apache2/php.ini on Debian/Ubuntu servers):</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ini" data-lang="ini"><span class="line"><span class="cl"><span class="na">expose_php Off</span>
</span></span></code></pre></div><p>Once again do not forget of course that Apache and PHP configuration changes require an Apache server restart.</p>
<p>Join in the conversation about this article on <a href="https://news.ycombinator.com/item?id=5594739">Hacker News</a> or <a href="http://www.reddit.com/r/linuxadmin/comments/1cxttr/3_things_i_set_on_new_servers/">reddit</a>.</p>
<p>If you liked this post then you might also like my follow up post <a href="/post/2013/05/improve-php-session-cookie-security.html">Improve PHP session security</a>.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="security" label="security"/><category scheme="taxonomy:Tags" term="apache" label="apache"/><category scheme="taxonomy:Tags" term="php" label="php"/><category scheme="taxonomy:Tags" term="nginx" label="nginx"/><category scheme="taxonomy:Tags" term="owasp" label="owasp"/></entry><entry xml:base="install-netbeans-scala-ubuntu"><title type="html">Install Netbeans and Scala on Ubuntu</title><link href="https://www.simonholywell.com/post/2013/03/install-netbeans-scala-ubuntu/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2011/04/ssh-agent-not-storing-unencrypted-key/?utm_source=atom_feed" rel="related" type="text/html" title="Why won't ssh-agent save my unencrypted key for later use?"/><link href="https://www.simonholywell.com/post/2010/08/php-ssdeep-fuzzy-hashing-php-extension/?utm_source=atom_feed" rel="related" type="text/html" title="php_ssdeep Fuzzy Hashing PHP Extension"/><link href="https://www.simonholywell.com/post/2010/08/php-wrapper-for-linux-at-command/?utm_source=atom_feed" rel="related" type="text/html" title="A PHP wrapper for the unix at command"/><link href="https://www.simonholywell.com/post/2010/08/linux-batch-remove-extension/?utm_source=atom_feed" rel="related" type="text/html" title="Batch remove extensions in Ubuntu"/><link href="https://www.simonholywell.com/post/2010/08/ubuntu-atd-not-running/?utm_source=atom_feed" rel="related" type="text/html" title="If you are having problems getting Ubuntu atd running"/><id>https://www.simonholywell.com/post/2013/03/install-netbeans-scala-ubuntu/</id><author><name>Simon Holywell</name></author><published>2013-03-17T16:06:29+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>If you want to install and run the latest version of Scala and/or Netbeans then you cannot simply install it from your distributions repositories or pre-built packages. It may sound easy enough to just grab Netbeans from their site and install it, but most Linux distributions no longer have Sun Java packages in their repositories.
So after a little bit of mucking about, reading manual pages and documentation I struck upon the following method of setting it all up.</summary><content type="html"><![CDATA[<p>If you want to install and run the latest version of Scala and/or Netbeans then you cannot simply install it from your distributions repositories or pre-built packages. It may sound easy enough to just grab Netbeans from their site and install it, but most Linux distributions no longer have Sun Java packages in their repositories.</p>
<p>So after a little bit of mucking about, reading manual pages and documentation I struck upon the following method of setting it all up. Fortunately it is very easy to install and I have used the following instructions to setup configure Ubuntu or Ubuntu like machines.</p>
<h1 id="installing-sun-java-jdk">Installing Sun Java JDK</h1>
<p>As I mentioned earlier most distributions no longer come with Sun Java and do not have the ability to include it in their extras/proprietary packages. This is caused by a <a href="http://sylvestre.ledru.info/blog/sylvestre/2011/08/26/sun_java6_packages_removed_from_debian_u">change in the licencing</a> of Java after Oracle bought out Sun. To compound this pain further Oracle do not produce packages for the various popular Linux variants.</p>
<p>Luckily a number of like minded people have set about creating custom packages for those of us that require Sun Java. On Ubuntu you can use <a href="http://www.webupd8.org/2012/01/install-oracle-java-jdk-7-in-ubuntu-via.html">the PPA</a> produced by the team at <a href="http://www.webupd8.org">webupd8.org</a> to install Sun JDK.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo add-apt-repository ppa:webupd8team/java
</span></span><span class="line"><span class="cl">sudo apt-get update
</span></span><span class="line"><span class="cl">sudo apt-get install oracle-java7-installer
</span></span></code></pre></div><p>To test and ensure that your system is running the correct version of Java you can execute the following command:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">java -version
</span></span></code></pre></div><p>The resulting output should look something like the following:</p>
<blockquote>
<p>java version “1.7.0_17”</p>
<p>Java(TM) SE Runtime Environment (build 1.7.0_17-b02)</p>
<p>Java HotSpot(TM) 64-Bit Server VM (build 23.7-b01, mixed mode)</p>
</blockquote>
<p>The webup8.org team have a number of troubleshooting hints on their <a href="http://www.webupd8.org/2012/01/install-oracle-java-jdk-7-in-ubuntu-via.html">announcement article</a> if you have some kind of trouble getting this PPA installed.</p>
<h1 id="installing-netbeans">Installing Netbeans</h1>
<p><a href="http://netbeans.org">Netbeans</a> is nice and simple to install on Linux as it has a handy graphical wizard to lead you through the installation steps. I use the following commands to download and install it (7.3 is the latest version at the time of writing, but you can easily supply an releases download URL here):</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">cd</span> ~
</span></span><span class="line"><span class="cl">wget download.netbeans.org/netbeans/7.3/final/bundles/netbeans-7.3-linux.sh
</span></span><span class="line"><span class="cl">chmod +x netbeans-7.3-linux.sh
</span></span><span class="line"><span class="cl">./netbeans-7.3-linux.sh
</span></span></code></pre></div><p>The installation wizard will then start up after a moment and you can pretty much stick with the default options. This should mean that it will install Netbeans to a directory at <code>/home/&lt;user&gt;/netbeans-7.3</code>.</p>
<p>Of course if you are more comfortable with a GUI then you can simply <a href="http://netbeans.org/downloads/">download it</a> from the Netbeans website in your web browser.</p>
<h1 id="installing-scala">Installing Scala</h1>
<p>Finally we get to Scala itself and thankfully it also has a reasonably simple set of setup instructions. You will need to <a href="http://www.scala-lang.org/downloads">download the latest release</a> from the Scala website. Once again here are the commands I used to download and install the latest release of Scala on my machine:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">wget http://www.scala-lang.org/downloads/distrib/files/scala-2.10.1.tgz
</span></span><span class="line"><span class="cl">tar -xzf scala-2.10.1.tgz
</span></span><span class="line"><span class="cl">sudo mv scala-2.10.1 /usr/share/scala
</span></span></code></pre></div><p>Now we need to tell Linux where to look when references to Scala are made so edit <code>~/.profile</code> to add the following environment variables:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">export</span> <span class="nv">SCALA_HOME</span><span class="o">=</span>/usr/share/scala
</span></span><span class="line"><span class="cl"><span class="nb">export</span> <span class="nv">PATH</span><span class="o">=</span><span class="nv">$PATH</span>:<span class="nv">$SCALA_HOME</span>/bin
</span></span></code></pre></div><p>You will now need to log out and back in again for the environment setting to take effect.</p>
<p>As an aside and in case you did not already know; <code>.bashrc</code> is executed whenever a new bash session is started (such as opening a new terminal) and <code>.profile</code> is executed when a user logs in. Netbeans is not able to see environment variables set in <code>.bashrc</code> as it is run after the environment Netbeans is started in has been constructed. This is explained in more detail by a <a href="https://netbeans.org/bugzilla/show_bug.cgi?id=175394">Netbeans issue report</a>.</p>
<p>There is another way around this problem, but I prefer the <code>.profile</code> route as it universally available. However if you wish you can set a Netbeans startup configuration variable called <code>scala.home</code> on end of the <code>netbeans_default_options</code> setting in <code>~/netbeans-7.3/etc/netbeans.conf</code> like so:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nv">netbeans_default_options</span><span class="o">=</span><span class="s2">&#34;-J-client -J-Xss2m -J-Xms32m -J-XX:PermSize=32m -J-Dapple.laf.useScreenMenuBar=true -J-Dapple.awt.graphics.UseQuartz=true -J-Dsun.java2d.noddraw=true -J-Dsun.java2d.dpiaware=true -J-Dsun.zip.disableMemoryMapping=true -J-Dsun.awt.disableMixing=true -J-Dscala.home=/usr/share/scala&#34;</span>
</span></span></code></pre></div><h1 id="installing-nbscala">Installing nbscala</h1>
<p>Now that Netbeans is successfully installed and it can see the <code>SCALA_HOME</code> environment variable we can install the <a href="http://wiki.netbeans.org/Scala">nbscala plugin</a>. The simplest method is to simply install the plugin using the Netbeans plugin manager, which can be found in <code>Tools</code> &gt; <code>Plugins</code> &gt; <code>Available Plugins</code>. Install all the available Scala plugins.</p>
<p>If you prefer a more manual route then you can download the latest nbscala from the <a href="http://sourceforge.net/projects/erlybird/files/nb-scala/">project on SourceForge</a>. It is then possible to manually install the plugin using the process <a href="http://wiki.netbeans.org/InstallingAPlugin#Installing_the_Netbeans_Plugin">documented on the Netbeans wiki</a>.</p>
<p>Restart Netbeans and then go <code>File &gt; New Project...</code> followed by choosing <code>Scala &gt; Scala Application</code> and clicking Next. After giving it a name and location click <code>Finish</code> to be presented with your new application. With the example <code>Main.scala</code> file open in your main Netbeans pane hit <code>F6</code> to compile and run the code.</p>
<p>You should be presented with a nice compile status message and the Hello World message in your output pane at the base of the Netbeans IDE.</p>
<p>The installation of all the tools is now complete and you can go ahead and begin developing with Scala!</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="netbeans" label="netbeans"/><category scheme="taxonomy:Tags" term="ubuntu" label="ubuntu"/><category scheme="taxonomy:Tags" term="linux" label="linux"/><category scheme="taxonomy:Tags" term="scala" label="scala"/></entry><entry xml:base="create-a-node-js-google-talk-bot-pt2"><title type="html">Create a Google Talk bot with Node.js Part Two</title><link href="https://www.simonholywell.com/post/2013/03/create-a-node-js-google-talk-bot-pt2/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2013/02/create-a-node-js-google-talk-bot-pt1/?utm_source=atom_feed" rel="related" type="text/html" title="Create a Google Talk bot with Node.js: Part One"/><link href="https://www.simonholywell.com/post/2013/02/node-js-for-hosting-websites/?utm_source=atom_feed" rel="related" type="text/html" title="Node.js for hosting websites"/><link href="https://www.simonholywell.com/post/2013/02/node-js-in-the-real-world/?utm_source=atom_feed" rel="related" type="text/html" title="Node.js in the real world"/><link href="https://www.simonholywell.com/post/2013/02/node-js-eco-system/?utm_source=atom_feed" rel="related" type="text/html" title="The Node.js eco-system"/><link href="https://www.simonholywell.com/post/2013/02/xmpp-and-jabber/?utm_source=atom_feed" rel="related" type="text/html" title="XMPP and Jabber"/><id>https://www.simonholywell.com/post/2013/03/create-a-node-js-google-talk-bot-pt2/</id><author><name>Simon Holywell</name></author><published>2013-03-01T12:32:16+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>In part one of the tutorial you built a bot with Node.js that could connect to the Google Talk network and announce its presence to other users with a status message. The bot was also configured to listen for subscription requests from other users and automatically accept them.
Now you are going to further enhance the bot with additional functionality and commands as you proceed through part two of the tutorial.</summary><content type="html"><![CDATA[<p>In <a href="/post/2013/02/create-a-node-js-google-talk-bot-pt1.html">part one of the tutorial</a> you built a bot with Node.js that could connect to the Google Talk network and announce its presence to other users with a status message. The bot was also configured to listen for subscription requests from other users and automatically accept them.</p>
<p>Now you are going to further enhance the bot with additional functionality and commands as you proceed through part two of the tutorial. Once complete your bot will be able to furnish users with help information, bounce messages back and search twitter for user supplied keywords.</p>
<p>So lets get back to the hacking!</p>
<blockquote>
<p><strong>note</strong></p>
<p>This article was originally published in the <a href="/post/2012/02/create-a-google-talk-bot-with-nodejs.html">April 2012 issue</a> of <a href="http://www.netmagazine.com">.net Magazine</a>. You can also <a href="http://dl.dropbox.com/u/3913347/Create%20a%20Google%20Talk%20bot%20with%20Node.js%20-%20Part%20Two.pdf">download a PDF</a> of the original article.</p>
<p><a href="/post/2013/02/create-a-node-js-google-talk-bot-pt1.html">Part one</a> of this article is also published on my blog.</p>
<p>There is a demo bot for this article documented at <a href="http://njsbot.simonholywell.com">http://njsbot.simonholywell.com</a> and the <a href="https://github.com/treffynnon/njsbot">complete code is on github</a>.</p>
</blockquote>
<h1 id="making-the-bot-do-something">Making the bot do something</h1>
<p>Whilst it was fun and exciting to get your bot to this point, it is, unfortunately a little boring. Wouldn’t it be neat if the bot could receive commands and action them?</p>
<p>To begin with a simple callback registry is added to allow for commands to be easily added to the bot. Near the top of bot.js add a new object variable definition and two new functions:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">commands</span> <span class="o">=</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"><span class="nx">The</span> <span class="nx">first</span> <span class="kd">function</span> <span class="nx">allows</span> <span class="nx">you</span> <span class="nx">to</span> <span class="nx">easily</span> <span class="nx">add</span> <span class="k">new</span> <span class="nx">functionality</span> <span class="nx">to</span> <span class="nx">the</span> <span class="nx">bot</span> <span class="nx">by</span> <span class="nx">simply</span> <span class="nx">setting</span> <span class="nx">up</span> <span class="nx">a</span> <span class="nx">callback</span> <span class="kd">function</span> <span class="k">for</span> <span class="nx">a</span> <span class="nx">command</span> <span class="nx">name</span><span class="p">.</span>
</span></span><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">add_command</span><span class="p">(</span><span class="nx">command</span><span class="p">,</span> <span class="nx">callback</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">commands</span><span class="p">[</span><span class="nx">command</span><span class="p">]</span> <span class="o">=</span> <span class="nx">callback</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Now to allow the execution of a request we need to check if the supplied command has been added to the bot’s registry with the add_command() function.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">execute_command</span><span class="p">(</span><span class="nx">request</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="p">(</span><span class="k">typeof</span> <span class="nx">commands</span><span class="p">[</span><span class="nx">request</span><span class="p">.</span><span class="nx">command</span><span class="p">]</span> <span class="o">===</span> <span class="s2">&#34;function&#34;</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nx">commands</span><span class="p">[</span><span class="nx">request</span><span class="p">.</span><span class="nx">command</span><span class="p">](</span><span class="nx">request</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="kc">false</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>These two functions mean that you can very easily add new commands to the bot. The following example changes the bot’s status message.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="nx">add_command</span><span class="p">(</span><span class="s2">&#34;s&#34;</span><span class="p">,</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">request</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">set_status_message</span><span class="p">(</span><span class="nx">request</span><span class="p">.</span><span class="nx">argument</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="kc">true</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><p>As you can see though a request object is passed as the parameter to the function, but where does this come from?</p>
<h1 id="dispatching-requests">Dispatching requests</h1>
<p>To handle the routing of incoming requests I like to use a simple dispatching mechanism that takes the incoming stanza and interprets it.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">message_dispatcher</span><span class="p">(</span><span class="nx">stanza</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="p">(</span><span class="s2">&#34;error&#34;</span> <span class="o">===</span> <span class="nx">stanza</span><span class="p">.</span><span class="nx">attrs</span><span class="p">.</span><span class="nx">type</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">util</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;[error] &#34;</span> <span class="o">+</span> <span class="nx">stanza</span><span class="p">.</span><span class="nx">toString</span><span class="p">());</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nx">stanza</span><span class="p">.</span><span class="nx">is</span><span class="p">(</span><span class="s2">&#34;message&#34;</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">util</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;[message] RECV: &#34;</span> <span class="o">+</span> <span class="nx">stanza</span><span class="p">.</span><span class="nx">toString</span><span class="p">());</span>
</span></span><span class="line"><span class="cl">    <span class="kd">var</span> <span class="nx">request</span> <span class="o">=</span> <span class="nx">split_request</span><span class="p">(</span><span class="nx">stanza</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="nx">request</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">execute_command</span><span class="p">(</span><span class="nx">request</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">send_unknown_command_message</span><span class="p">(</span><span class="nx">request</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>The first step in the code addresses a common oversight; an XMPP client must not respond to a stanza with a type of <code>error</code>. In this instance we should log it to the console using <code>util</code> for debugging purposes.</p>
<p>If the stanza is a message then this function will log it to the console and attempt to split it up into a custom request object created by the <code>split_request()</code> function (defined in the next code block). Given that a valid request has been made it will then attempt to execute the supplied command.</p>
<p>Should the command not exist it will send the user an error message suggesting that they try again or consult the help text.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">split_request</span><span class="p">(</span><span class="nx">stanza</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kd">var</span> <span class="nx">message_body</span> <span class="o">=</span> <span class="nx">stanza</span><span class="p">.</span><span class="nx">getChildText</span><span class="p">(</span><span class="s2">&#34;body&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="p">(</span><span class="kc">null</span> <span class="o">!==</span> <span class="nx">message_body</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">message_body</span> <span class="o">=</span> <span class="nx">message_body</span><span class="p">.</span><span class="nx">split</span><span class="p">(</span><span class="nx">config</span><span class="p">.</span><span class="nx">command_argument_separator</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="kd">var</span> <span class="nx">command</span> <span class="o">=</span> <span class="nx">message_body</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">trim</span><span class="p">().</span><span class="nx">toLowerCase</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="s2">&#34;help&#34;</span> <span class="o">===</span> <span class="nx">command</span> <span class="o">||</span> <span class="s2">&#34;?&#34;</span> <span class="o">==</span> <span class="nx">command</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">send_help_information</span><span class="p">(</span><span class="nx">stanza</span><span class="p">.</span><span class="nx">attrs</span><span class="p">.</span><span class="nx">from</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="k">typeof</span> <span class="nx">message_body</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">!==</span> <span class="s2">&#34;undefined&#34;</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="k">return</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">command</span><span class="o">:</span> <span class="nx">command</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">argument</span><span class="o">:</span> <span class="nx">message_body</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="nx">trim</span><span class="p">(),</span>
</span></span><span class="line"><span class="cl">        <span class="nx">stanza</span><span class="o">:</span> <span class="nx">stanza</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="p">};</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="kc">false</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>This simply extracts the message text from the supplied stanza object and then splits the message using the regular expression defined earlier in the configuration file. By default this will split on a semicolon and allow for any amount of white space surrounding the separator (<code>/\s*;\s*/</code>).</p>
<p>The command is assumed to be the first part of the message before the separator and the argument is after it. The following is an example of what a command message sent by a user might look like:</p>
<blockquote>
<p>s;This is the bot’s new status message!!</p>
</blockquote>
<p>If the user has simply typed help or ? then we should send them a message explaining the available commands otherwise the function will construct the <code>request</code> object.</p>
<p>The <code>request</code> object consists of the command string, an <code>argument</code> string and the full initial <code>stanza</code> object that was sent to the bot for processing.</p>
<p>Now let’s attach the dispatcher to an event so that it is triggered when each new stanza comes in over the wire.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="nx">conn</span><span class="p">.</span><span class="nx">addListener</span><span class="p">(</span><span class="s2">&#34;stanza&#34;</span><span class="p">,</span> <span class="nx">message_dispatcher</span><span class="p">);</span>
</span></span></code></pre></div><h1 id="handling-errors-and-help">Handling errors and help</h1>
<p>In the previous section the <code>send_help_information()</code> and <code>send_unknown_command_message()</code> functions were mentioned so here they are!</p>
<p>The help function outputs a simple message that describes how the user can make use of the bot’s commands.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">send_help_information</span><span class="p">(</span><span class="nx">to_jid</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kd">var</span> <span class="nx">message_body</span> <span class="o">=</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;Currently bounce (b), twitter (t) and status (s) are supported:\n&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">message_body</span> <span class="o">+=</span> <span class="s2">&#34;b;example text\n&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">message_body</span> <span class="o">+=</span> <span class="s2">&#34;t;some search string\n&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">message_body</span> <span class="o">+=</span> <span class="s2">&#34;s;A new status message\n&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">send_message</span><span class="p">(</span><span class="nx">to_jid</span><span class="p">,</span> <span class="nx">message_body</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Should the user attempt to access a command that the bot does not recognise then they will be sent an error message.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">send_unknown_command_message</span><span class="p">(</span><span class="nx">request</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">send_message</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="nx">request</span><span class="p">.</span><span class="nx">stanza</span><span class="p">.</span><span class="nx">attrs</span><span class="p">.</span><span class="nx">from</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;Unknown command: &#34;&#39;</span> <span class="o">+</span>
</span></span><span class="line"><span class="cl">      <span class="nx">request</span><span class="p">.</span><span class="nx">command</span> <span class="o">+</span>
</span></span><span class="line"><span class="cl">      <span class="s1">&#39;&#34;. Send &#34;help&#34; for more information.&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>As you may have noticed both of these functions depend upon the <code>send_message()</code> helper function that we have yet to define.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">send_message</span><span class="p">(</span><span class="nx">to_jid</span><span class="p">,</span> <span class="nx">message_body</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kd">var</span> <span class="nx">elem</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">xmpp</span><span class="p">.</span><span class="nx">Element</span><span class="p">(</span><span class="s2">&#34;message&#34;</span><span class="p">,</span> <span class="p">{</span> <span class="nx">to</span><span class="o">:</span> <span class="nx">to_jid</span><span class="p">,</span> <span class="nx">type</span><span class="o">:</span> <span class="s2">&#34;chat&#34;</span> <span class="p">})</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">c</span><span class="p">(</span><span class="s2">&#34;body&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">t</span><span class="p">(</span><span class="nx">message_body</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="nx">conn</span><span class="p">.</span><span class="nx">send</span><span class="p">(</span><span class="nx">elem</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="nx">util</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;[message] SENT: &#34;</span> <span class="o">+</span> <span class="nx">elem</span><span class="p">.</span><span class="nx">up</span><span class="p">().</span><span class="nx">toString</span><span class="p">());</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>This function accepts two strings as parameters; the JID of the receiving user and the message text. All messages that are sent are also logged to the console using the <code>util</code> package.</p>
<p>Finally we also need to add a handler for system error events originating from node-xmpp:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="nx">conn</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s2">&#34;error&#34;</span><span class="p">,</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">stanza</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">util</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;[error] &#34;</span> <span class="o">+</span> <span class="nx">stanza</span><span class="p">.</span><span class="nx">toString</span><span class="p">());</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><h1 id="increasing-ones-vocabulary">Increasing one’s vocabulary</h1>
<p>This is another good point to test your bot as there is already a command you can use: “s;My new status message” and error messages to provoke. This should be working flawlessly before you continue to add new functionality to the bot.</p>
<p>As the help function text alluded to earlier there will be two further commands added to the bot in this tutorial.</p>
<p>The first of which is the bounce functionality; when sent a message by the user the bot will bounce it straight back to them. This is a useful sanity check for when you are testing the bot as you add extra commands.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="nx">add_command</span><span class="p">(</span><span class="s2">&#34;b&#34;</span><span class="p">,</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">request</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">send_message</span><span class="p">(</span><span class="nx">request</span><span class="p">.</span><span class="nx">stanza</span><span class="p">.</span><span class="nx">attrs</span><span class="p">.</span><span class="nx">from</span><span class="p">,</span> <span class="nx">request</span><span class="p">.</span><span class="nx">stanza</span><span class="p">.</span><span class="nx">getChildText</span><span class="p">(</span><span class="s2">&#34;body&#34;</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="kc">true</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><h1 id="going-global-with-twitter">Going global with Twitter</h1>
<p>Next up the bot will talk to the outside world by searching Twitter for the user supplied request argument against the public JSON API.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="nx">add_command</span><span class="p">(</span><span class="s2">&#34;t&#34;</span><span class="p">,</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">request</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kd">var</span> <span class="nx">to_jid</span> <span class="o">=</span> <span class="nx">request</span><span class="p">.</span><span class="nx">stanza</span><span class="p">.</span><span class="nx">attrs</span><span class="p">.</span><span class="nx">from</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">send_message</span><span class="p">(</span><span class="nx">to_jid</span><span class="p">,</span> <span class="s2">&#34;Searching twitter, please be patient...&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="kd">var</span> <span class="nx">url</span> <span class="o">=</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;http://search.twitter.com/search.json?rpp=5&amp;show_user=true&amp;lang=en&amp;q=&#34;</span> <span class="o">+</span>
</span></span><span class="line"><span class="cl">    <span class="nb">encodeURIComponent</span><span class="p">(</span><span class="nx">request</span><span class="p">.</span><span class="nx">argument</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="nx">request_helper</span><span class="p">(</span><span class="nx">url</span><span class="p">,</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">error</span><span class="p">,</span> <span class="nx">response</span><span class="p">,</span> <span class="nx">body</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">error</span> <span class="o">&amp;&amp;</span> <span class="nx">response</span><span class="p">.</span><span class="nx">statusCode</span> <span class="o">==</span> <span class="mi">200</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="kd">var</span> <span class="nx">body</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="nx">body</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">      <span class="k">if</span> <span class="p">(</span><span class="nx">body</span><span class="p">.</span><span class="nx">results</span><span class="p">.</span><span class="nx">length</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">for</span> <span class="p">(</span><span class="kd">var</span> <span class="nx">i</span> <span class="k">in</span> <span class="nx">body</span><span class="p">.</span><span class="nx">results</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="nx">send_message</span><span class="p">(</span><span class="nx">to_jid</span><span class="p">,</span> <span class="nx">body</span><span class="p">.</span><span class="nx">results</span><span class="p">[</span><span class="nx">i</span><span class="p">].</span><span class="nx">text</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">send_message</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">          <span class="nx">to_jid</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="s2">&#34;There are no results for your query. Please try again.&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="p">);</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">send_message</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="nx">to_jid</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;Twitter was unable to provide a satisfactory response. Please try again.&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">});</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="kc">true</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><p>Whilst the function is the longest in the bot so far it is also possibly the easiest to follow so I will skip to the more interesting bits.</p>
<p>The <code>request_helper</code> object was created at the top of the bot.js file right at the beginning of the tutorial and now it is finally coming to some use. It is basically a nice simple wrapper around the <code>httpClient</code> functionality provided in Node.js by default.</p>
<p>If the request receives a satisfactory response then the JSON will be parsed and each tweet is sent to the user as a new message.</p>
<h1 id="c-ya-l8r">C ya l8r</h1>
<p>So you now possess a complete Google Talk bot (don’t get too giddy!), which you can easily add new functionality to with <code>add_command()</code>. It is pretty neat, but what use is it?</p>
<p>Perhaps you could program it to message you whenever a server drops offline or when your continuous integration builds break.</p>
<p>If your bot needs to handle exceptionally large numbers of users then you may wish to consider refactoring it as an XMPP Component rather than a XMPP Client (node-xmpp makes this very easy). The Twitter bot reached its limit with 40,000 subscribers though so there is plenty of head room with a client based bot.</p>
<h1 id="further-resources">Further resources</h1>
<ul>
<li><a href="http://www.amazon.co.uk/gp/product/1617290572/ref=as_li_ss_tl?ie=UTF8&amp;camp=1634&amp;creative=19450&amp;creativeASIN=1617290572&amp;linkCode=as2&amp;tag=simonholywell-21">Node.js in Action</a></li>
<li><a href="http://www.amazon.co.uk/gp/product/1449337392/ref=as_li_ss_tl?ie=UTF8&amp;camp=1634&amp;creative=19450&amp;creativeASIN=1449337392&amp;linkCode=as2&amp;tag=simonholywell-21">Building Node Applications with MongoDB and Backbone</a></li>
<li><a href="http://www.amazon.co.uk/gp/product/1449398588/ref=as_li_ss_tl?ie=UTF8&amp;camp=1634&amp;creative=19450&amp;creativeASIN=1449398588&amp;linkCode=as2&amp;tag=simonholywell-21">Node: Up and Running: Scalable Server-Side Code with JavaScript</a></li>
<li><a href="http://www.amazon.co.uk/gp/product/059652126X/ref=as_li_ss_tl?ie=UTF8&amp;camp=1634&amp;creative=19450&amp;creativeASIN=059652126X&amp;linkCode=as2&amp;tag=simonholywell-21">XMPP: The Definitive Guide: Building Real-Time Applications with Jabber Technologies</a></li>
<li><a href="http://www.amazon.co.uk/gp/product/0470540710/ref=as_li_ss_tl?ie=UTF8&amp;camp=1634&amp;creative=19450&amp;creativeASIN=0470540710&amp;linkCode=as2&amp;tag=simonholywell-21">Professional XMPP Programming with JavaScript and jQuery</a></li>
</ul>
<h1 id="stay-in-touch">Stay in touch</h1>
<p>If you liked this article then please <a href="https://twitter.com/Treffynnon">follow me on Twitter</a> and let me know.</p>
<blockquote>
<p><strong>note</strong></p>
<p><a href="/post/2013/02/create-a-node-js-google-talk-bot-pt1.html">Part one</a> of this article is also published on my blog.</p>
<p>This article was originally published in the <a href="/post/2012/02/create-a-google-talk-bot-with-nodejs.html">April 2012 issue</a> of <a href="http://www.netmagazine.com">.net Magazine</a>.</p>
<p>In tandem with the Google bot tutorial I wrote four smaller articles:</p>
<ul>
<li><a href="/post/2013/02/node-js-eco-system.html">The Node.js eco-system</a></li>
<li><a href="/post/2013/02/xmpp-and-jabber.html">XMPP and Jabber</a></li>
<li><a href="/post/2013/02/node-js-in-the-real-world.html">Node.js in the real world</a></li>
<li><a href="/post/2013/02/node-js-for-hosting-websites.html">Node.js for hosting websites</a></li>
</ul>
</blockquote>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="nodejs" label="Nodejs"/><category scheme="taxonomy:Tags" term="google-talk" label="Google Talk"/><category scheme="taxonomy:Tags" term="published" label="published"/><category scheme="taxonomy:Tags" term="net-magazine" label="net Magazine"/></entry><entry xml:base="node-js-for-hosting-websites"><title type="html">Node.js for hosting websites</title><link href="https://www.simonholywell.com/post/2013/02/node-js-for-hosting-websites/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2013/02/node-js-in-the-real-world/?utm_source=atom_feed" rel="related" type="text/html" title="Node.js in the real world"/><link href="https://www.simonholywell.com/post/2013/02/node-js-eco-system/?utm_source=atom_feed" rel="related" type="text/html" title="The Node.js eco-system"/><link href="https://www.simonholywell.com/post/2013/02/create-a-node-js-google-talk-bot-pt1/?utm_source=atom_feed" rel="related" type="text/html" title="Create a Google Talk bot with Node.js: Part One"/><link href="https://www.simonholywell.com/post/2013/02/xmpp-and-jabber/?utm_source=atom_feed" rel="related" type="text/html" title="XMPP and Jabber"/><link href="https://www.simonholywell.com/post/2011/10/getting-started-node-js-couch-db/?utm_source=atom_feed" rel="related" type="text/html" title="Getting started with Node.js and CouchDB"/><id>https://www.simonholywell.com/post/2013/02/node-js-for-hosting-websites/</id><author><name>Simon Holywell</name></author><published>2013-02-26T12:01:32+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Whilst Node.js is primarily aimed at creating non-blocking servers it can also be used to host simple web pages such as homepages and blogs.
We are going to be using a simple web framework for Node.js called Express (http://expressjs.com), which can be installed via the Node Package Manager on the command line.
npm install express Firstly, create a new file called server.js and begin by instantiating the express framework.
var app = require(&amp;#34;express&amp;#34;).</summary><content type="html"><![CDATA[<p>Whilst Node.js is primarily aimed at creating non-blocking servers it can also be used to host simple web pages such as homepages and blogs.</p>
<p>We are going to be using a simple web framework for Node.js called Express (<a href="http://expressjs.com">http://expressjs.com</a>), which can be installed via the Node Package Manager on the command line.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">npm install express
</span></span></code></pre></div><p>Firstly, create a new file called server.js and begin by instantiating the express framework.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">app</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s2">&#34;express&#34;</span><span class="p">).</span><span class="nx">createServer</span><span class="p">();</span>
</span></span></code></pre></div><p>The server now needs a web route to dispatch, so define the URL and pass in a callback function to handle the request.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="nx">app</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s2">&#34;/hello/:name&#34;</span><span class="p">,</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">request</span><span class="p">,</span> <span class="nx">response</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">response</span><span class="p">.</span><span class="nx">send</span><span class="p">(</span><span class="s2">&#34;Hello &#34;</span> <span class="o">+</span> <span class="nx">request</span><span class="p">.</span><span class="nx">params</span><span class="p">.</span><span class="nx">name</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><p>See how <code>:name</code> in the route becomes a variable you can access in the request parameters and is used in the response text from the server.</p>
<p>Finally from the server point of view you need to define a port number to listen to incoming requests on.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="nx">app</span><span class="p">.</span><span class="nx">listen</span><span class="p">(</span><span class="mi">3000</span><span class="p">);</span>
</span></span></code></pre></div><p>If you now run node server.js on the command line and navigate to <a href="http://localhost:3000/hello/Test">http://localhost:3000/hello/Test</a> in your web browser you will see the page you just created. Try swapping Test for your name in the URL and refresh the browser.</p>
<p>Now you are able to create simple pages with the Express framework and Node.js. For further experimentation you could take a look at using Jade (jade-lang.com) as a template engine and making use of static routes to serve images and CSS files.</p>
<p>If you like this article then you will probably also be interested in <a href="/post/2011/10/getting-started-node-js-couch-db.html">Getting started with Node.js and CouchDB</a> and <a href="/post/2011/10/nodester-environment-variables-for-sensitive-data.html">Nodester environment variables for sensitive data and passwords</a>.</p>
<blockquote>
<p><strong>note</strong></p>
<p>This article was originally published in the <a href="/post/2012/02/create-a-google-talk-bot-with-nodejs.html">April 2012 issue</a> of <a href="http://www.netmagazine.com">.net Magazine</a>.</p>
<p>The accompanying tutorial to create a Google Talk bot with Node.js is also <a href="/post/2013/02/create-a-node-js-google-talk-bot-pt1.html">published on my blog</a>.</p>
<p>In tandem with the Google bot tutorial I wrote four smaller articles:</p>
<ul>
<li><a href="/post/2013/02/node-js-eco-system.html">The Node.js eco-system</a></li>
<li><a href="/post/2013/02/xmpp-and-jabber.html">XMPP and Jabber</a></li>
<li><a href="/post/2013/02/node-js-in-the-real-world.html">Node.js in the real world</a></li>
<li><a href="/post/2013/02/node-js-for-hosting-websites.html">Node.js for hosting websites</a></li>
</ul>
</blockquote>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="nodejs" label="Nodejs"/><category scheme="taxonomy:Tags" term="express" label="Express"/><category scheme="taxonomy:Tags" term="published" label="published"/><category scheme="taxonomy:Tags" term="net-magazine" label="net Magazine"/></entry><entry xml:base="node-js-in-the-real-world"><title type="html">Node.js in the real world</title><link href="https://www.simonholywell.com/post/2013/02/node-js-in-the-real-world/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2013/02/node-js-eco-system/?utm_source=atom_feed" rel="related" type="text/html" title="The Node.js eco-system"/><link href="https://www.simonholywell.com/post/2013/02/create-a-node-js-google-talk-bot-pt1/?utm_source=atom_feed" rel="related" type="text/html" title="Create a Google Talk bot with Node.js: Part One"/><link href="https://www.simonholywell.com/post/2013/02/xmpp-and-jabber/?utm_source=atom_feed" rel="related" type="text/html" title="XMPP and Jabber"/><link href="https://www.simonholywell.com/post/2011/10/getting-started-node-js-couch-db/?utm_source=atom_feed" rel="related" type="text/html" title="Getting started with Node.js and CouchDB"/><link href="https://www.simonholywell.com/post/2013/02/php-ssdeep-in-git/?utm_source=atom_feed" rel="related" type="text/html" title="ssdeep PHP extension in git"/><id>https://www.simonholywell.com/post/2013/02/node-js-in-the-real-world/</id><author><name>Simon Holywell</name></author><published>2013-02-20T14:19:04+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>With Node.js yet to reach a major release you may be wondering if it is mature enough for production environments and live projects. Whilst it is also true, in the past, that the Node.js creators have warned off people with mission critical objectives it is now in a much more stable state.
Some well known companies including Plurk, LinkedIn and GitHub are using Node.js to deliver vital parts of their offerings everyday.</summary><content type="html"><![CDATA[<p>With Node.js yet to reach a major release you may be wondering if it is mature enough for production environments and live projects. Whilst it is also true, in the past, that the Node.js creators have warned off people with mission critical objectives it is now in a much more stable state.</p>
<p>Some well known companies including Plurk, LinkedIn and GitHub are using Node.js to deliver vital parts of their offerings everyday. In the case of Plurk this was a publicised move in January 2010 from Java and JBoss Netty to Node.js for a stated ten fold decrease in memory usage across their application. This version of Plurk is still live today and serving over 100k open connections simultaneously at any given moment.</p>
<p>LinkedIn have employed Node.js to handle the server aspect of their mobile applications. In pre-launch testing they estimated that the switch away from Ruby on Rails would take them from fifteen servers to just one whilst being able to handle over twice the traffic load.</p>
<p>Other companies such as Klout, Transloadit and LearnBoost (the team behind Socket.IO) are betting their main infrastructure on Node.js.</p>
<p>Yahoo! have also experimented with it internally most notably in the Yahoo! Mail and YUI Library groups, but nothing has been publicly launched at this time.</p>
<p>Another notable mention goes to the search engine DuckDuckGo who are using Node.js to power their XMPP bot at <a href="mailto:im@ddg.gg">im@ddg.gg</a>.</p>
<p>Of course it should also be noted that Node.js has a commercial sponsor of development in the form of Joyent with Node.js creator, Ryan Dahl, on their books. In addition they offer hosting on their SmartMachines service and also organise the Node.js Camp conference.</p>
<p>So even if it is to remain a peripheral technology for you it is well worth keeping an eye on its progress in the future. For the more adventurous it may just become a full time vocation with both Klout and Yahoo! looking for more Node.js engineers at the time of writing.</p>
<blockquote>
<p><strong>note</strong></p>
<p>This article was originally published in the <a href="/post/2012/02/create-a-google-talk-bot-with-nodejs.html">April 2012 issue</a> of <a href="http://www.netmagazine.com">.net Magazine</a>.</p>
<p>The accompanying tutorial to create a Google Talk bot with Node.js is also <a href="/post/2013/02/create-a-node-js-google-talk-bot-pt1.html">published on my blog</a>.</p>
<p>In tandem with the Google bot tutorial I wrote four smaller articles:</p>
<ul>
<li><a href="/post/2013/02/node-js-eco-system.html">The Node.js eco-system</a></li>
<li><a href="/post/2013/02/xmpp-and-jabber.html">XMPP and Jabber</a></li>
<li><a href="/post/2013/02/node-js-in-the-real-world.html">Node.js in the real world</a></li>
<li><a href="/post/2013/02/node-js-for-hosting-websites.html">Node.js for hosting websites</a></li>
</ul>
</blockquote>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="nodejs" label="Nodejs"/><category scheme="taxonomy:Tags" term="published" label="published"/><category scheme="taxonomy:Tags" term="net-magazine" label="net Magazine"/></entry><entry xml:base="xmpp-and-jabber"><title type="html">XMPP and Jabber</title><link href="https://www.simonholywell.com/post/2013/02/xmpp-and-jabber/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2013/02/node-js-eco-system/?utm_source=atom_feed" rel="related" type="text/html" title="The Node.js eco-system"/><link href="https://www.simonholywell.com/post/2013/02/create-a-node-js-google-talk-bot-pt1/?utm_source=atom_feed" rel="related" type="text/html" title="Create a Google Talk bot with Node.js: Part One"/><link href="https://www.simonholywell.com/post/2013/02/php-ssdeep-in-git/?utm_source=atom_feed" rel="related" type="text/html" title="ssdeep PHP extension in git"/><link href="https://www.simonholywell.com/post/2013/02/git-tag-secrets/?utm_source=atom_feed" rel="related" type="text/html" title="Git tag secrets"/><link href="https://www.simonholywell.com/post/2013/01/idiorm-and-paris-the-minimalist-orm/?utm_source=atom_feed" rel="related" type="text/html" title="Idiorm and Paris 1.3.0 released - the minimalist ORM and fluent query builder for PHP"/><id>https://www.simonholywell.com/post/2013/02/xmpp-and-jabber/</id><author><name>Simon Holywell</name></author><published>2013-02-18T12:34:16+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Jabber was originally invented by Jeremie Miller in 1998 who was sick of using many different closed protocol instant messenger clients. To begin fixing this situation he created jabberd as an open source server in 1999 and by May of the next year version 1.0 was released.
Over the course of the last twelve or so years Jabber has evolved into a standards organisation (XMPP Standards Foundation) and developed an open industry standard for instant messaging called the Extensible Messaging and Presence Protocol (XMPP).</summary><content type="html"><![CDATA[<p>Jabber was originally invented by Jeremie Miller in 1998 who was sick of using many different closed protocol instant messenger clients. To begin fixing this situation he created jabberd as an open source server in 1999 and by May of the next year version 1.0 was released.</p>
<p>Over the course of the last twelve or so years Jabber has evolved into a standards organisation (XMPP Standards Foundation) and developed an open industry standard for instant messaging called the Extensible Messaging and Presence Protocol (XMPP). As the name suggests XMPP is created using XML, which forms the basis for the systems message stanzas.</p>
<p>The protocol has been stable for sometime and now enables projects to take advantage of instant messaging, presence, conference and video chat. With all this on tap Google are not the only ones working with XMPP.</p>
<p>AOL Instant Messenger, Skype and Facebook have dabbled with the protocol although more recently Microsoft have announced that the Windows Live APIs support XMPP. This will allow any software to communicate with Windows Live Messenger via Live Connect. Apple, Cisco, IBM, Nokia (Ovi) and Sun have also made use of XMPP in one way or another in various projects.</p>
<p>More recently Google and XMPP have added a draft extension to the protocol called Jingle, which enables voice over IP and video conferencing. Whilst it is yet to be fully approved it is at a stage where it is ready for deployment with the libjingle library used by Google Talk freely available under a BSD licence.</p>
<p>One surprising implementation that demonstrates the flexibility of the protocol is RemoteVNC (an application to remotely control a computer), which uses Jingle to share desktops between users.</p>
<p>Some other implementations of the system include team collaboration, geo location and vehicle tracking, data syndication, identity services and even games.</p>
<p>The XMPP website (<a href="http://xmpp.org">http://xmpp.org</a>) maintains a large catalogue of client applications, server software and code API libraries along with full specifications for each aspect of the protocol so it is an excellent place to start learning more about the standard.</p>
<p>Join in the <a href="http://news.ycombinator.com/item?id=5250579">conversation about this article</a> on Hacker News.</p>
<blockquote>
<p><strong>note</strong></p>
<p>This article was originally published in the <a href="/post/2012/02/create-a-google-talk-bot-with-nodejs.html">March 2012 issue</a> of <a href="http://www.netmagazine.com">.net Magazine</a>.</p>
<p>The accompanying tutorial to create a Google Talk bot with Node.js is also <a href="/post/2013/02/create-a-node-js-google-talk-bot-pt1.html">published on my blog</a>.</p>
<p>In tandem with the Google bot tutorial I wrote four smaller articles:</p>
<ul>
<li><a href="/post/2013/02/node-js-eco-system.html">The Node.js eco-system</a></li>
<li><a href="/post/2013/02/xmpp-and-jabber.html">XMPP and Jabber</a></li>
<li><a href="/post/2013/02/node-js-in-the-real-world.html">Node.js in the real world</a></li>
<li><a href="/post/2013/02/node-js-for-hosting-websites.html">Node.js for hosting websites</a></li>
</ul>
</blockquote>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="xmpp" label="XMPP"/><category scheme="taxonomy:Tags" term="jabber" label="Jabber"/><category scheme="taxonomy:Tags" term="published" label="published"/><category scheme="taxonomy:Tags" term="net-magazine" label="net Magazine"/></entry><entry xml:base="php-ssdeep-in-git"><title type="html">ssdeep PHP extension in git</title><link href="https://www.simonholywell.com/post/2013/02/php-ssdeep-in-git/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2011/07/how-php-ssdeep-was-made/?utm_source=atom_feed" rel="related" type="text/html" title="How the ssdeep PHP extension came into being"/><link href="https://www.simonholywell.com/post/2010/10/pecl-install-issues-on-redhat/?utm_source=atom_feed" rel="related" type="text/html" title="PECL Install Issues on Redhat"/><link href="https://www.simonholywell.com/post/2010/09/15-excellent-resources-for-php-extension-development/?utm_source=atom_feed" rel="related" type="text/html" title="15 Excellent Resources for PHP Extension Development"/><link href="https://www.simonholywell.com/post/2010/09/php-ssdeep-in-pecl/?utm_source=atom_feed" rel="related" type="text/html" title="The PHP ssdeep Extension is Now in PECL"/><link href="https://www.simonholywell.com/post/2011/10/php-extensions-made-elrich/?utm_source=atom_feed" rel="related" type="text/html" title="PHP extension writing: PHP Extensions Made Eldrich"/><id>https://www.simonholywell.com/post/2013/02/php-ssdeep-in-git/</id><author><name>Simon Holywell</name></author><published>2013-02-13T16:12:43+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>The PHP project as a whole has been migrating to use git as its SCM of choice. This includes the core code and some PECL extensions such as BitSet and the sources for the PHP.net web properties like wiki.php.net
Well now the PHP team have helped me to migrate the source of ssdeep to git, which means it is now also mirrored (where you can star it) to the official PHP github account.</summary><content type="html"><![CDATA[<p>The PHP project as a whole has been migrating to use git as its SCM of choice. This includes the <a href="http://git.php.net/?p=php-src.git;a=summary">core code</a> and some PECL extensions such as <a href="http://git.php.net/?p=pecl/numbers/bitset.git;a=summary">BitSet</a> and the sources for the PHP.net web properties like <a href="http://git.php.net/?p=web/wiki.git;a=summary">wiki.php.net</a></p>
<p>Well now the PHP team have helped me to migrate the source of <a href="http://git.php.net/?p=pecl/text/ssdeep.git;a=summary">ssdeep to git</a>, which means it is now also <a href="https://github.com/php/pecl-text-ssdeep">mirrored</a> (where you can star it) to the official <a href="https://github.com/php">PHP github account</a>. If you also maintain a PECL extension then you might be interested in the <a href="http://news.php.net/php.pecl.dev/10317">thread I created</a> on the pecl.dev mailing list.</p>
<p>If you do not know what the <a href="http://pecl.php.net/package/ssdeep">ssdeep extension</a> is then I have previously <a href="/post/2011/07/how-php-ssdeep-was-made.html">written a post</a> describing it and how it came into being.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="php" label="php"/><category scheme="taxonomy:Tags" term="php_ssdeep" label="php_ssdeep"/><category scheme="taxonomy:Tags" term="php-extensions" label="php extensions"/><category scheme="taxonomy:Tags" term="git" label="git"/></entry><entry xml:base="node-js-eco-system"><title type="html">The Node.js eco-system</title><link href="https://www.simonholywell.com/post/2013/02/node-js-eco-system/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2013/02/create-a-node-js-google-talk-bot-pt1/?utm_source=atom_feed" rel="related" type="text/html" title="Create a Google Talk bot with Node.js: Part One"/><link href="https://www.simonholywell.com/post/2011/10/getting-started-node-js-couch-db/?utm_source=atom_feed" rel="related" type="text/html" title="Getting started with Node.js and CouchDB"/><link href="https://www.simonholywell.com/post/2013/02/git-tag-secrets/?utm_source=atom_feed" rel="related" type="text/html" title="Git tag secrets"/><link href="https://www.simonholywell.com/post/2013/01/idiorm-and-paris-the-minimalist-orm/?utm_source=atom_feed" rel="related" type="text/html" title="Idiorm and Paris 1.3.0 released - the minimalist ORM and fluent query builder for PHP"/><link href="https://www.simonholywell.com/post/2013/01/unicode-shortcut-in-netbeans/?utm_source=atom_feed" rel="related" type="text/html" title="Unicode shortcut in Netbeans for React/Curry"/><id>https://www.simonholywell.com/post/2013/02/node-js-eco-system/</id><author><name>Simon Holywell</name></author><published>2013-02-13T13:51:16+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>JavaScript started life as a project named Mocha created by Brendan Eich at Netscape in 1995. By the time Netscape Navigator 2.0 was due for release the language had changed names twice becoming LiveScript and then, finally, JavaScript (JS).
Originally Netscape were considering a derivative of Scheme for client side scripting, but swept up in the buzz of Sun’s Java at the time management stated that the language must look like Java.</summary><content type="html"><![CDATA[<p>JavaScript started life as a project named Mocha created by Brendan Eich at Netscape in 1995. By the time Netscape Navigator 2.0 was due for release the language had changed names twice becoming LiveScript and then, finally, JavaScript (JS).</p>
<p>Originally Netscape were considering a derivative of Scheme for client side scripting, but swept up in the buzz of Sun’s Java at the time management stated that the language must look like Java. Eich famously prototyped JS in just 10 days, which is astounding given the exposure the language would receive over the course of the next 16 years.</p>
<p>Server Side JavaScript (SSJS) is nothing new with Netscape’s LiveWire launching in 1996 in the Enterprise Server 2.0 offering. Since then there have been a number of projects built upon the venerable Rhino engine, but it was not until recently that blistering performance has been brought to SSJS.</p>
<p>One such advancement is Google’s V8 JavaScript engine, which underpins Node.js.</p>
<p>The popularity wave that Node.js currently rides upon is mostly focussed on its efficiency. It is at its best when serving short lived requests to many clients such as instant messaging, poll or rating applications for example rather than crunching numbers on the next aircraft wing design for days on end.</p>
<p>A concern for the Node.js project is born out of the event driven nature it employs with each action requiring a callback. This can lead to confusing code with nested callback functions obscuring the real business goals unless it is carefully managed.</p>
<p>There are rivals to Node.js out there looking to fulfil your SSJS needs such as Aptana’s Jaxer (similar to LiveWire), EJScript and RingoJS among others. All of them approach the task of JavaScript on the server in slightly different ways and therefore maybe a better fit for certain situations.</p>
<p>All these projects share one similarity though; rapidly evolving APIs, which can lead to your projects being left behind in obsolescence unless you keep on top of the changes.</p>
<p>Their ease of use makes them ideal for rapid development and prototyping, but their continuous evolution should also be factored into your language selection decision.</p>
<blockquote>
<p><strong>note</strong></p>
<p>This article was originally published in the <a href="/post/2012/02/create-a-google-talk-bot-with-nodejs.html">March 2012 issue</a> of <a href="http://www.netmagazine.com">.net Magazine</a>.</p>
<p>The accompanying tutorial to create a Google Talk bot with Node.js is also <a href="/post/2013/02/create-a-node-js-google-talk-bot-pt1.html">published on my blog</a>.</p>
<p>In tandem with the Google bot tutorial I wrote four smaller articles:</p>
<ul>
<li><a href="/post/2013/02/node-js-eco-system.html">The Node.js eco-system</a></li>
<li><a href="/post/2013/02/xmpp-and-jabber.html">XMPP and Jabber</a></li>
<li><a href="/post/2013/02/node-js-in-the-real-world.html">Node.js in the real world</a></li>
<li><a href="/post/2013/02/node-js-for-hosting-websites.html">Node.js for hosting websites</a></li>
</ul>
</blockquote>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="nodejs" label="Nodejs"/><category scheme="taxonomy:Tags" term="published" label="published"/><category scheme="taxonomy:Tags" term="net-magazine" label="net Magazine"/></entry><entry xml:base="create-a-node-js-google-talk-bot-pt1"><title type="html">Create a Google Talk bot with Node.js: Part One</title><link href="https://www.simonholywell.com/post/2013/02/create-a-node-js-google-talk-bot-pt1/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2011/10/getting-started-node-js-couch-db/?utm_source=atom_feed" rel="related" type="text/html" title="Getting started with Node.js and CouchDB"/><link href="https://www.simonholywell.com/post/2013/02/git-tag-secrets/?utm_source=atom_feed" rel="related" type="text/html" title="Git tag secrets"/><link href="https://www.simonholywell.com/post/2013/01/idiorm-and-paris-the-minimalist-orm/?utm_source=atom_feed" rel="related" type="text/html" title="Idiorm and Paris 1.3.0 released - the minimalist ORM and fluent query builder for PHP"/><link href="https://www.simonholywell.com/post/2013/01/unicode-shortcut-in-netbeans/?utm_source=atom_feed" rel="related" type="text/html" title="Unicode shortcut in Netbeans for React/Curry"/><link href="https://www.simonholywell.com/post/2013/01/navigator-geographic-calculations-library-for-php/?utm_source=atom_feed" rel="related" type="text/html" title="Navigator: Geographic calculation library for PHP"/><id>https://www.simonholywell.com/post/2013/02/create-a-node-js-google-talk-bot-pt1/</id><author><name>Simon Holywell</name></author><published>2013-02-06T13:35:23+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Programming a chat bot was once the domain of the hardcore hacker tapping packets as they passed over the wire from proprietary client applications to closed source servers, but not any more!
With the open Extensible Messaging and Presence Protocol (XMPP) once closed networks are becoming accessible to the rest of us. I selected Google Talk as it is probably the most well known implementation of XMPP and it is easy and free to sign up for, but Windows Live Messenger, AIM and Skype all support it to some extent.</summary><content type="html"><![CDATA[<p>Programming a chat bot was once the domain of the hardcore hacker tapping packets as they passed over the wire from proprietary client applications to closed source servers, but not any more!</p>
<p>With the open Extensible Messaging and Presence Protocol (XMPP) once closed networks are becoming accessible to the rest of us. I selected Google Talk as it is probably the most well known implementation of XMPP and it is easy and free to sign up for, but Windows Live Messenger, AIM and Skype all support it to some extent.</p>
<p>As an open protocol XMPP is supported by a large number of messaging networks and clients for just about all web enabled devices, which means your bot will also be able to communicate with users on other XMPP servers such as Jabber.</p>
<blockquote>
<p><strong>note</strong></p>
<p>This article was originally published in the <a href="/post/2012/02/create-a-google-talk-bot-with-nodejs.html">March 2012 issue</a> of <a href="http://www.netmagazine.com">.net Magazine</a>. You can also <a href="http://dl.dropbox.com/u/3913347/Create%20a%20Google%20Talk%20bot%20with%20Node.js%20-%20Part%20One.pdf">download a PDF</a> of the original article.</p>
<p>There is a demo bot for this article documented at <a href="http://njsbot.simonholywell.com">http://njsbot.simonholywell.com</a> and the <a href="https://github.com/treffynnon/njsbot">complete code is on github</a>.</p>
</blockquote>
<h1 id="lets-get-set-up">Let’s get set up</h1>
<p>Firstly, an admission; I use Linux as my main desktop operating system so these setup instructions are taken from that environment, but also apply to Mac OS systems. On Windows you can either use Cygwin or a Linux virtual machine such as Ubuntu.</p>
<p>I am going to assume that you are familiar with Node.js and already have it and the NPM (Node Package Manager) installed and working. If not then there is great installation documentation on both their respective websites.</p>
<p>One of the Node.js packages (node-xmpp) we are going to be using has an external dependency on libexpat1-dev for its XML parsing. Some Linux distributions and Mac OS appear to come with this by default, but Ubuntu does not so keep this in mind as you proceed.</p>
<p>It also has an optional dependency on libicu-dev, which is not necessary to get the bot up and running. If you decide to skip installing this library then you can safely ignore the StringPrep warnings the Node.js console issues when you start up your bot.</p>
<p>Back to NPM and we need to install the following packages so we can begin development:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">npm install node-xmpp
</span></span><span class="line"><span class="cl">npm install request
</span></span></code></pre></div><p>Optionally, although recommended, we can install the supervisor package so that we no longer need to restart the Node.js process.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">npm install supervisor -g
</span></span></code></pre></div><p>Supervisor will continually scan the project directory for any changes and restart the Node.js process for you, which makes development a little bit easier and faster.</p>
<p>Lastly, the bot will need a new Google Account (<a href="https://accounts.google.com/NewAccount">https://accounts.google.com/NewAccount</a>) so that users are able to contact it. The account name will become your bot’s Jabber ID (JID) for example my bot resides at <a href="mailto:n.js.bot@gmail.com">n.js.bot@gmail.com</a> as explained at <a href="http://njsbot.simonholywell.com">http://njsbot.simonholywell.com</a>.</p>
<h1 id="configuration">Configuration</h1>
<p>To keep the project simple and clean we are going to move the configuration settings into a separate JavaScript file, which can be included at the top of the main bot script. Create a new file called config.js and include the following lines of code:</p>
<p>Add your bot’s Google Account details for jid and password after which you are ready to begin programming. Create a new file in the same directory called bot.js and start by including the configuration file:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">config</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s2">&#34;./config.js&#34;</span><span class="p">).</span><span class="nx">settings</span><span class="p">;</span>
</span></span></code></pre></div><p>Then include the Node.js packages that you installed earlier and util for logging actions in the bot:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">xmpp</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s2">&#34;node-xmpp&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">request_helper</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s2">&#34;request&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">util</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s2">&#34;util&#34;</span><span class="p">);</span>
</span></span></code></pre></div><h1 id="connecting-to-the-server">Connecting to the server</h1>
<p>The node-xmpp package makes the process of communicating with XMPP servers very easy:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">conn</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">xmpp</span><span class="p">.</span><span class="nx">Client</span><span class="p">(</span><span class="nx">config</span><span class="p">.</span><span class="nx">client</span><span class="p">);</span>
</span></span></code></pre></div><p>Notice how the code is using the client element from the configuration file that you created earlier to setup the parameters for the XMPP connection.</p>
<p>To help our bot have the best chances of living a long life the Node.js default socket time out setting of 60 seconds should really be overridden. I am using the following settings in my project:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="nx">conn</span><span class="p">.</span><span class="nx">socket</span><span class="p">.</span><span class="nx">setTimeout</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">conn</span><span class="p">.</span><span class="nx">socket</span><span class="p">.</span><span class="nx">setKeepAlive</span><span class="p">(</span><span class="kc">true</span><span class="p">,</span> <span class="mi">10000</span><span class="p">);</span>
</span></span></code></pre></div><p>The keep alive setting should send white space pings through the wire to stop proxies or routers on the way from timing out the connection when it is idle. Without these settings your bot will stop communicating after a minute of inactivity.</p>
<h1 id="announcing-the-bots-arrival">Announcing the bot’s arrival</h1>
<p>The bot is now connected to the Google server, but nobody knows it is online so we have to announce its availability. We must now programme it to send out a presence XML stanza when it connects to the server. This is also an excellent opportunity to set a status message.</p>
<p>Firstly, let’s create a simple function to send out the stanza:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">set_status_message</span><span class="p">(</span><span class="nx">status_message</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kd">var</span> <span class="nx">presence_elem</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">xmpp</span><span class="p">.</span><span class="nx">Element</span><span class="p">(</span><span class="s2">&#34;presence&#34;</span><span class="p">,</span> <span class="p">{})</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">c</span><span class="p">(</span><span class="s2">&#34;show&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">t</span><span class="p">(</span><span class="s2">&#34;chat&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">up</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">c</span><span class="p">(</span><span class="s2">&#34;status&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">t</span><span class="p">(</span><span class="nx">status_message</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="nx">conn</span><span class="p">.</span><span class="nx">send</span><span class="p">(</span><span class="nx">presence_elem</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Whilst this code may look a little complex it is in actual fact quite straightforward. Initially a new XML element called presence is created and then two child elements are added to it.</p>
<p>The <code>show</code> child has the text content of <code>chat</code>, which tells the server that the bot is ready to receive messages.</p>
<p>The <code>up()</code> function call causes the current element to return its parent element. So in this example it causes <code>show</code> to return its parent element <code>presence</code>. Without this the <code>status</code> element would be added as a child of <code>show</code> instead of <code>presence</code>.</p>
<p>The second child, <code>status</code>, is a little more obvious as it sets the status message with its text content.</p>
<p>Finally this whole XML element object is sent to the server using the connection (conn) that was created earlier. So the server will receive an XML element similar to the following given the previous code:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-xml" data-lang="xml"><span class="line"><span class="cl"><span class="nt">&lt;presence&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;show&gt;</span>chat<span class="nt">&lt;/show&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;status&gt;</span>I am a happy bot<span class="nt">&lt;/status&gt;</span>
</span></span><span class="line"><span class="cl"><span class="nt">&lt;/presence&gt;</span>
</span></span></code></pre></div><p>For debug purposes you can see the XML in a <code>xmpp.Element()</code> or a stanza from the server (explained later) by calling <code>.toString()</code> on them.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">presence_elem</span><span class="p">.</span><span class="nx">toString</span><span class="p">());</span>
</span></span></code></pre></div><p>That all sounds fantastic, but the function will never be run without being added to an event listener on the connection. In this case it should be triggered by the online event, which occurs right after the bot connects to the server.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="nx">conn</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s2">&#34;online&#34;</span><span class="p">,</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">set_status_message</span><span class="p">(</span><span class="nx">config</span><span class="p">.</span><span class="nx">status_message</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><p>Once again the code is using the configuration file to set the content of the initial status message for the bot.</p>
<h1 id="meeting-new-people">Meeting new people</h1>
<p>The bot has now announced its arrival and other people can see it is available on the Google Talk network. Unfortunately if they attempt to connect with your bot in its current state their subscription requests will go unanswered.</p>
<p>Firstly, there is a Google specific roster call that needs to be made so that the bot will be registered to receive subscription request notifications from the server. Without including this function you will not be able see requests coming over the wire.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">request_google_roster</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kd">var</span> <span class="nx">roster_elem</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">xmpp</span><span class="p">.</span><span class="nx">Element</span><span class="p">(</span><span class="s2">&#34;iq&#34;</span><span class="p">,</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">from</span><span class="o">:</span> <span class="nx">conn</span><span class="p">.</span><span class="nx">jid</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">type</span><span class="o">:</span> <span class="s2">&#34;get&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">id</span><span class="o">:</span> <span class="s2">&#34;google-roster&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="p">}).</span><span class="nx">c</span><span class="p">(</span><span class="s2">&#34;query&#34;</span><span class="p">,</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">xmlns</span><span class="o">:</span> <span class="s2">&#34;jabber:iq:roster&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;xmlns:gr&#34;</span><span class="o">:</span> <span class="s2">&#34;google:roster&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;gr:ext&#34;</span><span class="o">:</span> <span class="s2">&#34;2&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="p">});</span>
</span></span><span class="line"><span class="cl">  <span class="nx">conn</span><span class="p">.</span><span class="nx">send</span><span class="p">(</span><span class="nx">roster_elem</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>As you can see this uses the same syntax as the <code>set_status_message()</code> you wrote earlier although it is a fraction more complex. The objects that are passed as the second parameter to <code>xmpp.Element()</code> and <code>c()</code> are interpreted as attributes on the XML element.</p>
<p>To make this a little clearer I will include the XML version of the call:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-xml" data-lang="xml"><span class="line"><span class="cl"><span class="nt">&lt;iq</span> <span class="na">type=</span><span class="s">&#39;get&#39;</span>
</span></span><span class="line"><span class="cl">    <span class="na">from=</span><span class="s">&#39;romeo@gmail.com/orchard&#39;</span>
</span></span><span class="line"><span class="cl">    <span class="na">id=</span><span class="s">&#39;google-roster-1&#39;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&lt;query</span> <span class="na">xmlns=</span><span class="s">&#39;jabber:iq:roster&#39;</span> <span class="na">xmlns:gr=</span><span class="s">&#39;google:roster&#39;</span> <span class="na">gr:ext=</span><span class="s">&#39;2&#39;</span><span class="nt">/&gt;</span>
</span></span><span class="line"><span class="cl"><span class="nt">&lt;/iq&gt;</span>
</span></span></code></pre></div><p>As with set_status_message() this function will need to be plumbed in with an event listener on the connection object.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="k">if</span> <span class="p">(</span><span class="nx">config</span><span class="p">.</span><span class="nx">allow_auto_subscribe</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">conn</span><span class="p">.</span><span class="nx">addListener</span><span class="p">(</span><span class="s2">&#34;online&#34;</span><span class="p">,</span> <span class="nx">request_google_roster</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="nx">conn</span><span class="p">.</span><span class="nx">addListener</span><span class="p">(</span><span class="s2">&#34;stanza&#34;</span><span class="p">,</span> <span class="nx">accept_subscription_requests</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>As you may wish to deactivate auto acceptance of subscription requests the listener is only added if the configuration file allows it. Just like when the status message was set earlier the <code>request_google_roster()</code> function is set to listen to the online event. The second listener is addressed in the next section.</p>
<h1 id="making-friends">Making friends</h1>
<p>The bot is now receiving subscription requests so it is time to begin accepting them with the <code>accept_subscription_requests()</code> function mentioned in the previous code sample.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">accept_subscription_requests</span><span class="p">(</span><span class="nx">stanza</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="p">(</span><span class="nx">stanza</span><span class="p">.</span><span class="nx">is</span><span class="p">(</span><span class="s2">&#34;presence&#34;</span><span class="p">)</span> <span class="o">&amp;&amp;</span> <span class="nx">stanza</span><span class="p">.</span><span class="nx">attrs</span><span class="p">.</span><span class="nx">type</span> <span class="o">===</span> <span class="s2">&#34;subscribe&#34;</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kd">var</span> <span class="nx">subscribe_elem</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">xmpp</span><span class="p">.</span><span class="nx">Element</span><span class="p">(</span><span class="s2">&#34;presence&#34;</span><span class="p">,</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">to</span><span class="o">:</span> <span class="nx">stanza</span><span class="p">.</span><span class="nx">attrs</span><span class="p">.</span><span class="nx">from</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nx">type</span><span class="o">:</span> <span class="s2">&#34;subscribed&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">});</span>
</span></span><span class="line"><span class="cl">    <span class="nx">conn</span><span class="p">.</span><span class="nx">send</span><span class="p">(</span><span class="nx">subscribe_elem</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>This function has already been added to a listener for the stanza event in the previous section. The event is triggered not only by subscription requests so each incoming stanza is checked for the type of subscription.</p>
<p>To accept the request another simple XML element is sent back to the requesting party, which is obtained from the subscription stanza they sent to the bot with <code>stanza.attrs.from</code>. Setting the type to subscribed accepts their subscription request whilst setting it to unsubscribed will reject their request.</p>
<h1 id="connect-with-your-bot">Connect with your bot</h1>
<p>This is the first point at which connecting with your bot will give you any meaningful results so let’s give it a run. On your system’s console run the following command (if you have not installed supervisor then substitute it for node).</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">supervisor bot.js
</span></span></code></pre></div><p>Now logging into your own Google Talk account (not the bot account you created earlier) add your bot as a contact. If the code is working properly then you will now see your bot online with the status message you set in the configuration file.</p>
<p>As mentioned earlier you will not need to restart the node process as supervisor will do this for you whenever you save changes to the project’s files.</p>
<h1 id="til-next-time">’til next time</h1>
<p>In part one of the tutorial you have successfully written a bot in Node.js that can announce its presence and auto accept new subscription requests. I will guide you through adding new functionality and commands to your bot in the next instalment.</p>
<p>Once you have completed part two your bot will be able to provide users with help information, bounce messages back and search twitter for user supplied keywords. It will also become clear just how easy it is to add your own custom commands to your project.</p>
<p><a href="/post/2013/03/create-a-node-js-google-talk-bot-pt2.html">Part two</a> of this is article is now also posted to my blog - you should check it out!</p>
<h1 id="further-resources">Further resources</h1>
<ul>
<li><a href="http://www.amazon.co.uk/gp/product/1617290572/ref=as_li_ss_tl?ie=UTF8&amp;camp=1634&amp;creative=19450&amp;creativeASIN=1617290572&amp;linkCode=as2&amp;tag=simonholywell-21">Node.js in Action</a></li>
<li><a href="http://www.amazon.co.uk/gp/product/1449337392/ref=as_li_ss_tl?ie=UTF8&amp;camp=1634&amp;creative=19450&amp;creativeASIN=1449337392&amp;linkCode=as2&amp;tag=simonholywell-21">Building Node Applications with MongoDB and Backbone</a></li>
<li><a href="http://www.amazon.co.uk/gp/product/1449398588/ref=as_li_ss_tl?ie=UTF8&amp;camp=1634&amp;creative=19450&amp;creativeASIN=1449398588&amp;linkCode=as2&amp;tag=simonholywell-21">Node: Up and Running: Scalable Server-Side Code with JavaScript</a></li>
<li><a href="http://www.amazon.co.uk/gp/product/059652126X/ref=as_li_ss_tl?ie=UTF8&amp;camp=1634&amp;creative=19450&amp;creativeASIN=059652126X&amp;linkCode=as2&amp;tag=simonholywell-21">XMPP: The Definitive Guide: Building Real-Time Applications with Jabber Technologies</a></li>
<li><a href="http://www.amazon.co.uk/gp/product/0470540710/ref=as_li_ss_tl?ie=UTF8&amp;camp=1634&amp;creative=19450&amp;creativeASIN=0470540710&amp;linkCode=as2&amp;tag=simonholywell-21">Professional XMPP Programming with JavaScript and jQuery</a></li>
</ul>
<h1 id="stay-in-touch">Stay in touch</h1>
<p>If you liked this article then please <a href="https://twitter.com/Treffynnon">follow me on Twitter</a> and let me know.</p>
<blockquote>
<p><strong>note</strong></p>
<p><a href="/post/2013/03/create-a-node-js-google-talk-bot-pt2.html">Part two</a> of this article is also published on my blog.</p>
<p>For now the <a href="https://github.com/treffynnon/njsbot">complete code is on github</a>.</p>
<p>This article was originally published in the <a href="/post/2012/02/create-a-google-talk-bot-with-nodejs.html">March 2012 issue</a> of <a href="http://www.netmagazine.com">.net Magazine</a>.</p>
<p>In tandem with the Google bot tutorial I wrote four smaller articles:</p>
<ul>
<li><a href="/post/2013/02/node-js-eco-system.html">The Node.js eco-system</a></li>
<li><a href="/post/2013/02/xmpp-and-jabber.html">XMPP and Jabber</a></li>
<li><a href="/post/2013/02/node-js-in-the-real-world.html">Node.js in the real world</a></li>
<li><a href="/post/2013/02/node-js-for-hosting-websites.html">Node.js for hosting websites</a></li>
</ul>
</blockquote>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="nodejs" label="Nodejs"/><category scheme="taxonomy:Tags" term="google-talk" label="Google Talk"/><category scheme="taxonomy:Tags" term="published" label="published"/><category scheme="taxonomy:Tags" term="net-magazine" label="net Magazine"/></entry><entry xml:base="git-tag-secrets"><title type="html">Git tag secrets</title><link href="https://www.simonholywell.com/post/2013/02/git-tag-secrets/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2009/08/moving-to-git-and-setting-up-indefero-as-a-web-frontend/?utm_source=atom_feed" rel="related" type="text/html" title="Moving to git and setting up InDefero as a web frontend"/><link href="https://www.simonholywell.com/post/2009/03/using-phing-for-good-unfuddle-add-repository-and-svn-imp/?utm_source=atom_feed" rel="related" type="text/html" title="Using phing for good - Unfuddle Add Repository and SVN Import Ta…"/><link href="https://www.simonholywell.com/post/2013/01/idiorm-and-paris-the-minimalist-orm/?utm_source=atom_feed" rel="related" type="text/html" title="Idiorm and Paris 1.3.0 released - the minimalist ORM and fluent query builder for PHP"/><link href="https://www.simonholywell.com/post/2013/01/unicode-shortcut-in-netbeans/?utm_source=atom_feed" rel="related" type="text/html" title="Unicode shortcut in Netbeans for React/Curry"/><link href="https://www.simonholywell.com/post/2013/01/navigator-geographic-calculations-library-for-php/?utm_source=atom_feed" rel="related" type="text/html" title="Navigator: Geographic calculation library for PHP"/><id>https://www.simonholywell.com/post/2013/02/git-tag-secrets/</id><author><name>Simon Holywell</name></author><published>2013-02-04T10:42:29+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Tags are quite a simple aspect of git, but there are a few things that a lot of people don’t know about. These shortcuts will make it quick for you to tag and manage those tags in your git repositories.
Probably the most common use of tags is to note when a version of the software the repository is tracking is released. Usually this will be something like ‘1.2.8’ if you are sticking with SemVer.</summary><content type="html"><![CDATA[<p><a href="http://git-scm.com/docs/git-tag">Tags</a> are quite a simple aspect of <a href="http://git-scm.com">git</a>, but there are a few things that a lot of people don’t know about. These shortcuts will make it quick for you to tag and manage those tags in your git repositories.</p>
<p>Probably the most common use of tags is to note when a version of the software the repository is tracking is released. Usually this will be something like ‘1.2.8’ if you are sticking with <a href="http://semver.org">SemVer</a>.</p>
<h1 id="creating-tags">Creating tags</h1>
<h2 id="lightweight-tags">Lightweight tags</h2>
<p>At its simplest level you can simply add a tag to your git repository with:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">git tag 1.2.8
</span></span></code></pre></div><p>These tags can then be used to easily revert to or diff between versions of the project. For example to see the changes between versions of the project you can simply execute:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">git diff 1.2.6 1.2.8
</span></span></code></pre></div><h2 id="annotated-tags">Annotated tags</h2>
<p>Tags can also include a more descriptive body message or annotation much like a commit message. Usually this is achieved using (-a for annotation):</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">git tag -a 1.2.8
</span></span></code></pre></div><p>This will open up your commit editor - in my case this is vim - so that you can enter an annotation with your tag.</p>
<p>However if you only have a one line description to include then you can simply use -m just like you can with git commit:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">git tag -m <span class="s2">&#34;Releasing version 1.2.8&#34;</span> 1.2.8
</span></span></code></pre></div><h1 id="listing-tags">Listing tags</h1>
<h2 id="lightweight-tags-1">Lightweight tags</h2>
<p>To simply list the tags in your repository you can call:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">git tag
</span></span></code></pre></div><p>If your project has many tags then it can be very useful to filter the list you are getting:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">git tag -l <span class="s1">&#39;1.2.*&#39;</span>
</span></span></code></pre></div><p>Which would show you all the tags beginning with 1.2. as * is a wildcard.</p>
<h2 id="annotated-tags-1">Annotated tags</h2>
<p>You will notice that when you call git tag you do not get to see the contents of your annotations, but just the headline tag (1.2.8). To see the annotations you must add -n to your command:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">git tag -n
</span></span></code></pre></div><p>If you have entered multiple lines in your annotation then you will need to specify how many of those lines you want git tag to display. By default -n only shows the first line so if you wanted to see the first 10 lines for example you would use:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">git tag -n10
</span></span></code></pre></div><h1 id="tag-details">Tag details</h1>
<p>To see the details of a particular tag you can call git show much like you would with a commit hash:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">git show 1.2.8
</span></span></code></pre></div><p>This will present you with the tag details and the information from the commit that was tagged.</p>
<h1 id="publishing-tags">Publishing tags</h1>
<p>When you push your changes to another repository git does not transfer the tags along with it by default.</p>
<p>This is easily overriden like so:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">git push --tags origin master
</span></span></code></pre></div><p>If you are pulling in someone elses changes then their tags will be pulled in and tracked by default. If you do not want this to happen then you can add the following switch:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">git pull --no-tags origin master
</span></span></code></pre></div>]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="git" label="git"/></entry><entry xml:base="idiorm-and-paris-the-minimalist-orm"><title type="html">Idiorm and Paris 1.3.0 released - the minimalist ORM and fluent query builder for PHP</title><link href="https://www.simonholywell.com/post/2013/01/idiorm-and-paris-the-minimalist-orm/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2013/01/unicode-shortcut-in-netbeans/?utm_source=atom_feed" rel="related" type="text/html" title="Unicode shortcut in Netbeans for React/Curry"/><link href="https://www.simonholywell.com/post/2013/01/navigator-geographic-calculations-library-for-php/?utm_source=atom_feed" rel="related" type="text/html" title="Navigator: Geographic calculation library for PHP"/><link href="https://www.simonholywell.com/post/2012/11/force-lowercase-urls-rewrite-php/?utm_source=atom_feed" rel="related" type="text/html" title="Force URLs to lowercase with Apache rewrite and PHP"/><link href="https://www.simonholywell.com/post/2011/10/php-extensions-made-elrich/?utm_source=atom_feed" rel="related" type="text/html" title="PHP extension writing: PHP Extensions Made Eldrich"/><link href="https://www.simonholywell.com/post/2011/07/how-php-ssdeep-was-made/?utm_source=atom_feed" rel="related" type="text/html" title="How the ssdeep PHP extension came into being"/><id>https://www.simonholywell.com/post/2013/01/idiorm-and-paris-the-minimalist-orm/</id><author><name>Simon Holywell</name></author><published>2013-01-31T13:56:29+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Idiorm is a PHP ORM that eschews complexity and deliberately remains lightweight with support for PHP5.2+. It consists of one file and primarily one class that can easily be configured in a few lines of code. There are no models to create, no convoluted configuration formats and there is no database introspection just a simple PDO connection string.
However, having said this, Idiorm is very powerful and it makes most of the queries PHP applications require pain free.</summary><content type="html"><![CDATA[<p><a href="http://github.com/j4mie/idiorm">Idiorm</a> is a PHP ORM that eschews complexity and deliberately remains lightweight with support for PHP5.2+. It consists of one file and primarily one class that can easily be configured in a few lines of code. There are no models to create, no convoluted configuration formats and there is no database introspection just a simple PDO connection string.</p>
<p>However, having said this, Idiorm is very powerful and it makes most of the queries PHP applications require pain free. Some of these features include fluent query building, multiple connection support and result sets for easy record manipulation.</p>
<p><a href="http://github.com/j4mie/paris">Paris</a> sits on top of Idiorm to provide a simplified active record implementation based upon the same minimalist philosophy. To configure Paris you just add simple models so that you can exploit the full power of Idiorm’s fluent query API, table/object associates (one-to-one, one-to-many, etc.) and filter methods to encompass common queries.</p>
<h1 id="some-simple-examples">Some simple examples</h1>
<p>Fetching and updating a record is easy with Idiorm:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o">&lt;?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl"><span class="nv">$user</span> <span class="o">=</span> <span class="nx">ORM</span><span class="o">::</span><span class="na">for_table</span><span class="p">(</span><span class="s1">&#39;user&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="o">-&gt;</span><span class="na">where_equal</span><span class="p">(</span><span class="s1">&#39;username&#39;</span><span class="p">,</span> <span class="s1">&#39;j4mie&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="o">-&gt;</span><span class="na">find_one</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">$user</span><span class="o">-&gt;</span><span class="na">first_name</span> <span class="o">=</span> <span class="s1">&#39;Jamie&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nv">$user</span><span class="o">-&gt;</span><span class="na">save</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">$tweets</span> <span class="o">=</span> <span class="nx">ORM</span><span class="o">::</span><span class="na">for_table</span><span class="p">(</span><span class="s1">&#39;tweet&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">          <span class="o">-&gt;</span><span class="na">select</span><span class="p">(</span><span class="s1">&#39;tweet.*&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">          <span class="o">-&gt;</span><span class="na">join</span><span class="p">(</span><span class="s1">&#39;user&#39;</span><span class="p">,</span> <span class="k">array</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">              <span class="s1">&#39;user.id&#39;</span><span class="p">,</span> <span class="s1">&#39;=&#39;</span><span class="p">,</span> <span class="s1">&#39;tweet.user_id&#39;</span>
</span></span><span class="line"><span class="cl">            <span class="p">))</span>
</span></span><span class="line"><span class="cl">          <span class="o">-&gt;</span><span class="na">where_equal</span><span class="p">(</span><span class="s1">&#39;user.username&#39;</span><span class="p">,</span> <span class="s1">&#39;j4mie&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">          <span class="o">-&gt;</span><span class="na">find_many</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">foreach</span> <span class="p">(</span><span class="nv">$tweets</span> <span class="k">as</span> <span class="nv">$tweet</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">echo</span> <span class="nv">$tweet</span><span class="o">-&gt;</span><span class="na">text</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Whereas Paris makes it easier to think of records and associations as objects:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o">&lt;?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">User</span> <span class="k">extends</span> <span class="nx">Model</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">tweets</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">has_many</span><span class="p">(</span><span class="s1">&#39;Tweet&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Tweet</span> <span class="k">extends</span> <span class="nx">Model</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">$user</span> <span class="o">=</span> <span class="nx">Model</span><span class="o">::</span><span class="na">factory</span><span class="p">(</span><span class="s1">&#39;User&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="o">-&gt;</span><span class="na">where_equal</span><span class="p">(</span><span class="s1">&#39;username&#39;</span><span class="p">,</span> <span class="s1">&#39;j4mie&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="o">-&gt;</span><span class="na">find_one</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="nv">$user</span><span class="o">-&gt;</span><span class="na">first_name</span> <span class="o">=</span> <span class="s1">&#39;Jamie&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nv">$user</span><span class="o">-&gt;</span><span class="na">save</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">$tweets</span> <span class="o">=</span> <span class="nv">$user</span><span class="o">-&gt;</span><span class="na">tweets</span><span class="p">()</span><span class="o">-&gt;</span><span class="na">find_many</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="k">foreach</span> <span class="p">(</span><span class="nv">$tweets</span> <span class="k">as</span> <span class="nv">$tweet</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">echo</span> <span class="nv">$tweet</span><span class="o">-&gt;</span><span class="na">text</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>These examples show a very simple use case worked in both the Idiorm ORM way and using the Paris Active Record method. Of course the documentation for each project is a good place to start and find out more information on each projects capabilities.</p>
<h1 id="a-potted-history">A potted history</h1>
<p>Both projects <a href="http://j4mie.org/blog/idiorm-a-simple-orm-for-php">were written</a> by <a href="http://www.j4mie.org">Jamie Matthews</a>; a friend and former colleague, but in recent times his focus has shifted to Python. This left <a href="http://j4mie.github.com/idiormandparis">Idiorm and Paris</a> in an unmaintained state until, first, <a href="http://durhamhale.com">Durham Hale</a> and then myself took up maintenance duties on the libraries.</p>
<p>This has led to a number of new features recently making their way into Idiorm and some long standing bugs being quashed. In this release quite a few changes have taken place including:</p>
<ul>
<li>Multiple connections</li>
<li>Result set implementation</li>
<li>Tests refactored to use <a href="http://www.phpunit.de">PHPUnit</a> and configured with <a href="http://travis-ci.org">Travis-CI</a> for continuous integration</li>
<li>Documentation revisited and now built with <a href="http://sphinx-doc.org">Sphinx</a> on <a href="https://readthedocs.org">Read the Docs</a> at <a href="http://idiorm.rtfd.org">idiorm.rtfd.org</a></li>
<li>Support for <a href="http://www.firebirdsql.org">Firebird</a> and <a href="http://www.postgresql.org">PostgreSQL</a> on top of the existing <a href="http://www.mysql.com">MySQL</a> and <a href="http://www.sqlite.org">SQLite</a></li>
<li>Installation via <a href="https://packagist.org/packages/j4mie/idiorm">Packagist/Composer for Idiorm</a></li>
<li>And much more besides in the <a href="https://github.com/j4mie/idiorm#130---release-2013-01-31">changelog</a></li>
</ul>
<p>These updates have been complemented by some similar changes in Paris:</p>
<ul>
<li>Documentation on <a href="https://readthedocs.org">Read the Docs</a> at <a href="http://paris.rtfd.org">paris.rtfd.org</a></li>
<li>Installation via <a href="https://packagist.org/packages/j4mie/paris">Packagist/Composer for Paris</a></li>
<li>With more minor updates <a href="https://github.com/j4mie/paris#130---released-2013-01-31">maintained in the changelog</a></li>
</ul>
<h1 id="the-future">The future</h1>
<p>The present aim with both Idiorm and Paris is to maintain the current code base and add suitable new features as and when they become required or useful. There have been a number of suggestions for possible improvements that would break backwards compatibility such as:</p>
<ul>
<li>Changing the code to utilise late static bindings and thereby drop PHP5.2 support</li>
<li>Updating the classes, tests and documentation to meet the <a href="https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-1-basic-coding-standard.md">PSR-1 FIG standard</a></li>
</ul>
<p>Neither of these two are holding the current project back or would significantly contribute to it use. They are proposals that would make the libraries inaccessible to a large number of users on cheap shared hosting environments or working on legacy projects.</p>
<p>It is likely that, at some point, Idiorm and Paris will make the move to only support PHP5.3+, but without a compelling reason there is no point in breaking backwards compatibility. I have previously addressed this in <a href="https://github.com/j4mie/idiorm/pull/77#issuecomment-12362395">a pull request</a> so for the full arguments please head over there.</p>
<p>If you have an suggestions or better yet pull requests then please lodge an issue on github for the relevant project. Some people disagree with this and others agree, but I would like to <a href="/contact-me.html">hear your opinion</a>.</p>
<h1 id="project-updates">Project updates</h1>
<p>If you like Idiorm and Paris then please <a href="https://twitter.com/Treffynnon">follow me on Twitter</a> and <a href="https://github.com/treffynnon">github</a> for updates. You might also like some of <a href="/my-projects.html">my other projects</a> such as <a href="https://github.com/treffynnon/Navigator">Navigator</a>, <a href="http://pecl.php.net/package/ssdeep">php_ssdeep</a> and <a href="https://github.com/treffynnon/PHP-at-Job-Queue-Wrapper">PHP at Job Queue Wrapper</a>.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="php" label="php"/><category scheme="taxonomy:Tags" term="idiorm" label="idiorm"/><category scheme="taxonomy:Tags" term="paris" label="paris"/><category scheme="taxonomy:Tags" term="orm" label="orm"/><category scheme="taxonomy:Tags" term="database" label="database"/></entry><entry xml:base="unicode-shortcut-in-netbeans"><title type="html">Unicode shortcut in Netbeans for React/Curry</title><link href="https://www.simonholywell.com/post/2013/01/unicode-shortcut-in-netbeans/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2013/01/navigator-geographic-calculations-library-for-php/?utm_source=atom_feed" rel="related" type="text/html" title="Navigator: Geographic calculation library for PHP"/><link href="https://www.simonholywell.com/post/2012/11/force-lowercase-urls-rewrite-php/?utm_source=atom_feed" rel="related" type="text/html" title="Force URLs to lowercase with Apache rewrite and PHP"/><link href="https://www.simonholywell.com/post/2012/03/netbeans-jvi-vim-bindings/?utm_source=atom_feed" rel="related" type="text/html" title="NetBeans with jVi vim bindings"/><link href="https://www.simonholywell.com/post/2011/10/php-extensions-made-elrich/?utm_source=atom_feed" rel="related" type="text/html" title="PHP extension writing: PHP Extensions Made Eldrich"/><link href="https://www.simonholywell.com/post/2011/07/how-php-ssdeep-was-made/?utm_source=atom_feed" rel="related" type="text/html" title="How the ssdeep PHP extension came into being"/><id>https://www.simonholywell.com/post/2013/01/unicode-shortcut-in-netbeans/</id><author><name>Simon Holywell</name></author><published>2013-01-22T13:16:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>In some of my code I use a PHP library called React/Curry and to save typing it uses a unicode ellipsis (…) for a method name. Yes, that is right unicode method names can be legal in PHP!
&amp;lt;?php $firstChar = Curry\bind(&amp;#39;substr&amp;#39;, Curry\…(), 0, 1); See I told you so!
Well that is great, but how do you type a unicode character into a Netbeans document?
To save having to constantly copy and paste the … character from a symbols list I have setup a very simple macro in Netbeans to print the character for me.</summary><content type="html"><![CDATA[<p>In some of my code I use a PHP library called <a href="https://github.com/reactphp/curry">React/Curry</a> and to save typing it uses a unicode ellipsis (…) for a method name. Yes, that is right unicode method names can be legal in PHP!</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o">&lt;?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl"><span class="nv">$firstChar</span> <span class="o">=</span> <span class="nx">Curry\bind</span><span class="p">(</span><span class="s1">&#39;substr&#39;</span><span class="p">,</span> <span class="nx">Curry\…</span><span class="p">(),</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
</span></span></code></pre></div><p>See I told you so!</p>
<p>Well that is great, but how do you type a unicode character into a Netbeans document?</p>
<p>To save having to constantly copy and paste the … character from a symbols list I have setup a very simple macro in Netbeans to print the character for me. This means that control + alt + . now dumps the … character into the document at the current cursor position.</p>
<p>You to can enjoy this revelation in four simple steps:</p>
<ol>
<li>Tools &gt; Options &gt; Editor &gt; Macros</li>
<li>Click New and give it a name (“ellipsis” perhaps)</li>
<li>Enter the following (include the quotes!) into the Macro Code box: <code>&quot;…&quot;</code></li>
<li>Click Set Shortcut and choose the keystroke you want (I chose control + alt + .)</li>
</ol>
<p>Now when you bash those keys in your documents you’ll get a nice … character or whatever other unicode character you have setup.</p>
<p>One little caveat is that if you are using jVi like I am then the Macro editor seems to play a little havoc with it after setting up a new macro. This is easily resolved by ticking jVi off and on again in the Options menu of Netbeans.</p>
<p>Slightly annoying, but perfectly liveable.</p>
<p>I picked this little tip up on the <a href="http://forums.netbeans.org/post-42518.html#42518">Netbeans forums</a> and as it took me a long time to find I thought I would share it!</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="netbeans" label="netbeans"/><category scheme="taxonomy:Tags" term="unicode" label="unicode"/><category scheme="taxonomy:Tags" term="functional" label="functional"/><category scheme="taxonomy:Tags" term="php" label="php"/><category scheme="taxonomy:Tags" term="curry" label="curry"/></entry><entry xml:base="navigator-geographic-calculations-library-for-php"><title type="html">Navigator: Geographic calculation library for PHP</title><link href="https://www.simonholywell.com/post/2013/01/navigator-geographic-calculations-library-for-php/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2012/11/force-lowercase-urls-rewrite-php/?utm_source=atom_feed" rel="related" type="text/html" title="Force URLs to lowercase with Apache rewrite and PHP"/><link href="https://www.simonholywell.com/post/2011/10/php-extensions-made-elrich/?utm_source=atom_feed" rel="related" type="text/html" title="PHP extension writing: PHP Extensions Made Eldrich"/><link href="https://www.simonholywell.com/post/2011/07/how-php-ssdeep-was-made/?utm_source=atom_feed" rel="related" type="text/html" title="How the ssdeep PHP extension came into being"/><link href="https://www.simonholywell.com/post/2011/02/gearman-php-mod-gearman-status/?utm_source=atom_feed" rel="related" type="text/html" title="Gearman, PHP and mod_gearman_status on Ubuntu"/><link href="https://www.simonholywell.com/post/2011/01/php-number-error/?utm_source=atom_feed" rel="related" type="text/html" title="PHP Hangs When Fed 2.2250738585072011e-308"/><id>https://www.simonholywell.com/post/2013/01/navigator-geographic-calculations-library-for-php/</id><author><name>Simon Holywell</name></author><published>2013-01-18T11:35:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Navigator is a PHP library for easily performing geographic calculations and distance unit conversions on Earth or any other spheroid.
Currently it supports distance calculations between two coordinates using Vincenty, Haversine, Great Circle or Cosine Law. By default it uses the most accurate, but computationally intensive: Vincenty.
To calculate the distance between two points on Earth in metres it is as simple as:
&amp;lt;?php use Treffynnon\Navigator as N; $distance = N::getDistance(10, 81.</summary><content type="html"><![CDATA[<p>Navigator is a PHP library for easily performing geographic calculations and distance unit conversions on Earth or any other spheroid.</p>
<p>Currently it supports distance calculations between two coordinates using Vincenty, Haversine, Great Circle or Cosine Law. By default it uses the most accurate, but computationally intensive: Vincenty.</p>
<p>To calculate the distance between two points on Earth in metres it is as simple as:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o">&lt;?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl"><span class="k">use</span> <span class="nx">Treffynnon\Navigator</span> <span class="k">as</span> <span class="nx">N</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nv">$distance</span> <span class="o">=</span> <span class="nx">N</span><span class="o">::</span><span class="na">getDistance</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="mf">81.098</span><span class="p">,</span> <span class="mf">50.821389</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.147222</span><span class="p">);</span>
</span></span></code></pre></div><p>The example above uses decimal notation for the latitude and longitude of the coordinate, but you can also specify them in DMS (degrees, minutes and seconds).</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o">&lt;?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl"><span class="nv">$distance</span> <span class="o">=</span> <span class="nx">N</span><span class="o">::</span><span class="na">getDistance</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="mf">81.098</span><span class="p">,</span> <span class="mf">15.6</span><span class="p">,</span> <span class="s1">&#39;5° 10\&#39; 11.009&#34;W&#39;</span><span class="p">);</span>
</span></span></code></pre></div><p>There are also helpers to swap coordinate notation back and forth between decimals and DMS.</p>
<p>In addition there are utilities for converting distance units between each other including metres to nautical miles, kilometres, miles, parsecs, furlongs and leagues. Custom converts can easily be added to support other units of measurement should you need them.</p>
<p>By default the library will perform calculations on Earth, but Mars and Earth’s Moon have also been configured. Of course it is easy to add new celestial bodies should you need to perform distance calculations on Mercury for some reason!</p>
<p>The <a href="https://github.com/treffynnon/Navigator">code is available</a> on github of course and it is <a href="/projects/navigator">fully documented</a>.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="navigator" label="navigator"/><category scheme="taxonomy:Tags" term="php" label="php"/><category scheme="taxonomy:Tags" term="geography" label="geography"/><category scheme="taxonomy:Tags" term="library" label="library"/></entry><entry xml:base="force-lowercase-urls-rewrite-php"><title type="html">Force URLs to lowercase with Apache rewrite and PHP</title><link href="https://www.simonholywell.com/post/2012/11/force-lowercase-urls-rewrite-php/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2011/10/php-extensions-made-elrich/?utm_source=atom_feed" rel="related" type="text/html" title="PHP extension writing: PHP Extensions Made Eldrich"/><link href="https://www.simonholywell.com/post/2011/07/how-php-ssdeep-was-made/?utm_source=atom_feed" rel="related" type="text/html" title="How the ssdeep PHP extension came into being"/><link href="https://www.simonholywell.com/post/2011/02/gearman-php-mod-gearman-status/?utm_source=atom_feed" rel="related" type="text/html" title="Gearman, PHP and mod_gearman_status on Ubuntu"/><link href="https://www.simonholywell.com/post/2011/01/php-number-error/?utm_source=atom_feed" rel="related" type="text/html" title="PHP Hangs When Fed 2.2250738585072011e-308"/><link href="https://www.simonholywell.com/post/2010/12/logging-global-php-objects-lazy-loading-proxy/?utm_source=atom_feed" rel="related" type="text/html" title="Logging global PHP objects and saving memory using a lazy loading proxy"/><id>https://www.simonholywell.com/post/2012/11/force-lowercase-urls-rewrite-php/</id><author><name>Simon Holywell</name></author><published>2012-11-01T09:07:16+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Canonical pages are an important aspect of maintaining a website and ensure that search engine rankings are not affected by any duplicated content.
In *NIX based systems file names with varying capitalisation are treated as separate files. For example filename.txt is not the same file as FileName.TXT. This extends into the world of Apache where URLs are also case sensitive.
So that means that we really should pick a case for our URLs and force all browsers to redirect to our chosen scheme.</summary><content type="html"><![CDATA[<p>Canonical pages are an important aspect of maintaining a website and ensure that search engine rankings are not affected by any duplicated content.</p>
<p>In *NIX based systems file names with varying capitalisation are treated as separate files. For example filename.txt is not the same file as FileName.TXT. This extends into the world of Apache where URLs are also case sensitive.</p>
<p>So that means that we really should pick a case for our URLs and force all browsers to redirect to our chosen scheme. Lowercase is the only sensible choice so my examples will only cover it.</p>
<p>mod_rewrite does not have an easy way to do this from a .htaccess file without a large amount of repeat (recursive) requests to itself for each letter. This is certainly not a desirable load to put Apache under when it can be handled in another way.</p>
<p>This is where your favourite programming language steps into save the day. I am using PHP in these examples as it is the most commonly paired language with Apache.</p>
<p>In your projects .htaccess file you’ll need to add the following rewrite rules.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-apacheconf" data-lang="apacheconf"><span class="line"><span class="cl"><span class="nb">RewriteEngine</span> <span class="k">on</span>
</span></span><span class="line"><span class="cl"><span class="nb">RewriteBase</span> /
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># force url to lowercase if upper case is found</span>
</span></span><span class="line"><span class="cl"><span class="nb">RewriteCond</span> %{REQUEST_URI} [A-Z]
</span></span><span class="line"><span class="cl"><span class="c"># ensure it is not a file on the drive first</span>
</span></span><span class="line"><span class="cl"><span class="nb">RewriteCond</span> %{REQUEST_FILENAME} !-s
</span></span><span class="line"><span class="cl"><span class="nb">RewriteRule</span> (.*) rewrite-strtolower.php?rewrite-strtolower-url=$1 [QSA,L]
</span></span></code></pre></div><p>To describe briefly what is happening here:</p>
<ol>
<li>Setup up the rewrite module</li>
<li>Check if the incoming URL contains any uppercase letters</li>
<li>Ensure that the incoming URL does not refer to a file on disk (you may want to host a file with upper case letters in its name - something like a PDF file that a client has uploaded through the CMS you have supplied them for instance)</li>
<li>Send all the requests that match aforementioned rules are then rewritten to our script that will do the actual conversion to lowercase work. The only thing to note here is the QSA modifier, which makes sure all the GET “variables” are passed onto the script</li>
</ol>
<p>Next up is the little snippet of PHP that does all the work! This is a file called rewrite-strtolower.php in the same directory as your .htaccess file mentioned above.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o">&lt;?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl"><span class="k">if</span><span class="p">(</span><span class="nx">isset</span><span class="p">(</span><span class="nv">$_GET</span><span class="p">[</span><span class="s1">&#39;rewrite-strtolower-url&#39;</span><span class="p">]))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nv">$url</span> <span class="o">=</span> <span class="nv">$_GET</span><span class="p">[</span><span class="s1">&#39;rewrite-strtolower-url&#39;</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">    <span class="nx">unset</span><span class="p">(</span><span class="nv">$_GET</span><span class="p">[</span><span class="s1">&#39;rewrite-strtolower-url&#39;</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl">    <span class="nv">$params</span> <span class="o">=</span> <span class="nx">http_build_query</span><span class="p">(</span><span class="nv">$_GET</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span><span class="p">(</span><span class="nx">strlen</span><span class="p">(</span><span class="nv">$params</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$params</span> <span class="o">=</span> <span class="s1">&#39;?&#39;</span> <span class="o">.</span> <span class="nv">$params</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// if you don&#39;t have SSL/a security certificate at the destination change https:// to http:// below
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="nx">header</span><span class="p">(</span><span class="s1">&#39;Location: https://&#39;</span> <span class="o">.</span> <span class="nv">$_SERVER</span><span class="p">[</span><span class="s1">&#39;HTTP_HOST&#39;</span><span class="p">]</span> <span class="o">.</span> <span class="s1">&#39;/&#39;</span> <span class="o">.</span> <span class="nx">strtolower</span><span class="p">(</span><span class="nv">$url</span><span class="p">)</span> <span class="o">.</span> <span class="nv">$params</span><span class="p">,</span> <span class="k">true</span><span class="p">,</span> <span class="mi">301</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">exit</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="nx">header</span><span class="p">(</span><span class="s2">&#34;HTTP/1.0 404 Not Found&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="k">die</span><span class="p">(</span><span class="s1">&#39;Unable to convert the URL to lowercase. You must supply a URL to work upon.&#39;</span><span class="p">);</span>
</span></span></code></pre></div><p>As you can quickly see this is a very simple script that simply takes in the URL passed to it from the rewrite rules above.</p>
<ol>
<li>It grabs the supplied URL and removes it from the $_GET variable to stop it from being passed to the destination page amongst the GET query parameters</li>
<li>It then rebuilds the GET parameters into a query string for use in the redirect. If there are none then this will just be an empty string which will have no consequence on the final URL</li>
<li>Finally the redirect is performed using PHP’s header() function</li>
</ol>
<p>After these few steps have been completed as browser will always be redirected to the lowercase version of a URL. Try entering /mY-TEST-url and you’ll see instantly become /my-test.</p>
<p>I first came up with this technique a good few years ago so if you know of a better solution for Apache that has appeared in the interim then please let me know.</p>
<h1 id="alternatives">Alternatives</h1>
<p>It is also worth noting that there are alternatives for those without the .htaccess file requirement.</p>
<p>If you are not on a shared hosting environment and happy to enter the rules directly into your Apache configuration you can use mod_rewrites RewriteMap directive to do the lowercase conversion:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-apacheconf" data-lang="apacheconf"><span class="line"><span class="cl"><span class="nb">RewriteMap</span> lc int:tolower
</span></span><span class="line"><span class="cl"><span class="nb">RewriteRule</span> (.*?[A-Z]+.*) ${lc:$1} [R]
</span></span></code></pre></div><p>For more information on this see the Apache manual: <a href="http://httpd.apache.org/docs/trunk/rewrite/rewritemap.html#int">Redirect a URI to an all-lowercase version of itself</a>. Although it is noted there that it is recommended to use <a href="http://httpd.apache.org/docs/trunk/mod/mod_speling.html">mod_speling</a> instead of this rewrite rule.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="apache" label="apache"/><category scheme="taxonomy:Tags" term="htaccess" label="htaccess"/><category scheme="taxonomy:Tags" term="rewrite" label="rewrite"/><category scheme="taxonomy:Tags" term="php" label="php"/></entry><entry xml:base="fish-console"><title type="html">Fish Console Reborn</title><link href="https://www.simonholywell.com/post/2012/06/fish-console/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2012/03/netbeans-jvi-vim-bindings/?utm_source=atom_feed" rel="related" type="text/html" title="NetBeans with jVi vim bindings"/><link href="https://www.simonholywell.com/post/2011/10/nodester-environment-variables-for-sensitive-data/?utm_source=atom_feed" rel="related" type="text/html" title="Nodester environment variables for sensitive data and passwords"/><link href="https://www.simonholywell.com/post/2011/06/linux-on-dell-inspiron-2500/?utm_source=atom_feed" rel="related" type="text/html" title="Running a sane version of Linux on a Dell Inspiron 2500"/><link href="https://www.simonholywell.com/post/2011/04/ssh-agent-not-storing-unencrypted-key/?utm_source=atom_feed" rel="related" type="text/html" title="Why won't ssh-agent save my unencrypted key for later use?"/><link href="https://www.simonholywell.com/post/2010/11/setup-a-new-portforward-on-vigor-over-telnet/?utm_source=atom_feed" rel="related" type="text/html" title="Set up a new port forward on a Draytek Vigor over the telnet interface"/><id>https://www.simonholywell.com/post/2012/06/fish-console/</id><author><name>Simon Holywell</name></author><published>2012-06-11T10:19:23+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Installing curses:
sudo apt-get install libncurses5-dev
fish is now installed on your system. To run fish, type ‘fish’ in your terminal.
To use fish as your login shell:
add the line ‘/usr/local/bin/fish’ to the file ‘/etc/shells’. use the command ‘chsh -s /usr/local/bin/fish’. To set your colors, run ‘fish_config’ To scan your man pages for completions, run ‘fish_update_completions’
Have fun!</summary><content type="html"><![CDATA[<p>Installing curses:</p>
<blockquote>
<p>sudo apt-get install libncurses5-dev</p>
</blockquote>
<p>fish is now installed on your system. To run fish, type ‘fish’ in your terminal.</p>
<p>To use fish as your login shell:</p>
<ul>
<li>add the line ‘/usr/local/bin/fish’ to the file ‘/etc/shells’.</li>
<li>use the command ‘chsh -s /usr/local/bin/fish’.</li>
</ul>
<p>To set your colors, run ‘fish_config’ To scan your man pages for completions, run ‘fish_update_completions’</p>
<p>Have fun!</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="command-line" label="command line"/><category scheme="taxonomy:Tags" term="linux" label="linux"/></entry><entry xml:base="netbeans-jvi-vim-bindings"><title type="html">NetBeans with jVi vim bindings</title><link href="https://www.simonholywell.com/post/2012/03/netbeans-jvi-vim-bindings/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2011/10/nodester-environment-variables-for-sensitive-data/?utm_source=atom_feed" rel="related" type="text/html" title="Nodester environment variables for sensitive data and passwords"/><link href="https://www.simonholywell.com/post/2011/05/netbeans-7-agavi-support/?utm_source=atom_feed" rel="related" type="text/html" title="New version of the Agavi framework support for NetBeans 7.0"/><link href="https://www.simonholywell.com/post/2010/11/setup-a-new-portforward-on-vigor-over-telnet/?utm_source=atom_feed" rel="related" type="text/html" title="Set up a new port forward on a Draytek Vigor over the telnet interface"/><link href="https://www.simonholywell.com/post/2010/10/force-netbeans-line-endings/?utm_source=atom_feed" rel="related" type="text/html" title="Forcing NetBeans to Use Unix (LF) Line Endings"/><link href="https://www.simonholywell.com/post/2009/11/netbeans-and-xdebug/?utm_source=atom_feed" rel="related" type="text/html" title="Netbeans and Remote XDebug"/><id>https://www.simonholywell.com/post/2012/03/netbeans-jvi-vim-bindings/</id><author><name>Simon Holywell</name></author><published>2012-03-20T13:20:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>I love vim and its very handy shortcuts, but I also like to be in a GUI IDE for most of my development. Thankfully there is an answer; add vims keybindings to the NetBeans environment with jVi.
Once you have Netbeans 7+ installed you can install jVi by going to Tools &amp;gt; Plugins &amp;gt; Available Plugins and searching for jVi. Select jVi for NB-7.0 Update Center and click Install.
Now click the Reload Catalog button and wait for the updates to stream in.</summary><content type="html"><![CDATA[<p>I love vim and its very handy shortcuts, but I also like to be in a GUI IDE for most of my development. Thankfully there is an answer; add vims keybindings to the NetBeans environment with jVi.</p>
<p>Once you have Netbeans 7+ installed you can install jVi by going to Tools &gt; Plugins &gt; Available Plugins and searching for jVi. Select jVi for NB-7.0 Update Center and click Install.</p>
<p>Now click the Reload Catalog button and wait for the updates to stream in. Select jVi for NetBeans and click Install.</p>
<p>You will then be asked to restart NetBeans and jVi will be installed. It can easily be enabled or disabled from the Tools menu by clicking jVi.</p>
<p>When enabled you can use vim commands as you would in vim. For example typing :w&lt;enter&gt; will save the document as in vim.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="command-line" label="command line"/><category scheme="taxonomy:Tags" term="netbeans" label="netbeans"/><category scheme="taxonomy:Tags" term="vim" label="vim"/></entry><entry xml:base="create-a-google-talk-bot-with-nodejs"><title type="html">.net magazine article: Create a Google Talk bot with Node.js</title><link href="https://www.simonholywell.com/post/2012/02/create-a-google-talk-bot-with-nodejs/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2011/10/nodester-environment-variables-for-sensitive-data/?utm_source=atom_feed" rel="related" type="text/html" title="Nodester environment variables for sensitive data and passwords"/><link href="https://www.simonholywell.com/post/2012/01/mysql-udf-install-error-function-already-exists/?utm_source=atom_feed" rel="related" type="text/html" title="Installing a MySQL UDF errors with Function already exists"/><link href="https://www.simonholywell.com/post/2011/10/php-extensions-made-elrich/?utm_source=atom_feed" rel="related" type="text/html" title="PHP extension writing: PHP Extensions Made Eldrich"/><link href="https://www.simonholywell.com/post/2011/10/getting-started-node-js-couch-db/?utm_source=atom_feed" rel="related" type="text/html" title="Getting started with Node.js and CouchDB"/><link href="https://www.simonholywell.com/post/2011/05/netbeans-7-agavi-support/?utm_source=atom_feed" rel="related" type="text/html" title="New version of the Agavi framework support for NetBeans 7.0"/><id>https://www.simonholywell.com/post/2012/02/create-a-google-talk-bot-with-nodejs/</id><author><name>Simon Holywell</name></author><published>2012-02-03T23:07:54+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>I have written a two part article for this months .net magazine detailing how easy it is to write a Google Talk bot with the evented power of Node.js.
“Programming a chat bot was once the domain of the hardcore hacker, tapping packets as they passed over the wire from proprietary client applications to closed source servers, but not any more!”
note
As of 6/2/2103 I have now published this article on my blog.</summary><content type="html"><![CDATA[<p>I have written a two part article for this months <a href="http://www.netmag.co.uk">.net magazine</a> detailing how easy it is to write a <a href="http://www.google.com/talk/">Google Talk</a> bot with the evented power of <a href="http://nodejs.org/">Node.js</a>.</p>
<blockquote>
<p>“Programming a chat bot was once the domain of the hardcore hacker, tapping packets as they passed over the wire from proprietary client applications to closed source servers, but not any more!”</p>
</blockquote>
<blockquote>
<p><strong>note</strong></p>
<p>As of 6/2/2103 I have now published this <a href="/post/2013/02/create-a-node-js-google-talk-bot-pt1.html">article on my blog</a>.</p>
</blockquote>
<p>In <a href="http://www.netmagazine.com/shop/magazines/march-2012-225">issue 225</a> (out now) you will learn how to build a Google Talk bot that is able to set its own status messages and accept new contact requests. I then follow this up in part two of the tutorial (<a href="http://www.netmagazine.com/shop/magazines/april-2012-226">issue 226</a> , on sale 28 February) by adding message bounce back and Twitter searching functionality.</p>
<p>Additionally, I give a little bit of history from both Node.js and <a href="http://xmpp.org">XMPP/Jabber</a> along with some background on projects and companies that are using Node.js and hiring experts. As an aside there is a micro-tutorial on creating webpages with Node.js using the <a href="http://expressjs.com/">express framework</a> like the <a href="http://njsbot.simonholywell.com">bots demo website</a>.</p>
<p>There is also a demo bot and documentation over at <a href="http://njsbot.simonholywell.com">njsbot.simonholywell.com</a>, which is hosted on <a href="http://cloudno.de">cloudno.de</a> (Thanks Hans). The <a href="https://github.com/treffynnon/njsbot">source code for the demo</a> site and bot can be found on <a href="http://github.com/treffynnon">github</a>.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="nodejs" label="nodejs"/><category scheme="taxonomy:Tags" term="internet" label="internet"/></entry><entry xml:base="mysql-udf-install-error-function-already-exists"><title type="html">Installing a MySQL UDF errors with Function already exists</title><link href="https://www.simonholywell.com/post/2012/01/mysql-udf-install-error-function-already-exists/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2011/10/nodester-environment-variables-for-sensitive-data/?utm_source=atom_feed" rel="related" type="text/html" title="Nodester environment variables for sensitive data and passwords"/><link href="https://www.simonholywell.com/post/2011/10/php-extensions-made-elrich/?utm_source=atom_feed" rel="related" type="text/html" title="PHP extension writing: PHP Extensions Made Eldrich"/><link href="https://www.simonholywell.com/post/2011/10/getting-started-node-js-couch-db/?utm_source=atom_feed" rel="related" type="text/html" title="Getting started with Node.js and CouchDB"/><link href="https://www.simonholywell.com/post/2011/05/netbeans-7-agavi-support/?utm_source=atom_feed" rel="related" type="text/html" title="New version of the Agavi framework support for NetBeans 7.0"/><link href="https://www.simonholywell.com/post/2011/01/php-number-error/?utm_source=atom_feed" rel="related" type="text/html" title="PHP Hangs When Fed 2.2250738585072011e-308"/><id>https://www.simonholywell.com/post/2012/01/mysql-udf-install-error-function-already-exists/</id><author><name>Simon Holywell</name></author><published>2012-01-31T11:47:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>When installing a UDF recently I got an annoying error message, which didn’t seem to want to go away. Deleting the function before attempting to remove it did not work so I used the following set of escalating commands to attempt to get it to install.
But back to the error for a moment:
bash &amp;gt; mysql -u user -p &amp;lt; installdb.sql Enter password: ERROR 1125 (HY000) at line 7: Function 'lib_mysqludf_ssdeep_info' already exists This can be solved really simply with the following options:</summary><content type="html"><![CDATA[<p>When <a href="https://github.com/treffynnon/lib_mysqludf_ssdeep">installing a UDF recently</a> I got an annoying error message, which didn’t seem to want to go away. Deleting the function before attempting to remove it did not work so I used the following set of escalating commands to attempt to get it to install.</p>
<p>But back to the error for a moment:</p>
<pre><code>bash &gt; mysql -u user -p &lt; installdb.sql
Enter password:
ERROR 1125 (HY000) at line 7: Function 'lib_mysqludf_ssdeep_info' already exists
</code></pre>
<p>This can be solved really simply with the following options:</p>
<ol>
<li>Attempt to delete the function and then reinstall it</li>
<li>Delete the function row from the mysql.func table and then reinstall it</li>
<li>Stop the MySQL server (after trying option 2), start it again and then reinstall it</li>
</ol>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="mysql" label="mysql"/><category scheme="taxonomy:Tags" term="udf" label="udf"/><category scheme="taxonomy:Tags" term="internet" label="internet"/></entry><entry xml:base="nodester-environment-variables-for-sensitive-data"><title type="html">Nodester environment variables for sensitive data and passwords</title><link href="https://www.simonholywell.com/post/2011/10/nodester-environment-variables-for-sensitive-data/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2010/11/setup-a-new-portforward-on-vigor-over-telnet/?utm_source=atom_feed" rel="related" type="text/html" title="Set up a new port forward on a Draytek Vigor over the telnet interface"/><link href="https://www.simonholywell.com/post/2011/10/php-extensions-made-elrich/?utm_source=atom_feed" rel="related" type="text/html" title="PHP extension writing: PHP Extensions Made Eldrich"/><link href="https://www.simonholywell.com/post/2011/10/getting-started-node-js-couch-db/?utm_source=atom_feed" rel="related" type="text/html" title="Getting started with Node.js and CouchDB"/><link href="https://www.simonholywell.com/post/2011/05/netbeans-7-agavi-support/?utm_source=atom_feed" rel="related" type="text/html" title="New version of the Agavi framework support for NetBeans 7.0"/><link href="https://www.simonholywell.com/post/2011/01/php-number-error/?utm_source=atom_feed" rel="related" type="text/html" title="PHP Hangs When Fed 2.2250738585072011e-308"/><id>https://www.simonholywell.com/post/2011/10/nodester-environment-variables-for-sensitive-data/</id><author><name>Simon Holywell</name></author><published>2011-10-27T23:21:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>When I began using Cloudno.de recently to have a go at Node.js and CouchDB I stored my username and password in plain text in a configuration file. If you are also looking to get CouchDB going with CloudNo.de then my earlier Getting started with Node.js and CouchDB post may be of interest.
The configuration file was fine for testing as nobody who came across the database login details could do any real damage, but as the project got more interesting I wanted to send it live and these details would need to be kept private.</summary><content type="html"><![CDATA[<p>When I began using <a href="http://cloudno.de/">Cloudno.de</a> recently to have a go at <a href="http://nodejs.org/">Node.js</a> and CouchDB I stored my username and password in plain text in a configuration file. If you are also looking to get CouchDB going with CloudNo.de then my earlier <a href="/post/2011/10/getting-started-node-js-couch-db.html">Getting started with Node.js and CouchDB</a> post may be of interest.</p>
<p>The configuration file was fine for testing as nobody who came across the database login details could do any real damage, but as the project got more interesting I wanted to send it live and these details would need to be kept private.</p>
<p>Thankfully the <a href="https://github.com/nodester/nodester">Nodester</a> platform, which CloudNo.de is using, has environment variables built in and you can use them to store sensitive data such as passwords. It is also good to know that the variables will persist even after the host machine is cycled.</p>
<p>To set an environment variable you simply make a curl request to the API like the following:</p>
<p><code>curl -k -X PUT -u &quot;[username]:[api key/password]&quot; -d &quot;appname=[app name]&amp;key=[environment variable name]&amp;value=[environment variable value]&quot; https://api.cloudno.de/env</code></p>
<p>Replace the items in the square brackets with the values from your Nodester based hosting solution (such as cloudno.de) and your environment variable content.</p>
<p>If you are not using CloudNo.de then you will also need change the URL at the end of the command above to point to the correct API URL for your service. For example with <a href="http://nodester.com/">Nodester’s own hosting</a> the URL should be <a href="http://api.nodester.com/env">http://api.nodester.com/env</a>.</p>
<p>So if I wanted to set an environment variable called “first_name” and set the value to “Simon” I would issue the following curl request.</p>
<p><code>curl -k -X PUT -u &quot;username:api_key&quot; -d &quot;appname=app_name&amp;key=first_name&amp;value=Simon&quot; https://api.cloudno.de/env</code></p>
<p>To check it has been set correctly you can GET the value:</p>
<p><code>curl -u &quot;[username]:[api key/password]&quot; -d &quot;appname=[app name]&amp;key=[environment variable name]&quot; https://api.cloudno.de/env</code></p>
<p>You can also delete an environment variable from the system using the following command:</p>
<p><code>curl -X DELETE -u &quot;[username]:[api key/password]&quot; -d &quot;appname=[app name]&amp;key=[environment variable name]&quot; https://api.cloudno.de/env</code></p>
<p>So that sets up the environment variable, but how do you access it from within Node.js?</p>
<p>It is as simple as accessing the global process object in the following manner:</p>
<p><code>var environment_variable_value = process.env.[environment variable name];</code></p>
<p>Again replace the square brackets with the actual environment variable name to access it. So to access the environment variable I set in my earlier example it would look like:</p>
<p><code>var environment_variable_value = process.env.first_name</code></p>
<p>Now you have a working environment variable setup to store you sensitive data in.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="nodejs" label="nodejs"/><category scheme="taxonomy:Tags" term="internet" label="internet"/><category scheme="taxonomy:Tags" term="command-line" label="command line"/></entry><entry xml:base="php-extensions-made-elrich"><title type="html">PHP extension writing: PHP Extensions Made Eldrich</title><link href="https://www.simonholywell.com/post/2011/10/php-extensions-made-elrich/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2010/09/15-excellent-resources-for-php-extension-development/?utm_source=atom_feed" rel="related" type="text/html" title="15 Excellent Resources for PHP Extension Development"/><link href="https://www.simonholywell.com/post/2011/07/how-php-ssdeep-was-made/?utm_source=atom_feed" rel="related" type="text/html" title="How the ssdeep PHP extension came into being"/><link href="https://www.simonholywell.com/post/2010/10/pecl-install-issues-on-redhat/?utm_source=atom_feed" rel="related" type="text/html" title="PECL Install Issues on Redhat"/><link href="https://www.simonholywell.com/post/2010/09/php-ssdeep-in-pecl/?utm_source=atom_feed" rel="related" type="text/html" title="The PHP ssdeep Extension is Now in PECL"/><link href="https://www.simonholywell.com/post/2011/01/php-number-error/?utm_source=atom_feed" rel="related" type="text/html" title="PHP Hangs When Fed 2.2250738585072011e-308"/><id>https://www.simonholywell.com/post/2011/10/php-extensions-made-elrich/</id><author><name>Simon Holywell</name></author><published>2011-10-26T09:56:45+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>PHP extension writing: PHP Extensions Made Eldrich
Since writing my 15 Excellent Resources for PHP Extension Development post in September last year Kristina Chodorow of 10gen (MongoDB) has written an excellent four part article on writing PHP Extensions on her blog Snail in a Turtleneck.</summary><content type="html"><![CDATA[<p><a href="http://www.snailinaturtleneck.com/blog/2011/08/11/php-extensions-made-eldrich-installing-php/">PHP extension writing: PHP Extensions Made Eldrich</a></p>
<p>Since writing my <a href="/post/1156691738/15-excellent-resources-for-php-extension-development">15 Excellent Resources for PHP Extension Development</a> post in September last year Kristina Chodorow of 10gen (MongoDB) has written an excellent four part article on writing PHP Extensions on her blog <a href="http://www.snailinaturtleneck.com/">Snail in a Turtleneck</a>.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="php-extension" label="php extension"/><category scheme="taxonomy:Tags" term="php-extensions" label="php extensions"/><category scheme="taxonomy:Tags" term="php" label="php"/><category scheme="taxonomy:Tags" term="internet" label="internet"/></entry><entry xml:base="marco-simoncelli"><title type="html">The world has lost an excellent and exciting rider in Marco Simoncelli</title><link href="https://www.simonholywell.com/post/2011/10/marco-simoncelli/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2011/04/prince-william-a-squid/?utm_source=atom_feed" rel="related" type="text/html" title="Whilst the wedding is a great event for the participants, I am n…"/><link href="https://www.simonholywell.com/post/2010/06/adenauer-forst-70s-crash-compilation/?utm_source=atom_feed" rel="related" type="text/html" title="sharonov: 1970 Adenauer Forst crashes"/><link href="https://www.simonholywell.com/post/2010/05/pirelli-diablo-rosso-corsa/?utm_source=atom_feed" rel="related" type="text/html" title="Pirelli Diablo Rosso Corsa"/><link href="https://www.simonholywell.com/post/2010/05/healtech-gi-pro-gear-indicator/?utm_source=atom_feed" rel="related" type="text/html" title="My review of the HealTech GIpro w/ATRE motorcycle gear position …"/><link href="https://www.simonholywell.com/post/2011/06/fucking-keep-it/?utm_source=atom_feed" rel="related" type="text/html" title="Ah, so eloquent! jeffreyshek: Only in Scotland. Photo taken by a…"/><id>https://www.simonholywell.com/post/2011/10/marco-simoncelli/</id><author><name>Simon Holywell</name></author><published>2011-10-24T01:10:39+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>The world has lost an excellent and exciting rider in Marco Simoncelli. He was a true character. RIP #58.
You can leave a tribute on the MotoGP website.</summary><content type="html"><![CDATA[<p><img src="/static/images/25.media.tumblr.com/tumblr_ltjn5ri0rb1qb2lcto1_1280.jpg" alt="image0"><img src="/static/images/24.media.tumblr.com/tumblr_ltjn5ri0rb1qb2lcto2_1280.jpg" alt="image1"><img src="/static/images/25.media.tumblr.com/tumblr_ltjn5ri0rb1qb2lcto3_1280.jpg" alt="image2"></p>
<p>The world has lost an excellent and exciting rider in <a href="http://www.marcosimoncelli.it/">Marco Simoncelli</a>. He was a true character. RIP #58.</p>
<p>You can leave a <a href="http://www.motogp.com/en/news/2011/malaysia+sepang+motogp+simoncelli+succumbs+to+injuries">tribute</a> on the <a href="http://www.motogp.com/en/news/2011/malaysia+sepang+motogp+simoncelli+succumbs+to+injuries">MotoGP website</a>.</p>
]]></content><category scheme="taxonomy:Tags" term="motors" label="motors"/><category scheme="taxonomy:Tags" term="bikes" label="bikes"/><category scheme="taxonomy:Tags" term="motogp" label="MotoGP"/></entry><entry xml:base="getting-started-node-js-couch-db"><title type="html">Getting started with Node.js and CouchDB</title><link href="https://www.simonholywell.com/post/2011/10/getting-started-node-js-couch-db/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2011/05/netbeans-7-agavi-support/?utm_source=atom_feed" rel="related" type="text/html" title="New version of the Agavi framework support for NetBeans 7.0"/><link href="https://www.simonholywell.com/post/2011/01/php-number-error/?utm_source=atom_feed" rel="related" type="text/html" title="PHP Hangs When Fed 2.2250738585072011e-308"/><link href="https://www.simonholywell.com/post/2011/01/fulloctane-introduction/?utm_source=atom_feed" rel="related" type="text/html" title="FullOctane: Bike and Car Blog"/><link href="https://www.simonholywell.com/post/2010/12/logging-global-php-objects-lazy-loading-proxy/?utm_source=atom_feed" rel="related" type="text/html" title="Logging global PHP objects and saving memory using a lazy loading proxy"/><link href="https://www.simonholywell.com/post/2010/11/setup-a-new-portforward-on-vigor-over-telnet/?utm_source=atom_feed" rel="related" type="text/html" title="Set up a new port forward on a Draytek Vigor over the telnet interface"/><id>https://www.simonholywell.com/post/2011/10/getting-started-node-js-couch-db/</id><author><name>Simon Holywell</name></author><published>2011-10-21T15:47:17+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Node.js and CouchDB feel like they were made for each other right from the very first time I used them. With the cradle node package the integration becomes even easier.
Whilst both Node.js and CouchDB are open source with packages for most operating systems it maybe easier for you to start out using a hosted solution such as CloudNo.de (has CouchDB now) or Nodester for example. As far as the CouchDB portion goes there is only one place to go and that is IrisCouch.</summary><content type="html"><![CDATA[<p><a href="http://nodejs.org/">Node.js</a> and <a href="http://couchdb.apache.org/">CouchDB</a> feel like they were made for each other right from the very first time I used them. With the <a href="http://cloudhead.io/cradle">cradle node package</a> the integration becomes even easier.</p>
<p>Whilst both Node.js and CouchDB are open source with packages for most operating systems it maybe easier for you to start out using a hosted solution such as <a href="https://cloudno.de/">CloudNo.de</a> (has CouchDB now) or <a href="http://nodester.com/">Nodester</a> for example. As far as the CouchDB portion goes there is only one place to go and that is <a href="http://www.iriscouch.com/">IrisCouch</a>.</p>
<p>With the exception of IrisCouch they are all in private beta so there might be a small wait before you get access.</p>
<p>I wrote the following example code before <a href="http://docs.cloudno.de/couchdb">CloudNo.de supported CouchDB</a> so it references <a href="http://www.iriscouch.com/">IrisCouch</a>, but the setup is similar.</p>
<p>So at this point I am going to assume that you have successfully installed Node.js and CouchDB or are using hosted services. All the projects have good installation documentation for most platforms and there are many blog posts rehashing this step out there.</p>
<p>Firstly you will need to install the <a href="http://cloudhead.io/cradle">cradle package</a> using:</p>
<p><code>npm install cradle</code></p>
<p>It should be noted here that if you are using a hosted service the command will be something like:</p>
<p><code>cloudnode app npm install cradle</code></p>
<p>from the applications root directory (the one with the .git folder in it). Both the <a href="http://docs.cloudno.de/">CloudNo.de documentation</a> and <a href="http://nodester.com/api.html">Nodester documentation</a> cover this process on their respective websites.</p>
<p>CouchDB is <a href="http://couchdb.apache.org/docs/intro.html">documented</a> on the Apache foundation’s web pages and the <a href="http://cloudhead.io/cradle">cradle middleware</a> has its <a href="https://github.com/cloudhead/cradle">source</a> and <a href="https://github.com/cloudhead/cradle/blob/master/README.md">documentation</a> on <a href="https://github.com">GitHub</a>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">http</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s2">&#34;http&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">http</span>
</span></span><span class="line"><span class="cl">  <span class="p">.</span><span class="nx">createServer</span><span class="p">(</span><span class="kd">function</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">http_res</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">http_res</span><span class="p">.</span><span class="nx">writeHead</span><span class="p">(</span><span class="mi">200</span><span class="p">,</span> <span class="p">{</span> <span class="s2">&#34;Content-Type&#34;</span><span class="o">:</span> <span class="s2">&#34;text/plain&#34;</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl">    <span class="kd">var</span> <span class="nx">response</span> <span class="o">=</span> <span class="s2">&#34;&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="kd">var</span> <span class="nx">cradle</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s2">&#34;cradle&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="kd">var</span> <span class="nx">connection</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">cradle</span><span class="p">.</span><span class="nx">Connection</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">      <span class="s2">&#34;https://subdomain.iriscouch.com&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="mi">443</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">auth</span><span class="o">:</span> <span class="p">{</span> <span class="nx">username</span><span class="o">:</span> <span class="s2">&#34;username&#34;</span><span class="p">,</span> <span class="nx">password</span><span class="o">:</span> <span class="s2">&#34;password&#34;</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">      <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="kd">var</span> <span class="nx">db</span> <span class="o">=</span> <span class="nx">connection</span><span class="p">.</span><span class="nx">database</span><span class="p">(</span><span class="s2">&#34;database_name&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">db</span><span class="p">.</span><span class="nx">save</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">      <span class="s2">&#34;document_key&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">name</span><span class="o">:</span> <span class="s2">&#34;A Funny Name&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="p">},</span>
</span></span><span class="line"><span class="cl">      <span class="kd">function</span> <span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="c1">// Handle error
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>          <span class="nx">response</span> <span class="o">+=</span> <span class="s2">&#34; SAVE ERROR: Could not save record!!\n&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="c1">// Handle success
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>          <span class="nx">response</span> <span class="o">+=</span> <span class="s2">&#34; SUCESSFUL SAVE\n&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="nx">db</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s2">&#34;document_key&#34;</span><span class="p">,</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">doc</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="nx">response</span> <span class="o">+=</span> <span class="s2">&#34; DOCUMENT: &#34;</span> <span class="o">+</span> <span class="nx">doc</span> <span class="o">+</span> <span class="s2">&#34;\n&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">          <span class="nx">http_res</span><span class="p">.</span><span class="nx">end</span><span class="p">(</span><span class="nx">response</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">});</span>
</span></span><span class="line"><span class="cl">      <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">})</span>
</span></span><span class="line"><span class="cl">  <span class="p">.</span><span class="nx">listen</span><span class="p">(</span><span class="mi">8071</span><span class="p">);</span>
</span></span></code></pre></div><p>I think that the code is fairly easy to follow if you have written JavaScript code utilising callbacks before, but I will step through it for clarity.</p>
<p>A new HTTP server is setup first so that we can access the Node.js programme through the a web browser to trigger the database changes. Incidentally this would be accessed at <a href="http://localhost:80871">http://localhost:80871</a> or <a href="http://subdomain.cloudno.de">http://subdomain.cloudno.de</a>.</p>
<p>Cradle is then setup and the connection parameters are set with the CouchDB database being selected on line 11.</p>
<p>Next a new document is saved into the DB (replace document_key with your document name to customise) with the contents of { name: “A funny name” }. Once this is saved a callback function is called that will attempt to retrieve the record.</p>
<p>Depending upon how successful the whole process is you should see something like</p>
<pre><code>SUCESSFUL SAVE
DOCUMENT: { name: &quot;A funny name&quot; }
</code></pre>
<p>in your browser.</p>
<p>As you can see it is really easy to change what is saved and how it is retrieved. This was just a very simple introduction, but there are many neat tricks documented at each projects homepage.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="couchdb" label="CouchDB"/><category scheme="taxonomy:Tags" term="nodejs" label="Nodejs"/><category scheme="taxonomy:Tags" term="internet" label="internet"/></entry><entry xml:base="php-elephants"><title type="html">PHP elephants</title><link href="https://www.simonholywell.com/post/2011/10/php-elephants/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2011/07/how-php-ssdeep-was-made/?utm_source=atom_feed" rel="related" type="text/html" title="How the ssdeep PHP extension came into being"/><link href="https://www.simonholywell.com/post/2011/06/linux-on-dell-inspiron-2500/?utm_source=atom_feed" rel="related" type="text/html" title="Running a sane version of Linux on a Dell Inspiron 2500"/><link href="https://www.simonholywell.com/post/2011/06/i-remember-watching-trains-from-this-bridge-when-i/?utm_source=atom_feed" rel="related" type="text/html" title="I remember watching trains from this bridge when I first arrived…"/><link href="https://www.simonholywell.com/post/2011/06/fucking-keep-it/?utm_source=atom_feed" rel="related" type="text/html" title="Ah, so eloquent! jeffreyshek: Only in Scotland. Photo taken by a…"/><link href="https://www.simonholywell.com/post/2011/05/netbeans-7-agavi-support/?utm_source=atom_feed" rel="related" type="text/html" title="New version of the Agavi framework support for NetBeans 7.0"/><id>https://www.simonholywell.com/post/2011/10/php-elephants/</id><author><name>Simon Holywell</name></author><published>2011-10-21T15:23:09+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>PHP elephants</summary><content type="html"><![CDATA[<p><img src="/static/images/25.media.tumblr.com/tumblr_ltevijqz3x1qb2lcto1_500.jpg" alt="image0"> <strong>PHP elephants</strong></p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/></entry><entry xml:base="how-php-ssdeep-was-made"><title type="html">How the ssdeep PHP extension came into being</title><link href="https://www.simonholywell.com/post/2011/07/how-php-ssdeep-was-made/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2010/10/pecl-install-issues-on-redhat/?utm_source=atom_feed" rel="related" type="text/html" title="PECL Install Issues on Redhat"/><link href="https://www.simonholywell.com/post/2010/09/15-excellent-resources-for-php-extension-development/?utm_source=atom_feed" rel="related" type="text/html" title="15 Excellent Resources for PHP Extension Development"/><link href="https://www.simonholywell.com/post/2010/09/php-ssdeep-in-pecl/?utm_source=atom_feed" rel="related" type="text/html" title="The PHP ssdeep Extension is Now in PECL"/><link href="https://www.simonholywell.com/post/2010/08/php-ssdeep-fuzzy-hashing-php-extension/?utm_source=atom_feed" rel="related" type="text/html" title="php_ssdeep Fuzzy Hashing PHP Extension"/><link href="https://www.simonholywell.com/post/2011/02/gearman-php-mod-gearman-status/?utm_source=atom_feed" rel="related" type="text/html" title="Gearman, PHP and mod_gearman_status on Ubuntu"/><id>https://www.simonholywell.com/post/2011/07/how-php-ssdeep-was-made/</id><author><name>Simon Holywell</name></author><published>2011-07-14T13:17:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Recently (well in a loose sense anyway) I had the need to build a document bank in PHP for a client at Mosaic. It was a fairly involved application with various public and private APIs for integration into the clients network of websites.
The core PHP code was written on top of the Agavi framework and various PHP libraries for extracting text and meta data from documents. One of the major features the client required was for the system to detect similar files to prevent unintentional duplicates making it into the document bank.</summary><content type="html"><![CDATA[<p>Recently (well in a loose sense anyway) I had the need to build a document bank in PHP for a client at <a href="http://www.emosaic.co.uk/">Mosaic</a>. It was a fairly involved application with various public and private APIs for integration into the clients network of websites.</p>
<p>The core PHP code was written on top of the <a href="http://www.agavi.org">Agavi</a> framework and various PHP libraries for extracting text and meta data from documents. One of the major features the client required was for the system to detect similar files to prevent unintentional duplicates making it into the document bank.</p>
<p>The idea was that this document bank would be the one central resource for all of the documents written and managed by the organisation. Duplicates or near duplicates would of course make this a pointless exercise. So I turned to <a href="http://www.stackoverflow.com">StackOverflow</a> for some pointers, but <a href="http://stackoverflow.com/q/1728977/461813">came up empty</a>.</p>
<p>After some research and much searching of the web I came across an open source package called <a href="http://www.ssdeep.sf.net">ssdeep</a> written by Jesse Kornblum. I found it through reading his research papers; <a href="http://dfrws.org/2006/proceedings/12-Kornblum.pdf">Identifying almost identical files using context triggered piecewise hashing</a>.</p>
<p>ssdeep is based upon work by <a href="http://samba.org/~tridge/">Andrew Tridgell</a> of <a href="http://www.samba.org">samba</a> fame who produced <a href="http://www.samba.org/ftp/unpacked/junkcode/spamsum/">spamsum</a> and the basis of the mathematics behind ssdeep. To summarise ssdeep would be to say that it can detect homologous files or signatures in files.</p>
<p>Despite the fact that ssdeep was originally intended to be used for malware detection it is equally suited to the more mundane task of detecting duplicate documents.</p>
<p>With this discovery I immediately began creating a prototype version written in basic PHP that would serve as a wrapper around the ssdeep binary. I have, by request, made <a href="https://gist.github.com/1075789">this code public</a> , but it is a pretty old hack and I would not recommend using it.</p>
<p>As I got this prototype up and running I began to see how powerful ssdeep was, but with one small caveat - it works best on files above 4KB as noted in an <a href="http://pecl.php.net/bugs/bug.php?id=20348">erroneous bug report</a> on the ssdeep package in PECL. In my application this was fine as it was handling large PDF and Word documents for the most part.</p>
<p>Soon I became aware that there was <a href="http://ssdeep.sourceforge.net/api/html/">API for the ssdeep package</a> that I could extend to create a PHP extension. So I spent quite some time figuring out how to actually write a PHP extension from various sources and then even more time looking into the autoconf build process.</p>
<p>If you are interested in writing your own extension I have documented my <a href="/post/2010/09/15-excellent-resources-for-php-extension-development.html">resources previously on this blog</a>.</p>
<p>After some annoying errors with baffling outputs I finally had my extension written, building and tested. Pretty soon it was a on a production box and working like a dream on thousands of documents.</p>
<p>Now I wanted to share the code for others to use so initially I hosted it all on <a href="http://github.com">github</a>, but soon realised it would get far more exposure if it was included in <a href="http://pecl.php.net">PECL</a>. I also wanted to have ssdeep properly documented in the main PHP manual to further promote the extension.</p>
<p>This did look <a href="http://news.php.net/php.pecl.dev/7607">unlikely in the beginning</a> as the ssdeep package is licenced using GPL, which cannot be accepted into PECL due to its viral nature. Thankfully after contacting Jesse it became clear that the original work by Tridgell had <a href="http://news.php.net/php.pecl.dev/7616">been dual licenced</a> and he could therefore <a href="http://news.php.net/php.pecl.dev/7625">grant me an exemption</a> from GPL for the purposes of PECL.</p>
<p>After completing the application process, accepting code reviews and jumping the legal hurdles I was finally ready to publish my first PECL extension! I began building the PECL extension locally and installing it on as many machines as possible through the PECL method.</p>
<p>Thankfully it all went to plan apart from a <a href="http://pear.php.net/bugs/bug.php?id=18040&amp;edit=3">bug I discovered in Pyrus</a> and I managed to get a release up. Next was the process of documenting it all for PHP, suffice to say <a href="/post/2010/09/15-excellent-resources-for-php-extension-development.html">its not as easy as it sounds</a>. (Two spaces of indent not four!)</p>
<p>In the end though with thanks to Pierre, Johannes, Gustavo and of course Jesse I had released my first extension into the wild.</p>
<ul>
<li><a href="http://php.net/ssdeep">ssdeep PHP extension documentation</a></li>
<li><a href="http://pecl.php.net/ssdeep">ssdeep PECL page</a></li>
<li><a href="http://treffynnon.github.com/php_ssdeep/">ssdeep PHP extension github hosted web page</a></li>
</ul>
<p>There you have it. That is how a PHP extension is born and merged into PECL.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="php" label="php"/><category scheme="taxonomy:Tags" term="php_ssdeep" label="php_ssdeep"/><category scheme="taxonomy:Tags" term="php-extension" label="php extension"/><category scheme="taxonomy:Tags" term="php-extensions" label="php extensions"/></entry><entry xml:base="linux-on-dell-inspiron-2500"><title type="html">Running a sane version of Linux on a Dell Inspiron 2500</title><link href="https://www.simonholywell.com/post/2011/06/linux-on-dell-inspiron-2500/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2011/04/ssh-agent-not-storing-unencrypted-key/?utm_source=atom_feed" rel="related" type="text/html" title="Why won't ssh-agent save my unencrypted key for later use?"/><link href="https://www.simonholywell.com/post/2010/08/php-ssdeep-fuzzy-hashing-php-extension/?utm_source=atom_feed" rel="related" type="text/html" title="php_ssdeep Fuzzy Hashing PHP Extension"/><link href="https://www.simonholywell.com/post/2010/08/php-wrapper-for-linux-at-command/?utm_source=atom_feed" rel="related" type="text/html" title="A PHP wrapper for the unix at command"/><link href="https://www.simonholywell.com/post/2010/08/linux-batch-remove-extension/?utm_source=atom_feed" rel="related" type="text/html" title="Batch remove extensions in Ubuntu"/><link href="https://www.simonholywell.com/post/2010/08/ubuntu-atd-not-running/?utm_source=atom_feed" rel="related" type="text/html" title="If you are having problems getting Ubuntu atd running"/><id>https://www.simonholywell.com/post/2011/06/linux-on-dell-inspiron-2500/</id><author><name>Simon Holywell</name></author><published>2011-06-22T21:33:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>I have ended up with a very old piece of hardware and of course the first thing I did was wipe the Windows 2000 installation and stick a few versions of Linux on it. Unfortunately it only came with 128MB of memory from factory so nothing would run very well. The PCMIA wireless card that came with it wouldn’t work with WPA2 under Windows 2000 so an upgrade was required.</summary><content type="html"><![CDATA[<p>I have ended up with a very old piece of hardware and of course the first thing I did was wipe the Windows 2000 installation and stick a few versions of Linux on it. Unfortunately it only came with 128MB of memory from factory so nothing would run very well. The PCMIA wireless card that came with it wouldn’t work with WPA2 under Windows 2000 so an upgrade was required.</p>
<p>£5 later I got a matched pair of Crucial 256MB sticks on ebay so I could try out <a href="http://www.linuxmint.com/edition.php?id=35">Linux Mint 6 Fluxbox</a> edition and <a href="http://www.linuxmint.com/edition.php?id=78">Linux Mint 10 LXDE</a>. Whilst both worked right out of the box I did have to configure the X11 monitor settings so that it would support the full 1024x768 splendour that the Inspiron 2500 affords you. See <a href="https://gist.github.com/1041046">the gist</a> I have setup on github for my configuration file and some short instructions on getting it setup.</p>
<p>In the end I decided to go with Mint 10 LXDE as it used a similar level of system resources, but ran more smoothly and of course benefited from being the latest version with full package update support.</p>
<p><img src="/static/images/2011-06-22_mint10_lxde.png" alt=""></p>
<p>I expected to have a load of issues getting the Belkin wireless adapter working, but in the end this distro had all the drivers so need for all those ndiswrapper recipes that are out there. It is running much better than the Windows 2000 OS was as well and benefits from having and running newer versions of all the applications I need.</p>
<p>Of course web streaming of Flash video is somewhat staccato with such a small CPU but it is a perfectly usable web browser and word processor.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="linux" label="linux"/></entry><entry xml:base="i-remember-watching-trains-from-this-bridge-when-i"><title type="html">I remember watching trains from this bridge when I first arrived…</title><link href="https://www.simonholywell.com/post/2011/06/i-remember-watching-trains-from-this-bridge-when-i/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2011/06/fucking-keep-it/?utm_source=atom_feed" rel="related" type="text/html" title="Ah, so eloquent! jeffreyshek: Only in Scotland. Photo taken by a…"/><link href="https://www.simonholywell.com/post/2011/05/netbeans-7-agavi-support/?utm_source=atom_feed" rel="related" type="text/html" title="New version of the Agavi framework support for NetBeans 7.0"/><link href="https://www.simonholywell.com/post/2011/05/tz3-stradale/?utm_source=atom_feed" rel="related" type="text/html" title="TZ3 Stradale"/><link href="https://www.simonholywell.com/post/2011/04/prince-william-a-squid/?utm_source=atom_feed" rel="related" type="text/html" title="Whilst the wedding is a great event for the participants, I am n…"/><link href="https://www.simonholywell.com/post/2011/04/ssh-agent-not-storing-unencrypted-key/?utm_source=atom_feed" rel="related" type="text/html" title="Why won't ssh-agent save my unencrypted key for later use?"/><id>https://www.simonholywell.com/post/2011/06/i-remember-watching-trains-from-this-bridge-when-i/</id><author><name>Simon Holywell</name></author><published>2011-06-10T09:55:51+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>I remember watching trains from this bridge when I first arrived in Edinburgh from Australia. It was cold then too!
nationalgeographicdaily:
Children Watching Train, Edninburgh
Photograph by Vishal Soniji
This photo was taken during my visit to Edinburgh as I was on my way to Edinburgh Castle.</summary><content type="html"><![CDATA[<p><img src="/static/images/25.media.tumblr.com/tumblr_lmk50lJZM01qbd38ro1_1280.jpg" alt=""></p>
<p>I remember watching trains from this bridge when I first arrived in Edinburgh from Australia. It was cold then too!</p>
<p><a href="http://nationalgeographicdaily.tumblr.com/post/6375638339">nationalgeographicdaily</a>:</p>
<blockquote>
<p><strong>Children Watching Train, Edninburgh</strong></p>
<p><strong><em>Photograph by Vishal Soniji</em></strong></p>
<p>This photo was taken during my visit to Edinburgh as I was on my way to Edinburgh Castle.</p>
</blockquote>
]]></content></entry><entry xml:base="fucking-keep-it"><title type="html">Ah, so eloquent! jeffreyshek: Only in Scotland. Photo taken by a…</title><link href="https://www.simonholywell.com/post/2011/06/fucking-keep-it/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2011/05/tz3-stradale/?utm_source=atom_feed" rel="related" type="text/html" title="TZ3 Stradale"/><link href="https://www.simonholywell.com/post/2010/08/new-lancia-stratos-by-pininfarina/?utm_source=atom_feed" rel="related" type="text/html" title="A nice modern take on the original Stratos by Pininfarina set to…"/><link href="https://www.simonholywell.com/post/2010/06/adenauer-forst-70s-crash-compilation/?utm_source=atom_feed" rel="related" type="text/html" title="sharonov: 1970 Adenauer Forst crashes"/><link href="https://www.simonholywell.com/post/2010/06/sainte-beaume-hill-norma-m20-climb/?utm_source=atom_feed" rel="related" type="text/html" title="Gives an amazing sense of speed. missedapex: Norma M20 makes its…"/><link href="https://www.simonholywell.com/post/2011/04/prince-william-a-squid/?utm_source=atom_feed" rel="related" type="text/html" title="Whilst the wedding is a great event for the participants, I am n…"/><id>https://www.simonholywell.com/post/2011/06/fucking-keep-it/</id><author><name>Simon Holywell</name></author><published>2011-06-03T10:14:35+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Ah, so eloquent!
jeffreyshek:
Only in Scotland. Photo taken by a friend of mine.</summary><content type="html"><![CDATA[<p><img src="/static/images/25.media.tumblr.com/tumblr_lm6r0mzsBx1qh6u46o1_1280.jpg" alt=""></p>
<p>Ah, so eloquent!</p>
<p><a href="http://jeffreyshek.tumblr.com/post/6121766086">jeffreyshek</a>:</p>
<blockquote>
<p>Only in Scotland. Photo taken by a friend of mine.</p>
</blockquote>
]]></content><category scheme="taxonomy:Tags" term="motors" label="motors"/><category scheme="taxonomy:Tags" term="cars" label="Cars"/><category scheme="taxonomy:Tags" term="rants" label="rants"/></entry><entry xml:base="netbeans-7-agavi-support"><title type="html">New version of the Agavi framework support for NetBeans 7.0</title><link href="https://www.simonholywell.com/post/2011/05/netbeans-7-agavi-support/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2010/04/agavi-on-the-auzre-platform/?utm_source=atom_feed" rel="related" type="text/html" title="Agavi: Agavi on the Azure Platform"/><link href="https://www.simonholywell.com/post/2011/01/php-number-error/?utm_source=atom_feed" rel="related" type="text/html" title="PHP Hangs When Fed 2.2250738585072011e-308"/><link href="https://www.simonholywell.com/post/2011/01/fulloctane-introduction/?utm_source=atom_feed" rel="related" type="text/html" title="FullOctane: Bike and Car Blog"/><link href="https://www.simonholywell.com/post/2010/12/logging-global-php-objects-lazy-loading-proxy/?utm_source=atom_feed" rel="related" type="text/html" title="Logging global PHP objects and saving memory using a lazy loading proxy"/><link href="https://www.simonholywell.com/post/2010/11/setup-a-new-portforward-on-vigor-over-telnet/?utm_source=atom_feed" rel="related" type="text/html" title="Set up a new port forward on a Draytek Vigor over the telnet interface"/><id>https://www.simonholywell.com/post/2011/05/netbeans-7-agavi-support/</id><author><name>Simon Holywell</name></author><published>2011-05-05T13:32:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>necora-markus:
Released a new version of the Agavi framework support plugin for the shiny new NetBeans 7.0. Still depends on implementation versions of the PHP-plugin, so if something doesn’t work, please let me know.
Prebuilt NBM available here, source code here.
UPDATE: Even newer version available for download here. Should fix a null pointer exception.</summary><content type="html"><![CDATA[<p><a href="http://markus.necora.fi/post/5067201758">necora-markus</a>:</p>
<blockquote>
<p>Released a new version of the Agavi framework support plugin for the shiny new NetBeans 7.0. Still depends on implementation versions of the PHP-plugin, so if something doesn’t work, please let me know.</p>
<p>Prebuilt NBM <a href="https://github.com/downloads/horros/NetBeans-Agavi-plugin/php-agavi-30042011.nbm">available here</a>, source code <a href="git://github.com/horros/NetBeans-Agavi-plugin.git">here</a>.</p>
<p>UPDATE: Even newer version <a href="https://github.com/downloads/horros/NetBeans-Agavi-plugin/php-agavi-06052011.nbm">available for download here</a>. Should fix a null pointer exception.</p>
</blockquote>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="internet" label="internet"/><category scheme="taxonomy:Tags" term="agavi" label="agavi"/><category scheme="taxonomy:Tags" term="netbeans" label="netbeans"/></entry><entry xml:base="tz3-stradale"><title type="html">TZ3 Stradale</title><link href="https://www.simonholywell.com/post/2011/05/tz3-stradale/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2010/08/new-lancia-stratos-by-pininfarina/?utm_source=atom_feed" rel="related" type="text/html" title="A nice modern take on the original Stratos by Pininfarina set to…"/><link href="https://www.simonholywell.com/post/2010/06/adenauer-forst-70s-crash-compilation/?utm_source=atom_feed" rel="related" type="text/html" title="sharonov: 1970 Adenauer Forst crashes"/><link href="https://www.simonholywell.com/post/2010/06/sainte-beaume-hill-norma-m20-climb/?utm_source=atom_feed" rel="related" type="text/html" title="Gives an amazing sense of speed. missedapex: Norma M20 makes its…"/><link href="https://www.simonholywell.com/post/2011/04/prince-william-a-squid/?utm_source=atom_feed" rel="related" type="text/html" title="Whilst the wedding is a great event for the participants, I am n…"/><link href="https://www.simonholywell.com/post/2011/01/fulloctane-introduction/?utm_source=atom_feed" rel="related" type="text/html" title="FullOctane: Bike and Car Blog"/><id>https://www.simonholywell.com/post/2011/05/tz3-stradale/</id><author><name>Simon Holywell</name></author><published>2011-05-05T13:28:59+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>TZ3 Stradale</summary><content type="html"><![CDATA[<p><img src="/static/images/25.media.tumblr.com/tumblr_lklrzqofRc1qzpsi6o1_1280.jpg" alt=""></p>
<p><a href="http://www.supercars.net/Pics?v=y&amp;s=c&amp;id=5329&amp;p=2011_AlfaRomeo_TZ3Stradale2.jpg">TZ3 Stradale</a></p>
]]></content><category scheme="taxonomy:Tags" term="motors" label="motors"/><category scheme="taxonomy:Tags" term="cars" label="Cars"/></entry><entry xml:base="prince-william-a-squid"><title type="html">Whilst the wedding is a great event for the participants, I am n…</title><link href="https://www.simonholywell.com/post/2011/04/prince-william-a-squid/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2010/06/adenauer-forst-70s-crash-compilation/?utm_source=atom_feed" rel="related" type="text/html" title="sharonov: 1970 Adenauer Forst crashes"/><link href="https://www.simonholywell.com/post/2010/05/pirelli-diablo-rosso-corsa/?utm_source=atom_feed" rel="related" type="text/html" title="Pirelli Diablo Rosso Corsa"/><link href="https://www.simonholywell.com/post/2010/05/healtech-gi-pro-gear-indicator/?utm_source=atom_feed" rel="related" type="text/html" title="My review of the HealTech GIpro w/ATRE motorcycle gear position …"/><link href="https://www.simonholywell.com/post/2011/01/fulloctane-introduction/?utm_source=atom_feed" rel="related" type="text/html" title="FullOctane: Bike and Car Blog"/><link href="https://www.simonholywell.com/post/2010/08/new-lancia-stratos-by-pininfarina/?utm_source=atom_feed" rel="related" type="text/html" title="A nice modern take on the original Stratos by Pininfarina set to…"/><id>https://www.simonholywell.com/post/2011/04/prince-william-a-squid/</id><author><name>Simon Holywell</name></author><published>2011-04-28T09:21:13+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Whilst the wedding is a great event for the participants, I am not interested in the slightest. However William was seen last night out on his motorbike in less than adequate gear (squidding) and confirming his continued love for Ducati - some would say at the cost of Hinckley. Triumph being the only mass produced British rival to the big Duke.</summary><content type="html"><![CDATA[<p><img src="/static/images/25.media.tumblr.com/tumblr_lkcsjeuexo1qb2lcto1_1280.jpg" alt=""></p>
<p>Whilst the wedding is a great event for the participants, I am not interested in the slightest. However William was seen last night out on his motorbike in less than adequate gear (<a href="http://www.bytebrothers.org/SquidTest.htm">squidding</a>) and confirming his <a href="http://www.sponkit.com/prince-william-leaves-on-his-black-ducati/">continued</a> <a href="http://www.visordown.com/motorcycle-news--general-news/prince-william-orders-17k-ducati-1198sp-superbike/15601.html">love</a> for Ducati - some would say at the cost of <a href="http://en.wikipedia.org/wiki/Triumph_Motorcycles_Ltd#Hinckley_production">Hinckley</a>. Triumph being the only mass produced British rival to the big Duke.</p>
]]></content><category scheme="taxonomy:Tags" term="motors" label="motors"/><category scheme="taxonomy:Tags" term="bikes" label="bikes"/></entry><entry xml:base="ssh-agent-not-storing-unencrypted-key"><title type="html">Why won't ssh-agent save my unencrypted key for later use?</title><link href="https://www.simonholywell.com/post/2011/04/ssh-agent-not-storing-unencrypted-key/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2009/05/handy-linux-commands/?utm_source=atom_feed" rel="related" type="text/html" title="Handy Linux Commands"/><link href="https://www.simonholywell.com/post/2009/04/samba-file-share-over-ssh-tunnel/?utm_source=atom_feed" rel="related" type="text/html" title="Samba File Share Over SSH Tunnel"/><link href="https://www.simonholywell.com/post/2010/08/php-ssdeep-fuzzy-hashing-php-extension/?utm_source=atom_feed" rel="related" type="text/html" title="php_ssdeep Fuzzy Hashing PHP Extension"/><link href="https://www.simonholywell.com/post/2010/08/php-wrapper-for-linux-at-command/?utm_source=atom_feed" rel="related" type="text/html" title="A PHP wrapper for the unix at command"/><link href="https://www.simonholywell.com/post/2010/08/linux-batch-remove-extension/?utm_source=atom_feed" rel="related" type="text/html" title="Batch remove extensions in Ubuntu"/><id>https://www.simonholywell.com/post/2011/04/ssh-agent-not-storing-unencrypted-key/</id><author><name>Simon Holywell</name></author><published>2011-04-26T12:09:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Why won’t ssh-agent save my unencrypted key for later use?
I recently was annoyed by always having to enter my private keys passphrase every time I wanted to do a git push to or pull from a public git repository. Turns out that if you are logged into a Gnome session on an Ubuntu machine it will automatically add you key to ssh-agent, but if you are logged into a bash session (as I was) then it won’t.</summary><content type="html"><![CDATA[<p><a href="http://askubuntu.com/questions/36255/why-wont-ssh-agent-save-my-unencrypted-key-for-later-use">Why won’t ssh-agent save my unencrypted key for later use?</a></p>
<p>I recently was annoyed by always having to enter my private keys passphrase every time I wanted to do a git push to or pull from a public git repository. Turns out that if you are logged into a Gnome session on an Ubuntu machine it will automatically add you key to ssh-agent, but if you are logged into a bash session (as I was) then it won’t.</p>
<p>So you can either manually do the ssh-add yourself or following the instructions in the <a href="http://askubuntu.com/questions/36255/why-wont-ssh-agent-save-my-unencrypted-key-for-later-use">answer to my question</a> you can setup an automatic way of facilitating this.</p>
<p>One problem I discovered is that if you have git displaying the current branch information in your bash prompt like me then when you start a session it will ask you for your passphrase before rendering your bash prompt.</p>
<p>I am thinking that to work around this I could change the git function in the .bash_profile file to look at the arguments passed to it and if it is a remote operation such as a pull, push or clone then trigger the ssh-add otherwise it can safely skip it.</p>
<p>Any other ideas or patches?</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="ssh" label="ssh"/><category scheme="taxonomy:Tags" term="ubuntu" label="ubuntu"/><category scheme="taxonomy:Tags" term="linux" label="linux"/></entry><entry xml:base="hotvvheels-cool-is-a-color"><title type="html">hotvvheels: Cool is a Color</title><link href="https://www.simonholywell.com/post/2011/03/hotvvheels-cool-is-a-color/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2011/02/gearman-php-mod-gearman-status/?utm_source=atom_feed" rel="related" type="text/html" title="Gearman, PHP and mod_gearman_status on Ubuntu"/><link href="https://www.simonholywell.com/post/2011/01/winter-motorcycle-electrics/?utm_source=atom_feed" rel="related" type="text/html" title="Winter motorcycle storage: battery and electrical systems"/><link href="https://www.simonholywell.com/post/2011/01/winter-motorcycle-tyres/?utm_source=atom_feed" rel="related" type="text/html" title="Winter motorcycle storage: suspension and tyres"/><link href="https://www.simonholywell.com/post/2011/01/php-number-error/?utm_source=atom_feed" rel="related" type="text/html" title="PHP Hangs When Fed 2.2250738585072011e-308"/><link href="https://www.simonholywell.com/post/2011/01/winter-motorcycle-fuel/?utm_source=atom_feed" rel="related" type="text/html" title="Winter motorcycle storage: fuel system"/><id>https://www.simonholywell.com/post/2011/03/hotvvheels-cool-is-a-color/</id><author><name>Simon Holywell</name></author><published>2011-03-09T13:18:13+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>hotvvheels:
Cool is a Color</summary><content type="html"><![CDATA[<p><img src="/static/images/24.media.tumblr.com/tumblr_lgm7bnzPeg1qads8no1_1280.jpg" alt=""></p>
<p><a href="http://hotvvheels.tumblr.com/post/3686708737">hotvvheels</a>:</p>
<blockquote>
<p><a href="http://coolisacolor.tumblr.com/post/3292699430">Cool is a Color</a></p>
</blockquote>
]]></content></entry><entry xml:base="gearman-php-mod-gearman-status"><title type="html">Gearman, PHP and mod_gearman_status on Ubuntu</title><link href="https://www.simonholywell.com/post/2011/02/gearman-php-mod-gearman-status/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2010/11/team-development-server/?utm_source=atom_feed" rel="related" type="text/html" title="An Excellent Development Server for a Team of Developers"/><link href="https://www.simonholywell.com/post/2010/08/php-wrapper-for-linux-at-command/?utm_source=atom_feed" rel="related" type="text/html" title="A PHP wrapper for the unix at command"/><link href="https://www.simonholywell.com/post/2010/08/php-ssdeep-fuzzy-hashing-php-extension/?utm_source=atom_feed" rel="related" type="text/html" title="php_ssdeep Fuzzy Hashing PHP Extension"/><link href="https://www.simonholywell.com/post/2010/08/get-gearman-to-install-on-ubuntu/?utm_source=atom_feed" rel="related" type="text/html" title="Getting gearman to install on Ubuntu"/><link href="https://www.simonholywell.com/post/2009/08/moving-to-git-and-setting-up-indefero-as-a-web-frontend/?utm_source=atom_feed" rel="related" type="text/html" title="Moving to git and setting up InDefero as a web frontend"/><id>https://www.simonholywell.com/post/2011/02/gearman-php-mod-gearman-status/</id><author><name>Simon Holywell</name></author><published>2011-02-11T14:01:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Installing Gearman is pretty easy as there are packages for it in Ubuntu:
sudo apt-get install gearman libgearman-dev
The development headers (libgearman-dev) are only required if you need to compile a library for your programming language such as a PHP extension. To install the PHP module you would run:
sudo pecl install channel://pecl.php.net/gearman-0.7.0
If you have trouble with the above step then it is probably because you are running an older version of Ubuntu.</summary><content type="html"><![CDATA[<p>Installing <a href="http://www.gearman.org">Gearman</a> is pretty easy as there are packages for it in Ubuntu:</p>
<blockquote>
<p><code>sudo apt-get install gearman libgearman-dev</code></p>
</blockquote>
<p>The development headers (libgearman-dev) are only required if you need to compile a library for your programming language such as a PHP extension. To install the PHP module you would run:</p>
<blockquote>
<p><code>sudo pecl install channel://pecl.php.net/gearman-0.7.0</code></p>
</blockquote>
<p>If you have trouble with the above step then it is probably because you are running an older version of Ubuntu. In this case take a look at my previous post <a href="/post/2010/08/get-gearman-to-install-on-ubuntu.html">Getting gearman to install on Ubuntu</a>.</p>
<p>Moving onto <a href="https://github.com/amir/mod_gearman_status">mod_gearman_status</a>, which is an Apache module to show the status of Jobs and their associated workers. It looks like the following:</p>
<p><img src="/static/images/2011-02-11_mod_gearman_status.png" alt=""></p>
<p>Firstly lets ensure that the system has the build-essentials package installed:</p>
<blockquote>
<p><code>sudo apt-get install build-essentials</code></p>
</blockquote>
<p>We now need to install the Apache2 development headers, which assuming you installed the standard Ubuntu Apache2 package will be the prefork edition. If you don’t understand this then don’t worry you can just continue below.</p>
<blockquote>
<p><code>sudo apt-get install apache2-prefork-dev</code></p>
</blockquote>
<p>Now download <a href="https://github.com/amir/mod_gearman_status/blob/master/mod_gearman_status.c">modules C file</a> and run the following command to build it and install it as an Apache module:</p>
<blockquote>
<p><code>sudo apxs2 -c -i mod_gearman_status.c</code></p>
</blockquote>
<p>Apache now needs to be told how to load the module and what configuration settings to use. In /etc/apache2/mods-available you need to create two files.</p>
<p>/etc/apache2/mods-available/gearman_status.load:</p>
<blockquote>
<p><code>LoadModule gearman_status_module /usr/lib/apache2/modules/mod_gearman_status.so</code></p>
</blockquote>
<p>/etc/apache2/mods-available/gearman_status.conf:</p>
<blockquote>
<pre><code>&lt;IfModule mod_gearman_status.c&gt;
    &lt;Location /gearman-status&gt;
        SetHandler gearman_status
    &lt;/Location&gt;
&lt;/IfModule&gt;
</code></pre>
</blockquote>
<p>Enable the module with the following command:</p>
<blockquote>
<p><code>sudo a2enmod gearman_status</code></p>
</blockquote>
<p>Restart Apache to load the module:</p>
<blockquote>
<p><code>sudo service apache2 restart</code></p>
</blockquote>
<p>Now in your browser you can visit <a href="http://example.org/gearman-status">http://example.org/gearman-status</a> where example.org is your servers address.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="gearman" label="gearman"/><category scheme="taxonomy:Tags" term="php" label="php"/><category scheme="taxonomy:Tags" term="ubuntu" label="ubuntu"/><category scheme="taxonomy:Tags" term="debian" label="debian"/><category scheme="taxonomy:Tags" term="apache" label="Apache"/></entry><entry xml:base="winter-motorcycle-electrics"><title type="html">Winter motorcycle storage: battery and electrical systems</title><link href="https://www.simonholywell.com/post/2011/01/winter-motorcycle-electrics/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2011/01/winter-motorcycle-tyres/?utm_source=atom_feed" rel="related" type="text/html" title="Winter motorcycle storage: suspension and tyres"/><link href="https://www.simonholywell.com/post/2011/01/winter-motorcycle-fuel/?utm_source=atom_feed" rel="related" type="text/html" title="Winter motorcycle storage: fuel system"/><link href="https://www.simonholywell.com/post/2010/12/why-does-fuel-go-stale/?utm_source=atom_feed" rel="related" type="text/html" title="Why does fuel go stale?"/><link href="https://www.simonholywell.com/post/2011/01/php-number-error/?utm_source=atom_feed" rel="related" type="text/html" title="PHP Hangs When Fed 2.2250738585072011e-308"/><link href="https://www.simonholywell.com/post/2011/01/fulloctane-introduction/?utm_source=atom_feed" rel="related" type="text/html" title="FullOctane: Bike and Car Blog"/><id>https://www.simonholywell.com/post/2011/01/winter-motorcycle-electrics/</id><author><name>Simon Holywell</name></author><published>2011-01-23T01:53:38+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>There are many things to consider as you wrap your bike up for winter such as ensuring your fuel does not go stale, but the electrical system needs attention too. One of the most common failures when placing your motorcycle in storage is the battery losing charge and eventually becoming damaged beyond repair.
Causes of battery failure Most vehicles have a residual draw that slowly saps power from the battery even with the ignition switched off, but this is exacerbated by the fitment of alarms or other after market accessories.</summary><content type="html"><![CDATA[<p>There are many things to consider as you wrap your bike up for winter such as ensuring your <a href="/post/2011/01/winter-motorcycle-fuel">fuel does not go stale</a>, but the electrical system needs attention too. One of the most common failures when placing your motorcycle in storage is the battery losing charge and eventually becoming damaged beyond repair.</p>
<h2 id="causes-of-battery-failure">Causes of battery failure</h2>
<p>Most vehicles have a residual draw that slowly saps power from the battery even with the ignition switched off, but this is exacerbated by the fitment of alarms or other after market accessories. I highlighted this in an article I recently wrote for webBikeWorld reviewing the <a href="http://www.webbikeworld.com/t2/healtech-gear-indicator/healtech-gipro.htm">HealTech GIpro</a> gear indicator, which was flattening my battery in about 3 weeks.</p>
<p>On top of this batteries also have a natural dissipation of the charge over time as well and require regular top up charges to remain in optimum shape. When a battery is left for a long time in state of discharge a reaction occurs between the lead and the acid that results in lead sulfate resulting in what is known as a sulfated battery. The longer the sulfation is allowed to progress the more permanent damage is done to the battery.</p>
<p>Another issue of long term storage of a lead acid battery is stratification, which is the separation of the electrolyte in the battery. The water and the acid will eventually begin to become distinct layers in the battery with the water forming on top of the acid, which can cause greater corrosion to the lead plates. Charging helps to mix the two again as does moving the battery. So riding your bike is one of the best cures for stratification!</p>
<h2 id="corrosion">Corrosion</h2>
<p>In humid environments electrical systems often begin to corrode when they are left sitting for extended periods of time. This leads to poor operating performance, which can manifest itself as dim headlights or a dead horn. Sometimes the motorcycle will no longer be able to start as the earths have stopped passing current.</p>
<p>Problems with the wiring or electrical systems can be very hard to diagnose and may take hours of probing with a <a href="https://www.amazon.com/Etekcity-Multimeter-Electronic-Continuity-Backlight/dp/B01N9QW620/ref=as_li_ss_tl?s=automotive&amp;ie=UTF8&amp;qid=1492569255&amp;sr=1-1-spons&amp;keywords=multimeter&amp;psc=1&amp;linkCode=ll1&amp;tag=treffynnon-20&amp;linkId=fcb19df175de4d1e41faaa4fe685eb4c">multimeter</a>. In general the more modern the motorcycle is the more complex its electrical system will be.</p>
<h2 id="battery-maintenance">Battery maintenance</h2>
<p>To protect yourself from these problems there are a couple of simple defences you can employ. When placing a motorcycle into storage always ensure the battery charge is maintained. Preferably the battery should be removed from the bike and brought inside so that it is not exposed to extremes of temperature. Regular charging of at least once a fortnight is then required to keep the battery in top condition.</p>
<p>The best chargers for this duty are called <a href="https://www.amazon.com/Extreme-Max-1229-4000-Intelligent-Maintainer/dp/B00K72C1T4/ref=sr_1_3?s=automotive&amp;ie=UTF8&amp;qid=1492569210&amp;sr=1-3&amp;keywords=motorcycle+tender">battery tenders</a> or <a href="https://www.amazon.com/OptiMATE-Ampmatic-TM-181-Battery-charger-tester-maintainer/dp/B003UANXCE/ref=as_li_ss_tl?s=automotive&amp;ie=UTF8&amp;qid=1492569136&amp;sr=1-1&amp;keywords=optimate&amp;linkCode=ll1&amp;tag=treffynnon-20&amp;linkId=42935d1e0f12de2c2b79cbc7542a5c00">trickle chargers</a>, which as their name suggests gently ensure that the battery is always charged up. Some of the more expensive chargers are also smart enough to be able to recover partially damaged batteries and attempt to reverse the destructive sulfation process.</p>
<h2 id="wiring-and-general-electrics">Wiring and general electrics</h2>
<p>The wiring and electrical systems need to be protected from moisture so connections should be coated in a non-conductive hydrophobic material. Often this can be as simple as daubing the connectors in some grease such as the <a href="https://www.amazon.com/Loctite-38650-Copper-Anti-Seize-Lubricant/dp/B0006Q7H36/ref=as_li_ss_tl?ie=UTF8&amp;qid=1492568859&amp;sr=8-1&amp;keywords=copper+slip&amp;linkCode=ll1&amp;tag=treffynnon-20&amp;linkId=26c0c2fff779a839fb0e043ad9fc1b3c">copper slip</a> used behind brake pads or just about any anti-seize lubricant. This serves as a water repellent layer over the metal of connections and prevents corrosion.</p>
<p>When selecting the grease to you it is important that it does not conduct electricity if you plan to use it on connectors with many wires. Otherwise you may end up inadvertently shorting out some wiring or a connector, which could lead to expensive damage or a poorly running motorcycle.</p>
<p>As you bring the bike back out of storage in the spring it is a good idea to thoroughly check that all the electrical systems are operating as you would expect. You dont want a car missing that brake light!</p>
]]></content><category scheme="taxonomy:Categories" term="motors" label="Motors"/><category scheme="taxonomy:Tags" term="battery" label="battery"/><category scheme="taxonomy:Tags" term="bike" label="bike"/><category scheme="taxonomy:Tags" term="electrics" label="electrics"/><category scheme="taxonomy:Tags" term="motorcycles" label="motorcycles"/><category scheme="taxonomy:Tags" term="winter-storage" label="winter storage"/><category scheme="taxonomy:Tags" term="fulloctane" label="fulloctane"/></entry><entry xml:base="winter-motorcycle-tyres"><title type="html">Winter motorcycle storage: suspension and tyres</title><link href="https://www.simonholywell.com/post/2011/01/winter-motorcycle-tyres/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2011/01/winter-motorcycle-fuel/?utm_source=atom_feed" rel="related" type="text/html" title="Winter motorcycle storage: fuel system"/><link href="https://www.simonholywell.com/post/2010/12/why-does-fuel-go-stale/?utm_source=atom_feed" rel="related" type="text/html" title="Why does fuel go stale?"/><link href="https://www.simonholywell.com/post/2011/01/php-number-error/?utm_source=atom_feed" rel="related" type="text/html" title="PHP Hangs When Fed 2.2250738585072011e-308"/><link href="https://www.simonholywell.com/post/2011/01/fulloctane-introduction/?utm_source=atom_feed" rel="related" type="text/html" title="FullOctane: Bike and Car Blog"/><link href="https://www.simonholywell.com/post/2010/12/wombert-xkcd-convincing/?utm_source=atom_feed" rel="related" type="text/html" title="wombert: xkcd: Convincing"/><id>https://www.simonholywell.com/post/2011/01/winter-motorcycle-tyres/</id><author><name>Simon Holywell</name></author><published>2011-01-05T01:53:38+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>This is by no means an exhaustive list of steps for long term motorcycle (or car for that matter) storage, but a few tips I have picked up along the way.
When a motorcycle is put into storage it will often remain in the same position for extended periods of time. This is not the intended purpose from factory though and as such the tyres and suspension will not thank you for it.</summary><content type="html"><![CDATA[<p>This is by no means an exhaustive list of steps for long term motorcycle (or car for that matter) storage, but a few tips I have picked up along the way.</p>
<p>When a motorcycle is put into storage it will often remain in the same position for extended periods of time. This is not the intended purpose from factory though and as such the tyres and suspension will not thank you for it.</p>
<h2 id="tyres">Tyres</h2>
<p>Tyres tend to lose pressure through the winter months and under inflated tyres are more likely to get flat spots. If the pressure drops significantly then the side walls will tend to crack if they are left sitting on cold concrete.</p>
<p>Once a tyre has been affected by either a flat spot or a crack then it should be replaced immediately. Both problems are a major hazard that could lead to dramatic tyre deflation at speed or big blow outs. Often this will lead to the bike continuing down the street on its side.</p>
<h2 id="suspension">Suspension</h2>
<p>Although it is not a significant issue in my experience or research it also makes sense to unload the suspension so that it can relax for the duration of the storage. This might help to prevent spring sag, but I am unaware of any other benefits.</p>
<p>Suspension is basically comprised of oil, springs and seals. Seals are made of rubber and when not in use rubber stiffens and becomes brittle, which can cause cracking and seal failure.</p>
<p>Replacing fork seals is a reasonably time consuming process and therefore can be an expensive trip to the dealer if you are not doing it yourself.</p>
<p>The best way to avoid this issue is visit your motorcycle every fortnight or so, sit in the saddle and drop the bike off of the stand. Now it may sound odd but you need to have a good bounce on the bike to cause the suspension to compress and extend a number of times. This puts seals through their paces so that their propensity to stiffen is reduced.</p>
<p>I find the easiest way to get the forks to travel nicely is to rock the bike back and forth applying the brake firmly as the bike comes forward. If there is more than one person present you can have them push down on the head stock as you sit on the bike to stabilise it.</p>
<p>Another tip is to add little fork oil to your fork stanchions so that your seals remain a little more protected. I like to add some onto the stanchions before I attempt to bounce the bike as mentioned above. Avoid <a href="https://www.amazon.com/WD-40-110057-Multi-Use-Product-Spray/dp/B000JCGU8U/ref=as_li_ss_tl?s=automotive&amp;ie=UTF8&amp;qid=1492572360&amp;sr=1-1&amp;keywords=wd-40&amp;linkCode=ll1&amp;tag=treffynnon-20&amp;linkId=8e9a8f069c807baee4c4c71f24cfe0e5">WD-40</a> as it can swell rubber seals and if it penetrates the seal it can mix with the oil in fork and thin it reducing damping.</p>
<h2 id="stand-solutions">Stand Solutions</h2>
<p>If your motorcycle has a centre stand then you can make use of it to avoid both problems. With be bike on the stand the rear wheel will clear the ground, which leaves you the simple task of propping the front wheel off of the ground.</p>
<p>A lot of modern bikes do not come with centre stands to improve ground clearance, but there are solutions such as the <a href="http://www.abbastands.co.uk/product-detail.asp?pid=1">Superbike Stand</a> from abba. Other options include the <a href="http://motorradteile-bursig.de/">Bursig</a> and the <a href="http://shop.becker-technik.de/en/">Becker-Technik Motorbike-Lifter</a>. I am using an abba stand myself, but the Becker-Technik does look like a nice alternative.</p>
<p>If you just want to get the wheels off the ground then you can use a pair of paddock stands, but this will not take the pressure off of the suspension. A couple of paddock stand options include the <a href="https://www.amazon.com/Venom-Motorcycle-Triple-Headlift-Kawasaki/dp/B00CX7L1LA/ref=as_li_ss_tl?s=automotive&amp;ie=UTF8&amp;qid=1492572826&amp;sr=1-5&amp;keywords=paddock+stand+headlift&amp;linkCode=ll1&amp;tag=treffynnon-20&amp;linkId=5143a1e98f3ab4053e9fd971bd4d1e52">Venom Headlift Paddock Stand</a>, <a href="https://www.amazon.com/Motorcycle-Stand-Front-Spool-Combo/dp/B01N00QU2I/ref=as_li_ss_tl?s=automotive&amp;ie=UTF8&amp;qid=1492572915&amp;sr=1-10&amp;keywords=paddock+stands+front+and+rear&amp;linkCode=ll1&amp;tag=treffynnon-20&amp;linkId=4272befc8de915a0c6517865785e5ad3">Genssi Motorcyle Pro Front &amp; Rear Stands</a> or <a href="https://www.amazon.com/MOTO-D-Swingarm-Motorcycle-Stands-Front/dp/B00L4G4XWA/ref=as_li_ss_tl?s=automotive&amp;ie=UTF8&amp;qid=1492572915&amp;sr=1-11&amp;keywords=paddock+stands+front+and+rear&amp;linkCode=ll1&amp;tag=treffynnon-20&amp;linkId=ce07f5b051737ee1824baa646282059d">MOTO-D Front &amp; Rear Paddock Stands</a>.</p>
<h2 id="flooring-solutions">Flooring Solutions</h2>
<p>Seems like too much effort? Then you should at least consider putting the bike a sheet of timber or chipboard to help protect the tyres from the cold concrete. Some people have also used foam or rubber tiles under the bike. Like these <a href="https://www.amazon.com/Interlocking-Waterproof-Exercise-Basement-Protective/dp/B00IBCP46E/ref=as_li_ss_tl?s=automotive&amp;ie=UTF8&amp;qid=1492572724&amp;sr=1-2&amp;keywords=foam+tile+interlocking&amp;linkCode=ll1&amp;tag=treffynnon-20&amp;linkId=3fca2eb19a8d60eed7fe87b877804191">NT interlocking rubber tiles</a> for example.</p>
<p>You will still need to move your bike or rotate the wheels regularly so that the tyres do not develop flat spots.</p>
<p>The essential information to take away from this is that your bike does not like being stationary and it should be kept off of its wheels.</p>
]]></content><category scheme="taxonomy:Categories" term="motors" label="Motors"/><category scheme="taxonomy:Tags" term="suspension" label="suspension"/><category scheme="taxonomy:Tags" term="tyres" label="tyres"/><category scheme="taxonomy:Tags" term="bike" label="bike"/><category scheme="taxonomy:Tags" term="motorcycles" label="motorcycles"/><category scheme="taxonomy:Tags" term="winter-storage" label="winter storage"/><category scheme="taxonomy:Tags" term="fulloctane" label="fulloctane"/></entry><entry xml:base="php-number-error"><title type="html">PHP Hangs When Fed 2.2250738585072011e-308</title><link href="https://www.simonholywell.com/post/2011/01/php-number-error/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2010/12/logging-global-php-objects-lazy-loading-proxy/?utm_source=atom_feed" rel="related" type="text/html" title="Logging global PHP objects and saving memory using a lazy loading proxy"/><link href="https://www.simonholywell.com/post/2010/11/team-development-server/?utm_source=atom_feed" rel="related" type="text/html" title="An Excellent Development Server for a Team of Developers"/><link href="https://www.simonholywell.com/post/2010/09/15-excellent-resources-for-php-extension-development/?utm_source=atom_feed" rel="related" type="text/html" title="15 Excellent Resources for PHP Extension Development"/><link href="https://www.simonholywell.com/post/2010/08/get-gearman-to-install-on-ubuntu/?utm_source=atom_feed" rel="related" type="text/html" title="Getting gearman to install on Ubuntu"/><link href="https://www.simonholywell.com/post/2010/08/drop-cap-php-regex/?utm_source=atom_feed" rel="related" type="text/html" title="Drop Cap with PHP Regular Expression"/><id>https://www.simonholywell.com/post/2011/01/php-number-error/</id><author><name>Simon Holywell</name></author><published>2011-01-04T14:25:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>PHP Hangs When Fed 2.2250738585072011e-308
A pretty horrible bug when you assign the number 2.2250738585072011e-308 to a variable PHP will hang on Linux or Windows 32bit builds of PHP. This does affect $_GET and $_POST variables as well and as such could be an exploit in some PHP sites.
So the following code will break your PHP for example:
$var = 2.2250738585072011e-308; Or if a page is given a GET parameter like page.</summary><content type="html"><![CDATA[<p><a href="http://bugs.php.net/bug.php?id=53632">PHP Hangs When Fed 2.2250738585072011e-308</a></p>
<p>A pretty horrible bug when you assign the number 2.2250738585072011e-308 to a variable PHP will hang on Linux or Windows 32bit builds of PHP. This does affect $_GET and $_POST variables as well and as such could be an exploit in some PHP sites.</p>
<p>So the following code will break your PHP for example:</p>
<pre><code>$var = 2.2250738585072011e-308;
</code></pre>
<p>Or if a page is given a GET parameter like page.php?param=2.2250738585072011e-308</p>
<pre><code>$var = $_GET['param'] + 1;
//OR
$var = (double)$_GET['param'];
</code></pre>
<p>More debate available on <a href="http://news.ycombinator.com/item?id=2066084"><a href="http://news.ycombinator.com/item?id=2066084">http://news.ycombinator.com/item?id=2066084</a></a></p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="php" label="php"/><category scheme="taxonomy:Tags" term="internet" label="internet"/></entry><entry xml:base="winter-motorcycle-fuel"><title type="html">Winter motorcycle storage: fuel system</title><link href="https://www.simonholywell.com/post/2011/01/winter-motorcycle-fuel/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2010/12/why-does-fuel-go-stale/?utm_source=atom_feed" rel="related" type="text/html" title="Why does fuel go stale?"/><link href="https://www.simonholywell.com/post/2011/01/fulloctane-introduction/?utm_source=atom_feed" rel="related" type="text/html" title="FullOctane: Bike and Car Blog"/><link href="https://www.simonholywell.com/post/2010/12/wombert-xkcd-convincing/?utm_source=atom_feed" rel="related" type="text/html" title="wombert: xkcd: Convincing"/><link href="https://www.simonholywell.com/post/2010/12/logging-global-php-objects-lazy-loading-proxy/?utm_source=atom_feed" rel="related" type="text/html" title="Logging global PHP objects and saving memory using a lazy loading proxy"/><link href="https://www.simonholywell.com/post/2010/11/setup-a-new-portforward-on-vigor-over-telnet/?utm_source=atom_feed" rel="related" type="text/html" title="Set up a new port forward on a Draytek Vigor over the telnet interface"/><id>https://www.simonholywell.com/post/2011/01/winter-motorcycle-fuel/</id><author><name>Simon Holywell</name></author><published>2011-01-04T01:53:38+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>This is by no means an exhaustive list of steps for long term motorcycle (or car for that matter) storage, but a few tips I have picked up along the way.
The most commonly known issue with bikes in storage is bad or stale fuel, which I have described the causes of in a previous post; Why does fuel go stale?. Generally petrol is fairly stable and won’t break down all that quickly, but motorcycle fuel tanks present problems that dedicated fuel containers do not.</summary><content type="html"><![CDATA[<p>This is by no means an exhaustive list of steps for long term motorcycle (or car for that matter) storage, but a few tips I have picked up along the way.</p>
<p>The most commonly known issue with bikes in storage is bad or <a href="/post/2010/12/why-does-fuel-go-stale">stale fuel</a>, which I have described the causes of in a previous post; <a href="/post/2010/12/why-does-fuel-go-stale">Why does fuel go stale?</a>. Generally petrol is fairly stable and won’t break down all that quickly, but motorcycle fuel tanks present problems that dedicated fuel containers do not.
All tanks are vented to the outside world, which means that air can get in and bring moisture with it that will condense inside the tank therefore adding water to your fuel! If you do not have a plastic fuel tank like my Cagiva then you will also potentially suffer from rust inside the tank that will leach into your fuel.</p>
<p>When fuel goes off it begins to lose its volatility and then starts to turn into a sludge, which begins to block the fuel hoses and carburettors or throttle bodies on an injected bike.</p>
<p>This sludge will eventually leave a varnish like effect all through your fuel system that will have to be removed with combination of special cleaners and a good few blasts of compressed air. I alluded to this process in a <a href="/post/2008/05/suzuki-bandit-carburettor-clean">previous post</a> about my old Suzuki Bandit.</p>
<p>For more information about fuel systems I recommend the following books:</p>
<ul>
<li><a href="https://www.amazon.com/Motorcycle-Fuel-Systems-TechBook-3514/dp/B00M02G6C2/ref=as_li_ss_tl?s=automotive&amp;ie=UTF8&amp;qid=1492569717&amp;sr=1-1&amp;keywords=Motorcycle+Fuel+Systems+TechBook&amp;linkCode=ll1&amp;tag=treffynnon-20&amp;linkId=ff15908a4a9b6ab735db8dad3f45f6ce">Motorcycle Fuel Systems TechBook (Haynes Techbooks)</a></li>
<li>The Haynes Manual on Carburettors (Haynes DIY Manuals)</li>
<li>Motor Cycle Carburettor Manual</li>
</ul>
<p>To avoid having to remove the fuel system, flush it out and potentially rebuild your carburettors; there are at least two things you can do:</p>
<ol>
<li>
<p>Drain the fuel tank completely of all fuel as much as you can and then you can:</p>
<ol>
<li>Run the bike until all the fuel in the system has been burnt and the machine conks out.</li>
<li>Open up the carb float bowl drain plugs and drain all the fuel out that way.</li>
</ol>
<p>Once this is done if you have a steel fuel tank you will want to either prep it with some thin oil to stop it from rusting or re-fill the tank with fresh fuel (potentially think about adding a fuel stabiliser for longer periods of storage – see below) to the absolute brim.</p>
</li>
<li>
<p>Take the bike out for a nice long run and get the empty light flashing whereupon you pull into a petrol station and add some fuel stabiliser to the tank such as <a href="https://www.amazon.com/Lucas-10303-fuel-stabilizer/dp/B00EXFTL4E/ref=as_li_ss_tl?s=automotive&amp;ie=UTF8&amp;qid=1492569931&amp;sr=1-4&amp;keywords=lucas+fuel+stabilizer&amp;linkCode=ll1&amp;tag=treffynnon-20&amp;linkId=4df11ed504927aa89b4b6befdb6421a7">Lucas</a>, <a href="https://www.amazon.com/dp/B000B68V6I/ref=as_li_ss_tl?ref_=ams_ad_dp_asin_1&amp;linkCode=ll1&amp;tag=treffynnon-20&amp;linkId=b5a1776ff5ae9b97070d820fe6891e08">Sta-Bil</a>, Putoline Fuel Stabiliser or Sea Foam. Then fill the tank to the brim to prevent the possibility of the build up of condensation.</p>
<p>By adding the fuel stabiliser first you will get a good mix as the fuel is added because the flow of fuel will cause turbulence inside the tank.</p>
<p>To ensure that the fuel stabiliser works its way through the entire system take the bike for a quick blast.</p>
</li>
</ol>
<p>The bike is now ready from a fuel point of view for its winter storage.</p>
]]></content><category scheme="taxonomy:Categories" term="motors" label="Motors"/><category scheme="taxonomy:Tags" term="fuel" label="fuel"/><category scheme="taxonomy:Tags" term="bike" label="bike"/><category scheme="taxonomy:Tags" term="motorcycles" label="motorcycles"/><category scheme="taxonomy:Tags" term="winter-storage" label="winter storage"/><category scheme="taxonomy:Tags" term="fulloctane" label="fulloctane"/></entry><entry xml:base="fulloctane-introduction"><title type="html">FullOctane: Bike and Car Blog</title><link href="https://www.simonholywell.com/post/2011/01/fulloctane-introduction/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2010/06/adenauer-forst-70s-crash-compilation/?utm_source=atom_feed" rel="related" type="text/html" title="sharonov: 1970 Adenauer Forst crashes"/><link href="https://www.simonholywell.com/post/2010/12/logging-global-php-objects-lazy-loading-proxy/?utm_source=atom_feed" rel="related" type="text/html" title="Logging global PHP objects and saving memory using a lazy loading proxy"/><link href="https://www.simonholywell.com/post/2010/11/setup-a-new-portforward-on-vigor-over-telnet/?utm_source=atom_feed" rel="related" type="text/html" title="Set up a new port forward on a Draytek Vigor over the telnet interface"/><link href="https://www.simonholywell.com/post/2010/11/team-development-server/?utm_source=atom_feed" rel="related" type="text/html" title="An Excellent Development Server for a Team of Developers"/><link href="https://www.simonholywell.com/post/2010/10/redis-under-the-hood/?utm_source=atom_feed" rel="related" type="text/html" title="Redis: under the hood (internals)"/><id>https://www.simonholywell.com/post/2011/01/fulloctane-introduction/</id><author><name>Simon Holywell</name></author><published>2011-01-03T03:20:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>FullOctane: Bike and Car Blog
I have setup a site to post all my automotive related discoveries. Currently I have two posts up there about fuel degradation and storage.
Putting motorcycles into storage or “winterizing” can be an involved procedure so I have decide to cover it in a series of posts beginning with the fuel system in the post entitled ‘Winter Motorcycle Storage: Fuel System’.
Continuing the fuel theme the reasoning behind previous post is backed up by a technical article that addresses the question; ‘Why does fuel go stale?</summary><content type="html"><![CDATA[<p><a href="http://fulloctane.com/">FullOctane: Bike and Car Blog</a></p>
<p>I have setup a site to post all my automotive related discoveries. Currently I have two posts up there about fuel degradation and storage.</p>
<p>Putting motorcycles into storage or “winterizing” can be an involved procedure so I have decide to cover it in a series of posts beginning with the fuel system in the post entitled ‘<a href="http://blog.fulloctane.com/post/2555367842/winter-motorcycle-storage-fuel-system">Winter Motorcycle Storage: Fuel System</a>’.</p>
<p>Continuing the fuel theme the reasoning behind previous post is backed up by a technical article that addresses the question; ‘<a href="http://blog.fulloctane.com/post/2569500124/why-does-fuel-go-stale">Why does fuel go stale?</a>’.</p>
]]></content><category scheme="taxonomy:Categories" term="motors" label="Motors"/><category scheme="taxonomy:Tags" term="fulloctane" label="FullOctane"/><category scheme="taxonomy:Tags" term="bikes" label="bikes"/><category scheme="taxonomy:Tags" term="cars" label="Cars"/><category scheme="taxonomy:Tags" term="internet" label="internet"/></entry><entry xml:base="why-does-fuel-go-stale"><title type="html">Why does fuel go stale?</title><link href="https://www.simonholywell.com/post/2010/12/why-does-fuel-go-stale/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2010/12/wombert-xkcd-convincing/?utm_source=atom_feed" rel="related" type="text/html" title="wombert: xkcd: Convincing"/><link href="https://www.simonholywell.com/post/2010/12/logging-global-php-objects-lazy-loading-proxy/?utm_source=atom_feed" rel="related" type="text/html" title="Logging global PHP objects and saving memory using a lazy loading proxy"/><link href="https://www.simonholywell.com/post/2010/11/setup-a-new-portforward-on-vigor-over-telnet/?utm_source=atom_feed" rel="related" type="text/html" title="Set up a new port forward on a Draytek Vigor over the telnet interface"/><link href="https://www.simonholywell.com/post/2010/11/team-development-server/?utm_source=atom_feed" rel="related" type="text/html" title="An Excellent Development Server for a Team of Developers"/><link href="https://www.simonholywell.com/post/2010/10/redis-under-the-hood/?utm_source=atom_feed" rel="related" type="text/html" title="Redis: under the hood (internals)"/><id>https://www.simonholywell.com/post/2010/12/why-does-fuel-go-stale/</id><author><name>Simon Holywell</name></author><published>2010-12-23T01:53:38+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>When stored correctly, high quality gasolene should continue to be stable forever (well almost!). There are few factors that contribute to the degradation of petrol with the two primary concerns being oxidisation and water.
Oxidation If petrol is not stored in an air tight container then the process of oxidation occurs. Fuel that has been exposed to air flow will begin to look cloudy and get darker in colour. Sometimes you may even be able to see particles floating in the fuel if it is badly oxidised.</summary><content type="html"><![CDATA[<p>When stored correctly, high quality gasolene should continue to be stable forever (well almost!). There are few factors that contribute to the degradation of petrol with the two primary concerns being oxidisation and water.</p>
<h2 id="oxidation">Oxidation</h2>
<p>If petrol is not stored in an air tight container then the process of oxidation occurs. Fuel that has been exposed to air flow will begin to look cloudy and get darker in colour. Sometimes you may even be able to see particles floating in the fuel if it is badly oxidised.</p>
<p>Once the fuel is in this state it is dangerous to add it to an engine as the fuel will form deposits in the fuel system. Fuel stored in a vehicle is not air tight – particularly in motorcycles and therefore these deposits can build up and affect the proper working of the engine.</p>
<p>A common way to prevent this is to add anti-oxidants such as <a href="https://www.amazon.com/Lucas-10303-fuel-stabilizer/dp/B00EXFTL4E/ref=as_li_ss_tl?s=automotive&amp;ie=UTF8&amp;qid=1492569931&amp;sr=1-4&amp;keywords=lucas+fuel+stabilizer&amp;linkCode=ll1&amp;tag=treffynnon-20&amp;linkId=4df11ed504927aa89b4b6befdb6421a7">Lucas Fuel Stabilizer</a>.</p>
<h2 id="water-in-the-fuel">Water in the fuel</h2>
<p>Water in fuel is a big problem as internal combustion engines cannot ignite water! Water and petrol do not mix so if your fuel tank had transparent sides you would see the petrol sitting on top of a layer of water. This water is sometimes clear, but usually appears as a rusty or dirty colour.</p>
<p>The fuel pickup for most fuel pumps is located towards the bottom of the fuel tank so the engine will be fed the water first. Once the water gets through the fuel lines the engine will be starved of petrol and fail.</p>
<p>Many countries now have up to 10% ethanol (Brazil has 25%!) mixed into fuel for a variety of reasons such as the reduction of carbon emissions or to increase the octane rating of the fuel. Ethyl alcohols are hydroscopic and can easily absorb the moisture in air humidity and therefore increase the water content of the fuel.</p>
<p>This may not be such a big problem because the water that binds with the alcohol will be burnt by the engine, but it will reduce the quality of performance that can be achieved.</p>
<p>An old trick that can remove water from fuel is to throw a bottle of methylated spirits into the fuel tank. This trick exploits the hydroscopic properties of the alcohol so that water is absorbed into the alcohol and can ignite in the engine. However it is important to note that the alcohol will become saturated if there is more water in the tank than it can bind with.</p>
<p>A more controlled way of dealing with water in the fuel is to add a bottle of <a href="https://www.amazon.com/Wynns-petrol-diesel-engines-remover/dp/B006I4AHNC/ref=as_li_ss_tl?ie=UTF8&amp;qid=1492570551&amp;sr=8-1&amp;keywords=Wynns+Dry+Fuel&amp;linkCode=ll1&amp;tag=treffynnon-20&amp;linkId=a35a0e835db994c8165b89985317f184">Wynns Dry Fuel</a> or Wurth Petrol Engine Additive to the suspect fuel.</p>
<h2 id="other-factors">Other Factors</h2>
<p>Other factors in fuel deterioration include contaminants such as rust, dirt or oil and the temperature. The degradation of fuel is accelerated by higher temperatures (above 26°C or 80°F) so fuel should be stored in cool areas and obviously out of direct sunlight!</p>
<h2 id="vapour-pressure">Vapour Pressure</h2>
<p>Whilst not strictly stale fuel; poor starting using stored fuel could be attributed to government regulated volatility. I believe this is likely to only be a problem for the US.</p>
<p>This is measured using RVP (<a href="https://en.wikipedia.org/wiki/Reid_vapor_pressure">Reid vapour pressure</a>) and differing levels are used depending on the ambient temperature. Fuels with a higher RVP evaporate more easily than those with a lower RVP rating because the components in the latter have a heavier molecular weight.</p>
<p>In summer a fuel of lower RVP (~7.8 to ~9 PSI) is used, which prevents the fuel from evaporating and being wasted into the atmosphere or causing vapour lock. Vapour lock is caused by the fuel turning into a gas in the fuel lines, which then starves the engine of fuel because the pump can only move liquid.</p>
<p>As winter comes around the RVP will be increased with as many as eight graduations and it could eventually end up in the region of ~15 PSI. This means that the fuel can evaporate more easily in colder temperatures therefore making it easier to start a vehicle.</p>
<p>The change in the fuel mixture or <a href="https://web.archive.org/web/20090509035641/http://earth1.epa.gov/otaq/oxygenate.htm">oxygenates</a> is usually performed to improve the clean burning of fuels in the summer months to reduce smog and pollution. More information on this subject can be found on <a href="https://web.archive.org/web/20150531015752/http://earth1.epa.gov/otaq/fuels/gasolinefuels/volatility/index.htm">Environmental Protection Agency</a> website.</p>
<p>This being the case you could find it difficult to start a vehicle in winter that is filled up with stored fuel from summer. One potential solution in this case is to get it started with some <a href="https://www.amazon.com/Gumout-5072866-Starting-Fluid-oz/dp/B001GLSIKG/ref=as_li_ss_tl?s=automotive&amp;ie=UTF8&amp;qid=1492571905&amp;sr=1-1&amp;keywords=start+spray&amp;linkCode=ll1&amp;tag=treffynnon-20&amp;linkId=590904011a14b32117459bc6ad1aeed4">start spray</a> or drain the fuel and replace it with the correct winter fuel.</p>
<h2 id="protecting-fuel-in-storage">Protecting fuel in storage</h2>
<p>To prevent these problems from affecting your fuel there are five things you can do:</p>
<ol>
<li>Only use dedicated fuel containers such as <a href="https://www.amazon.com/Best-Choice-Products-SKY1705-Emergency/dp/B00JY5SQ3A/ref=as_li_ss_tl?s=automotive&amp;ie=UTF8&amp;qid=1492571999&amp;sr=1-3&amp;keywords=jerry+can&amp;linkCode=ll1&amp;tag=treffynnon-20&amp;linkId=b75cfba46240d7fe72a69ca3b699d750">jerry cans</a>.</li>
<li>Ensure containers are air tight and capped tightly to prevent evaporation and exposure to air and moisture.</li>
<li>Use a fuel stabiliser product like <a href="https://www.amazon.com/Lucas-10303-fuel-stabilizer/dp/B00EXFTL4E/ref=as_li_ss_tl?s=automotive&amp;ie=UTF8&amp;qid=1492569931&amp;sr=1-4&amp;keywords=lucas+fuel+stabilizer&amp;linkCode=ll1&amp;tag=treffynnon-20&amp;linkId=4df11ed504927aa89b4b6befdb6421a7">Lucas Fuel Stabilizer</a>.</li>
<li>Fill containers as completely as possible leaving a 5% air gap for expansion if the temperature rises.</li>
<li>Store containers out of direct sunlight where the temperature does not exceed 26°C or 80°F. If the temperature is exceeded then fuel will begin to degrade more rapidly.</li>
</ol>
<p>With these precautions in place some people have reported up to 5 years of stable storage, but I am sure there are others out there who have managed to keep fuel for longer.</p>
]]></content><category scheme="taxonomy:Categories" term="motors" label="Motors"/><category scheme="taxonomy:Tags" term="fuel" label="fuel"/><category scheme="taxonomy:Tags" term="bike" label="bike"/><category scheme="taxonomy:Tags" term="motorcycles" label="motorcycles"/><category scheme="taxonomy:Tags" term="winter-storage" label="winter storage"/><category scheme="taxonomy:Tags" term="fulloctane" label="fulloctane"/></entry><entry xml:base="wombert-xkcd-convincing"><title type="html">wombert: xkcd: Convincing</title><link href="https://www.simonholywell.com/post/2010/12/wombert-xkcd-convincing/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2010/12/logging-global-php-objects-lazy-loading-proxy/?utm_source=atom_feed" rel="related" type="text/html" title="Logging global PHP objects and saving memory using a lazy loading proxy"/><link href="https://www.simonholywell.com/post/2010/11/setup-a-new-portforward-on-vigor-over-telnet/?utm_source=atom_feed" rel="related" type="text/html" title="Set up a new port forward on a Draytek Vigor over the telnet interface"/><link href="https://www.simonholywell.com/post/2010/11/team-development-server/?utm_source=atom_feed" rel="related" type="text/html" title="An Excellent Development Server for a Team of Developers"/><link href="https://www.simonholywell.com/post/2010/10/redis-under-the-hood/?utm_source=atom_feed" rel="related" type="text/html" title="Redis: under the hood (internals)"/><link href="https://www.simonholywell.com/post/2010/10/pecl-install-issues-on-redhat/?utm_source=atom_feed" rel="related" type="text/html" title="PECL Install Issues on Redhat"/><id>https://www.simonholywell.com/post/2010/12/wombert-xkcd-convincing/</id><author><name>Simon Holywell</name></author><published>2010-12-13T13:29:56+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>wombert:
xkcd: Convincing</summary><content type="html"><![CDATA[<p><img src="/static/images/www.tumblr.com/photo/1280/holywell/2300529330/1/tumblr_ldcu6pRImj1qz6yfh.png" alt=""></p>
<p><a href="http://blog.wombert.de/post/2196899785/xkcd-convincing">wombert</a>:</p>
<blockquote>
<p><a href="http://xkcd.com/833/">xkcd: Convincing</a></p>
</blockquote>
]]></content></entry><entry xml:base="logging-global-php-objects-lazy-loading-proxy"><title type="html">Logging global PHP objects and saving memory using a lazy loading proxy</title><link href="https://www.simonholywell.com/post/2010/12/logging-global-php-objects-lazy-loading-proxy/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2010/11/team-development-server/?utm_source=atom_feed" rel="related" type="text/html" title="An Excellent Development Server for a Team of Developers"/><link href="https://www.simonholywell.com/post/2010/09/15-excellent-resources-for-php-extension-development/?utm_source=atom_feed" rel="related" type="text/html" title="15 Excellent Resources for PHP Extension Development"/><link href="https://www.simonholywell.com/post/2010/08/get-gearman-to-install-on-ubuntu/?utm_source=atom_feed" rel="related" type="text/html" title="Getting gearman to install on Ubuntu"/><link href="https://www.simonholywell.com/post/2010/08/drop-cap-php-regex/?utm_source=atom_feed" rel="related" type="text/html" title="Drop Cap with PHP Regular Expression"/><link href="https://www.simonholywell.com/post/2010/08/updated-tumblr-backup-php-now-disqus/?utm_source=atom_feed" rel="related" type="text/html" title="Updated: Back up Tumblr Blog and/or Disqus Comments"/><id>https://www.simonholywell.com/post/2010/12/logging-global-php-objects-lazy-loading-proxy/</id><author><name>Simon Holywell</name></author><published>2010-12-02T17:23:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Quite often when you are working with legacy code you will come across a mess of globals. Every single method will make use of the same global instance of the database class for example. So where do you begin to work with this massive impediment?
Logging is a great way to see what methods and classes are being used by you application and where. To achieve this you would normally need to add a logging call to each and every method in the code base.</summary><content type="html"><![CDATA[<p>Quite often when you are working with legacy code you will come across a mess of globals. Every single method will make use of the same global instance of the database class for example. So where do you begin to work with this massive impediment?</p>
<p>Logging is a great way to see what methods and classes are being used by you application and where. To achieve this you would normally need to add a logging call to each and every method in the code base. Clearly this would be incredibly tedious and time consuming.</p>
<p>This is where a proxy object can be implemented to save time and centralise the logging functions. The basic idea of a proxy object is that it will be instantiated in place of the actual class and the proxy will delegate any calls through to the original class. For the purposes of this example the original class will be called Database and the proxy object will be called LazyLoadingProxy.</p>
<p><img src="/static/images/LazyLoadingProxyDiagram.png" alt="Lazy Loading Proxy diagram"></p>
<p>Based upon the diagram above we can work through a simple example to demonstrate this powerful technique. Initially the class lazy loading proxy is instantiated and assigned to the global variable <code>$Database</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o">&lt;?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl"><span class="nv">$Database</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">LazyLoadingProxy</span><span class="p">(</span><span class="s1">&#39;Database&#39;</span><span class="p">,</span> <span class="s1">&#39;/home/simon/DatabaseClass.php&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nv">$Blog</span>     <span class="o">=</span> <span class="k">new</span> <span class="nx">LazyLoadingProxy</span><span class="p">(</span><span class="s1">&#39;Blog&#39;</span><span class="p">,</span> <span class="s1">&#39;/var/www/classes/Blog.class.php5&#39;</span><span class="p">);</span>
</span></span></code></pre></div><p>When the proxy is setup it is told the class name and then the exact path where it can find the class. The proxy will now lie in wait for a request to a method or class property of the proxied class (<code>Database</code>).</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o">&lt;?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl"><span class="k">echo</span> <span class="nv">$Database</span><span class="o">-&gt;</span><span class="na">getTable</span><span class="p">();</span> <span class="c1">// echo the name of the table
</span></span></span></code></pre></div><p>If the underlying class is accessed the proxy will <code>require_once()</code> Database.class.php and create a new instance of it on the fly. This is the lazy loading aspect of the process. In this way resources are not consumed until the Database class is really needed. Once instantiated the object is “cached” so that any future requests will reuse the same instance of the class.</p>
<p>So our proxy lazy load class is very simple like the following:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o">&lt;?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl"><span class="sd">/**
</span></span></span><span class="line"><span class="cl"><span class="sd"> * @author Simon Holywell &lt;treffynnon@php.net&gt;
</span></span></span><span class="line"><span class="cl"><span class="sd"> */</span>
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">LazyLoadingProxy</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="sd">/**
</span></span></span><span class="line"><span class="cl"><span class="sd">     * Where the instance of the actual class is stored.
</span></span></span><span class="line"><span class="cl"><span class="sd">     * @var $instance object
</span></span></span><span class="line"><span class="cl"><span class="sd">     */</span>
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="nv">$instance</span> <span class="o">=</span> <span class="k">null</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="sd">/**
</span></span></span><span class="line"><span class="cl"><span class="sd">     * The name of the class to load
</span></span></span><span class="line"><span class="cl"><span class="sd">     * @var $class_name string
</span></span></span><span class="line"><span class="cl"><span class="sd">     */</span>
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="nv">$class_name</span> <span class="o">=</span> <span class="k">null</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="sd">/**
</span></span></span><span class="line"><span class="cl"><span class="sd">     * The path to the class to load
</span></span></span><span class="line"><span class="cl"><span class="sd">     * @var $class_path string
</span></span></span><span class="line"><span class="cl"><span class="sd">     */</span>
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="nv">$class_path</span> <span class="o">=</span> <span class="k">null</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="sd">/**
</span></span></span><span class="line"><span class="cl"><span class="sd">     * Set the name of the class this LazyLoader should proxy
</span></span></span><span class="line"><span class="cl"><span class="sd">     * at the time of instantiation
</span></span></span><span class="line"><span class="cl"><span class="sd">     * @param $class_name string
</span></span></span><span class="line"><span class="cl"><span class="sd">     */</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="fm">__construct</span><span class="p">(</span><span class="nv">$class_name</span><span class="p">,</span> <span class="nv">$class_path</span> <span class="o">=</span> <span class="k">null</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">setClassName</span><span class="p">(</span><span class="nv">$class_name</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">setClassPath</span><span class="p">(</span><span class="nv">$class_path</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">setClassName</span><span class="p">(</span><span class="nv">$class_name</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span><span class="p">(</span><span class="k">null</span> <span class="o">!==</span> <span class="nv">$class_name</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">class_name</span> <span class="o">=</span> <span class="nv">$class_name</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">getClassName</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">class_name</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">setClassPath</span><span class="p">(</span><span class="nv">$class_path</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span><span class="p">(</span><span class="k">null</span> <span class="o">!==</span> <span class="nv">$class_path</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">class_path</span> <span class="o">=</span> <span class="nv">$class_path</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">getClassPath</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">class_path</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="sd">/**
</span></span></span><span class="line"><span class="cl"><span class="sd">     * Get the instance of the class this LazyLoader is proxying.
</span></span></span><span class="line"><span class="cl"><span class="sd">     * If the instance does not already exist then it is initialised.
</span></span></span><span class="line"><span class="cl"><span class="sd">     * @return object An instance of the class this LazyLoader is proxying
</span></span></span><span class="line"><span class="cl"><span class="sd">     */</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="nf">getInstance</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span><span class="p">(</span><span class="k">null</span> <span class="o">===</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">instance</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">instance</span> <span class="o">=</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">initInstance</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">instance</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="sd">/**
</span></span></span><span class="line"><span class="cl"><span class="sd">     * Load an instance of the class that is being proxied.
</span></span></span><span class="line"><span class="cl"><span class="sd">     * @return object An instance of the class this LazyLoader is proxying
</span></span></span><span class="line"><span class="cl"><span class="sd">     */</span>
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="k">function</span> <span class="nf">initInstance</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">Logger</span><span class="o">::</span><span class="na">log</span><span class="p">(</span><span class="s1">&#39;Loaded: &#39;</span> <span class="o">.</span> <span class="nv">$class_name</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">require_once</span><span class="p">(</span><span class="nv">$this</span><span class="o">-&gt;</span><span class="na">class_path</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$class_name</span> <span class="o">=</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">class_name</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="k">new</span> <span class="nv">$class_name</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="sd">/**
</span></span></span><span class="line"><span class="cl"><span class="sd">     * Magic Method to call functions on the class that is being proxied.
</span></span></span><span class="line"><span class="cl"><span class="sd">     * @return mixed Whatever the requested method would normally return
</span></span></span><span class="line"><span class="cl"><span class="sd">     */</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="fm">__call</span><span class="p">(</span><span class="nv">$name</span><span class="p">,</span> <span class="nv">$arguments</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$instance</span> <span class="o">=</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">getInstance</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">        <span class="nx">Logger</span><span class="o">::</span><span class="na">log</span><span class="p">(</span><span class="s1">&#39;Called: &#39;</span> <span class="o">.</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">class_name</span> <span class="o">.</span> <span class="s1">&#39;-&gt;&#39;</span> <span class="o">.</span> <span class="nv">$name</span> <span class="o">.</span> <span class="s1">&#39;(&#39;</span> <span class="o">.</span> <span class="nx">print_r</span><span class="p">(</span><span class="nv">$arguments</span><span class="p">,</span> <span class="k">true</span><span class="p">)</span> <span class="o">.</span> <span class="s1">&#39;);&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nx">call_user_func_array</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">                <span class="k">array</span><span class="p">(</span><span class="nv">$instance</span><span class="p">,</span> <span class="nv">$name</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">                <span class="nv">$arguments</span>
</span></span><span class="line"><span class="cl">            <span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="sd">/**
</span></span></span><span class="line"><span class="cl"><span class="sd">     * These are the standard PHP Magic Methods to access
</span></span></span><span class="line"><span class="cl"><span class="sd">     * the class properties of the class that is being proxied.
</span></span></span><span class="line"><span class="cl"><span class="sd">     */</span>
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="fm">__get</span><span class="p">(</span><span class="nv">$name</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">Logger</span><span class="o">::</span><span class="na">log</span><span class="p">(</span><span class="s1">&#39;Getting property: &#39;</span> <span class="o">.</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">class_name</span> <span class="o">.</span> <span class="s1">&#39;-&gt;&#39;</span> <span class="o">.</span> <span class="nv">$name</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">getInstance</span><span class="p">()</span><span class="o">-&gt;</span><span class="nv">$name</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="fm">__set</span><span class="p">(</span><span class="nv">$name</span><span class="p">,</span> <span class="nv">$value</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">Logger</span><span class="o">::</span><span class="na">log</span><span class="p">(</span><span class="s1">&#39;Setting property: &#39;</span> <span class="o">.</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">class_name</span> <span class="o">.</span> <span class="s1">&#39;-&gt;&#39;</span> <span class="o">.</span> <span class="nv">$name</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">getInstance</span><span class="p">()</span><span class="o">-&gt;</span><span class="nv">$name</span> <span class="o">=</span> <span class="nv">$value</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="fm">__isset</span><span class="p">(</span><span class="nv">$name</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">Logger</span><span class="o">::</span><span class="na">log</span><span class="p">(</span><span class="s1">&#39;Checking isset for property: &#39;</span> <span class="o">.</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">class_name</span> <span class="o">.</span> <span class="s1">&#39;-&gt;&#39;</span> <span class="o">.</span> <span class="nv">$name</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nx">isset</span><span class="p">(</span><span class="nv">$this</span><span class="o">-&gt;</span><span class="na">getInstance</span><span class="p">()</span><span class="o">-&gt;</span><span class="nv">$name</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">function</span> <span class="fm">__unset</span><span class="p">(</span><span class="nv">$name</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">Logger</span><span class="o">::</span><span class="na">log</span><span class="p">(</span><span class="s1">&#39;Unsetting property: &#39;</span> <span class="o">.</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">class_name</span> <span class="o">.</span> <span class="s1">&#39;-&gt;&#39;</span> <span class="o">.</span> <span class="nv">$name</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="nx">unset</span><span class="p">(</span><span class="nv">$this</span><span class="o">-&gt;</span><span class="na">getInstance</span><span class="p">()</span><span class="o">-&gt;</span><span class="nv">$name</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>To log the calls you can simply echo out the request in each magic method or you could make it more sophisticated with the help of FirePHP and FireBug. I use the latter and it is really handy to see where the legacy code is calling classes and methods that it should not be!</p>
<p>The only hiccup I have found with this system is that all tests using <code>method_exists()</code> need to be changed to be <code>is_callable()</code>. This is because the former appears to use PHPs introspection methods where as the latter attempts to call the method from what I can guess.</p>
<p>This design pattern also has another application in systems that make extensive use of global objects which are instantiated at bootstrap. It will save memory as only the classes that are actually referenced will be instantiated just in time.</p>
<p>I recently used this to make a large legacy application more efficient. In the bootstrap file it simply looped through all the files in a directory called classes and looked for files beginning with a certain prefix (for example SYSBlog.php or SYSSessions.php). When it found a file it would load it via <code>require_once()</code> and then using <code>eval()</code> it would instantiate the class. This would subsequently be used globally as you can see below.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o">&lt;?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl"><span class="nv">$dir</span> <span class="o">=</span> <span class="s1">&#39;classes/&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="p">(</span><span class="nx">is_dir</span><span class="p">(</span><span class="nv">$dir</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="nv">$dh</span> <span class="o">=</span> <span class="nx">opendir</span><span class="p">(</span><span class="nv">$dir</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">while</span> <span class="p">((</span><span class="nv">$file</span> <span class="o">=</span> <span class="nx">readdir</span><span class="p">(</span><span class="nv">$dh</span><span class="p">))</span> <span class="o">!==</span> <span class="k">false</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">if</span><span class="p">(</span><span class="nv">$file</span> <span class="o">!=</span> <span class="s1">&#39;.&#39;</span> <span class="o">&amp;&amp;</span> <span class="nv">$file</span> <span class="o">!=</span> <span class="s1">&#39;..&#39;</span> <span class="o">&amp;&amp;</span> <span class="o">!</span><span class="nx">is_dir</span><span class="p">(</span><span class="nv">$dir</span><span class="o">.</span><span class="nv">$file</span><span class="p">)){</span>
</span></span><span class="line"><span class="cl">                <span class="k">require_once</span><span class="p">(</span><span class="nv">$dir</span><span class="o">.</span><span class="nv">$file</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="nx">closedir</span><span class="p">(</span><span class="nv">$dh</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="c1">// SNIP
</span></span></span><span class="line"><span class="cl"><span class="c1">// some unrelated code such as DB connectors appeared here
</span></span></span><span class="line"><span class="cl"><span class="c1">// /SNIP
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nv">$classes</span> <span class="o">=</span> <span class="nx">get_declared_classes</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="k">foreach</span><span class="p">(</span><span class="nv">$classes</span> <span class="k">as</span> <span class="nv">$class</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span><span class="p">(</span><span class="nx">substr</span><span class="p">(</span><span class="nv">$class</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="mi">3</span><span class="p">)</span><span class="o">==</span><span class="s1">&#39;SYS&#39;</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$class2</span> <span class="o">=</span> <span class="nx">str_replace</span><span class="p">(</span><span class="s1">&#39;SYS&#39;</span><span class="p">,</span><span class="s1">&#39;&#39;</span><span class="p">,</span><span class="nv">$class</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">eval</span><span class="p">(</span><span class="s1">&#39;$&#39;</span><span class="o">.</span><span class="nx">strtolower</span><span class="p">(</span><span class="nv">$class2</span><span class="p">)</span><span class="o">.</span><span class="s1">&#39; = new &#39;</span><span class="o">.</span><span class="nv">$class</span><span class="o">.</span><span class="s1">&#39;();&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>A few optimisations that could be applied to the aforementioned code would be to:</p>
<ul>
<li>make use of the <a href="http://php.net/manual/en/function.glob.php">glob() function</a> in PHP, which allows you loop through files that match a pattern. In this case something like <code>glob('SYS*.php')</code> would have done the trick.</li>
<li>remove the use of <a href="http://php.net/manual/en/function.eval.php">eval()</a> which could just as easily be implemented using <a href="http://php.net/manual/en/language.variables.variable.php">variable variables</a>. So in the example this should be implemented as <code>$$className = $className()</code> and if you need to access a property <code>$$className-&gt;getMethod()</code>.</li>
<li>make use of the SPL autoload functions that PHP provides to call the classes when they are needed.</li>
</ul>
<p>But lets just be honest with ourselves; the code is crap and needs to be rewritten, but what if we do not have the time? Then we can use the following (only slightly improved I know):</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o">&lt;?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl"><span class="nv">$dir</span> <span class="o">=</span> <span class="s1">&#39;classes/&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="p">(</span><span class="nx">is_dir</span><span class="p">(</span><span class="nv">$dir</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="nv">$dh</span> <span class="o">=</span> <span class="nx">opendir</span><span class="p">(</span><span class="nv">$dir</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">while</span> <span class="p">((</span><span class="nv">$file</span> <span class="o">=</span> <span class="nx">readdir</span><span class="p">(</span><span class="nv">$dh</span><span class="p">))</span> <span class="o">!==</span> <span class="k">false</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">if</span><span class="p">(</span><span class="nv">$file</span> <span class="o">!=</span> <span class="s1">&#39;.&#39;</span> <span class="o">&amp;&amp;</span> <span class="nv">$file</span> <span class="o">!=</span> <span class="s1">&#39;..&#39;</span> <span class="o">&amp;&amp;</span> <span class="o">!</span><span class="nx">is_dir</span><span class="p">(</span><span class="nv">$dir</span><span class="o">.</span><span class="nv">$file</span><span class="p">)){</span>
</span></span><span class="line"><span class="cl">                <span class="k">require_once</span><span class="p">(</span><span class="nv">$dir</span><span class="o">.</span><span class="nv">$file</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="nx">closedir</span><span class="p">(</span><span class="nv">$dh</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="c1">// SNIP
</span></span></span><span class="line"><span class="cl"><span class="c1">// some unrelated code such as DB connectors appeared here
</span></span></span><span class="line"><span class="cl"><span class="c1">// /SNIP
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nv">$classes</span> <span class="o">=</span> <span class="nx">get_declared_classes</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="k">foreach</span><span class="p">(</span><span class="nv">$classes</span> <span class="k">as</span> <span class="nv">$class</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span><span class="p">(</span><span class="nx">substr</span><span class="p">(</span><span class="nv">$class</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="mi">3</span><span class="p">)</span><span class="o">==</span><span class="s1">&#39;SYS&#39;</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$class2</span> <span class="o">=</span> <span class="nx">str_replace</span><span class="p">(</span><span class="s1">&#39;SYS&#39;</span><span class="p">,</span><span class="s1">&#39;&#39;</span><span class="p">,</span><span class="nv">$class</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">eval</span><span class="p">(</span><span class="s1">&#39;$&#39;</span><span class="o">.</span><span class="nx">strtolower</span><span class="p">(</span><span class="nv">$class2</span><span class="p">)</span><span class="o">.</span><span class="s1">&#39; = new &#39;</span><span class="o">.</span><span class="nv">$class</span><span class="o">.</span><span class="s1">&#39;();&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Now the class will only be loaded into memory when it is actually being used. This makes sense when you think that a response to a poll would never need to use methods in the blog classes for example. I found this technique was saving 30-70% of memory depending on the request. This could be most easily seen when making ajax requests as they often only made use of one class to perform their actions.</p>
<p>In the actual project the code is slightly different in that it does use an autoloader called <a href="https://github.com/j4mie/uberloader">Überloader</a> written by <a href="http://www.j4mie.org/">Jamie Matthews</a> (a colleague at <a href="http://www.emosaic.co.uk">Mosaic</a>), which is available over on his github account. With the autoloader I was able to dispense with all the <code>require_once()</code>s and the need to pass the class path into the lazy loading proxy class.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="php" label="php"/><category scheme="taxonomy:Tags" term="internet" label="internet"/></entry><entry xml:base="setup-a-new-portforward-on-vigor-over-telnet"><title type="html">Set up a new port forward on a Draytek Vigor over the telnet interface</title><link href="https://www.simonholywell.com/post/2010/11/setup-a-new-portforward-on-vigor-over-telnet/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2010/11/team-development-server/?utm_source=atom_feed" rel="related" type="text/html" title="An Excellent Development Server for a Team of Developers"/><link href="https://www.simonholywell.com/post/2010/10/redis-under-the-hood/?utm_source=atom_feed" rel="related" type="text/html" title="Redis: under the hood (internals)"/><link href="https://www.simonholywell.com/post/2010/09/15-excellent-resources-for-php-extension-development/?utm_source=atom_feed" rel="related" type="text/html" title="15 Excellent Resources for PHP Extension Development"/><link href="https://www.simonholywell.com/post/2010/09/per-tag-rss-feeds-for-tumblr/?utm_source=atom_feed" rel="related" type="text/html" title="Per-tag RSS feeds for Tumblr from notes.husk.org"/><link href="https://www.simonholywell.com/post/2010/08/get-gearman-to-install-on-ubuntu/?utm_source=atom_feed" rel="related" type="text/html" title="Getting gearman to install on Ubuntu"/><id>https://www.simonholywell.com/post/2010/11/setup-a-new-portforward-on-vigor-over-telnet/</id><author><name>Simon Holywell</name></author><published>2010-11-20T14:31:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>I needed to add a new port forward to a router, but I did not have access to the web interface through a graphical browser. Attempts to get in using Lynx stalled as it seems the router will not serve up the frames in the interface independently of each other and it kept issuing 404 errors.
Either way I had to use the telnet interface using the following command (replace 192.</summary><content type="html"><![CDATA[<p>I needed to add a new port forward to a router, but I did not have access to the web interface through a graphical browser. Attempts to get in using Lynx stalled as it seems the router will not serve up the frames in the interface independently of each other and it kept issuing 404 errors.</p>
<p>Either way I had to use the telnet interface using the following command (replace 192.168.1.1 23 with the IP address of your router):</p>
<pre><code> telnet 192.168.1.1 23
</code></pre>
<p>This is fine except that Draytek have absolutely no documentation available for the commands. So to discover the correct command I had to go through all the available options (and sub options and sub sub options) as it was not immediately clear to me which option port forwarding was hiding under. To give you an idea here is a list of the top level options (run the <code>?</code> command to get this view):</p>
<pre><code> &gt; ?
 % Valid commands are:
 adsl         bpa          csm          webf         ddns         ddos
 urlf         kw           exit         fe           internet     ip
 ipf          log          mngt         port         portmaptime  prn
 quit         show         srv          sys          tsmail       upnp
 vigbrg       vlan         vpn          wan          wol          qos
</code></pre>
<p>The option we are interested in is <code>srv</code> which has a number of sub options but we are only interested in <code>nat</code>. Now we have yet more options but lets just stick with <code>portmap</code>.</p>
<p>If you need extra information about a command or it’s sub options you can run the <code>?</code> option at any time. For example:</p>
<pre><code> srv nat portmap ?
</code></pre>
<p>Of the options available under <code>portmap</code> we are interested in <code>add</code> and <code>table</code>.</p>
<p>Firstly you need to execute:</p>
<pre><code> srv nat portmap table
</code></pre>
<p>So you can see the port forwards that have already been setup. This will allow you find the next available index and find out the WAN numbers. Do not use <code>q</code> for quit but just press enter until you get back to the telnet prompt. My print out looks something like this:</p>
<pre><code> &gt; srv nat portmap table

 NAT Port Redirection Configuration Table:

 Index  Service Name    Protocol  Public Port  Private IP      Private Port ifno
  1     SSH                6         1963   192.168.0.255          22      -2
  2                        0            0                        0      -2
  3                        0            0                        0      -2
  4                        0            0                        0      -2
  5                        0            0                        0      -2
  6                        0            0                        0      -2
  7                        0            0                        0      -2
  8                        0            0                        0      -2
  9                        0            0                        0      -2
 10                        0            0                        0      -2
 11                        0            0                        0      -2
 12                        0            0                        0      -2
 13                        0            0                        0      -2
 14                        0            0                        0      -2
 15                        0            0                        0      -2
 16                        0            0                        0      -2
 17                        0            0                        0      -2
 18                        0            0                        0      -2
 19                        0            0                        0      -2
 20                        0            0                        0      -2

 Protocol: 0 = Disable, 6 = TCP, 17 = UDP
 --- MORE ---   ['q': Quit, 'Enter': New Lines, 'Space Bar': Next Page] ---

 ifno: 0 = all, 3 = wan1, 4 = wan2
</code></pre>
<p>ifno is the interface number, which translate to our WAN number in the <code>srv nat portmap add</code> command. I am using 0 so that is available to all WANs. From the index column I can also see that the next available slot is 2.</p>
<p>Now we have enough information to add the port forward! The add command has the following syntax (we are looking at the second line):</p>
<pre><code> &gt; srv nat portmap add ?
 % srv nat portmap add &lt;idx&gt; &lt;serv name&gt; &lt;proto&gt; &lt;pub port&gt; &lt;pri ip&gt; &lt;pri port&gt; &lt;wan1/wan2&gt;
</code></pre>
<p>So let us translate this to use the same terms as the table we saw earlier:</p>
<table>
<thead>
<tr>
<th>idx</th>
<th>Index</th>
</tr>
</thead>
<tbody>
<tr>
<td>serv name</td>
<td>Service Name Surround this with quotes if you want to have spaces in the name.</td>
</tr>
<tr>
<td>proto</td>
<td>Protocol This must be in lowercase only such as tcp or udp.</td>
</tr>
<tr>
<td>pub port</td>
<td>Public Port The public port number you want to forward to your internal machine.</td>
</tr>
<tr>
<td>pri ip</td>
<td>Private IP The IP address of your internal machine.</td>
</tr>
<tr>
<td>pri port</td>
<td>Private Port The port number you are using on the internal machine.</td>
</tr>
<tr>
<td>wan1/wan2</td>
<td>ifno In my case this was 0 for all, 3 for wan1 and 4 for wan2.</td>
</tr>
</tbody>
</table>
<p>So this means I need to run:</p>
<pre><code> srv nat portmap add 2 &quot;Simons Test&quot; tcp 3840 192.168.0.255 3841 0
</code></pre>
<p>to add a new port forward. Your done and you can now access the machine via the public port.</p>
<p>As a simple example if I wanted to open up HTTP over port 8080 instead of the standard port 80 I can use the following port forward command:</p>
<pre><code> srv nat portmap add 2 &quot;Non-standard HTTP Port&quot; tcp 8080 192.168.0.255 80 0
</code></pre>
<p>Now Apache on my internal machine (192.168.0.255) is still serving on port 80 internally to the network, but to access it from the outside world you need to specify port 8080.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="draytek" label="draytek"/><category scheme="taxonomy:Tags" term="vigor" label="vigor"/><category scheme="taxonomy:Tags" term="telnet" label="telnet"/><category scheme="taxonomy:Tags" term="command-line" label="command line"/><category scheme="taxonomy:Tags" term="internet" label="internet"/><category scheme="taxonomy:Tags" term="port-forward" label="port forward"/></entry><entry xml:base="team-development-server"><title type="html">An Excellent Development Server for a Team of Developers</title><link href="https://www.simonholywell.com/post/2010/11/team-development-server/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2010/08/php-wrapper-for-linux-at-command/?utm_source=atom_feed" rel="related" type="text/html" title="A PHP wrapper for the unix at command"/><link href="https://www.simonholywell.com/post/2010/08/get-gearman-to-install-on-ubuntu/?utm_source=atom_feed" rel="related" type="text/html" title="Getting gearman to install on Ubuntu"/><link href="https://www.simonholywell.com/post/2009/04/memcached-and-apc-two-simple-techniques-to-speed-up-your/?utm_source=atom_feed" rel="related" type="text/html" title="Memcached and APC: Two Simple Techniques to Speed up your PHP Webpages"/><link href="https://www.simonholywell.com/post/2009/04/installing-apc-and-memcached-for-php-sessions-on-ubuntu/?utm_source=atom_feed" rel="related" type="text/html" title="Installing APC and Memcached for PHP Sessions on Ubuntu and Debi…"/><link href="https://www.simonholywell.com/post/2009/02/a-good-windows-development-environment-and-ubuntu-virtua/?utm_source=atom_feed" rel="related" type="text/html" title="A Good Windows Development Environment and Ubuntu Virtualbox"/><id>https://www.simonholywell.com/post/2010/11/team-development-server/</id><author><name>Simon Holywell</name></author><published>2010-11-08T16:04:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Introduction When working in a team it is very useful to have a central web server with multiple environments and a configuration as close to the live server as possible. This can be a bit of a nightmare though if you need to setup a new VirtualHost container in Apache every time a new project is brought on or when a developer wants to work on a version of the site in their own environment.</summary><content type="html"><![CDATA[<h1 id="introduction">Introduction</h1>
<p>When working in a team it is very useful to have a central web server with multiple environments and a configuration as close to the live server as possible. This can be a bit of a nightmare though if you need to setup a new VirtualHost container in Apache every time a new project is brought on or when a developer wants to work on a version of the site in their own environment.</p>
<p>The good news is that this can all be handled automatically and new sites can be setup by simply adding a new directory to the file system. There are at least two ways of getting this going; the first of which is the <a href="http://httpd.apache.org/docs/2.0/mod/mod_vhost_alias.html">mod_vhost_alias module</a> for Apache and the second is enabled via <a href="http://httpd.apache.org/docs/2.0/mod/mod_rewrite.html">mod_rewrite</a>. I prefer to use the second method as it is more flexible and it allows you tap into the ability of mod_rewrite to introduce environment variables and redirect requests (this is particularly useful for robots.txt - you’ll see).</p>
<p>The Apache2 Manual does have a <a href="http://httpd.apache.org/docs/2.0/vhosts/mass.html">very good page dedicated</a> to overcoming this problem, but I will be sharing with you all the <a href="http://gist.github.com/608936">settings I am using</a> which you will need to stop Google et. al. from crawling your sites served from the staging environment for example.</p>
<h2 id="intended-audience">Intended Audience</h2>
<p>This article is targeted at people who have a fairly good working knowledge of Apache and VirtualHost container configuration. I have previously written a more basic and step by step development server configuration article, but it is focused at single developers as it uses a virtual machine.</p>
<p>It is still a good introduction though and takes you through all the installation steps on an Ubuntu machine. If you are not confident installing and configuring a LAMP server then head over and give my <a href="/post/2009/02/a-good-windows-development-environment-and-ubuntu-virtua.html">A Good Windows Development Environment and Ubuntu Virtualbox</a> article a read first. Skip to step eight if you are not going to be using a virtual machine.</p>
<h1 id="my-setup">My Setup</h1>
<p>In my environment I have three subdomains that I use to host various aspects of a project:</p>
<ul>
<li>proof.example.org</li>
<li>*.dev.example.org</li>
<li>staging.dev.example.org</li>
</ul>
<p>They are all essentially handled the same by Apache. When a request comes into the server from one of the above domains mod_rewrite will direct the request to the correct file location. I use the following (respectively):</p>
<ul>
<li>/var/vhosts/proof</li>
<li>/home/*/www/</li>
<li>/var/vhosts/staging</li>
</ul>
<p>The *.dev subdomain is used for each users individual development area. So simon.dev.example.org would map to /home/simon/www/ in the file system. Staging is for demonstrating sites to clients and proof is a location used to show designs &amp; wireframes for sign off.</p>
<p>I will now run through how you would create a staging site using this system. Simply:</p>
<ol>
<li>Create a new directory in /var/vhosts/staging using the name of your site (eg. mysitename).</li>
<li>Now create a directory called pub inside your newly created directory (/var/vhosts/staging/mysitename).</li>
<li>Copy or create your public files in pub (/var/vhosts/staging/mysitename/pub). <em>You may need to include a .htaccess file here with a <code>RewriteBase /</code> line in it.</em></li>
<li>Navigate to mysitename.staging.example.org to see the served page.</li>
</ol>
<p>Having the pub directory allows you have the bulk of your application outside of public HTTP folder.</p>
<p>So now you can see how easy, quick and simple it is to use lets delve into how it works.</p>
<h1 id="development-server-configuration">Development Server Configuration</h1>
<h2 id="initial-include">Initial Include</h2>
<p>The first file that is necessary is a simple link to our main development server configuration file. This keeps the main Apache configuration file simple and clean, which will make upgrades further down the line less painful.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-apacheconf" data-lang="apacheconf"><span class="line"><span class="cl"><span class="c"># This file is /etc/apache2/httpd.conf</span>
</span></span><span class="line"><span class="cl"><span class="c"># This file is automatically included by Ubuntu in /etc/apache2/apache2.conf</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">Include</span> <span class="sx">/etc/apache2/dev-server.conf</span>
</span></span></code></pre></div><p>The above file is at /etc/apache2/httpd.conf by default in Ubuntu, but your distribution may differ in which case it might be /etc/httpd/httpd.conf. Essentially you need to add the <code>Include</code> line to your default Apache configuration.</p>
<h2 id="virtualhost-containers">VirtualHost Containers</h2>
<p>This leads us to the VirtualHost configuration file. This includes two VirtualHost containers, one for port 80 traffic and one for SSL port 443 traffic.</p>
<p>Both containers are essentially the same except for the actual SSL options so I have included the main or common elements in a separate file (/etc/apache2/dev-server-vhost.conf) so they can easily be reused in both. This saves a lot of duplication and allows you to easily update them both in once place. This will make more sense when I describe the dev-server-vhost.conf file further on.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-apacheconf" data-lang="apacheconf"><span class="line"><span class="cl"><span class="c"># This file is /etc/apache2/dev-server.conf</span>
</span></span><span class="line"><span class="cl"><span class="c"># This file is included by /etc/apache2/httpd.conf</span>
</span></span><span class="line"><span class="cl"><span class="c"># Hide server information and setup VirtualHost container skeletons for HTTP and HTTPS</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># Hide server vitals from responses</span>
</span></span><span class="line"><span class="cl"><span class="nb">ServerSignature</span> <span class="k">Off</span>
</span></span><span class="line"><span class="cl"><span class="nb">ServerTokens</span> <span class="k">Min</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># Mass Virtual Hosting</span>
</span></span><span class="line"><span class="cl"><span class="nt">&lt;VirtualHost</span> <span class="s">*:80</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;IfModule</span> <span class="s">mod_ssl.c</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="nb">SSLEngine</span> <span class="k">off</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;/IfModule&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nb">Include</span> <span class="sx">/etc/apache2/dev-server-vhost.conf</span>
</span></span><span class="line"><span class="cl"><span class="nt">&lt;/VirtualHost&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># SSL Mass Virtual Hosting</span>
</span></span><span class="line"><span class="cl"><span class="nt">&lt;VirtualHost</span> <span class="s">*:443</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;IfModule</span> <span class="s">mod_ssl.c</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="nb">SSLEngine</span> <span class="k">on</span>
</span></span><span class="line"><span class="cl">        <span class="nb">SSLOptions</span> +StrictRequire
</span></span><span class="line"><span class="cl">        <span class="nb">SSLCertificateFile</span> <span class="sx">/etc/ssl/certs/server.crt</span>
</span></span><span class="line"><span class="cl">        <span class="nb">SSLCertificateKeyFile</span> <span class="sx">/etc/ssl/private/server.key</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;/IfModule&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nb">Include</span> <span class="sx">/etc/apache2/dev-server-vhost.conf</span>
</span></span><span class="line"><span class="cl"><span class="nt">&lt;/VirtualHost&gt;</span>
</span></span></code></pre></div><p>In this file I firstly configure the server to broadcast as little as possible about itself as a simple way of slowing down possible attackers and hopefull deterring script kiddies. Next the first VirtualHost container is specified for standard port eighty traffic.</p>
<p>In the VirtualHost container I have ensured that SSL is definitely deactivated for this port and then included the common elements from the dev-server-vhost.conf file mentioned earlier.</p>
<p>The second VirtualHost container is basically the same except for the mod_ssl options. Firstly it enables SSL and forces all traffic on this port through SSL encryption. Also specified here are the SSL certificate and the encryption key that the server should use for communication with the client. If you do not know how to create an SSL certificate then <a href="http://httpd.apache.org/docs/2.0/ssl/ssl_faq.html#selfcert">the Apache2 manual</a> has you covered. Finally the dev-server-vhost.conf file is included again.</p>
<h2 id="virtualhost-container-common-configuration-include">VirtualHost Container Common Configuration Include</h2>
<p>The third file is the dev-server-vhost.conf file which is included in both of our VirtualHost containers as mentioned above. This is quite a large set of configuration options, but nothing overly complex.</p>
<h3 id="basic-configuration">Basic Configuration</h3>
<p>The first few options should be familiar to you; simply setting the DocumentRoot and ServerName etc. After this there is a simple line to block any known robots just incase they do not intend to respect the robots.txt. Followed by Directory directives that enforce the bad_bot blocking. They also stop the contents of directories being displayed or indexed.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-apacheconf" data-lang="apacheconf"><span class="line"><span class="cl"><span class="c"># This file is /etc/apache2/dev-server-vhost.conf</span>
</span></span><span class="line"><span class="cl"><span class="c"># This file is included from the virtual hosts in /etc/apache2/conf.d/dev-server.conf</span>
</span></span><span class="line"><span class="cl"><span class="c"># The guts of the VirtualHost container with robot blocking and mass virtual hosting via mod_rewrite</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">ServerName</span> dev.example.org
</span></span><span class="line"><span class="cl"><span class="nb">ServerAdmin</span> example@example.org
</span></span><span class="line"><span class="cl"><span class="nb">ServerAlias</span> *.dev *.dev.example.org staging.example.org *.staging *.staging.example.org proof.example.org *.proof *.proof.example.org
</span></span><span class="line"><span class="cl"><span class="nb">DocumentRoot</span> <span class="sx">/var/www</span>
</span></span><span class="line"><span class="cl"><span class="nb">LimitInternalRecursion</span> <span class="m">15</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># Detect bots by user agent</span>
</span></span><span class="line"><span class="cl"><span class="nb">SetEnvIfNoCase</span> <span class="k">User</span>-Agent <span class="s2">&#34;.*(Googlebot|msnbot|Yahoo! Slurp|YahooSeeker|Yahoo-Blogs|bot|robot|spider|Ask Jeeves|ArchitextSpider|Scooter|AltaVista|Slurp|Crawler|WebCrawler|Lycos).*&#34;</span> bad_bot
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># Detect incorrect website access by referer. This is to stop anybody</span>
</span></span><span class="line"><span class="cl"><span class="c"># clicking on a link from the following search engine&#39;s listings.</span>
</span></span><span class="line"><span class="cl"><span class="nb">SetEnvIfNoCase</span> Referer <span class="s2">&#34;.*(Google\.|Yahoo\.|Bing\.|Ask\.|Excite\.|Lycos\.|AltaVista\.|WebCrawler\.).*&#34;</span> bad_bot
</span></span><span class="line"><span class="cl"><span class="nt">&lt;Directory</span> <span class="s">/home/</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nb">Options</span> Indexes FollowSymLinks Multiviews
</span></span><span class="line"><span class="cl">    <span class="nb">AllowOverride</span> <span class="k">All</span>
</span></span><span class="line"><span class="cl">    <span class="nb">Order</span> allow,deny
</span></span><span class="line"><span class="cl">    <span class="nb">Allow</span> from <span class="k">all</span>
</span></span><span class="line"><span class="cl">    <span class="nb">Deny</span> from env=bad_bot
</span></span><span class="line"><span class="cl"><span class="nt">&lt;/Directory&gt;</span>
</span></span><span class="line"><span class="cl"><span class="nt">&lt;Directory</span> <span class="s">/var/vhosts/virtual</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">   <span class="nb">Options</span> Indexes FollowSymLinks Multiviews
</span></span><span class="line"><span class="cl">    <span class="nb">AllowOverride</span> <span class="k">All</span>
</span></span><span class="line"><span class="cl">    <span class="nb">Order</span> allow,deny
</span></span><span class="line"><span class="cl">    <span class="nb">Allow</span> from <span class="k">all</span>
</span></span><span class="line"><span class="cl">    <span class="nb">Deny</span> from env=bad_bot
</span></span><span class="line"><span class="cl"><span class="nt">&lt;/Directory&gt;</span>
</span></span><span class="line"><span class="cl"><span class="nt">&lt;Directory</span> <span class="s">/var/vhosts/proof</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nb">Options</span> Indexes FollowSymLinks Multiviews
</span></span><span class="line"><span class="cl">    <span class="nb">AllowOverride</span> <span class="k">All</span>
</span></span><span class="line"><span class="cl">    <span class="nb">Order</span> allow,deny
</span></span><span class="line"><span class="cl">    <span class="nb">Allow</span> from <span class="k">all</span>
</span></span><span class="line"><span class="cl">    <span class="nb">Deny</span> from env=bad_bot
</span></span><span class="line"><span class="cl"><span class="nt">&lt;/Directory&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">RewriteEngine</span> <span class="k">on</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># Rewrite log settings</span>
</span></span><span class="line"><span class="cl"><span class="nb">RewriteLog</span> <span class="sx">/var/log/apache2/dev-rewrite.log</span>
</span></span><span class="line"><span class="cl"><span class="c">#0-9: 0 = none 9 = verbose</span>
</span></span><span class="line"><span class="cl"><span class="nb">RewriteLogLevel</span> <span class="m">0</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># Block robots with a central robots.txt for all sites</span>
</span></span><span class="line"><span class="cl"><span class="nb">RewriteRule</span> ^/robots.txt$ <span class="sx">/var/vhosts/robots.txt</span> [L]
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># Filter to parse URLs to lowercase</span>
</span></span><span class="line"><span class="cl"><span class="nb">RewriteMap</span> lowercase int:tolower
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># Dev sites</span>
</span></span><span class="line"><span class="cl"><span class="c"># With the format &#34;user    /home/dir/&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nb">RewriteMap</span> vhost txt:/etc/apache2/dev-server-rewrite.map
</span></span><span class="line"><span class="cl"><span class="nb">RewriteCond</span> ${lowercase:%{SERVER_NAME}} ([^.]+)\.([^.]+)\.dev\.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># Windows:</span>
</span></span><span class="line"><span class="cl"><span class="c"># RewriteCond %1.${vhost:%2}£%2 ^([a-z]+)\.([d].*)£([a-z]+)$</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># Linux:</span>
</span></span><span class="line"><span class="cl"><span class="nb">RewriteCond</span> %1.${vhost:%2}£%2 ^([a-z]+)\.(/.*)£([a-z]+)$
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># The £%2 is only there so that the developer</span>
</span></span><span class="line"><span class="cl"><span class="c"># username can be passed between RewriteConds.</span>
</span></span><span class="line"><span class="cl"><span class="c"># The £ symbol is just a delimiter.</span>
</span></span><span class="line"><span class="cl"><span class="nb">RewriteRule</span> ^/(.*)$ %2/%1/pub/$1 [L,E=VIRTUAL_DOCUMENT_ROOT:%2/%1/pub,E=WE_ARE_ON_STAGING:TRUE,E=DEVELOPER_USERNAME:%3]
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># Staging sites</span>
</span></span><span class="line"><span class="cl"><span class="nb">RewriteCond</span> ${lowercase:%{SERVER_NAME}} ([^.]+)\.staging\.
</span></span><span class="line"><span class="cl"><span class="nb">RewriteRule</span> ^/(.*)$ <span class="sx">/var/vhosts/staging/</span>%1/pub/$1 [L,E=VIRTUAL_DOCUMENT_ROOT:/var/vhosts/staging/%1/pub,E=WE_ARE_ON_STAGING:TRUE]
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># Proof sites</span>
</span></span><span class="line"><span class="cl"><span class="nb">RewriteCond</span> ${lowercase:%{SERVER_NAME}} ([^.]+)\.proof\.
</span></span><span class="line"><span class="cl"><span class="nb">RewriteRule</span> ^/(.*)$ <span class="sx">/var/vhosts/proof/</span>%1/pub/$1 [L,E=VIRTUAL_DOCUMENT_ROOT:/var/vhosts/proof/%1/pub,E=WE_ARE_ON_STAGING:TRUE]
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># Logging</span>
</span></span><span class="line"><span class="cl"><span class="nb">LogLevel</span> <span class="k">debug</span>
</span></span><span class="line"><span class="cl"><span class="nb">LogFormat</span> <span class="s2">&#34;%{Host}i %h %l %u %t \&#34;%r\&#34; %s %b&#34;</span> vcommon
</span></span><span class="line"><span class="cl"><span class="nb">CustomLog</span> <span class="sx">/var/log/apache2/dev-access.log</span> vcommon
</span></span><span class="line"><span class="cl"><span class="nb">ErrorLog</span> <span class="sx">/var/log/apache2/dev-error.log</span>
</span></span></code></pre></div><h3 id="mod_rewrite-setup-and-logging">mod_rewrite Setup and Logging</h3>
<p>Next mod_rewrite is employed and a log file is specified for debugging rewrite requests. I have set the log level to zero by default to disable logging but bump it up to 9 and it will give you full request logging.</p>
<h3 id="central-robotstxt">Central Robots.txt</h3>
<p>All requests to robots.txt on a particular site are rewritten to a central file that simply denies all robot traffic to all URLs. If you are not sure how to specify this then check out the documentation on <a href="http://www.robotstxt.org/">Robotstxt.org</a>.</p>
<pre tabindex="0"><code># This file is /var/vhosts/robots.txt
# The central robots.txt file.

User-agent: *
Disallow: /
</code></pre><h3 id="development-environments-for-individuals">Development Environments for Individuals</h3>
<p>Further on we have the first rewrite rule for *.dev.example.org sites. These are for each developers individual development environment. It uses a RewriteMap file to match developers name in the URL to a location in the file system. This looks like the following and it is self explanatory:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-apacheconf" data-lang="apacheconf"><span class="line"><span class="cl"><span class="c"># This file is /etc/apache2/dev-server-rewrite.map</span>
</span></span><span class="line"><span class="cl"><span class="c"># This file is included from the virtual hosts in /etc/apache2/dev-server-vhost.conf</span>
</span></span><span class="line"><span class="cl"><span class="c"># Maps a username to a location in the file system uses the following format:</span>
</span></span><span class="line"><span class="cl"><span class="c"># name&lt;tab&gt;/dir/location</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">simon</span>   <span class="sx">/home/simon/www</span>
</span></span><span class="line"><span class="cl"><span class="nb">joe</span>     <span class="sx">/home/joe/www</span>
</span></span><span class="line"><span class="cl"><span class="nb">jane</span>    <span class="sx">/home/jane/www</span>
</span></span></code></pre></div><p>As you can see from the directory layout above you will need to setup a new user for each developer and add their path and username to the map file.</p>
<h3 id="environment-variables-for-bootstrapping">Environment Variables for Bootstrapping</h3>
<p>When the developers environment is rewritten three environment variables are set for use in your scripts (in PHP this is available in <code>$_SERVER</code>). The variables would look like the following if you were to access the site mysitename.simon.dev.example.org:</p>
<ol>
<li><code>VIRTUAL_DOCUMENT_ROOT</code> = /home/simon/www/mysitename/pub</li>
<li><code>WE_ARE_ON_STAGING</code> = TRUE</li>
<li><code>DEVELOPER_USERNAME</code> = simon</li>
</ol>
<p>VIRTUAL_DOCUMENT_ROOT</p>
<p>The <code>VIRTUAL_DOCUMENT_ROOT</code> is the location of the files that are being served and can be used in place of <code>DOCUMENT_ROOT</code> in your scripts.</p>
<p>This can get tedious however so I have setup an auto_prepend file in my PHP configuration that converts <code>VIRTUAL_DOCUMENT_ROOT</code> to <code>DOCUMENT_ROOT</code> automatically.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o">&lt;?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl"><span class="c1">// This file is /etc/php/auto_prepend.php
</span></span></span><span class="line"><span class="cl"><span class="c1">// It is actioned by setting auto_prepend_file=&#34;/etc/php/auto_prepend.php&#34; in your PHP INI/Config
</span></span></span><span class="line"><span class="cl"><span class="c1">// Converts the virtual document root to be the standard document root
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="k">if</span><span class="p">(</span><span class="nx">isset</span><span class="p">(</span><span class="nv">$_SERVER</span><span class="p">[</span><span class="s1">&#39;VIRTUAL_DOCUMENT_ROOT&#39;</span><span class="p">])</span> <span class="k">and</span>
</span></span><span class="line"><span class="cl">   <span class="o">!</span><span class="k">empty</span><span class="p">(</span><span class="nv">$_SERVER</span><span class="p">[</span><span class="s1">&#39;VIRTUAL_DOCUMENT_ROOT&#39;</span><span class="p">]))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nv">$_SERVER</span><span class="p">[</span><span class="s1">&#39;DOCUMENT_ROOT&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="nv">$_SERVER</span><span class="p">[</span><span class="s1">&#39;VIRTUAL_DOCUMENT_ROOT&#39;</span><span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Then set the PHP INI configuration variable <code>auto_prepend_file</code> to the path of your file. In my case above this would look like: <code>auto_prepend_file=&quot;/etc/php/auto_prepend.php&quot;</code></p>
<p>This is the only way I have found to override the value in the <code>DOCUMENT_ROOT</code> environment variable. Attempting to do so in the <code>RewriteRule</code> will not work.</p>
<p>WE_ARE_ON_STAGING and DEVELOPER_USERNAME</p>
<p>The next two environment variables <code>WE_ARE_ON_STAGING</code> and <code>DEVELOPER_USERNAME</code> are used to automatically setup the correct configuration environment in development, staging and production.</p>
<p>So I currently use an XML configuration file that is interpreted by the <a href="http://framework.zend.com/manual/en/zend.config.adapters.xml.html">ZendFramework Zend_Config</a> class. Zend_Config has the concept of multiple environments that can extend each other. This is described in more detail in the <a href="http://framework.zend.com/manual/en/zend.config.adapters.xml.html">ZendFramework manual</a>, but you could just as easily write your own or tie it into any frameworks bootstrap.</p>
<p>Essentially these variables allow me to work out which set of configuration data I should use when bootstrapping the application. Each developer maybe working from their own database for example so if <code>DEVELOPER_USERNAME</code> is set we can automatically use their configuration.</p>
<p>If the <code>WE_ARE_ON_STAGING</code> variable is not set then we are on the production server so we can use the live configuration options.</p>
<p>This works for me but you may want to tweak it to suit your work flow.</p>
<h3 id="apache-logging">Apache Logging</h3>
<p>I have this set to the maximum logging level and I have redirected all logging for sites going through this VirtualHost container to a central error and access log. This is all explained in more depth in the <a href="http://httpd.apache.org/docs/2.2/logs.html">Apache2 manual</a> section on Log Files.</p>
<h1 id="other-niceties">Other Niceties</h1>
<p>There are a few the other helpful things I have running on the server as well to aid development. I would go into more detail about them but they are fairly easy to install and configure plus they are not required for the main functioning of the server.</p>
<ol>
<li><a href="https://help.ubuntu.com/6.06/ubuntu/serverguide/C/configuring-samba.html">Install and setup Samba</a> shares for the dev, staging and proof directories so Windows users can easily access the files and create new sites.</li>
<li>Setup a mail server so that your applications can send out test emails. I use Postfix for this and there is a nice <a href="https://help.ubuntu.com/community/Postfix">help tutorial for Ubuntu</a> to help you along.</li>
<li>If you are using PHP then seriously consider installing <a href="http://www.xdebug.org/">XDebug</a> and looking into is profiling capabilities.</li>
<li>Also on PHP install <a href="http://pecl.php.net/apc">APC</a> to speed up PHP.</li>
<li>Consider setting up <a href="http://httpd.apache.org/docs/2.0/mod/mod_cache.html">mod_cache</a> to test your long life caches.</li>
<li>I have added <a href="http://memcached.org/">memcached</a> and <a href="http://redis.io/">Redis</a> to the mix as well.</li>
</ol>
<p>I have recently written about <a href="/post/2009/04/memcached-and-apc-two-simple-techniques-to-speed-up-your.html">installing memcached and APC</a> on my blog for both <a href="/post/2009/03/installing-apc-and-memcached-for-php-sessions-on-redhat.html">RedHat</a> and <a href="/post/2009/04/installing-apc-and-memcached-for-php-sessions-on-ubuntu.html">Ubuntu</a>.</p>
<h1 id="conclusion">Conclusion</h1>
<p>I have found this to be a very effective development environment when working with groups of people. You can develop in your own environment and then push it to staging for client approval. It also ensures that the staging environment and development environments are almost identical. I hope that this proves useful to you as well.</p>
]]></content><category scheme="taxonomy:Tags" term="php" label="php"/><category scheme="taxonomy:Tags" term="internet" label="internet"/><category scheme="taxonomy:Tags" term="debian" label="debian"/><category scheme="taxonomy:Tags" term="ubuntu" label="ubuntu"/><category scheme="taxonomy:Tags" term="apache" label="Apache"/><category scheme="taxonomy:Tags" term="memcached" label="memcached"/><category scheme="taxonomy:Tags" term="memcache" label="memcache"/><category scheme="taxonomy:Tags" term="redis" label="Redis"/><category scheme="taxonomy:Tags" term="virtualhosting" label="virtualhosting"/></entry><entry xml:base="redis-under-the-hood"><title type="html">Redis: under the hood (internals)</title><link href="https://www.simonholywell.com/post/2010/10/redis-under-the-hood/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2010/09/15-excellent-resources-for-php-extension-development/?utm_source=atom_feed" rel="related" type="text/html" title="15 Excellent Resources for PHP Extension Development"/><link href="https://www.simonholywell.com/post/2010/09/per-tag-rss-feeds-for-tumblr/?utm_source=atom_feed" rel="related" type="text/html" title="Per-tag RSS feeds for Tumblr from notes.husk.org"/><link href="https://www.simonholywell.com/post/2010/08/get-gearman-to-install-on-ubuntu/?utm_source=atom_feed" rel="related" type="text/html" title="Getting gearman to install on Ubuntu"/><link href="https://www.simonholywell.com/post/2010/08/john-resig-tech4africa2010/?utm_source=atom_feed" rel="related" type="text/html" title="In this video, John Resig presents his 6 Secrets to becoming a j…"/><link href="https://www.simonholywell.com/post/2010/08/firefox-radio-buttons/?utm_source=atom_feed" rel="related" type="text/html" title=""/><id>https://www.simonholywell.com/post/2010/10/redis-under-the-hood/</id><author><name>Simon Holywell</name></author><published>2010-10-18T20:02:11+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Redis: under the hood (internals)
I was curious to learn more about Redis’s internals, so I’ve been familiarizing myself with the source, largely by reading and jumping around in Emacs. After I had peeled back enough of the onion’s layers, I realized I was trying to keep track of too many details in my head, and it wasn’t clear how it all hung together. I decided to write out in narrative form how an instance of the Redis server starts up and initializes itself, and how it handles the request/response cycle with a client, as a way of explaining it to myself, hopefully in a clear fashion.</summary><content type="html"><![CDATA[<p><a href="http://www.pauladamsmith.com/articles/redis_under_the_hood.html">Redis: under the hood (internals)</a></p>
<blockquote>
<p>I was curious to learn more about Redis’s internals, so I’ve been familiarizing myself with the source, largely by reading and jumping around in Emacs. After I had peeled back enough of the onion’s layers, I realized I was trying to keep track of too many details in my head, and it wasn’t clear how it all hung together. I decided to write out in narrative form how an instance of the Redis server starts up and initializes itself, and how it handles the request/response cycle with a client, as a way of explaining it to myself, hopefully in a clear fashion.</p>
</blockquote>
]]></content><category scheme="taxonomy:Tags" term="redis" label="redis"/><category scheme="taxonomy:Tags" term="computing" label="computing"/><category scheme="taxonomy:Tags" term="internet" label="internet"/></entry><entry xml:base="pecl-install-issues-on-redhat"><title type="html">PECL Install Issues on Redhat</title><link href="https://www.simonholywell.com/post/2010/10/pecl-install-issues-on-redhat/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2010/09/15-excellent-resources-for-php-extension-development/?utm_source=atom_feed" rel="related" type="text/html" title="15 Excellent Resources for PHP Extension Development"/><link href="https://www.simonholywell.com/post/2010/09/php-ssdeep-in-pecl/?utm_source=atom_feed" rel="related" type="text/html" title="The PHP ssdeep Extension is Now in PECL"/><link href="https://www.simonholywell.com/post/2010/08/php-ssdeep-fuzzy-hashing-php-extension/?utm_source=atom_feed" rel="related" type="text/html" title="php_ssdeep Fuzzy Hashing PHP Extension"/><link href="https://www.simonholywell.com/post/2010/08/php-wrapper-for-linux-at-command/?utm_source=atom_feed" rel="related" type="text/html" title="A PHP wrapper for the unix at command"/><link href="https://www.simonholywell.com/post/2010/08/get-gearman-to-install-on-ubuntu/?utm_source=atom_feed" rel="related" type="text/html" title="Getting gearman to install on Ubuntu"/><id>https://www.simonholywell.com/post/2010/10/pecl-install-issues-on-redhat/</id><author><name>Simon Holywell</name></author><published>2010-10-06T11:03:06+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Installing via the pecl command can be a pain on Redhat. First off all you will need to install the php-devel package:
yum install php-devel
Then you will need ensure that the PEAR/PECL installer is at the latest version so as root run:
pear channel-update pear.php.net pear upgrade pear
You may need to force pear to upgrade itself by using:
pear upgrade –force pear
I had to use the –force option because my version of PEAR was so old that the installer thought my version of Tar_Archive might not have been up to muster.</summary><content type="html"><![CDATA[<p>Installing via the pecl command can be a pain on Redhat. First off all you will need to install the php-devel package:</p>
<blockquote>
<p>yum install php-devel</p>
</blockquote>
<p>Then you will need ensure that the PEAR/PECL installer is at the latest version so as root run:</p>
<blockquote>
<p>pear channel-update pear.php.net pear upgrade pear</p>
</blockquote>
<p>You may need to force pear to upgrade itself by using:</p>
<blockquote>
<p>pear upgrade –force pear</p>
</blockquote>
<p>I had to use the –force option because my version of PEAR was so old that the installer thought my version of Tar_Archive might not have been up to muster. It was however.</p>
<p>With all this in place you are ready to attempt to install your chosen extension:</p>
<blockquote>
<p>pecl install ssdeep</p>
</blockquote>
<p>If you get something like the following back:</p>
<blockquote>
<p>/usr/bin/phpize: /tmp/ssdeep/build/shtool: /bin/sh: bad interpreter: Permission</p>
</blockquote>
<p>Then it is likely that your temporary directory is mounted in a safer noexec state, which means that you cannot execute scripts within the /tmp directory. To test this you can put a simple bash script into your /tmp directory and chmod it with +x. I used the following bash script:</p>
<blockquote>
<p>#!/bin/bash echo “SIMON”</p>
</blockquote>
<p>If you do not get SIMON back when you execute the file, but an error like “/bin/sh: bad interpreter: Permission” then the directory is set to noexec.</p>
<p>There are a few ways to overcome this with the easiest being to:</p>
<ol>
<li>
<p>Remount the directory as exec:</p>
<blockquote>
<p>mount -o remount,exec /tmp</p>
</blockquote>
</li>
<li>
<p>Install your pecl extension</p>
<blockquote>
<p>pecl install ssdeep</p>
</blockquote>
</li>
<li>
<p>Remount the directory as noexec again for safety</p>
<blockquote>
<p>mount -o remount,noexec /tmp</p>
</blockquote>
</li>
</ol>
<p>There are a <a href="http://wiki.mediatemple.net/index.php/Getting_around_%27noexec%27_issues_with_/tmp">variety of other ways</a> to get this working documented in the <a href="http://wiki.mediatemple.net/index.php/Getting_around_%27noexec%27_issues_with_/tmp">Media Temple wiki pages</a> if the above technique does not work for you.</p>
]]></content><category scheme="taxonomy:Tags" term="redhat" label="redhat"/><category scheme="taxonomy:Tags" term="php" label="php"/><category scheme="taxonomy:Tags" term="pecl" label="pecl"/><category scheme="taxonomy:Tags" term="php-extension" label="php extension"/><category scheme="taxonomy:Tags" term="php-extensions" label="php extensions"/><category scheme="taxonomy:Tags" term="php_ssdeep" label="php_ssdeep"/></entry><entry xml:base="force-netbeans-line-endings"><title type="html">Forcing NetBeans to Use Unix (LF) Line Endings</title><link href="https://www.simonholywell.com/post/2010/10/force-netbeans-line-endings/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2009/11/netbeans-and-xdebug/?utm_source=atom_feed" rel="related" type="text/html" title="Netbeans and Remote XDebug"/><link href="https://www.simonholywell.com/post/2010/09/15-excellent-resources-for-php-extension-development/?utm_source=atom_feed" rel="related" type="text/html" title="15 Excellent Resources for PHP Extension Development"/><link href="https://www.simonholywell.com/post/2010/09/php-ssdeep-in-pecl/?utm_source=atom_feed" rel="related" type="text/html" title="The PHP ssdeep Extension is Now in PECL"/><link href="https://www.simonholywell.com/post/2010/09/per-tag-rss-feeds-for-tumblr/?utm_source=atom_feed" rel="related" type="text/html" title="Per-tag RSS feeds for Tumblr from notes.husk.org"/><link href="https://www.simonholywell.com/post/2010/08/php-ssdeep-fuzzy-hashing-php-extension/?utm_source=atom_feed" rel="related" type="text/html" title="php_ssdeep Fuzzy Hashing PHP Extension"/><id>https://www.simonholywell.com/post/2010/10/force-netbeans-line-endings/</id><author><name>Simon Holywell</name></author><published>2010-10-05T17:38:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Forcing NetBeans to Use Unix (LF) Line Endings
NetBeans usually uses the operating systems default line ending when creating a new file (it establishes this by what the JVM tells it). So for example in Windows it will automatically use CRLF and in Unix it will automatically use LF. This behaviour has its advantages, but sometimes you want to to be specific about the line endings you need.
To do this you can add the following switch to your call to the NetBeans binary.</summary><content type="html"><![CDATA[<p><a href="http://forums.netbeans.org/post-84987.html#84987">Forcing NetBeans to Use Unix (LF) Line Endings</a></p>
<p>NetBeans usually uses the operating systems default line ending when creating a new file (it establishes this by what the JVM tells it). So for example in Windows it will automatically use CRLF and in Unix it will automatically use LF. This behaviour has its advantages, but sometimes you want to to be specific about the line endings you need.</p>
<p>To do this you can add the following switch to your call to the NetBeans binary. On Windows this would be done on the shortcut by opening its properties and adding the switch at the very end of the Target line.</p>
<blockquote>
<p><code>-J-Dline.separator=LF</code></p>
</blockquote>
<p>Whilst this is handy a proper setting in the preferences of NetBeans would be preferable as it could then easily be backed up and taken from machine to machine. <a href="http://netbeans.org/bugzilla/show_bug.cgi?id=72515">Vote for the issue</a> on the NetBeans bug tracker.</p>
]]></content><category scheme="taxonomy:Tags" term="netbeans" label="netbeans"/><category scheme="taxonomy:Tags" term="web-development" label="web development"/><category scheme="taxonomy:Tags" term="java" label="java"/></entry><entry xml:base="15-excellent-resources-for-php-extension-development"><title type="html">15 Excellent Resources for PHP Extension Development</title><link href="https://www.simonholywell.com/post/2010/09/15-excellent-resources-for-php-extension-development/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2010/09/php-ssdeep-in-pecl/?utm_source=atom_feed" rel="related" type="text/html" title="The PHP ssdeep Extension is Now in PECL"/><link href="https://www.simonholywell.com/post/2010/08/php-ssdeep-fuzzy-hashing-php-extension/?utm_source=atom_feed" rel="related" type="text/html" title="php_ssdeep Fuzzy Hashing PHP Extension"/><link href="https://www.simonholywell.com/post/2010/08/get-gearman-to-install-on-ubuntu/?utm_source=atom_feed" rel="related" type="text/html" title="Getting gearman to install on Ubuntu"/><link href="https://www.simonholywell.com/post/2010/08/drop-cap-php-regex/?utm_source=atom_feed" rel="related" type="text/html" title="Drop Cap with PHP Regular Expression"/><link href="https://www.simonholywell.com/post/2010/08/updated-tumblr-backup-php-now-disqus/?utm_source=atom_feed" rel="related" type="text/html" title="Updated: Back up Tumblr Blog and/or Disqus Comments"/><id>https://www.simonholywell.com/post/2010/09/15-excellent-resources-for-php-extension-development/</id><author><name>Simon Holywell</name></author><published>2010-09-20T18:40:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Whilst developing a PHP extension recently I spent quite a bit of time researching exactly how to create an extension, the best practices and the DocBook format of the PHP manual for documenting the extension.
By the time I finished writing the extension I had found some very good resources both on the web and in print.
Printed books: Sara Golemon’s Extending and Embedding PHP Advanced PHP Programming by George Schlossnagle Building Custom PHP Extensions by Blake Schwendiman Online articles and presentations: The Internals section of the PHP manual Kristina Chodorow’s PHP Extensions Made Eldrich on her blog in 2011: Installing PHP Hello, World!</summary><content type="html"><![CDATA[<p>Whilst developing a <a href="/post/2010/08/php-ssdeep-fuzzy-hashing-php-extension.html">PHP extension</a> recently I spent quite a bit of time researching exactly how to create an extension, the best practices and the DocBook format of the PHP manual for documenting the extension.</p>
<p>By the time I finished writing the extension I had found some very good resources both on the web and in print.</p>
<h1 id="printed-books">Printed books:</h1>
<ul>
<li>Sara Golemon’s <a href="http://www.amazon.co.uk/gp/product/067232704X?ie=UTF8&amp;tag=simonholywell-21&amp;linkCode=as2&amp;camp=1634&amp;creative=6738&amp;creativeASIN=067232704X">Extending and Embedding PHP</a></li>
<li><a href="http://www.amazon.co.uk/gp/product/B00388I8PU?ie=UTF8&amp;tag=simonholywell-21&amp;linkCode=as2&amp;camp=1634&amp;creative=6738&amp;creativeASIN=B00388I8PU">Advanced PHP Programming</a> by George Schlossnagle</li>
<li><a href="http://www.amazon.co.uk/gp/product/1411601882/ref=as_li_ss_tl?ie=UTF8&amp;camp=1634&amp;creative=19450&amp;creativeASIN=1411601882&amp;linkCode=as2&amp;tag=simonholywell-21">Building Custom PHP Extensions</a> by Blake Schwendiman</li>
</ul>
<h1 id="online-articles-and-presentations">Online articles and presentations:</h1>
<ul>
<li>The <a href="http://php.net/manual/en/internals2.php">Internals section</a> of the <a href="http://www.php.net/manual/">PHP manual</a></li>
<li>Kristina Chodorow’s <a href="http://www.kchodorow.com/blog/2011/08/11/php-extensions-made-eldrich-installing-php/">PHP Extensions Made Eldrich</a> on her blog in 2011:
<ul>
<li><a href="http://www.kchodorow.com/blog/2011/08/11/php-extensions-made-eldrich-installing-php/">Installing PHP</a></li>
<li><a href="http://www.kchodorow.com/blog/2011/08/11/php-extensions-made-eldrich-hello-world/">Hello, World!</a></li>
<li><a href="http://www.kchodorow.com/blog/2011/08/11/php-extensions-made-eldrich-php-variables/">PHP Variables</a></li>
<li><a href="http://www.kchodorow.com/blog/2011/08/11/php-extensions-made-eldrich-classes/">Classes</a></li>
</ul>
</li>
<li>Sara Golemon’s <a href="http://devzone.zend.com/article/1021">Zend DevZone articles</a> with parts <a href="http://devzone.zend.com/303/extension-writing-part-i-introduction-to-php-and-zend/">I</a>, <a href="http://devzone.zend.com/317/extension-writing-part-ii-parameters-arrays-and-zvals/">II</a> and <a href="http://devzone.zend.com/446/extension-writing-part-iii-resources/">III</a> (2005, 2006):
<ul>
<li><a href="http://devzone.zend.com/303/extension-writing-part-i-introduction-to-php-and-zend/">Extension Writing Part I: Introduction to PHP and Zend</a></li>
<li><a href="http://devzone.zend.com/317/extension-writing-part-ii-parameters-arrays-and-zvals/">Extension Writing Part II: Parameters, Arrays, and ZVALs</a></li>
<li><a href="http://devzone.zend.com/446/extension-writing-part-iii-resources/">Extension Writing Part III: Resources</a></li>
</ul>
</li>
<li>Wez Furlong’s <a href="http://www.php.net/~wez/extending-php.pdf">Extending PHP slides</a></li>
<li>Marcus Börger and Johannes Schlüter: <a href="http://talks.somabo.de/200903_montreal_php_extension_writing.pdf">PHP Extension Writing</a> slides</li>
<li>O’Reilly Programming PHP Chapter 14: <a href="http://docstore.mik.ua/orelly/webprog/php/ch14_01.htm">Extending PHP</a></li>
<li>Paul Osman’s <a href="http://devzone.zend.com/1435/wrapping-c-classes-in-a-php-extension/">Wrapping C++ Classes in a PHP Extension</a> article on Zend DevZone</li>
</ul>
<h1 id="documenting-php-and-pecl-extensions">Documenting PHP and PECL extensions:</h1>
<ul>
<li>PHP Wiki: <a href="http://wiki.php.net/doc/howto">Documentation Introduction</a></li>
<li>PHP Wiki: <a href="http://wiki.php.net/doc/howto/editing">Editing Documentation</a></li>
<li>PHP Documentation Team: <a href="http://doc.php.net/php/dochowto/">How to pages</a></li>
<li>PHP Wiki: <a href="http://wiki.php.net/doc/howto/pecldocs">Documenting PECL Extensions</a></li>
</ul>
<h1 id="pyrus">Pyrus</h1>
<p>Also worth a mention is the ability of the new <a href="http://pear2.php.net/">PEAR2 Pyrus installer</a> to generate a skeleton for you to build your PECL extension upon - see the <a href="http://pear.php.net/manual/en/pyrus.commands.generateext.php">generate-ext section</a> of the manual.</p>
<p>Pyrus can also be used to package your extension up for release using the <a href="http://pear.php.net/manual/en/pyrus.commands.pickle.php">pickle command</a>.</p>
<h1 id="support">Support</h1>
<p>For more help there is a <a href="http://news.php.net/group.php?group=php.pecl.dev">PECL mailing list</a> and IRC channel (#php.pecl on efnet), both of which are in the support section of the <a href="http://pecl.php.net/support.php">PECL website</a>.</p>
<h1 id="build-tools">Build tools</h1>
<p>Whilst not strictly for PHP extensions the <a href="http://www.freesoftwaremagazine.com/books/autotools_a_guide_to_autoconf_automake_libtool">Autotools: a practitioner’s guide to Autoconf, Automake and Libtool</a> book by John Calcote on the <a href="http://www.freesoftwaremagazine.com/">Free Software Magazine</a> is very useful reading for an understanding of the build process involved in extension writing.</p>
<p>There is also the <a href="http://www.gnu.org/software/autoconf/manual/index.html">GNU Manual for Autoconf</a> and <a href="http://sourceware.org/autobook/">GNU Autoconf, Automake, and Libtool</a> by Gary V. Vaughan et al.</p>
<blockquote>
<p><strong>note</strong></p>
<p>This article has been updated a number of times as it is reasonably popular and new resources have become available since it was written.</p>
<p>Since writing this article a new <a href="https://wiki.php.net/internals/references">Wiki article</a> has been added on php.net with a list of resources. Some of which I have not already covered here.</p>
</blockquote>
]]></content><category scheme="taxonomy:Tags" term="computing" label="computing"/><category scheme="taxonomy:Tags" term="internet" label="internet"/><category scheme="taxonomy:Tags" term="php" label="php"/><category scheme="taxonomy:Tags" term="php-extension" label="php extension"/><category scheme="taxonomy:Tags" term="php-extensions" label="php extensions"/><category scheme="taxonomy:Tags" term="php_ssdeep" label="php_ssdeep"/><category scheme="taxonomy:Tags" term="ssdeep" label="ssdeep"/><category scheme="taxonomy:Tags" term="autoconf" label="autoconf"/><category scheme="taxonomy:Tags" term="autotools" label="autotools"/><category scheme="taxonomy:Tags" term="automake" label="automake"/></entry><entry xml:base="php-ssdeep-in-pecl"><title type="html">The PHP ssdeep Extension is Now in PECL</title><link href="https://www.simonholywell.com/post/2010/09/php-ssdeep-in-pecl/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2010/08/php-ssdeep-fuzzy-hashing-php-extension/?utm_source=atom_feed" rel="related" type="text/html" title="php_ssdeep Fuzzy Hashing PHP Extension"/><link href="https://www.simonholywell.com/post/2010/08/php-wrapper-for-linux-at-command/?utm_source=atom_feed" rel="related" type="text/html" title="A PHP wrapper for the unix at command"/><link href="https://www.simonholywell.com/post/2010/08/get-gearman-to-install-on-ubuntu/?utm_source=atom_feed" rel="related" type="text/html" title="Getting gearman to install on Ubuntu"/><link href="https://www.simonholywell.com/post/2010/08/drop-cap-php-regex/?utm_source=atom_feed" rel="related" type="text/html" title="Drop Cap with PHP Regular Expression"/><link href="https://www.simonholywell.com/post/2010/08/updated-tumblr-backup-php-now-disqus/?utm_source=atom_feed" rel="related" type="text/html" title="Updated: Back up Tumblr Blog and/or Disqus Comments"/><id>https://www.simonholywell.com/post/2010/09/php-ssdeep-in-pecl/</id><author><name>Simon Holywell</name></author><published>2010-09-18T11:46:25+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>The PHP ssdeep Extension is Now in PECL
This means you can now install it easily by simply running:
sudo pecl install ssdeep
There is also proper documentation in the PHP manual which can be found at php.net/ssdeep.
For more information on the extension either see the PECL project page or the ssdeep PHP/PECL extension’s homepage.</summary><content type="html"><![CDATA[<p><a href="http://pecl.php.net/package/ssdeep">The PHP ssdeep Extension is Now in PECL</a></p>
<p>This means you can now install it easily by simply running:</p>
<blockquote>
<p>sudo pecl install ssdeep</p>
</blockquote>
<p>There is also proper documentation in the PHP manual which can be found at <a href="http://php.net/ssdeep">php.net/ssdeep</a>.</p>
<p>For more information on the extension either see the <a href="http://pecl.php.net/package/ssdeep">PECL project page</a> or the <a href="http://treffynnon.github.com/php_ssdeep/">ssdeep PHP/PECL extension’s homepage</a>.</p>
]]></content><category scheme="taxonomy:Tags" term="php_ssdeep" label="php_ssdeep"/><category scheme="taxonomy:Tags" term="ssdeep" label="ssdeep"/><category scheme="taxonomy:Tags" term="php-extension" label="php extension"/><category scheme="taxonomy:Tags" term="php-extensions" label="php extensions"/><category scheme="taxonomy:Tags" term="php" label="php"/></entry><entry xml:base="per-tag-rss-feeds-for-tumblr"><title type="html">Per-tag RSS feeds for Tumblr from notes.husk.org</title><link href="https://www.simonholywell.com/post/2010/09/per-tag-rss-feeds-for-tumblr/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2010/08/updated-tumblr-backup-php-now-disqus/?utm_source=atom_feed" rel="related" type="text/html" title="Updated: Back up Tumblr Blog and/or Disqus Comments"/><link href="https://www.simonholywell.com/post/2010/08/tumblr-backup-php/?utm_source=atom_feed" rel="related" type="text/html" title="Backing up Tumblr blogs with PHP and SQLite"/><link href="https://www.simonholywell.com/post/2010/08/get-gearman-to-install-on-ubuntu/?utm_source=atom_feed" rel="related" type="text/html" title="Getting gearman to install on Ubuntu"/><link href="https://www.simonholywell.com/post/2010/08/john-resig-tech4africa2010/?utm_source=atom_feed" rel="related" type="text/html" title="In this video, John Resig presents his 6 Secrets to becoming a j…"/><link href="https://www.simonholywell.com/post/2010/08/firefox-radio-buttons/?utm_source=atom_feed" rel="related" type="text/html" title=""/><id>https://www.simonholywell.com/post/2010/09/per-tag-rss-feeds-for-tumblr/</id><author><name>Simon Holywell</name></author><published>2010-09-03T12:03:54+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Per-tag RSS feeds for Tumblr from notes.husk.org
I didn’t think that Tumblr offered per-tag RSS feeds, but after spending some time trying to hack the JSON output from the Tumblr API into my aggregated front page, I tried appending “/rss” to the URL of one of my tag archive pages, and somewhat to my surprise, it worked.
Of course, RSS is…
A nice Tumblr tip.</summary><content type="html"><![CDATA[<p><a href="http://notes.husk.org/post/318051556/per-tag-rss">Per-tag RSS feeds for Tumblr from notes.husk.org</a></p>
<blockquote>
<p>I didn’t think that Tumblr offered per-tag RSS feeds, but after spending some time trying to hack the JSON output from the <a href="http://www.tumblr.com/docs/api">Tumblr API</a> into my aggregated front page, I tried appending “/rss” to the URL of one of my <a href="http://notes.husk.org/tagged/tumblr">tag archive pages</a>, and somewhat to my surprise, it worked.</p>
<p>Of course, RSS is…</p>
</blockquote>
<p>A nice Tumblr tip.</p>
]]></content><category scheme="taxonomy:Tags" term="tumblr" label="tumblr"/><category scheme="taxonomy:Tags" term="rss" label="rss"/><category scheme="taxonomy:Tags" term="internet" label="internet"/><category scheme="taxonomy:Tags" term="computing" label="computing"/></entry><entry xml:base="php-ssdeep-fuzzy-hashing-php-extension"><title type="html">php_ssdeep Fuzzy Hashing PHP Extension</title><link href="https://www.simonholywell.com/post/2010/08/php-ssdeep-fuzzy-hashing-php-extension/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2010/08/php-wrapper-for-linux-at-command/?utm_source=atom_feed" rel="related" type="text/html" title="A PHP wrapper for the unix at command"/><link href="https://www.simonholywell.com/post/2010/08/linux-batch-remove-extension/?utm_source=atom_feed" rel="related" type="text/html" title="Batch remove extensions in Ubuntu"/><link href="https://www.simonholywell.com/post/2010/08/ubuntu-atd-not-running/?utm_source=atom_feed" rel="related" type="text/html" title="If you are having problems getting Ubuntu atd running"/><link href="https://www.simonholywell.com/post/2010/08/get-gearman-to-install-on-ubuntu/?utm_source=atom_feed" rel="related" type="text/html" title="Getting gearman to install on Ubuntu"/><link href="https://www.simonholywell.com/post/2010/08/drop-cap-php-regex/?utm_source=atom_feed" rel="related" type="text/html" title="Drop Cap with PHP Regular Expression"/><id>https://www.simonholywell.com/post/2010/08/php-ssdeep-fuzzy-hashing-php-extension/</id><author><name>Simon Holywell</name></author><published>2010-08-31T21:50:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>php_ssdeep Fuzzy Hashing PHP Extension
**Updated 16/9:**php_ssdeep is now in PECL so I have updated this post to reflect that.
On a recent project I needed a fast way to compare documents for likeness and return a percentage match. With much research and one unanswered Stackoverflow post later I came across Jesse Kornblum’s ssdeep utility intended for computer forensics such as looking for signatures in files when hunting rootkits etc. All the technical details of fuzzy hashing are described in his 2006 journal article Identifying almost identical files using context triggered piecewise hashing.</summary><content type="html"><![CDATA[<p><a href="http://pecl.php.net/package/ssdeep">php_ssdeep Fuzzy Hashing PHP Extension</a></p>
<p>**Updated 16/9:**php_ssdeep is now in PECL so I have updated this post to reflect that.</p>
<p>On a recent project I needed a fast way to compare documents for likeness and return a percentage match. With much research and one unanswered <a href="http://stackoverflow.com/questions/1728977/checking-for-document-duplicates-and-similar-documents-in-a-document-management-a">Stackoverflow post</a> later I came across Jesse Kornblum’s <a href="http://ssdeep.sourceforge.net/">ssdeep utility</a> intended for computer forensics such as looking for signatures in files when hunting rootkits etc. All the technical details of fuzzy hashing are described in his 2006 journal article <a href="http://dfrws.org/2006/proceedings/12-Kornblum.pdf">Identifying almost identical files using context triggered piecewise hashing</a>.</p>
<p>I was using a <a href="https://gist.github.com/1075789">wrapper around the ssdeep binary written in pure PHP</a>, but I recently decided to write my first PHP extension by tying into the <a href="http://ssdeep.sourceforge.net/api/html/">fuzzy hashing API</a> ssdeep provides. The result is now a PECL extension or module and the <a href="http://en.wikipedia.org/wiki/BSD_licenses">BSD licensed</a> source code is hosted on <a href="http://svn.php.net/pecl/ssdeep">PHP.net’s SVN</a>.</p>
<p>There are full instructions provided in the <a href="http://docs.php.net/manual/en/book.ssdeep.php">PHP manual</a> and the <a href="http://treffynnon.github.com/php_ssdeep/">php_ssdeep site</a> to install the exension and use the provided functions. If you end up using this extension or its code I would be very interested to find out more about your project.</p>
]]></content><category scheme="taxonomy:Tags" term="computing" label="computing"/><category scheme="taxonomy:Tags" term="extension" label="extension"/><category scheme="taxonomy:Tags" term="fuzzy-hashing" label="fuzzy hashing"/><category scheme="taxonomy:Tags" term="linux" label="linux"/><category scheme="taxonomy:Tags" term="php" label="php"/><category scheme="taxonomy:Tags" term="php-extension" label="php extension"/><category scheme="taxonomy:Tags" term="ssdeep" label="ssdeep"/><category scheme="taxonomy:Tags" term="ubuntu" label="ubuntu"/><category scheme="taxonomy:Tags" term="php_ssdeep" label="php_ssdeep"/></entry><entry xml:base="wombert-expendables-body-count"><title type="html">wombert: Expendables Body Count</title><link href="https://www.simonholywell.com/post/2010/08/wombert-expendables-body-count/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2010/08/php-wrapper-for-linux-at-command/?utm_source=atom_feed" rel="related" type="text/html" title="A PHP wrapper for the unix at command"/><link href="https://www.simonholywell.com/post/2010/08/linux-batch-remove-extension/?utm_source=atom_feed" rel="related" type="text/html" title="Batch remove extensions in Ubuntu"/><link href="https://www.simonholywell.com/post/2010/08/ubuntu-atd-not-running/?utm_source=atom_feed" rel="related" type="text/html" title="If you are having problems getting Ubuntu atd running"/><link href="https://www.simonholywell.com/post/2010/08/get-gearman-to-install-on-ubuntu/?utm_source=atom_feed" rel="related" type="text/html" title="Getting gearman to install on Ubuntu"/><link href="https://www.simonholywell.com/post/2010/08/john-resig-tech4africa2010/?utm_source=atom_feed" rel="related" type="text/html" title="In this video, John Resig presents his 6 Secrets to becoming a j…"/><id>https://www.simonholywell.com/post/2010/08/wombert-expendables-body-count/</id><author><name>Simon Holywell</name></author><published>2010-08-25T12:32:09+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>wombert:
Expendables Body Count - originally from termlifeinsurance.org/expendables-body-count</summary><content type="html"><![CDATA[<p><img src="/static/images/www.tumblr.com/photo/1280/holywell/1008470456/1/tumblr_l7pfu4v21H1qz6yfh.png" alt=""></p>
<p><a href="http://blog.wombert.de/post/1008370510/expendables-body-count">wombert</a>:</p>
<blockquote>
<p>Expendables Body Count - originally from termlifeinsurance.org/expendables-body-count</p>
</blockquote>
]]></content></entry><entry xml:base="php-wrapper-for-linux-at-command"><title type="html">A PHP wrapper for the unix at command</title><link href="https://www.simonholywell.com/post/2010/08/php-wrapper-for-linux-at-command/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2010/08/linux-batch-remove-extension/?utm_source=atom_feed" rel="related" type="text/html" title="Batch remove extensions in Ubuntu"/><link href="https://www.simonholywell.com/post/2009/08/moving-to-git-and-setting-up-indefero-as-a-web-frontend/?utm_source=atom_feed" rel="related" type="text/html" title="Moving to git and setting up InDefero as a web frontend"/><link href="https://www.simonholywell.com/post/2009/05/handy-linux-commands/?utm_source=atom_feed" rel="related" type="text/html" title="Handy Linux Commands"/><link href="https://www.simonholywell.com/post/2009/04/memcached-and-apc-two-simple-techniques-to-speed-up-your/?utm_source=atom_feed" rel="related" type="text/html" title="Memcached and APC: Two Simple Techniques to Speed up your PHP Webpages"/><link href="https://www.simonholywell.com/post/2009/04/installing-apc-and-memcached-for-php-sessions-on-ubuntu/?utm_source=atom_feed" rel="related" type="text/html" title="Installing APC and Memcached for PHP Sessions on Ubuntu and Debi…"/><id>https://www.simonholywell.com/post/2010/08/php-wrapper-for-linux-at-command/</id><author><name>Simon Holywell</name></author><published>2010-08-24T21:51:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>A project I am working on at the moment requires time delayed job queues and having found nothing yet that can manage it properly so I decided to wrap up `at` into a PHP class. This gives you simple methods to add, list and remove jobs from the `at` queue using object oriented code.
The code is very simple and I have documented it reasonably well so along with the examples you should get on your way quickly.</summary><content type="html"><![CDATA[<p>A project I am working on at the moment requires time delayed job queues and having found nothing yet that can manage it properly so I decided to wrap up `at` into a <a href="http://github.com/treffynnon/PHP-at-Job-Queue-Wrapper">PHP class</a>. This gives you simple methods to add, list and remove jobs from the `at` queue using object oriented code.</p>
<p>The code is very simple and I have <a href="http://github.com/treffynnon/PHP-at-Job-Queue-Wrapper/blob/master/README.markdown">documented it</a> reasonably well so along with <a href="http://github.com/treffynnon/PHP-at-Job-Queue-Wrapper/blob/master/examples.php">the examples</a> you should get on your way quickly. The class can, of course, be used from the command line as well so if you want to write batch scripts in PHP to handle adding a collection of predefined `at` jobs for example - it can make it easier.</p>
<p>I feel the important features of `at` have been added into the code, but if you want to wrap any of the other functions then please do fork my code and make a patch or post a pull request. For more information on what `at` can do please either run `man at` in your console or visit the Edinburgh University’s <a href="http://unixhelp.ed.ac.uk/CGI/man-cgi?at">man at page</a>.</p>
<p>You can get the code from my repository on GitHub: <a href="http://github.com/treffynnon/PHP-at-Job-Queue-Wrapper">PHP-at-Job-Queue-Wrapper</a>.</p>
<p>If you do have any trouble getting the `at` daemon (atd) going then my previous post may help you debug it - please see <a href="/post/2010/08/ubuntu-atd-not-running.html">If you are having problems getting Ubuntu atd running</a> for more on that.</p>
]]></content><category scheme="taxonomy:Tags" term="ubuntu" label="ubuntu"/><category scheme="taxonomy:Tags" term="linux" label="linux"/><category scheme="taxonomy:Tags" term="computing" label="computing"/><category scheme="taxonomy:Tags" term="php" label="php"/><category scheme="taxonomy:Tags" term="wrapper" label="wrapper"/><category scheme="taxonomy:Tags" term="debian" label="debian"/></entry><entry xml:base="linux-batch-remove-extension"><title type="html">Batch remove extensions in Ubuntu</title><link href="https://www.simonholywell.com/post/2010/08/linux-batch-remove-extension/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2010/08/ubuntu-atd-not-running/?utm_source=atom_feed" rel="related" type="text/html" title="If you are having problems getting Ubuntu atd running"/><link href="https://www.simonholywell.com/post/2009/08/moving-to-git-and-setting-up-indefero-as-a-web-frontend/?utm_source=atom_feed" rel="related" type="text/html" title="Moving to git and setting up InDefero as a web frontend"/><link href="https://www.simonholywell.com/post/2009/05/handy-linux-commands/?utm_source=atom_feed" rel="related" type="text/html" title="Handy Linux Commands"/><link href="https://www.simonholywell.com/post/2009/04/samba-file-share-over-ssh-tunnel/?utm_source=atom_feed" rel="related" type="text/html" title="Samba File Share Over SSH Tunnel"/><link href="https://www.simonholywell.com/post/2009/04/memcached-and-apc-two-simple-techniques-to-speed-up-your/?utm_source=atom_feed" rel="related" type="text/html" title="Memcached and APC: Two Simple Techniques to Speed up your PHP Webpages"/><id>https://www.simonholywell.com/post/2010/08/linux-batch-remove-extension/</id><author><name>Simon Holywell</name></author><published>2010-08-24T16:44:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Batch remove extensions in Ubuntu
Sometimes you will want to batch remove extensions from a load of files:
for i in $(ls *.png); do mv $i ${i%.png}; done
If you want to remove extensions from files with a .txt extension then you would replace the two instances of .png in the script above with .txt.
You can take the extension off of all files using the following:
for i in $(ls *.</summary><content type="html"><![CDATA[<p><a href="http://ubuntuforums.org/showthread.php?t=728213">Batch remove extensions in Ubuntu</a></p>
<p>Sometimes you will want to batch remove extensions from a load of files:</p>
<blockquote>
<p>for i in $(ls *<strong>.png</strong>); do mv $i ${i%<strong>.png</strong>}; done</p>
</blockquote>
<p>If you want to remove extensions from files with a .txt extension then you would replace the two instances of .png in the script above with .txt.</p>
<p>You can take the extension off of all files using the following:</p>
<blockquote>
<p>for i in $(ls *.*); do mv $i ${i%.*}; done</p>
</blockquote>
<p>I also extended it by using it for a batch change of extensions rather than just removing the extension:</p>
<blockquote>
<p>for i in $(ls *.html); do mv $i ${i%.html}<strong>.htm</strong>; done</p>
</blockquote>
<p>Note the extra .htm after the curly braces in the above command.</p>
]]></content><category scheme="taxonomy:Tags" term="linux" label="linux"/><category scheme="taxonomy:Tags" term="ubuntu" label="ubuntu"/><category scheme="taxonomy:Tags" term="computing" label="computing"/></entry><entry xml:base="ubuntu-atd-not-running"><title type="html">If you are having problems getting Ubuntu atd running</title><link href="https://www.simonholywell.com/post/2010/08/ubuntu-atd-not-running/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2009/08/moving-to-git-and-setting-up-indefero-as-a-web-frontend/?utm_source=atom_feed" rel="related" type="text/html" title="Moving to git and setting up InDefero as a web frontend"/><link href="https://www.simonholywell.com/post/2009/05/handy-linux-commands/?utm_source=atom_feed" rel="related" type="text/html" title="Handy Linux Commands"/><link href="https://www.simonholywell.com/post/2009/04/samba-file-share-over-ssh-tunnel/?utm_source=atom_feed" rel="related" type="text/html" title="Samba File Share Over SSH Tunnel"/><link href="https://www.simonholywell.com/post/2009/04/memcached-and-apc-two-simple-techniques-to-speed-up-your/?utm_source=atom_feed" rel="related" type="text/html" title="Memcached and APC: Two Simple Techniques to Speed up your PHP Webpages"/><link href="https://www.simonholywell.com/post/2009/04/installing-apc-and-memcached-for-php-sessions-on-ubuntu/?utm_source=atom_feed" rel="related" type="text/html" title="Installing APC and Memcached for PHP Sessions on Ubuntu and Debi…"/><id>https://www.simonholywell.com/post/2010/08/ubuntu-atd-not-running/</id><author><name>Simon Holywell</name></author><published>2010-08-23T17:55:57+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>If you just cannot get atd to start running check the permissions on your /var/spool/cron/atjobs and /var/spool/cron/atspool directories. The should be `chmod 770` and then `chmod +t`. Also they should be owned by `daemon:daemon`.
I was getting this error when attempting to set new at jobs:
Can’t open /var/run/atd.pid to signal atd. No atd running?
If I tried to start the daemon through the service management I was getting:
sudo service atd start start: Job is already running: atd</summary><content type="html"><![CDATA[<p>If you just cannot get <a href="http://linux.die.net/man/8/atd">atd</a> to start running check the permissions on your /var/spool/cron/atjobs and /var/spool/cron/atspool directories. The should be `chmod 770` and then `chmod +t`. Also they should be owned by `daemon:daemon`.</p>
<p>I was getting this error when attempting to set new at jobs:</p>
<blockquote>
<p>Can’t open /var/run/atd.pid to signal atd. No atd running?</p>
</blockquote>
<p>If I tried to start the daemon through the service management I was getting:</p>
<blockquote>
<p>sudo service atd start start: Job is already running: atd</p>
</blockquote>
<p>But running `ps -elf | grep ‘atd’` yielded no appropriate results.</p>
<p>When trying to start the atd daemon manually on the command line I was getting:</p>
<blockquote>
<p><a href="mailto:simon@forge">simon@forge</a>:~$ sudo atd -d Cannot change to /var/spool/cron/atjobs: Permission denied</p>
</blockquote>
<p>Which finally gave me the clue!</p>
]]></content><category scheme="taxonomy:Tags" term="ubuntu" label="ubuntu"/><category scheme="taxonomy:Tags" term="linux" label="linux"/><category scheme="taxonomy:Tags" term="atd" label="atd"/><category scheme="taxonomy:Tags" term="at" label="at"/></entry><entry xml:base="get-gearman-to-install-on-ubuntu"><title type="html">Getting gearman to install on Ubuntu</title><link href="https://www.simonholywell.com/post/2010/08/get-gearman-to-install-on-ubuntu/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2010/08/drop-cap-php-regex/?utm_source=atom_feed" rel="related" type="text/html" title="Drop Cap with PHP Regular Expression"/><link href="https://www.simonholywell.com/post/2010/08/updated-tumblr-backup-php-now-disqus/?utm_source=atom_feed" rel="related" type="text/html" title="Updated: Back up Tumblr Blog and/or Disqus Comments"/><link href="https://www.simonholywell.com/post/2010/08/tumblr-backup-php/?utm_source=atom_feed" rel="related" type="text/html" title="Backing up Tumblr blogs with PHP and SQLite"/><link href="https://www.simonholywell.com/post/2010/04/agavi-on-the-auzre-platform/?utm_source=atom_feed" rel="related" type="text/html" title="Agavi: Agavi on the Azure Platform"/><link href="https://www.simonholywell.com/post/2010/08/john-resig-tech4africa2010/?utm_source=atom_feed" rel="related" type="text/html" title="In this video, John Resig presents his 6 Secrets to becoming a j…"/><id>https://www.simonholywell.com/post/2010/08/get-gearman-to-install-on-ubuntu/</id><author><name>Simon Holywell</name></author><published>2010-08-23T11:06:22+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Getting gearman to install on Ubuntu
Getting the gearman PHP PECL package to build on Ubuntu is problematic with many unaccounted for dependency issues.
I only made a couple changes when following the instructions from JSJoy as I am running Karmic rather than Lucid I changed the apt-get sources to:
deb http://ppa.launchpad.net/gearman-developers/ppa/ubuntu karmic main deb-src http://ppa.launchpad.net/gearman-developers/ppa/ubuntu karmic main
My sources file was also located at /etc/apt/sources.list and not /etc/sources.list as stated in the original post from JSJoy.</summary><content type="html"><![CDATA[<p><a href="http://jsjoy.com/blog/84/installing-gearman-on-ubuntu-10-4-lucid">Getting gearman to install on Ubuntu</a></p>
<p>Getting the <a href="http://pecl.php.net/package/gearman">gearman PHP PECL</a> package to build on Ubuntu is problematic with many unaccounted for dependency issues.</p>
<p>I only made a couple changes when following the <a href="http://jsjoy.com/blog/84/installing-gearman-on-ubuntu-10-4-lucid">instructions from JSJoy</a> as I am running Karmic rather than Lucid I changed the apt-get sources to:</p>
<blockquote>
<p>deb <a href="http://ppa.launchpad.net/gearman-developers/ppa/ubuntu">http://ppa.launchpad.net/gearman-developers/ppa/ubuntu</a> karmic main deb-src <a href="http://ppa.launchpad.net/gearman-developers/ppa/ubuntu">http://ppa.launchpad.net/gearman-developers/ppa/ubuntu</a> karmic main</p>
</blockquote>
<p>My sources file was also located at /etc/apt/sources.list and not /etc/sources.list as stated in the original post from JSJoy.</p>
]]></content><category scheme="taxonomy:Tags" term="gearman" label="gearman"/><category scheme="taxonomy:Tags" term="php" label="php"/><category scheme="taxonomy:Tags" term="internet" label="internet"/><category scheme="taxonomy:Tags" term="memcache" label="memcache"/><category scheme="taxonomy:Tags" term="computing" label="computing"/></entry><entry xml:base="john-resig-tech4africa2010"><title type="html">In this video, John Resig presents his 6 Secrets to becoming a j…</title><link href="https://www.simonholywell.com/post/2010/08/john-resig-tech4africa2010/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2010/08/firefox-radio-buttons/?utm_source=atom_feed" rel="related" type="text/html" title=""/><link href="https://www.simonholywell.com/post/2010/08/drop-cap-php-regex/?utm_source=atom_feed" rel="related" type="text/html" title="Drop Cap with PHP Regular Expression"/><link href="https://www.simonholywell.com/post/2010/08/updated-tumblr-backup-php-now-disqus/?utm_source=atom_feed" rel="related" type="text/html" title="Updated: Back up Tumblr Blog and/or Disqus Comments"/><link href="https://www.simonholywell.com/post/2010/08/tumblr-backup-php/?utm_source=atom_feed" rel="related" type="text/html" title="Backing up Tumblr blogs with PHP and SQLite"/><link href="https://www.simonholywell.com/post/2010/04/agavi-on-the-auzre-platform/?utm_source=atom_feed" rel="related" type="text/html" title="Agavi: Agavi on the Azure Platform"/><id>https://www.simonholywell.com/post/2010/08/john-resig-tech4africa2010/</id><author><name>Simon Holywell</name></author><published>2010-08-19T14:01:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary/><content type="html"></content><category scheme="taxonomy:Tags" term="jquery" label="jquery"/><category scheme="taxonomy:Tags" term="computing" label="computing"/><category scheme="taxonomy:Tags" term="internet" label="internet"/></entry><entry xml:base="wombert-the-worlds-best-countries"><title type="html">wombert: The World’s Best Countries</title><link href="https://www.simonholywell.com/post/2010/08/wombert-the-worlds-best-countries/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2010/08/new-lancia-stratos-by-pininfarina/?utm_source=atom_feed" rel="related" type="text/html" title="A nice modern take on the original Stratos by Pininfarina set to…"/><link href="https://www.simonholywell.com/post/2010/08/firefox-radio-buttons/?utm_source=atom_feed" rel="related" type="text/html" title=""/><link href="https://www.simonholywell.com/post/2010/08/drop-cap-php-regex/?utm_source=atom_feed" rel="related" type="text/html" title="Drop Cap with PHP Regular Expression"/><link href="https://www.simonholywell.com/post/2010/08/updated-tumblr-backup-php-now-disqus/?utm_source=atom_feed" rel="related" type="text/html" title="Updated: Back up Tumblr Blog and/or Disqus Comments"/><link href="https://www.simonholywell.com/post/2010/08/tumblr-backup-php/?utm_source=atom_feed" rel="related" type="text/html" title="Backing up Tumblr blogs with PHP and SQLite"/><id>https://www.simonholywell.com/post/2010/08/wombert-the-worlds-best-countries/</id><author><name>Simon Holywell</name></author><published>2010-08-18T10:01:17+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>wombert:
The World’s Best Countries</summary><content type="html"><![CDATA[<p><img src="/static/images/www.tumblr.com/photo/1280/holywell/971284310/1/tumblr_l7bfcrNHoa1qz6yfh.jpg" alt=""></p>
<p><a href="http://blog.wombert.de/post/968487947/the-worlds-best-countries">wombert</a>:</p>
<blockquote>
<p><a href="http://www.newsweek.com/feature/2010/the-world-s-best-countries.html">The World’s Best Countries</a></p>
</blockquote>
]]></content></entry><entry xml:base="new-lancia-stratos-by-pininfarina"><title type="html">A nice modern take on the original Stratos by Pininfarina set to…</title><link href="https://www.simonholywell.com/post/2010/08/new-lancia-stratos-by-pininfarina/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2010/06/adenauer-forst-70s-crash-compilation/?utm_source=atom_feed" rel="related" type="text/html" title="sharonov: 1970 Adenauer Forst crashes"/><link href="https://www.simonholywell.com/post/2010/06/sainte-beaume-hill-norma-m20-climb/?utm_source=atom_feed" rel="related" type="text/html" title="Gives an amazing sense of speed. missedapex: Norma M20 makes its…"/><link href="https://www.simonholywell.com/post/2010/05/pirelli-diablo-rosso-corsa/?utm_source=atom_feed" rel="related" type="text/html" title="Pirelli Diablo Rosso Corsa"/><link href="https://www.simonholywell.com/post/2010/05/healtech-gi-pro-gear-indicator/?utm_source=atom_feed" rel="related" type="text/html" title="My review of the HealTech GIpro w/ATRE motorcycle gear position …"/><link href="https://www.simonholywell.com/post/2010/04/driver-misses-wall-death-parking/?utm_source=atom_feed" rel="related" type="text/html" title="Seven stories up.  Whoops."/><id>https://www.simonholywell.com/post/2010/08/new-lancia-stratos-by-pininfarina/</id><author><name>Simon Holywell</name></author><published>2010-08-15T13:19:28+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>A nice modern take on the original Stratos by Pininfarina set to be sent into production. Thankfully they preserved original rear end lights and lip spoiler. Not so sure about the headlights.
hotvvheels:
Stratos</summary><content type="html"><![CDATA[<p><img src="/static/images/www.tumblr.com/photo/1280/holywell/957192799/1/tumblr_l74rw5uPZa1qzpsi6.jpg" alt=""></p>
<p>A nice modern take on the original Stratos by Pininfarina set to be sent into production. Thankfully they preserved original rear end lights and lip spoiler. Not so sure about the headlights.</p>
<p><a href="http://hotvvheels.tumblr.com/post/951351462/stratos">hotvvheels</a>:</p>
<blockquote>
<p><a href="http://jalopnik.com/5612430/the-new-lancia-stratos-says-hi">Stratos</a></p>
</blockquote>
]]></content><category scheme="taxonomy:Tags" term="motors" label="motors"/><category scheme="taxonomy:Tags" term="lancia" label="lancia"/><category scheme="taxonomy:Tags" term="stratos" label="stratos"/><category scheme="taxonomy:Tags" term="cars" label="Cars"/></entry><entry xml:base="firefox-radio-buttons"><title type="html"></title><link href="https://www.simonholywell.com/post/2010/08/firefox-radio-buttons/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2010/08/drop-cap-php-regex/?utm_source=atom_feed" rel="related" type="text/html" title="Drop Cap with PHP Regular Expression"/><link href="https://www.simonholywell.com/post/2010/08/updated-tumblr-backup-php-now-disqus/?utm_source=atom_feed" rel="related" type="text/html" title="Updated: Back up Tumblr Blog and/or Disqus Comments"/><link href="https://www.simonholywell.com/post/2010/08/tumblr-backup-php/?utm_source=atom_feed" rel="related" type="text/html" title="Backing up Tumblr blogs with PHP and SQLite"/><link href="https://www.simonholywell.com/post/2010/04/jquery-ui-datepicker-in-dialogue/?utm_source=atom_feed" rel="related" type="text/html" title="jQuery UI Datepicker appearing below Dialog"/><link href="https://www.simonholywell.com/post/2010/04/agavi-on-the-auzre-platform/?utm_source=atom_feed" rel="related" type="text/html" title="Agavi: Agavi on the Azure Platform"/><id>https://www.simonholywell.com/post/2010/08/firefox-radio-buttons/</id><author><name>Simon Holywell</name></author><published>2010-08-10T10:00:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Firefox with Radio Inputs and it’s Annoying Autocomplete
I recently had problem with Firefox’s autocomplete when using a jQuery star rating plugin. The linked article explains the problem more in depth and the code snippet below should get you going.
if ($.browser.mozilla) { $(&amp;#34;form&amp;#34;).attr(&amp;#34;autocomplete&amp;#34;, &amp;#34;off&amp;#34;); }</summary><content type="html"><![CDATA[<p><a href="http://www.ryancramer.com/journal/entries/radio_buttons_firefox/">Firefox with Radio Inputs and it’s Annoying Autocomplete</a></p>
<p>I recently had problem with Firefox’s autocomplete when using a jQuery star rating plugin. The linked article explains the problem more in depth and the code snippet below should get you going.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="k">if</span> <span class="p">(</span><span class="nx">$</span><span class="p">.</span><span class="nx">browser</span><span class="p">.</span><span class="nx">mozilla</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">$</span><span class="p">(</span><span class="s2">&#34;form&#34;</span><span class="p">).</span><span class="nx">attr</span><span class="p">(</span><span class="s2">&#34;autocomplete&#34;</span><span class="p">,</span> <span class="s2">&#34;off&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div>]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="jquery" label="jquery"/><category scheme="taxonomy:Tags" term="javascript" label="javascript"/><category scheme="taxonomy:Tags" term="firefox" label="firefox"/><category scheme="taxonomy:Tags" term="internet" label="internet"/><category scheme="taxonomy:Tags" term="computing" label="computing"/></entry><entry xml:base="drop-cap-php-regex"><title type="html">Drop Cap with PHP Regular Expression</title><link href="https://www.simonholywell.com/post/2010/08/drop-cap-php-regex/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2010/08/updated-tumblr-backup-php-now-disqus/?utm_source=atom_feed" rel="related" type="text/html" title="Updated: Back up Tumblr Blog and/or Disqus Comments"/><link href="https://www.simonholywell.com/post/2010/08/tumblr-backup-php/?utm_source=atom_feed" rel="related" type="text/html" title="Backing up Tumblr blogs with PHP and SQLite"/><link href="https://www.simonholywell.com/post/2010/04/agavi-on-the-auzre-platform/?utm_source=atom_feed" rel="related" type="text/html" title="Agavi: Agavi on the Azure Platform"/><link href="https://www.simonholywell.com/post/2010/03/plesk-custom-config-files/?utm_source=atom_feed" rel="related" type="text/html" title="Plesk and its custom configuration files"/><link href="https://www.simonholywell.com/post/2010/07/julian-assange-at-tedglobal-2010/?utm_source=atom_feed" rel="related" type="text/html" title="Julian Assange: Why the world needs WikiLeaks at TEDGlobal 2010"/><id>https://www.simonholywell.com/post/2010/08/drop-cap-php-regex/</id><author><name>Simon Holywell</name></author><published>2010-08-09T19:49:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>This is a simple regular expression I wrote to convert the first letter of an article into a drop cap. It will surround the first letter with a span tag containing the class drop-cap. You can then apply any styling you like to the span with CSS. It will skip over any HTML encoded characters or tags at the beginning of the article as well so it always highlights the first letter of the content and not any HTML formatting.</summary><content type="html"><![CDATA[<p>This is a simple regular expression I wrote to convert the first letter of an article into a drop cap. It will surround the first letter with a <strong>span</strong> tag containing the class <strong>drop-cap</strong>. You can then apply any styling you like to the span with CSS. It will skip over any HTML encoded characters or tags at the beginning of the article as well so it always highlights the first letter of the content and not any HTML formatting.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o">&lt;?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl"><span class="nv">$article</span><span class="p">[</span><span class="s1">&#39;full_text&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="nx">preg_replace</span><span class="p">(</span><span class="s1">&#39;/^([\&lt;\sa-z\d\/\&gt;]*)(([a-z\&amp;\;]+)|([\&#34;\&#39;\w]))/&#39;</span><span class="p">,</span> <span class="s1">&#39;$1&lt;span class=&#34;drop-cap&#34;&gt;$2&lt;/span&gt;&#39;</span><span class="p">,</span> <span class="nv">$article</span><span class="p">[</span><span class="s1">&#39;full_text&#39;</span><span class="p">]);</span>
</span></span></code></pre></div>]]></content><category scheme="taxonomy:Tags" term="php" label="php"/><category scheme="taxonomy:Tags" term="regex" label="regex"/><category scheme="taxonomy:Tags" term="computing" label="computing"/><category scheme="taxonomy:Tags" term="internet" label="internet"/></entry><entry xml:base="updated-tumblr-backup-php-now-disqus"><title type="html">Updated: Back up Tumblr Blog and/or Disqus Comments</title><link href="https://www.simonholywell.com/post/2010/08/updated-tumblr-backup-php-now-disqus/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2010/08/tumblr-backup-php/?utm_source=atom_feed" rel="related" type="text/html" title="Backing up Tumblr blogs with PHP and SQLite"/><link href="https://www.simonholywell.com/post/2010/04/agavi-on-the-auzre-platform/?utm_source=atom_feed" rel="related" type="text/html" title="Agavi: Agavi on the Azure Platform"/><link href="https://www.simonholywell.com/post/2010/03/plesk-custom-config-files/?utm_source=atom_feed" rel="related" type="text/html" title="Plesk and its custom configuration files"/><link href="https://www.simonholywell.com/post/2010/07/julian-assange-at-tedglobal-2010/?utm_source=atom_feed" rel="related" type="text/html" title="Julian Assange: Why the world needs WikiLeaks at TEDGlobal 2010"/><link href="https://www.simonholywell.com/post/2010/06/adenauer-forst-70s-crash-compilation/?utm_source=atom_feed" rel="related" type="text/html" title="sharonov: 1970 Adenauer Forst crashes"/><id>https://www.simonholywell.com/post/2010/08/updated-tumblr-backup-php-now-disqus/</id><author><name>Simon Holywell</name></author><published>2010-08-09T01:37:23+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Updated: Back up Tumblr Blog and/or Disqus Comments
A simple and somewhat dirty script for backing up Tumblr and/or Disqus via its API to an SQLite DB. It now handles backing up Disqus comments to SQLite as well.</summary><content type="html"><![CDATA[<p><a href="http://github.com/treffynnon/Tumblr-Backup-PHP">Updated: Back up Tumblr Blog and/or Disqus Comments</a></p>
<p>A simple and somewhat dirty <a href="http://github.com/treffynnon/Tumblr-Backup-PHP">script for backing up</a> Tumblr and/or Disqus via its API to an SQLite DB. It <strong>now</strong> handles backing up Disqus comments to SQLite as well.</p>
]]></content><category scheme="taxonomy:Tags" term="disqus" label="disqus"/><category scheme="taxonomy:Tags" term="tumblr" label="tumblr"/><category scheme="taxonomy:Tags" term="api" label="api"/><category scheme="taxonomy:Tags" term="computing" label="computing"/><category scheme="taxonomy:Tags" term="internet" label="internet"/><category scheme="taxonomy:Tags" term="sql" label="SQL"/><category scheme="taxonomy:Tags" term="php" label="php"/><category scheme="taxonomy:Tags" term="backup" label="backup"/></entry><entry xml:base="tumblr-backup-php"><title type="html">Backing up Tumblr blogs with PHP and SQLite</title><link href="https://www.simonholywell.com/post/2010/08/tumblr-backup-php/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2010/04/agavi-on-the-auzre-platform/?utm_source=atom_feed" rel="related" type="text/html" title="Agavi: Agavi on the Azure Platform"/><link href="https://www.simonholywell.com/post/2010/03/plesk-custom-config-files/?utm_source=atom_feed" rel="related" type="text/html" title="Plesk and its custom configuration files"/><link href="https://www.simonholywell.com/post/2010/07/julian-assange-at-tedglobal-2010/?utm_source=atom_feed" rel="related" type="text/html" title="Julian Assange: Why the world needs WikiLeaks at TEDGlobal 2010"/><link href="https://www.simonholywell.com/post/2010/06/adenauer-forst-70s-crash-compilation/?utm_source=atom_feed" rel="related" type="text/html" title="sharonov: 1970 Adenauer Forst crashes"/><link href="https://www.simonholywell.com/post/2010/06/electricity-meter/?utm_source=atom_feed" rel="related" type="text/html" title="How to make something impossible for someone to use without a ma…"/><id>https://www.simonholywell.com/post/2010/08/tumblr-backup-php/</id><author><name>Simon Holywell</name></author><published>2010-08-08T20:14:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Backing up Tumblr blogs with PHP and SQLite
I have knocked together a very simple and somewhat dirty PHP CLI script to download copies of an entire Tumblr blog through their API. I have imaginatively called it Tumblr Backup PHP. I will be adding extra features as and when I can. The first new feature on the list will be ability backup the associated Disqus comments at the same time.</summary><content type="html"><![CDATA[<p><a href="http://github.com/treffynnon/Tumblr-Backup-PHP">Backing up Tumblr blogs with PHP and SQLite</a></p>
<p>I have knocked together a very simple and somewhat dirty PHP CLI script to download copies of an entire Tumblr blog through their <a href="http://www.tumblr.com/docs/en/api">API</a>. I have imaginatively called it <a href="http://github.com/treffynnon/Tumblr-Backup-PHP">Tumblr Backup PHP</a>. I will be adding extra features as and when I can. The first new feature on the list will be ability backup the associated Disqus comments at the same time.</p>
<p>This script was developed on Windows so you will need to update the PHP binary location in the top of the <a href="http://github.com/treffynnon/Tumblr-Backup-PHP/blob/master/run.php">run.php</a> file. More installation information is available in the <a href="http://github.com/treffynnon/Tumblr-Backup-PHP/blob/master/README.markdown">readme file</a> on GitHub.</p>
<p>Essentially the script uses <a href="http://code.google.com/p/php-rest-api/">php-rest-api</a> by Jason Tan to download all your blog posts in 50 post chunks from the <a href="http://www.tumblr.com/docs/en/api">Tumblr API</a> and <a href="http://github.com/j4mie/idiorm">Idiorm</a> by <a href="http://www.j4mie.org/">Jamie Matthews</a> to then save all the posts into an SQLite database.</p>
<p>All you need to do is update the configuration file with your blogs details and then execute run.php in your console/command prompt. You will need SQLite, cURL and PHP5 to run the script. You do <strong>not</strong> need a web server you can just install PHP on your machine and run the script from the command line just like you would with a Python or Ruby script.</p>
<p>There is currently no allowances for time outs when accessing the API and there is also no restore script at the moment.</p>
]]></content><category scheme="taxonomy:Tags" term="sql" label="SQL"/><category scheme="taxonomy:Tags" term="api" label="api"/><category scheme="taxonomy:Tags" term="computing" label="computing"/><category scheme="taxonomy:Tags" term="internet" label="internet"/><category scheme="taxonomy:Tags" term="php" label="php"/><category scheme="taxonomy:Tags" term="tumblr" label="tumblr"/><category scheme="taxonomy:Tags" term="backup" label="backup"/></entry><entry xml:base="julian-assange-at-tedglobal-2010"><title type="html">Julian Assange: Why the world needs WikiLeaks at TEDGlobal 2010</title><link href="https://www.simonholywell.com/post/2010/07/julian-assange-at-tedglobal-2010/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2010/06/adenauer-forst-70s-crash-compilation/?utm_source=atom_feed" rel="related" type="text/html" title="sharonov: 1970 Adenauer Forst crashes"/><link href="https://www.simonholywell.com/post/2010/06/electricity-meter/?utm_source=atom_feed" rel="related" type="text/html" title="How to make something impossible for someone to use without a ma…"/><link href="https://www.simonholywell.com/post/2010/06/sainte-beaume-hill-norma-m20-climb/?utm_source=atom_feed" rel="related" type="text/html" title="Gives an amazing sense of speed. missedapex: Norma M20 makes its…"/><link href="https://www.simonholywell.com/post/2010/05/spiriteddrive-stratos-delta-jameslipman/?utm_source=atom_feed" rel="related" type="text/html" title="spiriteddrive: Stratos / Delta (jameslipman)"/><link href="https://www.simonholywell.com/post/2010/05/pirelli-diablo-rosso-corsa/?utm_source=atom_feed" rel="related" type="text/html" title="Pirelli Diablo Rosso Corsa"/><id>https://www.simonholywell.com/post/2010/07/julian-assange-at-tedglobal-2010/</id><author><name>Simon Holywell</name></author><published>2010-07-20T14:46:50+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary/><content type="html"></content></entry><entry xml:base="adenauer-forst-70s-crash-compilation"><title type="html">sharonov: 1970 Adenauer Forst crashes</title><link href="https://www.simonholywell.com/post/2010/06/adenauer-forst-70s-crash-compilation/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2010/06/sainte-beaume-hill-norma-m20-climb/?utm_source=atom_feed" rel="related" type="text/html" title="Gives an amazing sense of speed. missedapex: Norma M20 makes its…"/><link href="https://www.simonholywell.com/post/2010/05/pirelli-diablo-rosso-corsa/?utm_source=atom_feed" rel="related" type="text/html" title="Pirelli Diablo Rosso Corsa"/><link href="https://www.simonholywell.com/post/2010/05/healtech-gi-pro-gear-indicator/?utm_source=atom_feed" rel="related" type="text/html" title="My review of the HealTech GIpro w/ATRE motorcycle gear position …"/><link href="https://www.simonholywell.com/post/2010/04/driver-misses-wall-death-parking/?utm_source=atom_feed" rel="related" type="text/html" title="Seven stories up.  Whoops."/><link href="https://www.simonholywell.com/post/2009/11/lancia-stratos-replica-fast-lap-on-top-gear-uk/?utm_source=atom_feed" rel="related" type="text/html" title="Lancia Stratos Replica Fast Lap on Top Gear UK"/><id>https://www.simonholywell.com/post/2010/06/adenauer-forst-70s-crash-compilation/</id><author><name>Simon Holywell</name></author><published>2010-06-28T13:07:58+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>http://www.youtube.com/watch?v=0xwc54G2Ur8</summary><content type="html">&lt;p>&lt;a href="http://www.youtube.com/watch?v=0xwc54G2Ur8">http://www.youtube.com/watch?v=0xwc54G2Ur8&lt;/a>&lt;/p></content><category scheme="taxonomy:Tags" term="motors" label="motors"/><category scheme="taxonomy:Tags" term="cars" label="Cars"/><category scheme="taxonomy:Tags" term="bikes" label="bikes"/></entry><entry xml:base="electricity-meter"><title type="html">How to make something impossible for someone to use without a ma…</title><link href="https://www.simonholywell.com/post/2010/06/electricity-meter/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2010/06/sainte-beaume-hill-norma-m20-climb/?utm_source=atom_feed" rel="related" type="text/html" title="Gives an amazing sense of speed. missedapex: Norma M20 makes its…"/><link href="https://www.simonholywell.com/post/2010/05/spiriteddrive-stratos-delta-jameslipman/?utm_source=atom_feed" rel="related" type="text/html" title="spiriteddrive: Stratos / Delta (jameslipman)"/><link href="https://www.simonholywell.com/post/2010/05/pirelli-diablo-rosso-corsa/?utm_source=atom_feed" rel="related" type="text/html" title="Pirelli Diablo Rosso Corsa"/><link href="https://www.simonholywell.com/post/2010/05/healtech-gi-pro-gear-indicator/?utm_source=atom_feed" rel="related" type="text/html" title="My review of the HealTech GIpro w/ATRE motorcycle gear position …"/><link href="https://www.simonholywell.com/post/2010/04/driver-misses-wall-death-parking/?utm_source=atom_feed" rel="related" type="text/html" title="Seven stories up.  Whoops."/><id>https://www.simonholywell.com/post/2010/06/electricity-meter/</id><author><name>Simon Holywell</name></author><published>2010-06-11T13:37:48+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>How to make something impossible for someone to use without a manual.
Have dials that rotate clockwise and anti-clockwise Put the final unit (1kWh) before all the other units just to confuse the hell out of ’em Make your instructions inaccurate (see below) Here is how you are actually supposed to read this horrendous piece of design (or not-designed as the case maybe):
Dial meter Your dial meter comprises of six dials.</summary><content type="html"><![CDATA[<p><img src="/static/images/www.tumblr.com/photo/1280/holywell/686899709/1/tumblr_l3uof0szUE1qb2lct.jpg" alt=""></p>
<p>How to make something impossible for someone to use without a manual.</p>
<ol>
<li>Have dials that rotate clockwise and anti-clockwise</li>
<li>Put the final unit (1kWh) before all the other units just to confuse the hell out of ’em</li>
<li>Make your instructions inaccurate (see below)</li>
</ol>
<p>Here is how you are actually supposed to read this horrendous piece of design (or not-designed as the case maybe):</p>
<blockquote>
<p><strong>Dial meter</strong>  Your dial meter comprises of six dials. These read from left to right. <strong>[Not in my case as you can see from the pic above]</strong></p>
<p>You only need to read the first five dials - starting with the 10,000kWh dial on the left and stopping after the 1 kWh dial. Don’t read the last dial on the right – it is for testing purposes only. Remember that the dials move in opposite directions, as shown by the red arrows in the picture below.</p>
<p><strong>Reading a dial meter</strong>  If the pointer falls between two numbers, always read the lower number – in Fig A you would write down the number 4. If the pointer is directly over a number always record it – in Fig B you would write down the number 5. If the pointer on a dial falls between 9 and 0, reduce the reading already taken for the dial on the left by one – for example, if your original recorded 5, reduce this to 4.</p>
<p>Following these instructions, the correct meter reading for the dial in the diagram will be 44928.</p>
<p><img src="/static/images/2011-06-11_elec_meter_dial1.jpg" alt="How to read this crap"></p>
</blockquote>
<p>Source: <a href="http://www.edfenergy.com/products-services/for-your-home/my-account/how-to-read-your-electricity-meter.shtml"><a href="http://www.edfenergy.com/products-services/for-your-home/my-account/how-to-read-your-electricity-meter.shtml">http://www.edfenergy.com/products-services/for-your-home/my-account/how-to-read-your-electricity-meter.shtml</a></a></p>
]]></content></entry><entry xml:base="sainte-beaume-hill-norma-m20-climb"><title type="html">Gives an amazing sense of speed. missedapex: Norma M20 makes its…</title><link href="https://www.simonholywell.com/post/2010/06/sainte-beaume-hill-norma-m20-climb/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2010/05/pirelli-diablo-rosso-corsa/?utm_source=atom_feed" rel="related" type="text/html" title="Pirelli Diablo Rosso Corsa"/><link href="https://www.simonholywell.com/post/2010/05/healtech-gi-pro-gear-indicator/?utm_source=atom_feed" rel="related" type="text/html" title="My review of the HealTech GIpro w/ATRE motorcycle gear position …"/><link href="https://www.simonholywell.com/post/2010/04/driver-misses-wall-death-parking/?utm_source=atom_feed" rel="related" type="text/html" title="Seven stories up.  Whoops."/><link href="https://www.simonholywell.com/post/2009/11/lancia-stratos-replica-fast-lap-on-top-gear-uk/?utm_source=atom_feed" rel="related" type="text/html" title="Lancia Stratos Replica Fast Lap on Top Gear UK"/><link href="https://www.simonholywell.com/post/2008/12/carver-carver-one/?utm_source=atom_feed" rel="related" type="text/html" title="Carver Carver One"/><id>https://www.simonholywell.com/post/2010/06/sainte-beaume-hill-norma-m20-climb/</id><author><name>Simon Holywell</name></author><published>2010-06-10T13:18:34+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary/><content type="html"></content><category scheme="taxonomy:Tags" term="motors" label="motors"/><category scheme="taxonomy:Tags" term="cars" label="Cars"/></entry><entry xml:base="spiriteddrive-stratos-delta-jameslipman"><title type="html">spiriteddrive: Stratos / Delta (jameslipman)</title><link href="https://www.simonholywell.com/post/2010/05/spiriteddrive-stratos-delta-jameslipman/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2010/05/pirelli-diablo-rosso-corsa/?utm_source=atom_feed" rel="related" type="text/html" title="Pirelli Diablo Rosso Corsa"/><link href="https://www.simonholywell.com/post/2010/05/healtech-gi-pro-gear-indicator/?utm_source=atom_feed" rel="related" type="text/html" title="My review of the HealTech GIpro w/ATRE motorcycle gear position …"/><link href="https://www.simonholywell.com/post/2010/04/driver-misses-wall-death-parking/?utm_source=atom_feed" rel="related" type="text/html" title="Seven stories up.  Whoops."/><link href="https://www.simonholywell.com/post/2010/04/jquery-ui-datepicker-in-dialogue/?utm_source=atom_feed" rel="related" type="text/html" title="jQuery UI Datepicker appearing below Dialog"/><link href="https://www.simonholywell.com/post/2010/04/agavi-on-the-auzre-platform/?utm_source=atom_feed" rel="related" type="text/html" title="Agavi: Agavi on the Azure Platform"/><id>https://www.simonholywell.com/post/2010/05/spiriteddrive-stratos-delta-jameslipman/</id><author><name>Simon Holywell</name></author><published>2010-05-26T14:20:51+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>spiriteddrive:
Stratos / Delta (jameslipman)</summary><content type="html"><![CDATA[<p><img src="/static/images/www.tumblr.com/photo/1280/holywell/634424974/1/tumblr_l2euvnJhj71qa9ygk.jpg" alt=""></p>
<p><a href="http://spiriteddrive.tumblr.com/post/598061715/stratos-delta-jameslipman">spiriteddrive</a>:</p>
<blockquote>
<p>Stratos / Delta (<a href="http://www.jameslipman">jameslipman</a>)</p>
</blockquote>
]]></content></entry><entry xml:base="pirelli-diablo-rosso-corsa"><title type="html">Pirelli Diablo Rosso Corsa</title><link href="https://www.simonholywell.com/post/2010/05/pirelli-diablo-rosso-corsa/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2010/05/healtech-gi-pro-gear-indicator/?utm_source=atom_feed" rel="related" type="text/html" title="My review of the HealTech GIpro w/ATRE motorcycle gear position …"/><link href="https://www.simonholywell.com/post/2010/04/driver-misses-wall-death-parking/?utm_source=atom_feed" rel="related" type="text/html" title="Seven stories up.  Whoops."/><link href="https://www.simonholywell.com/post/2010/04/jquery-ui-datepicker-in-dialogue/?utm_source=atom_feed" rel="related" type="text/html" title="jQuery UI Datepicker appearing below Dialog"/><link href="https://www.simonholywell.com/post/2010/04/agavi-on-the-auzre-platform/?utm_source=atom_feed" rel="related" type="text/html" title="Agavi: Agavi on the Azure Platform"/><link href="https://www.simonholywell.com/post/2010/03/plesk-custom-config-files/?utm_source=atom_feed" rel="related" type="text/html" title="Plesk and its custom configuration files"/><id>https://www.simonholywell.com/post/2010/05/pirelli-diablo-rosso-corsa/</id><author><name>Simon Holywell</name></author><published>2010-05-26T14:11:33+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Pirelli Diablo Rosso Corsa
Taking wank factor to a whole new level you can customise your new Diablo Rosso Corsa tyres with special stickers bought through the Pirelli website.</summary><content type="html"><![CDATA[<p><a href="http://www.pirelli.co.uk/web/motorcycle/tyres/diablo_rosso_corsa/my_diablo/default.page">Pirelli Diablo Rosso Corsa</a></p>
<p>Taking wank factor to a whole new level you can customise your new Diablo Rosso Corsa tyres with special stickers bought through the Pirelli website.</p>
]]></content><category scheme="taxonomy:Tags" term="motors" label="motors"/><category scheme="taxonomy:Tags" term="bikes" label="bikes"/></entry><entry xml:base="healtech-gi-pro-gear-indicator"><title type="html">My review of the HealTech GIpro w/ATRE motorcycle gear position …</title><link href="https://www.simonholywell.com/post/2010/05/healtech-gi-pro-gear-indicator/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2010/04/driver-misses-wall-death-parking/?utm_source=atom_feed" rel="related" type="text/html" title="Seven stories up.  Whoops."/><link href="https://www.simonholywell.com/post/2008/12/twitter-jaiku-rejaw-and-tumblr/?utm_source=atom_feed" rel="related" type="text/html" title="Twitter, Jaiku, Rejaw and Tumblr"/><link href="https://www.simonholywell.com/post/2010/04/jquery-ui-datepicker-in-dialogue/?utm_source=atom_feed" rel="related" type="text/html" title="jQuery UI Datepicker appearing below Dialog"/><link href="https://www.simonholywell.com/post/2010/04/agavi-on-the-auzre-platform/?utm_source=atom_feed" rel="related" type="text/html" title="Agavi: Agavi on the Azure Platform"/><link href="https://www.simonholywell.com/post/2010/03/plesk-custom-config-files/?utm_source=atom_feed" rel="related" type="text/html" title="Plesk and its custom configuration files"/><id>https://www.simonholywell.com/post/2010/05/healtech-gi-pro-gear-indicator/</id><author><name>Simon Holywell</name></author><published>2010-05-21T10:59:32+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>My review of the HealTech GIpro w/ATRE motorcycle gear position indicator on webBikeWorld
I recently wrote a review of the GIpro and it has now been published by webBikeWorld. Follow the link and check it out!</summary><content type="html"><![CDATA[<p><a href="http://bit.ly/gipro-review">My review of the HealTech GIpro w/ATRE motorcycle gear position indicator on webBikeWorld</a></p>
<p>I recently wrote a review of the GIpro and it has now been published by webBikeWorld. Follow the link and check it out!</p>
]]></content><category scheme="taxonomy:Tags" term="motors" label="motors"/><category scheme="taxonomy:Tags" term="bikes" label="bikes"/><category scheme="taxonomy:Tags" term="reviews" label="reviews"/></entry><entry xml:base="driver-misses-wall-death-parking"><title type="html">Seven stories up.  Whoops.</title><link href="https://www.simonholywell.com/post/2010/04/driver-misses-wall-death-parking/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2010/04/jquery-ui-datepicker-in-dialogue/?utm_source=atom_feed" rel="related" type="text/html" title="jQuery UI Datepicker appearing below Dialog"/><link href="https://www.simonholywell.com/post/2010/04/agavi-on-the-auzre-platform/?utm_source=atom_feed" rel="related" type="text/html" title="Agavi: Agavi on the Azure Platform"/><link href="https://www.simonholywell.com/post/2010/03/plesk-custom-config-files/?utm_source=atom_feed" rel="related" type="text/html" title="Plesk and its custom configuration files"/><link href="https://www.simonholywell.com/post/2010/02/the-little-manual-of-api-design/?utm_source=atom_feed" rel="related" type="text/html" title="The Little Manual of API Design"/><link href="https://www.simonholywell.com/post/2010/02/sun-oracle-deal-closed/?utm_source=atom_feed" rel="related" type="text/html" title="Sun + Oracle Deal Closed"/><id>https://www.simonholywell.com/post/2010/04/driver-misses-wall-death-parking/</id><author><name>Simon Holywell</name></author><published>2010-04-30T14:51:59+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Seven stories up. Whoops.</summary><content type="html"><![CDATA[<p><img src="/static/images/www.tumblr.com/photo/1280/holywell/560922545/1/tumblr_l1ozunlL1M1qb2lct.jpg" alt=""></p>
<p>Seven stories up.  Whoops.</p>
]]></content><category scheme="taxonomy:Tags" term="motors" label="motors"/><category scheme="taxonomy:Tags" term="cars" label="cars"/></entry><entry xml:base="jquery-ui-datepicker-in-dialogue"><title type="html">jQuery UI Datepicker appearing below Dialog</title><link href="https://www.simonholywell.com/post/2010/04/jquery-ui-datepicker-in-dialogue/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2010/04/agavi-on-the-auzre-platform/?utm_source=atom_feed" rel="related" type="text/html" title="Agavi: Agavi on the Azure Platform"/><link href="https://www.simonholywell.com/post/2010/03/plesk-custom-config-files/?utm_source=atom_feed" rel="related" type="text/html" title="Plesk and its custom configuration files"/><link href="https://www.simonholywell.com/post/2010/02/the-little-manual-of-api-design/?utm_source=atom_feed" rel="related" type="text/html" title="The Little Manual of API Design"/><link href="https://www.simonholywell.com/post/2010/02/sun-oracle-deal-closed/?utm_source=atom_feed" rel="related" type="text/html" title="Sun + Oracle Deal Closed"/><link href="https://www.simonholywell.com/post/2009/11/lancia-stratos-replica-fast-lap-on-top-gear-uk/?utm_source=atom_feed" rel="related" type="text/html" title="Lancia Stratos Replica Fast Lap on Top Gear UK"/><id>https://www.simonholywell.com/post/2010/04/jquery-ui-datepicker-in-dialogue/</id><author><name>Simon Holywell</name></author><published>2010-04-15T15:43:29+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>When creating a dialogue with jQuery that contains a Datepicker text input the Datepicker calendar will appear below the dialogue due to the dialogue’s z-index being higher. The easiest universal way to work around this is to include a one liner in the open event function of the initial dialogue call.
$(&amp;#34;#dialogue&amp;#34;).dialog({ modal: true, open: function () { $(&amp;#34;#ui-datepicker-div&amp;#34;).css( &amp;#34;z-index&amp;#34;, $(this).parents(&amp;#34;.ui-dialog&amp;#34;).css(&amp;#34;z-index&amp;#34;) + 1, ); }, });</summary><content type="html"><![CDATA[<p>When creating a dialogue with jQuery that contains a Datepicker text input the Datepicker calendar will appear below the dialogue due to the dialogue’s z-index being higher.  The easiest universal way to work around this is to include a one liner in the <strong>open</strong> event function of the initial dialogue call.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="nx">$</span><span class="p">(</span><span class="s2">&#34;#dialogue&#34;</span><span class="p">).</span><span class="nx">dialog</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">  <span class="nx">modal</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">open</span><span class="o">:</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">$</span><span class="p">(</span><span class="s2">&#34;#ui-datepicker-div&#34;</span><span class="p">).</span><span class="nx">css</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">      <span class="s2">&#34;z-index&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nx">$</span><span class="p">(</span><span class="k">this</span><span class="p">).</span><span class="nx">parents</span><span class="p">(</span><span class="s2">&#34;.ui-dialog&#34;</span><span class="p">).</span><span class="nx">css</span><span class="p">(</span><span class="s2">&#34;z-index&#34;</span><span class="p">)</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div>]]></content><category scheme="taxonomy:Tags" term="jquery" label="jquery"/><category scheme="taxonomy:Tags" term="javascript" label="javascript"/></entry><entry xml:base="agavi-on-the-auzre-platform"><title type="html">Agavi: Agavi on the Azure Platform</title><link href="https://www.simonholywell.com/post/2010/04/agavi-on-the-auzre-platform/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2010/03/plesk-custom-config-files/?utm_source=atom_feed" rel="related" type="text/html" title="Plesk and its custom configuration files"/><link href="https://www.simonholywell.com/post/2009/11/agavi-form-population-filter/?utm_source=atom_feed" rel="related" type="text/html" title="Agavi Form Population Filter"/><link href="https://www.simonholywell.com/post/2009/11/agavi-php-framework-resources/?utm_source=atom_feed" rel="related" type="text/html" title="Agavi PHP Framework Resources"/><link href="https://www.simonholywell.com/post/2009/04/samba-file-share-over-ssh-tunnel/?utm_source=atom_feed" rel="related" type="text/html" title="Samba File Share Over SSH Tunnel"/><link href="https://www.simonholywell.com/post/2009/03/using-phing-for-good-unfuddle-add-repository-and-svn-imp/?utm_source=atom_feed" rel="related" type="text/html" title="Using phing for good - Unfuddle Add Repository and SVN Import Ta…"/><id>https://www.simonholywell.com/post/2010/04/agavi-on-the-auzre-platform/</id><author><name>Simon Holywell</name></author><published>2010-04-14T09:50:16+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Agavi: Agavi on the Azure Platform
The next release of Agavi will have initial support for running applications on the Microsoft Windows Azure platform, as well as a database adapter for the new ext/sqlsrv driver to communicate with Microsoft SQL Server and support for the IIS7 web server, which now finally has a very nice …</summary><content type="html"><![CDATA[<p><a href="http://blog.agavi.org/post/518901216/agavi-on-the-azure-platform">Agavi: Agavi on the Azure Platform</a></p>
<blockquote>
<p>The next release of Agavi will have initial support for running applications on the Microsoft <a href="http://www.microsoft.com/windowsazure/">Windows Azure</a> platform, as well as a database adapter for the new <a href="http://sqlsrvphp.codeplex.com/">ext/sqlsrv</a> driver to communicate with Microsoft SQL Server and support for the IIS7 web server, which now finally has a very nice <a href="http://www.iis.net/download/urlrewrite">…</a></p>
</blockquote>
]]></content><category scheme="taxonomy:Tags" term="agavi" label="agavi"/><category scheme="taxonomy:Tags" term="php" label="php"/><category scheme="taxonomy:Tags" term="azure" label="azure"/><category scheme="taxonomy:Tags" term="ms" label="ms"/><category scheme="taxonomy:Tags" term="windows" label="windows"/><category scheme="taxonomy:Tags" term="computing" label="computing"/><category scheme="taxonomy:Tags" term="internet" label="internet"/></entry><entry xml:base="plesk-custom-config-files"><title type="html">Plesk and its custom configuration files</title><link href="https://www.simonholywell.com/post/2010/03/plesk-custom-config-files/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2010/02/the-little-manual-of-api-design/?utm_source=atom_feed" rel="related" type="text/html" title="The Little Manual of API Design"/><link href="https://www.simonholywell.com/post/2010/02/sun-oracle-deal-closed/?utm_source=atom_feed" rel="related" type="text/html" title="Sun + Oracle Deal Closed"/><link href="https://www.simonholywell.com/post/2009/11/lancia-stratos-replica-fast-lap-on-top-gear-uk/?utm_source=atom_feed" rel="related" type="text/html" title="Lancia Stratos Replica Fast Lap on Top Gear UK"/><link href="https://www.simonholywell.com/post/2009/11/agavi-form-population-filter/?utm_source=atom_feed" rel="related" type="text/html" title="Agavi Form Population Filter"/><link href="https://www.simonholywell.com/post/2009/11/netbeans-and-xdebug/?utm_source=atom_feed" rel="related" type="text/html" title="Netbeans and Remote XDebug"/><id>https://www.simonholywell.com/post/2010/03/plesk-custom-config-files/</id><author><name>Simon Holywell</name></author><published>2010-03-19T11:04:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Plesk allows you to control settings for each domains virtual host container (subdomains are also configured in the same way).
To override the default configuration you will need to make the new vhost file, which should appear in the following locations:
domain/conf/vhost.conf domain/subdomain/conf/vhost.conf The vhost.conf file must not contain the entire vhost container but only its contents. So this means that you cannot make changes to the IP address or port the virtual host container is listening on in this file, but you can override the PHP open_basedir setting and other directory settings.</summary><content type="html"><![CDATA[<p>Plesk allows you to control settings for each domains virtual host container (subdomains are also configured in the same way).</p>
<p>To override the default configuration you will need to make the new vhost file, which should appear in the following locations:</p>
<ul>
<li>domain/conf/vhost.conf</li>
<li>domain/subdomain/conf/vhost.conf</li>
</ul>
<p>The vhost.conf file must not contain the entire vhost container but only its contents.  So this means that you cannot make changes to the IP address or port the virtual host container is listening on in this file, but you can override the PHP open_basedir setting and other directory settings.  You could even put ReWrite rules in here like you would in your .htaccess.  Anything that goes in a vhost container for Apache can go in here.</p>
<p>To turn off open_basedir for example set:</p>
<blockquote>
<p><code>php_admin_value open_basedir none</code></p>
</blockquote>
<p>Once you have made the overrides and additions you need to tell Plesk about the changes using one of the following commands.</p>
<p>Use <code>/usr/local/psa/admin/sbin/websrvmng --vhost-name=domain.com</code> to update a particular domain or <code>/usr/local/psa/admin/sbin/websrvmng --vhost-name=subdomain.domain.com</code> to change a particular subdomain.</p>
<p><strong>Update (15/03/2012):</strong> In Plesk version 10+ you would use <code>/usr/local/psa/admin/sbin/httpdmng --reconfigure-domain domain.com</code></p>
<p>Should you need to update all the sites at once then you can execute the following command <code>/usr/local/psa/admin/bin/websrvmng -a</code> Be warned though that this will update all settings files and wipe anything you may have changed in /domain/conf/httpd.include.</p>
<p>Once you have executed the above commands the settings will be effective immediately with no need for restarting the Apache process.</p>
]]></content><category scheme="taxonomy:Tags" term="plesk" label="plesk"/><category scheme="taxonomy:Tags" term="internet" label="internet"/><category scheme="taxonomy:Tags" term="apache" label="Apache"/></entry><entry xml:base="the-little-manual-of-api-design"><title type="html">The Little Manual of API Design</title><link href="https://www.simonholywell.com/post/2010/02/the-little-manual-of-api-design/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2008/04/sql-server-2005-dump-to-sql-statements/?utm_source=atom_feed" rel="related" type="text/html" title="SQL Server 2005 Dump to SQL statements"/><link href="https://www.simonholywell.com/post/2007/08/iso-3166-country-list/?utm_source=atom_feed" rel="related" type="text/html" title="ISO 3166 Country List"/><link href="https://www.simonholywell.com/post/2006/12/geographic-calculations-in-php/?utm_source=atom_feed" rel="related" type="text/html" title="Geographic Calculations in PHP"/><link href="https://www.simonholywell.com/post/2006/03/flickering-images/?utm_source=atom_feed" rel="related" type="text/html" title="Flickering Images"/><link href="https://www.simonholywell.com/post/2005/12/adodb/?utm_source=atom_feed" rel="related" type="text/html" title="ADODB"/><id>https://www.simonholywell.com/post/2010/02/the-little-manual-of-api-design/</id><author><name>Simon Holywell</name></author><published>2010-02-22T09:48:18+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>The Little Manual of API Design
This manual gathers together the key insights into API design that were discovered through many years of software development on the Qt application development framework at Trolltech (now part of Nokia). When designing and implementing a library, you should also keep other factors in mind, such as efficiency and ease of implementation, in addition to pure API considerations. And although the focus is on public APIs, there is no harm in applying the principles described here when writing application code or internal library code.</summary><content type="html"><![CDATA[<p><a href="http://chaos.troll.no/~shausman/api-design/api-design.pdf">The Little Manual of API Design</a></p>
<p>This manual gathers together the key insights into API design that were discovered through many years of software development on the Qt application development framework at Trolltech (now part of Nokia). When designing and implementing a library, you should also keep other factors in mind, such as efficiency and ease of implementation, in addition to pure API considerations. And although the focus is on public APIs, there is no harm in applying the principles described here when writing application code or internal library code.</p>
]]></content><category scheme="taxonomy:Tags" term="api-design" label="API Design"/><category scheme="taxonomy:Tags" term="code" label="code"/></entry><entry xml:base="sun-oracle-deal-closed"><title type="html">Sun + Oracle Deal Closed</title><link href="https://www.simonholywell.com/post/2010/02/sun-oracle-deal-closed/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2009/11/lancia-stratos-replica-fast-lap-on-top-gear-uk/?utm_source=atom_feed" rel="related" type="text/html" title="Lancia Stratos Replica Fast Lap on Top Gear UK"/><link href="https://www.simonholywell.com/post/2009/11/agavi-form-population-filter/?utm_source=atom_feed" rel="related" type="text/html" title="Agavi Form Population Filter"/><link href="https://www.simonholywell.com/post/2009/11/netbeans-and-xdebug/?utm_source=atom_feed" rel="related" type="text/html" title="Netbeans and Remote XDebug"/><link href="https://www.simonholywell.com/post/2009/11/agavi-php-framework-resources/?utm_source=atom_feed" rel="related" type="text/html" title="Agavi PHP Framework Resources"/><link href="https://www.simonholywell.com/post/2009/10/jquery-and-iframes/?utm_source=atom_feed" rel="related" type="text/html" title="jQuery and iFrames"/><id>https://www.simonholywell.com/post/2010/02/sun-oracle-deal-closed/</id><author><name>Simon Holywell</name></author><published>2010-02-04T16:00:05+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>You may have noticed that the Oracle logo has begun to appear across all the Sun websites, which is a visible indication that the Oracle buy out of Sun is now complete. In the spring of last year the deal was announced and many people were very worried about Oracle’s intentions for Sun’s open source projects – most notably MySQL. Many seemed to consider MySQL a competitor for Oracle’s 11g database software and therefore Oracle would be looking to reduce development investment to stifle the perceived competition.</summary><content type="html"><![CDATA[<p>You may have noticed that the Oracle logo has begun to appear across all the Sun websites, which is a visible indication that the Oracle buy out of Sun is now complete.  In the spring of last year the deal was announced and many people were very worried about Oracle’s intentions for Sun’s open source projects – most notably MySQL.  Many seemed to consider MySQL a competitor for Oracle’s 11g database software and therefore Oracle would be looking to reduce development investment to stifle the perceived competition.  This is something that both Larry Ellison and the audience at the Oracle + Sun close presentation found laughable.</p>
<p>Larry Ellison has also written a short open letter to Sun’s customers, which highlights Oracle’s intended investment in the future.</p>
<p><img src="/static/images/sun_customers_lg.gif" alt="Open Letter to Sun Customers"></p>
<p>So we can all rest easily now!</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/></entry><entry xml:base="lancia-stratos-replica-fast-lap-on-top-gear-uk"><title type="html">Lancia Stratos Replica Fast Lap on Top Gear UK</title><link href="https://www.simonholywell.com/post/2009/11/lancia-stratos-replica-fast-lap-on-top-gear-uk/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2008/09/lancia-fulvia-hf/?utm_source=atom_feed" rel="related" type="text/html" title="Lancia Fulvia HF"/><link href="https://www.simonholywell.com/post/2005/04/lancia-stratos/?utm_source=atom_feed" rel="related" type="text/html" title="Lancia Stratos"/><link href="https://www.simonholywell.com/post/2008/12/carver-carver-one/?utm_source=atom_feed" rel="related" type="text/html" title="Carver Carver One"/><link href="https://www.simonholywell.com/post/2008/05/vauxhall-astra-front-brakes/?utm_source=atom_feed" rel="related" type="text/html" title="Vauxhall Astra Front Brakes"/><link href="https://www.simonholywell.com/post/2008/04/sql-server/?utm_source=atom_feed" rel="related" type="text/html" title="SQL SERVER"/><id>https://www.simonholywell.com/post/2009/11/lancia-stratos-replica-fast-lap-on-top-gear-uk/</id><author><name>Simon Holywell</name></author><published>2009-11-30T16:43:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>During a reasonably long and fitting homage to Lancia (Fulvia, Montecarlo, 037 and Delta) on Top Gear last night “The Stig” was given a Hawk HF3000 (that is the Alfa V6 based one) replica to drive around the track.
It sounds fantastic but the bucking and diving under braking looks really scary! Hawk are not the only maker of replicas as I found out when I did some research a couple years ago.</summary><content type="html"><![CDATA[<p>During a reasonably long and fitting homage to Lancia (<a href="/post/2008/09/lancia-fulvia-hf.html">Fulvia</a>, Montecarlo, 037 and Delta) on Top Gear last night “The Stig” was given a <a href="http://www.hawkcars.co.uk/hf3000/index.html">Hawk HF3000</a> (that is the Alfa V6 based one) replica to drive around the track.</p>
<p>It sounds fantastic but the bucking and diving under braking looks really scary!  Hawk are not the only maker of replicas as I found out when I did some <a href="/post/2005/04/lancia-stratos.html">research a couple years ago</a>.</p>
<p>Oh they also mentioned the Beta and the HPE in the <a href="http://delta.hi.fi/kuvat/VIDEO/9405623905-93162.avi">full episode</a>.</p>
<p>A couple of Lancia Stratos books that I found very interesting <a href="http://www.amazon.co.uk/gp/product/1845840410?ie=UTF8&amp;tag=simonholywell-21&amp;linkCode=as2&amp;camp=1634&amp;creative=6738&amp;creativeASIN=1845840410">Lancia Stratos (Rally Giants Series)</a> and <a href="http://www.amazon.co.uk/gp/product/0948207027?ie=UTF8&amp;tag=simonholywell-21&amp;linkCode=as2&amp;camp=1634&amp;creative=6738&amp;creativeASIN=0948207027">Lancia Stratos, 1972-85 (Brooklands Books Road Tests Series)</a>.</p>
]]></content><category scheme="taxonomy:Categories" term="motors" label="Motors"/><category scheme="taxonomy:Tags" term="fulvia" label="Fulvia"/><category scheme="taxonomy:Tags" term="lancia" label="Lancia"/><category scheme="taxonomy:Tags" term="stratos" label="Stratos"/><category scheme="taxonomy:Tags" term="cars" label="Cars"/></entry><entry xml:base="agavi-form-population-filter"><title type="html">Agavi Form Population Filter</title><link href="https://www.simonholywell.com/post/2009/11/agavi-form-population-filter/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2009/11/agavi-php-framework-resources/?utm_source=atom_feed" rel="related" type="text/html" title="Agavi PHP Framework Resources"/><link href="https://www.simonholywell.com/post/2009/03/using-phing-for-good-unfuddle-add-repository-and-svn-imp/?utm_source=atom_feed" rel="related" type="text/html" title="Using phing for good - Unfuddle Add Repository and SVN Import Ta…"/><link href="https://www.simonholywell.com/post/2009/02/agavi-release-candidate-1/?utm_source=atom_feed" rel="related" type="text/html" title="Agavi Release Candidate 1"/><link href="https://www.simonholywell.com/post/2009/01/agavi-1-0-beta-on-xampp-1-7-0/?utm_source=atom_feed" rel="related" type="text/html" title="Agavi 1.0 Beta on XAMPP 1.7.0"/><link href="https://www.simonholywell.com/post/2009/11/netbeans-and-xdebug/?utm_source=atom_feed" rel="related" type="text/html" title="Netbeans and Remote XDebug"/><id>https://www.simonholywell.com/post/2009/11/agavi-form-population-filter/</id><author><name>Simon Holywell</name></author><published>2009-11-24T14:58:05+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Attaching the population filter without using form IDs (suitable where the current form is on the same page as the URL in forms action parameter)
&amp;lt;?php // Like so $this-&amp;gt;getContext()-&amp;gt;getRequest()-&amp;gt;setAttribute(&amp;#39;populate&amp;#39;, new AgaviParameterHolder(array( &amp;#39;question[0]&amp;#39; =&amp;gt; &amp;#39;Can you eat cheese?&amp;#39;, &amp;#39;answer[0]&amp;#39; =&amp;gt; &amp;#39;No&amp;#39; )), &amp;#39;org.agavi.filter.FormPopulationFilter&amp;#39;); // Or like so... $populate =&amp;amp; $this-&amp;gt;getContext()-&amp;gt;getRequest()-&amp;gt;getAttribute(&amp;#39;populate&amp;#39;, &amp;#39;org.agavi.filter.FormPopulationFilter&amp;#39;); $populate = new AgaviParameterHolder(array( &amp;#39;question[0]&amp;#39; =&amp;gt; &amp;#39;Can you eat cheese?&amp;#39;, &amp;#39;answer[0]&amp;#39; =&amp;gt; &amp;#39;No&amp;#39; )); Use form ids to link the pre-population to a particular form</summary><content type="html"><![CDATA[<p>Attaching the population filter without using form IDs (suitable where the current form is on the same page as the URL in forms action parameter)</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o">&lt;?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl"><span class="c1">// Like so
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="nv">$this</span><span class="o">-&gt;</span><span class="na">getContext</span><span class="p">()</span><span class="o">-&gt;</span><span class="na">getRequest</span><span class="p">()</span><span class="o">-&gt;</span><span class="na">setAttribute</span><span class="p">(</span><span class="s1">&#39;populate&#39;</span><span class="p">,</span> <span class="k">new</span> <span class="nx">AgaviParameterHolder</span><span class="p">(</span><span class="k">array</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;question[0]&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;Can you eat cheese?&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;answer[0]&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;No&#39;</span>
</span></span><span class="line"><span class="cl"><span class="p">)),</span> <span class="s1">&#39;org.agavi.filter.FormPopulationFilter&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// Or like so...
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="nv">$populate</span> <span class="o">=&amp;</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">getContext</span><span class="p">()</span><span class="o">-&gt;</span><span class="na">getRequest</span><span class="p">()</span><span class="o">-&gt;</span><span class="na">getAttribute</span><span class="p">(</span><span class="s1">&#39;populate&#39;</span><span class="p">,</span> <span class="s1">&#39;org.agavi.filter.FormPopulationFilter&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nv">$populate</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">AgaviParameterHolder</span><span class="p">(</span><span class="k">array</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;question[0]&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;Can you eat cheese?&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;answer[0]&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;No&#39;</span>
</span></span><span class="line"><span class="cl"><span class="p">));</span>
</span></span></code></pre></div><p>Use form ids to link the pre-population to a particular form</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o">&lt;?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl"><span class="c1">// With ID
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="nv">$populate</span> <span class="o">=&amp;</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">getContext</span><span class="p">()</span><span class="o">-&gt;</span><span class="na">getRequest</span><span class="p">()</span><span class="o">-&gt;</span><span class="na">getAttribute</span><span class="p">(</span><span class="s1">&#39;populate&#39;</span><span class="p">,</span> <span class="s1">&#39;org.agavi.filter.FormPopulationFilter&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nv">$populate</span><span class="p">[</span><span class="s1">&#39;form-id-1&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">AgaviParameterHolder</span><span class="p">(</span><span class="k">array</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;question[0]&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;Can you eat cheese?&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;answer[0]&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;No&#39;</span>
</span></span><span class="line"><span class="cl"><span class="p">));</span>
</span></span><span class="line"><span class="cl"><span class="nv">$populate</span><span class="p">[</span><span class="s1">&#39;form-id-2&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">AgaviParameterHolder</span><span class="p">(</span><span class="k">array</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;question[0]&#39;</span> <span class="o">=&gt;</span> <span class="s2">&#34;How many frags do I have to get before I&#39;m considered awesome?&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;answer[0]&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;At least 15&#39;</span>
</span></span><span class="line"><span class="cl"><span class="p">));</span>
</span></span></code></pre></div><p>The above hints were created with help from IRC.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="agavi" label="agavi"/><category scheme="taxonomy:Tags" term="php" label="PHP"/></entry><entry xml:base="netbeans-and-xdebug"><title type="html">Netbeans and Remote XDebug</title><link href="https://www.simonholywell.com/post/2009/11/netbeans-and-xdebug/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2009/11/agavi-php-framework-resources/?utm_source=atom_feed" rel="related" type="text/html" title="Agavi PHP Framework Resources"/><link href="https://www.simonholywell.com/post/2009/08/moving-to-git-and-setting-up-indefero-as-a-web-frontend/?utm_source=atom_feed" rel="related" type="text/html" title="Moving to git and setting up InDefero as a web frontend"/><link href="https://www.simonholywell.com/post/2009/04/memcached-and-apc-two-simple-techniques-to-speed-up-your/?utm_source=atom_feed" rel="related" type="text/html" title="Memcached and APC: Two Simple Techniques to Speed up your PHP Webpages"/><link href="https://www.simonholywell.com/post/2009/04/installing-apc-and-memcached-for-php-sessions-on-ubuntu/?utm_source=atom_feed" rel="related" type="text/html" title="Installing APC and Memcached for PHP Sessions on Ubuntu and Debi…"/><link href="https://www.simonholywell.com/post/2009/03/using-phing-for-good-unfuddle-add-repository-and-svn-imp/?utm_source=atom_feed" rel="related" type="text/html" title="Using phing for good - Unfuddle Add Repository and SVN Import Ta…"/><id>https://www.simonholywell.com/post/2009/11/netbeans-and-xdebug/</id><author><name>Simon Holywell</name></author><published>2009-11-24T14:55:03+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>To get Netbeans to listen for browser initiated debug sessions please consider the following steps:
Go to Project Properties &amp;gt; Run Configuration &amp;gt; Advanced &amp;gt; Debug URL and choose the Do not open a web browser. Save. (you may like to setup Path Mapping, but it works for me without it) In the projects listing right click on your intended project and choose Debug, which will start Netbeans listening for connections.</summary><content type="html"><![CDATA[<p>To get Netbeans to listen for browser initiated debug sessions please consider the following steps:</p>
<ol>
<li>Go to Project Properties &gt; Run Configuration &gt; Advanced &gt; Debug URL and choose the Do not open a web browser.  Save.  (you may like to setup Path Mapping, but it works for me without it)</li>
<li>In the projects listing right click on your intended project and choose Debug, which will start Netbeans listening for connections.</li>
<li>In your web browser you can now access your website <a href="http://www.example.org?XDEBUG_SESSION_START=netbeans-xdebug">http://www.example.org?XDEBUG\_SESSION\_START=netbeans-xdebug</a></li>
<li>You will now see the debug information appear in the debug log area of Netbeans.</li>
</ol>
<p>(Para-phrased and expanded upon an <a href="http://stackoverflow.com/questions/1531391/launch-xdebug-in-netbeans-on-an-external-request/1544745#1544745">answer on StackOverflow</a>)</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="netbeans" label="netbeans"/><category scheme="taxonomy:Tags" term="php" label="PHP"/><category scheme="taxonomy:Tags" term="xdebug" label="xdebug"/></entry><entry xml:base="agavi-php-framework-resources"><title type="html">Agavi PHP Framework Resources</title><link href="https://www.simonholywell.com/post/2009/11/agavi-php-framework-resources/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2009/02/agavi-release-candidate-1/?utm_source=atom_feed" rel="related" type="text/html" title="Agavi Release Candidate 1"/><link href="https://www.simonholywell.com/post/2009/01/agavi-1-0-beta-on-xampp-1-7-0/?utm_source=atom_feed" rel="related" type="text/html" title="Agavi 1.0 Beta on XAMPP 1.7.0"/><link href="https://www.simonholywell.com/post/2009/08/moving-to-git-and-setting-up-indefero-as-a-web-frontend/?utm_source=atom_feed" rel="related" type="text/html" title="Moving to git and setting up InDefero as a web frontend"/><link href="https://www.simonholywell.com/post/2009/04/memcached-and-apc-two-simple-techniques-to-speed-up-your/?utm_source=atom_feed" rel="related" type="text/html" title="Memcached and APC: Two Simple Techniques to Speed up your PHP Webpages"/><link href="https://www.simonholywell.com/post/2009/04/installing-apc-and-memcached-for-php-sessions-on-ubuntu/?utm_source=atom_feed" rel="related" type="text/html" title="Installing APC and Memcached for PHP Sessions on Ubuntu and Debi…"/><id>https://www.simonholywell.com/post/2009/11/agavi-php-framework-resources/</id><author><name>Simon Holywell</name></author><published>2009-11-16T19:48:05+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Bitextender backed Agavi is a very secure and helpful open source (LGPL) MVC framework with the core development being headed by David Zülke (Wombert) and Felix Gilcher (certainly in the IRC channel!). It can take some time to get the hang of the framework so I have put together all the resources I use or have used to help you get started.
Documentation Resources:
Official Agavi Tutorial - Incomplete at time of writing API Documentation Agavi Cookbook Official Agavi FAQ Unofficial Agavi FAQ – Very helpful Package Docs in SVN – You need to dig around these folders in the SVN source code viewer of Trac (some of it is also old) Veikko Mäkinen’s Blog: http://blog.</summary><content type="html"><![CDATA[<p><img src="/static/images/wp/2009/02/agavi.jpg" alt="Agavi Framework Logo"></p>
<p>Bitextender backed <a href="http://www.agavi.org">Agavi</a> is a very secure and helpful open source (LGPL) MVC framework with the core development being headed by David Zülke (Wombert) and Felix Gilcher (certainly in the <a href="irc://irc.freenode.net/agavi">IRC channel</a>!). It can take some time to get the hang of the framework so I have put together all the resources I use or have used to help you get started.</p>
<p>Documentation Resources:</p>
<ul>
<li><a href="http://agavi.org/documentation/tutorial">Official Agavi Tutorial</a> <em>- Incomplete</em> at time of writing</li>
<li><a href="http://agavi.org/apidocs/">API Documentation</a></li>
<li><a href="http://svn.agavi.org/trunk/docs/docbook/cookbook.xml">Agavi Cookbook</a></li>
<li><a href="http://trac.agavi.org/wiki/FAQ">Official Agavi FAQ</a></li>
<li><a href="http://www.mivesto.de/agavi/agavi-faq.html">Unofficial Agavi FAQ</a> – <em>Very</em> helpful</li>
<li><a href="http://trac.agavi.org/browser/trunk/docs">Package Docs in SVN</a> – You need to dig around these folders in the SVN source code viewer of Trac (some of it is also old)</li>
<li>Veikko Mäkinen’s Blog: <a href="http://blog.veikko.fi/tagged/agavi"><a href="http://blog.veikko.fi/tagged/agavi">http://blog.veikko.fi/tagged/agavi</a></a></li>
<li>David Zülke’s Blog: <a href="http://blog.wombert.de/tagged/agavi"><a href="http://blog.wombert.de/tagged/agavi">http://blog.wombert.de/tagged/agavi</a></a> (take a look through the PHPLondon talk and learn of the Mike controversy mentioned in one of my <a href="/post/2008/05/installing-agavi-on-xampp-windows.html">previous posts</a>! Plus lots of Agavi tips as well of course.)</li>
<li>IBM Developer Works Article series:
<ul>
<li><a href="http://www.ibm.com/developerworks/library/x-agavipt1/">Part 1</a></li>
<li><a href="http://www.ibm.com/developerworks/library/x-agavipt2/">Part 2</a></li>
<li><a href="http://www.ibm.com/developerworks/library/x-agavipt3/">Part 3</a></li>
<li><a href="http://www.ibm.com/developerworks/library/x-agavipt4/">Part 4</a></li>
<li><a href="http://www.ibm.com/developerworks/library/x-agavipt5/">Part 5</a></li>
<li><a href="http://www.ibm.com/developerworks/opensource/library/x-agavipt6/index.html">Part 6</a></li>
</ul>
</li>
</ul>
<p>Support Resources:</p>
<ul>
<li><a href="http://agavi.org/support">Agavi Support page</a> <strong>IRC</strong> is very helpful (be patient when waiting for a response though)</li>
</ul>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="agavi" label="agavi"/><category scheme="taxonomy:Tags" term="php" label="PHP"/><category scheme="taxonomy:Tags" term="internet" label="Internet"/></entry><entry xml:base="jquery-and-iframes"><title type="html">jQuery and iFrames</title><link href="https://www.simonholywell.com/post/2009/10/jquery-and-iframes/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2009/08/jquery-using-and-manipulating-select-lists/?utm_source=atom_feed" rel="related" type="text/html" title="jQuery Using and Manipulating Select Lists"/><link href="https://www.simonholywell.com/post/2009/03/firefox-3-1-has-web-workers-threading-and-geolocation/?utm_source=atom_feed" rel="related" type="text/html" title="Firefox 3.1 has Web Workers (threading) and Geolocation"/><link href="https://www.simonholywell.com/post/2009/08/moving-to-git-and-setting-up-indefero-as-a-web-frontend/?utm_source=atom_feed" rel="related" type="text/html" title="Moving to git and setting up InDefero as a web frontend"/><link href="https://www.simonholywell.com/post/2009/04/memcached-and-apc-two-simple-techniques-to-speed-up-your/?utm_source=atom_feed" rel="related" type="text/html" title="Memcached and APC: Two Simple Techniques to Speed up your PHP Webpages"/><link href="https://www.simonholywell.com/post/2009/04/installing-apc-and-memcached-for-php-sessions-on-ubuntu/?utm_source=atom_feed" rel="related" type="text/html" title="Installing APC and Memcached for PHP Sessions on Ubuntu and Debi…"/><id>https://www.simonholywell.com/post/2009/10/jquery-and-iframes/</id><author><name>Simon Holywell</name></author><published>2009-10-29T16:17:54+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>I worked on a project while ago that required the use of iFrames to create “AJAX” file uploads. It took me a little while but I finally worked out how to get the contents of an iFrame using jQuery. To get the contents of an iFrame we need to wait until the iFramed content has finished loading as well.
var iFrameBody = &amp;#34;&amp;#34;; $(&amp;#34;#iframe&amp;#34;).load(function () { iFrameBody = $(this).contents().find(&amp;#34;body&amp;#34;); });</summary><content type="html"><![CDATA[<p>I worked on a project while ago that required the use of iFrames to create “AJAX” file uploads.  It took me a little while but I finally worked out how to get the contents of an iFrame using jQuery.  To get the contents of an iFrame we need to wait until the iFramed content has finished loading as well.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">iFrameBody</span> <span class="o">=</span> <span class="s2">&#34;&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nx">$</span><span class="p">(</span><span class="s2">&#34;#iframe&#34;</span><span class="p">).</span><span class="nx">load</span><span class="p">(</span><span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">iFrameBody</span> <span class="o">=</span> <span class="nx">$</span><span class="p">(</span><span class="k">this</span><span class="p">).</span><span class="nx">contents</span><span class="p">().</span><span class="nx">find</span><span class="p">(</span><span class="s2">&#34;body&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div>]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="javascript" label="Javascript"/><category scheme="taxonomy:Tags" term="jquery" label="jQuery"/><category scheme="taxonomy:Tags" term="internet" label="Internet"/></entry><entry xml:base="opera-mini-5-beta"><title type="html">Opera Mini 5 Beta</title><link href="https://www.simonholywell.com/post/2009/10/opera-mini-5-beta/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2009/08/jquery-using-and-manipulating-select-lists/?utm_source=atom_feed" rel="related" type="text/html" title="jQuery Using and Manipulating Select Lists"/><link href="https://www.simonholywell.com/post/2009/08/moving-to-git-and-setting-up-indefero-as-a-web-frontend/?utm_source=atom_feed" rel="related" type="text/html" title="Moving to git and setting up InDefero as a web frontend"/><link href="https://www.simonholywell.com/post/2009/05/handy-linux-commands/?utm_source=atom_feed" rel="related" type="text/html" title="Handy Linux Commands"/><link href="https://www.simonholywell.com/post/2009/04/samba-file-share-over-ssh-tunnel/?utm_source=atom_feed" rel="related" type="text/html" title="Samba File Share Over SSH Tunnel"/><link href="https://www.simonholywell.com/post/2009/04/memcached-and-apc-two-simple-techniques-to-speed-up-your/?utm_source=atom_feed" rel="related" type="text/html" title="Memcached and APC: Two Simple Techniques to Speed up your PHP Webpages"/><id>https://www.simonholywell.com/post/2009/10/opera-mini-5-beta/</id><author><name>Simon Holywell</name></author><published>2009-10-09T14:03:55+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Opera has released a new version of their free mobile browser Mini for beta testing. Head on over to mini.opera.com to download it or if you are reading this from your mobile the direct link to the beta is m.opera.com/next. The new version is much improved in many areas. The first thing you will notice is a new sleeker user interface and a “Speed Dial” interface when it first loads up.</summary><content type="html"><![CDATA[<p>Opera has released a new version of their free mobile browser Mini for beta testing.  Head on over to <a href="http://mini.opera.com">mini.opera.com</a> to download it or if you are reading this from your mobile the direct link to the beta is <a href="m.opera.com/next">m.opera.com/next</a>.  The new version is much improved in many areas.  The first thing you will notice is a new sleeker user interface and a “Speed Dial” interface when it first loads up.  My favourite is the addition of tabbed browsing and a neat little password manager.</p>
<p>I have been using it on my <a href="http://en.wikipedia.org/wiki/Symbian_OS">Symbian</a> based phone during the train journeys to work and its great.</p>
<p><a href="http://www.youtube.com/watch?v=joBaCW8abNE">Opera Mini 5 Beta Reviewers Guide</a></p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="opera" label="opera"/></entry><entry xml:base="jquery-using-and-manipulating-select-lists"><title type="html">jQuery Using and Manipulating Select Lists</title><link href="https://www.simonholywell.com/post/2009/08/jquery-using-and-manipulating-select-lists/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2009/03/firefox-3-1-has-web-workers-threading-and-geolocation/?utm_source=atom_feed" rel="related" type="text/html" title="Firefox 3.1 has Web Workers (threading) and Geolocation"/><link href="https://www.simonholywell.com/post/2009/08/moving-to-git-and-setting-up-indefero-as-a-web-frontend/?utm_source=atom_feed" rel="related" type="text/html" title="Moving to git and setting up InDefero as a web frontend"/><link href="https://www.simonholywell.com/post/2009/04/memcached-and-apc-two-simple-techniques-to-speed-up-your/?utm_source=atom_feed" rel="related" type="text/html" title="Memcached and APC: Two Simple Techniques to Speed up your PHP Webpages"/><link href="https://www.simonholywell.com/post/2009/04/installing-apc-and-memcached-for-php-sessions-on-ubuntu/?utm_source=atom_feed" rel="related" type="text/html" title="Installing APC and Memcached for PHP Sessions on Ubuntu and Debi…"/><link href="https://www.simonholywell.com/post/2009/03/installing-apc-and-memcached-for-php-sessions-on-redhat/?utm_source=atom_feed" rel="related" type="text/html" title="Installing APC and Memcached for PHP Sessions on Redhat"/><id>https://www.simonholywell.com/post/2009/08/jquery-using-and-manipulating-select-lists/</id><author><name>Simon Holywell</name></author><published>2009-08-10T13:54:32+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>JQuery is a fantastic tool but sometimes its functionality can be obscure or doing it one way might not work in a certain browser (MSIE6 anybody!). I have often found myself trying to remember the best way to work with HTML select lists so I am compiling this list of hints for future use and I hope that you find it useful. All the examples below are written where this represents the select element of the select list.</summary><content type="html"><![CDATA[<p>JQuery is a fantastic tool but sometimes its functionality can be obscure or doing it one way might not work in a certain browser (MSIE6 anybody!).  I have often found myself trying to remember the best way to work with HTML select lists so I am compiling this list of hints for future use and I hope that you find it useful.  All the examples below are written where <code>this</code> represents the select element of the select list.</p>
<p>First up getting the selected value from a select list is as simple as using the jQuery shortcut <code>$(this).val();</code>.  Simple isn’t it!  Setting the selected item is just as easy too…</p>
<p>jQuery has a nice shortcut for setting the selectedIndex/value of an HTML select list and its syntax is as so <code>$(this).val('value');</code>.</p>
<p>Finding an option in a select list by its value works out to be something like this <code>$('option[value=&quot;value-to-search-for&quot;]', this);</code>.</p>
<p>Often I need to be able to reset the select list to its initial state when clearing/resetting a form for the next submission.  There is a jQuery shortcut for this which is <code>$(this).val('');</code>, but it does not work in IE for whatever reason so I devised <code>$(this).val($('option:first', this).val());</code>.  This basically sets the select lists value equal to the first option in the list.</p>
<p>The next item on the list is resetting the select list to a blank option, which is easy with the following syntax <code>$(this).val(null);</code>.</p>
<p>Now to add an option into a select list with jQuery <code>$(this).append('&lt;option value=&quot;Option Value&quot;&gt;Option Name&lt;/option&gt;');</code> and to remove an option from the list by value <code>$('option[value=&quot;value-to-search-for&quot;]', this).remove();</code>.</p>
<p>The aforementioned tips and some extras are included in a syntax highlighted manner below for your perusal.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="c1">//Get the currently selected option&#39;s value
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">$</span><span class="p">(</span><span class="k">this</span><span class="p">).</span><span class="nx">val</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">//Get the currently selected option&#39;s title
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">$</span><span class="p">(</span><span class="k">this</span><span class="p">).</span><span class="nx">text</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">//Set the currently selected option to the supplied value
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">$</span><span class="p">(</span><span class="k">this</span><span class="p">).</span><span class="nx">val</span><span class="p">(</span><span class="s2">&#34;value&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">//Get an option with a specified value
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">$</span><span class="p">(</span><span class="s1">&#39;option[value=&#34;value-to-search-for&#34;]&#39;</span><span class="p">,</span> <span class="k">this</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">//Reset select list to first value
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">$</span><span class="p">(</span><span class="k">this</span><span class="p">).</span><span class="nx">val</span><span class="p">(</span><span class="s2">&#34;&#34;</span><span class="p">);</span> <span class="c1">//this doesn&#39;t work in IE
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="c1">//Reset the select list to the first value
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">$</span><span class="p">(</span><span class="k">this</span><span class="p">).</span><span class="nx">val</span><span class="p">(</span><span class="nx">$</span><span class="p">(</span><span class="s2">&#34;option:first&#34;</span><span class="p">,</span> <span class="k">this</span><span class="p">).</span><span class="nx">val</span><span class="p">());</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">//Reset select list to blank option
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">$</span><span class="p">(</span><span class="k">this</span><span class="p">).</span><span class="nx">val</span><span class="p">(</span><span class="kc">null</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">//Add an option onto the top of a select list
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">$</span><span class="p">(</span><span class="k">this</span><span class="p">).</span><span class="nx">prepend</span><span class="p">(</span><span class="s1">&#39;&lt;option value=&#34;Option Value&#34;&gt;Option Name&lt;/option&gt;&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">//Add an option onto the end of a select list
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">$</span><span class="p">(</span><span class="k">this</span><span class="p">).</span><span class="nx">append</span><span class="p">(</span><span class="s1">&#39;&lt;option value=&#34;Option Value&#34;&gt;Option Name&lt;/option&gt;&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">//Add an option before a certain option in a select list
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">$</span><span class="p">(</span><span class="s1">&#39;option[value=&#34;value-to-search-for&#34;]&#39;</span><span class="p">,</span> <span class="k">this</span><span class="p">).</span><span class="nx">before</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">  <span class="s1">&#39;&lt;option value=&#34;Option Value&#34;&gt;Option Name&lt;/option&gt;&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">//Add an option after a certain option in a select list
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">$</span><span class="p">(</span><span class="s1">&#39;option[value=&#34;value-to-search-for&#34;]&#39;</span><span class="p">,</span> <span class="k">this</span><span class="p">).</span><span class="nx">after</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">  <span class="s1">&#39;&lt;option value=&#34;Option Value&#34;&gt;Option Name&lt;/option&gt;&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">//Remove an option from a select list by value
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">$</span><span class="p">(</span><span class="s1">&#39;option[value=&#34;value-to-search-for&#34;]&#39;</span><span class="p">,</span> <span class="k">this</span><span class="p">).</span><span class="nx">remove</span><span class="p">();</span>
</span></span></code></pre></div>]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="javascript" label="Javascript"/><category scheme="taxonomy:Tags" term="jquery" label="jQuery"/><category scheme="taxonomy:Tags" term="internet" label="Internet"/></entry><entry xml:base="moving-to-git-and-setting-up-indefero-as-a-web-frontend"><title type="html">Moving to git and setting up InDefero as a web frontend</title><link href="https://www.simonholywell.com/post/2009/08/moving-to-git-and-setting-up-indefero-as-a-web-frontend/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2009/04/memcached-and-apc-two-simple-techniques-to-speed-up-your/?utm_source=atom_feed" rel="related" type="text/html" title="Memcached and APC: Two Simple Techniques to Speed up your PHP Webpages"/><link href="https://www.simonholywell.com/post/2009/04/installing-apc-and-memcached-for-php-sessions-on-ubuntu/?utm_source=atom_feed" rel="related" type="text/html" title="Installing APC and Memcached for PHP Sessions on Ubuntu and Debi…"/><link href="https://www.simonholywell.com/post/2009/03/using-phing-for-good-unfuddle-add-repository-and-svn-imp/?utm_source=atom_feed" rel="related" type="text/html" title="Using phing for good - Unfuddle Add Repository and SVN Import Ta…"/><link href="https://www.simonholywell.com/post/2009/02/a-good-windows-development-environment-and-ubuntu-virtua/?utm_source=atom_feed" rel="related" type="text/html" title="A Good Windows Development Environment and Ubuntu Virtualbox"/><link href="https://www.simonholywell.com/post/2009/05/handy-linux-commands/?utm_source=atom_feed" rel="related" type="text/html" title="Handy Linux Commands"/><id>https://www.simonholywell.com/post/2009/08/moving-to-git-and-setting-up-indefero-as-a-web-frontend/</id><author><name>Simon Holywell</name></author><published>2009-08-04T14:07:44+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Most of our development is done on Vista desktops (although I also run Ubuntu of course) and we wanted a web interface for easy browsing of code so I needed to use a pervasive and well supported VCS. After much hunting around and looking at Bazaar, Mercurial and git I decided to go with the latter due to its support in the community. There are still some reservations I have against git, which work well for Linux kernal development but not our day to day web development – the major one being that subversion would allow you to commit and update on a file by file basis where as git versions the entire repository at once as far as I am aware.</summary><content type="html"><![CDATA[<p><img src="/static/images/wp/2009/08/git-logo.png" alt="git Logo"></p>
<p>Most of our development is done on Vista desktops (although I also run Ubuntu of course) and we wanted a web interface for easy browsing of code so I needed to use a pervasive and well supported VCS. After much hunting around and looking at Bazaar, Mercurial and git I decided to go with the latter due to its support in the community.  There are still some reservations I have against git, which work well for Linux kernal development but not our day to day web development – the major one being that subversion would allow you to commit and update on a file by file basis where as git versions the entire repository at once as far as I am aware.</p>
<p>Anyway now I have an Ubuntu server that I am using for storing the repositories and as a pretty frontend I have installed <a href="http://www.indefero.net/">InDefero</a> which also allows us to manage tickets.  InDefero is much like the code.google.com forge to manage and look at it so it is very simple.  I like Trac but I was not happy with the existing integrations with git.</p>
<p>It was not all plain sailing with the InDefero install as I had to make some very minor changes in the git plugin’s core code (the git plugin comes as part of InDefero and does not need to be installed seperately).  Basically the plugin was creating new repositories with very strict permissions which meant that the neither my backup user nor the apache process user could access them.  What this meant from the frontend was that the repository statistics (disk usage) were not displayed because it could not stat the directories and my back up process could not open them to make backups.</p>
<p>This problem is caused by the use of permissions setting in a PHP mkdir() command in the src/IDF/Plugin/SyncGit/Serve.php on lines 94 and 193.  You will want to increase the file permission octal just enough for your other users to gain access.  It is also worth mentioning that on line 111 there is a umask() command which you might also wish to tweak to improve your access.  Also don’t forget to update all $pluf_path values in the files in the scripts directory.  The rest of the way you should be fine just following the included documentation in doc/syncgit.mdtext</p>
<p>So far I am enjoying using InDefero though I think I will need to hack it so that when you add a new repository/project all the users names are placed in the project members as default to save vast amounts of copying and pasting.  Our development team is not large enough to warrant only giving certain people access to certain repositories/projects.</p>
<p>[UPDATE] I have made a small (and nasty) hack to the source of InDefero to cause the members text area when creating a new project to be pre-filled with my member’s names.  This involved changing /src/IDF/Form/Admin/ProjectCreate.php on line 107 by setting the array element initial to the value you want to appear in the text area.</p>
<p>For our desktop access to git we are using <a href="http://code.google.com/p/msysgit/">msysGit</a>, <a href="http://the.earth.li/~sgtatham/putty/0.60/htmldoc/Chapter7.html#plink">PuTTY Plink</a> and <a href="http://code.google.com/p/tortoisegit/">TortoiseGit</a>.  This combination is working well for us so far and means that even non-technical users can begin versioning their documents and push them to a central repository for backup purposes.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="debian" label="debian"/><category scheme="taxonomy:Tags" term="git" label="git"/><category scheme="taxonomy:Tags" term="linux" label="linux"/><category scheme="taxonomy:Tags" term="php" label="PHP"/><category scheme="taxonomy:Tags" term="ubuntu" label="ubuntu"/><category scheme="taxonomy:Tags" term="internet" label="Internet"/></entry><entry xml:base="handy-linux-commands"><title type="html">Handy Linux Commands</title><link href="https://www.simonholywell.com/post/2009/05/handy-linux-commands/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2009/04/samba-file-share-over-ssh-tunnel/?utm_source=atom_feed" rel="related" type="text/html" title="Samba File Share Over SSH Tunnel"/><link href="https://www.simonholywell.com/post/2009/04/memcached-and-apc-two-simple-techniques-to-speed-up-your/?utm_source=atom_feed" rel="related" type="text/html" title="Memcached and APC: Two Simple Techniques to Speed up your PHP Webpages"/><link href="https://www.simonholywell.com/post/2009/04/installing-apc-and-memcached-for-php-sessions-on-ubuntu/?utm_source=atom_feed" rel="related" type="text/html" title="Installing APC and Memcached for PHP Sessions on Ubuntu and Debi…"/><link href="https://www.simonholywell.com/post/2009/03/crunchbang-linux-on-the-eee-pc/?utm_source=atom_feed" rel="related" type="text/html" title="CrunchBang Linux on the Eee Pc"/><link href="https://www.simonholywell.com/post/2009/02/a-good-windows-development-environment-and-ubuntu-virtua/?utm_source=atom_feed" rel="related" type="text/html" title="A Good Windows Development Environment and Ubuntu Virtualbox"/><id>https://www.simonholywell.com/post/2009/05/handy-linux-commands/</id><author><name>Simon Holywell</name></author><published>2009-05-12T17:52:18+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>I use most of these commands every day to simplify my terminal interactions with an Ubuntu development box. This is more of a personal reference but thought I would share incase you find it useful.
Task
Command
Get all users on the system
for user in `getent passwd | cut -d: -f1`; do id $user; done
Delete all .svn or any file name by replacing .svn in the command with your filename</summary><content type="html"><![CDATA[<p>I use most of these commands every day to simplify my terminal interactions with an Ubuntu development box.  This is more of a personal reference but thought I would share incase you find it useful.</p>
<p>Task</p>
<p>Command</p>
<p>Get all users on the system</p>
<p><code>for user in `getent passwd | cut -d: -f1`; do id $user; done</code></p>
<p>Delete all .svn or any file name by replacing .svn in the command with your filename</p>
<p><strong><code>find ./ -name &quot;.svn&quot; | xargs rm -Rf</code></strong></p>
<p>Look for enabled modules or particular environment settings in PHP</p>
<p><code>php -r 'phpinfo();' | grep 'searchkeyword'</code></p>
<p>for example <code>php -r 'phpinfo();' | grep 'json'</code> to find out if JSON is installed and what version of the module is available</p>
<p>Push a line of text into a file</p>
<p>to reset file content to ‘text to push’ – <code>echo 'text to push' &gt; /etc/file</code></p>
<p>to append to file content ‘text to push’ – <code>echo 'text to push' &gt;&gt; /etc/file</code></p>
<p>Create an empty file</p>
<p><code>touch filename.ext</code></p>
<p>Watch a file on the command line.  Useful for viewing logs whilst debugging.</p>
<p><code>tail -f /var/log/filename.ext</code> <strong>use <code>control + c</code> to break</strong></p>
<p>Break the current command</p>
<p>Use the keyboard combination <code>control + c</code></p>
<p>Access to MySQL</p>
<p><a href="http://blog.moybella.net/2007/03/10/converting-microsoft-access-mdb-into-csv-or-mysql-in-linux/">Converting Microsoft Access MDB Into CSV Or MySQL In Linux</a></p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="debian" label="debian"/><category scheme="taxonomy:Tags" term="linux" label="linux"/><category scheme="taxonomy:Tags" term="ssh" label="ssh"/><category scheme="taxonomy:Tags" term="ubuntu" label="ubuntu"/></entry><entry xml:base="samba-file-share-over-ssh-tunnel"><title type="html">Samba File Share Over SSH Tunnel</title><link href="https://www.simonholywell.com/post/2009/04/samba-file-share-over-ssh-tunnel/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2009/02/a-good-windows-development-environment-and-ubuntu-virtua/?utm_source=atom_feed" rel="related" type="text/html" title="A Good Windows Development Environment and Ubuntu Virtualbox"/><link href="https://www.simonholywell.com/post/2009/04/memcached-and-apc-two-simple-techniques-to-speed-up-your/?utm_source=atom_feed" rel="related" type="text/html" title="Memcached and APC: Two Simple Techniques to Speed up your PHP Webpages"/><link href="https://www.simonholywell.com/post/2009/04/installing-apc-and-memcached-for-php-sessions-on-ubuntu/?utm_source=atom_feed" rel="related" type="text/html" title="Installing APC and Memcached for PHP Sessions on Ubuntu and Debi…"/><link href="https://www.simonholywell.com/post/2009/03/using-phing-for-good-unfuddle-add-repository-and-svn-imp/?utm_source=atom_feed" rel="related" type="text/html" title="Using phing for good - Unfuddle Add Repository and SVN Import Ta…"/><link href="https://www.simonholywell.com/post/2009/03/putty-and-control-s-or-ctrl-s/?utm_source=atom_feed" rel="related" type="text/html" title="PuTTY and Control + S or Ctrl + S"/><id>https://www.simonholywell.com/post/2009/04/samba-file-share-over-ssh-tunnel/</id><author><name>Simon Holywell</name></author><published>2009-04-30T20:41:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>This is not a post about setting up Samba shares. If that is what you are looking for then I can recommend the following book; Using Samba: A File &amp;amp; Print Server for Linux, Unix &amp;amp; Mac OS X.
Sometimes you need to be able to access a remote Samba server in a secure manner from a Windows machine. This is a relatively simple procedure on an XP SP3 machine like mine linking into an Ubuntu server pre setup with Samba file sharing.</summary><content type="html"><![CDATA[<p>This is not a post about setting up Samba shares. If that is what you are looking for then I can recommend the following book; <a href="http://www.amazon.co.uk/gp/product/0596007698?ie=UTF8&amp;tag=simonholywell-21&amp;linkCode=as2&amp;camp=1634&amp;creative=6738&amp;creativeASIN=0596007698">Using Samba: A File &amp; Print Server for Linux, Unix &amp; Mac OS X</a>.</p>
<p>Sometimes you need to be able to access a remote Samba server in a secure manner from a Windows machine.  This is a relatively simple procedure on an XP SP3 machine like mine linking into an Ubuntu server pre setup with Samba file sharing.</p>
<p>Windows is a little bit annoying as it binds all filesharing operations to port 139 so you cannot have more than one filesharing system in operation at once.  If you were to tunnel directly across to your Samba server it would bang heads with the Windows filesharing layer.  You could just disable file sharing in Windows but that is an in elegant method and you may need access to both Windows and remote Samba shares.  So we will need to setup a new loopback adapter with a local ip address that we can tunnel Samba request through thus allowing Windows filesharing to operate normally along side Samba.  This effectively makes Windows think that it is accessing Samba shares on a seperate machine whereas a tunnel usually acts as a port on the local machine.</p>
<h1 id="add-the-loopback-adapter-to-the-windows-client-machine">Add the Loopback Adapter to the Windows client machine</h1>
<ol>
<li>Open up the Add Hardware control panel (Start &gt; Control Panel &gt; Add Hardware)</li>
<li>Click next and wait for the annoying wizard to finish hunting around your system</li>
<li>Choose ‘Yes, I have already connected the hardware’</li>
<li>Then scroll to the bottom of the ‘Installed hardware’ list box and choose ‘Add new hardware device’</li>
<li>Now choose ‘Install the hardware that I manually select from a list (Advanced)’</li>
<li>Select  ‘Network adapters’</li>
<li>Under ‘Manufacturer’ you want ‘Microsoft’</li>
<li>For ‘Network Adapter’ choose ‘Microsoft Loopback Adapter’</li>
<li>You may have a to wait a little while for the adapter to be fully installed</li>
</ol>
<h1 id="set-the-loopback-adapters-configuration">Set the Loopback Adapters Configuration</h1>
<ol>
<li>
<p>Pull up the adapters properties dialogue (Start &gt; Control Panel &gt; Network Connections and then right click on the adapter and choose properties)</p>
</li>
<li>
<p>Disable ‘File and Printer Sharing for Microsoft Networks’</p>
</li>
<li>
<p>Highlight ‘Internet Protocol (TCP/IP)’ and click the ‘Properties’ button</p>
<ol>
<li>
<p>Choose ‘Use the following IP address’</p>
<ol>
<li>Enter ‘10.0.0.1′ for ‘IP address’</li>
<li>Enter ‘255.255.255.0′ for ‘Subnet mask’</li>
</ol>
</li>
<li>
<p>Click the ‘Advanced’ button and on the ‘WINS’ tab</p>
<ol>
<li>Enable ‘Enable LMHOSTS Lookup’</li>
<li>Check ‘Disable NetBIOS over TCP/IP’</li>
</ol>
</li>
</ol>
</li>
<li>
<p>You will now need to restart you computer even though Windows does not prompt for this step</p>
</li>
</ol>
<h1 id="configure-the-ssh-tunnel">Configure the SSH Tunnel</h1>
<ol>
<li>On your PuTTY session configuration dialogue choose Connection &gt; SSH &gt; Tunnels</li>
<li>Check/enable ‘Local ports accept connections from other hosts’</li>
<li>In ‘Source port’ enter ‘10.0.0.1:139′</li>
<li>In ‘Destination’ enter ‘localhost:139′ (127.0.0.1:139 did not work for me)</li>
</ol>
<h1 id="test-and-map-the-connection">Test and Map the Connection</h1>
<p>In the Run command console (Start &gt; Run) enter <code>\\10.0.0.1</code> and you should be presented with file explorer window containing the contents of your Samba share.</p>
<p>So if that worked we are ready to roll, but you can give your Samba share ’server’ a more friendly name by opening <code>C:\WINDOWS\system32\drivers\etc\hosts</code> in your favourite editor (Vim in my case).  Scroll to the bottom and enter the following <code>\\10.0.0.1    samba</code>.  You can now access <code>//samba</code> in the same way we did above via the Run dialogue.  If you have assigned the loopback device to a different subnet then you will need use the lmhosts file in the same directory instead – please see <a href="http://support.microsoft.com/kb/105997">Microsoft KB Article Q105997</a>.</p>
<p>Now you can Map the Samba share like any other by using the ‘Tools’ menu in a Windows file explorer window.  In the ‘Folder’ input enter \\samba or for a home directory called simon <code>\\samba\simon</code> (you must have enabled home directory sharing in your Samba smb.conf (/etc/samba/smb.conf)).</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="linux" label="linux"/><category scheme="taxonomy:Tags" term="putty" label="putty"/><category scheme="taxonomy:Tags" term="samba" label="samba"/><category scheme="taxonomy:Tags" term="ssh" label="ssh"/><category scheme="taxonomy:Tags" term="ubuntu" label="ubuntu"/><category scheme="taxonomy:Tags" term="windows" label="windows"/></entry><entry xml:base="memcached-and-apc-two-simple-techniques-to-speed-up-your"><title type="html">Memcached and APC: Two Simple Techniques to Speed up your PHP Webpages</title><link href="https://www.simonholywell.com/post/2009/04/memcached-and-apc-two-simple-techniques-to-speed-up-your/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2009/04/installing-apc-and-memcached-for-php-sessions-on-ubuntu/?utm_source=atom_feed" rel="related" type="text/html" title="Installing APC and Memcached for PHP Sessions on Ubuntu and Debi…"/><link href="https://www.simonholywell.com/post/2009/02/a-good-windows-development-environment-and-ubuntu-virtua/?utm_source=atom_feed" rel="related" type="text/html" title="A Good Windows Development Environment and Ubuntu Virtualbox"/><link href="https://www.simonholywell.com/post/2009/03/using-phing-for-good-unfuddle-add-repository-and-svn-imp/?utm_source=atom_feed" rel="related" type="text/html" title="Using phing for good - Unfuddle Add Repository and SVN Import Ta…"/><link href="https://www.simonholywell.com/post/2009/03/installing-apc-and-memcached-for-php-sessions-on-redhat/?utm_source=atom_feed" rel="related" type="text/html" title="Installing APC and Memcached for PHP Sessions on Redhat"/><link href="https://www.simonholywell.com/post/2009/03/crunchbang-linux-on-the-eee-pc/?utm_source=atom_feed" rel="related" type="text/html" title="CrunchBang Linux on the Eee Pc"/><id>https://www.simonholywell.com/post/2009/04/memcached-and-apc-two-simple-techniques-to-speed-up-your/</id><author><name>Simon Holywell</name></author><published>2009-04-23T18:51:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Memcached and APC are two tools that you can install on your server and gain almost instant gratification! APC basically caches executions that you send to a PHP process so that the next time you ask the parser to run your script it only has to look for some pre-chewed opcode in memory rather than parsing your PHP from the disk. APC also has another feature up its sleeve, memory object caching, which allows you to store objects such as results from a database table in memory.</summary><content type="html"><![CDATA[<p><a href="http://www.danga.com/">Memcached</a> and <a href="http://php.net/apc">APC</a> are two tools that you can install on your server and gain almost instant gratification!  APC basically caches executions that you send to a PHP process so that the next time you ask the parser to run your script it only has to look for some pre-chewed opcode in memory rather than parsing your PHP from the disk.  APC also has another feature up its sleeve, memory object caching, which allows you to store objects such as results from a database table in memory.  Memcached works in much the same way, but it can be used as a session handler as well as a persistent store for object data.  Another advantage memcached has over APC is that it can be distributed so you could have a number of servers all maintaining memcached daemons to distribute the load.</p>
<p>APC is faster as a straight PHP call on the memory cache, but you can only access the memory cache from the local PHP process.  I have not tested it but I am unsure if that means you can access it from CLI PHP as well as via PHP running on Apache.  Often I will have a PHP frontend with any server scripts (for example cronjobs) written in Python so it is very handy to be able to access the cache from a central location, which with memcached is possible but not with APC as it is PHP specific.  For more information on performance and advice on when various caching methods may be more useful Peter over at MySQLPerformanceBlog has written an interest article <a href="http://www.mysqlperformanceblog.com/2006/08/09/cache-performance-comparison/">Cache Performance Comparison</a>.</p>
<p>So for code that I know will only ever be used by the local PHP process I store the object in the APC memory object store, but if I need portability or the server is under high load and I want to separate out my object cache server from my script server then I use memcached.</p>
<p>I have written two articles detailing the steps involved in installing both the binaries on <a href="/post/2009/03/installing-apc-and-memcached-for-php-sessions-on-redhat.html">RedHat Enterprise Linux</a> and <a href="/post/2009/04/installing-apc-and-memcached-for-php-sessions-on-ubuntu.html">Ubuntu or Debian</a>.  Currently the live servers I use are either running CentOS or RedHat and the local development server is very nice setup based upon Ubuntu.</p>
<p>The <a href="http://dev.myssql.com/doc/">MySQL documentation</a> contains a very nice set of examples and <a href="http://dev.mysql.com/doc/refman/5.0/en/ha-memcached.html">documentation on using memcached</a> to reduce hits on the database, which includes examples in a few languages including Python and PHP.  There is also some very handy hints to be gleened from <a href="http://www.search-this.com/2007/07/24/an-introduction-to-memcached/">An Introduction to memcached</a> by <a href="http://www.webhack.com/">Jeremy Ashcraft</a><a href="http://www.webhack.com/">a.k.a</a><a href="http://www.webhack.com/">MrSpooky</a> over at <a href="http://www.search-this.com">Search-This</a>.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="apache" label="apache"/><category scheme="taxonomy:Tags" term="debian" label="debian"/><category scheme="taxonomy:Tags" term="linux" label="linux"/><category scheme="taxonomy:Tags" term="memcached" label="memcached"/><category scheme="taxonomy:Tags" term="php" label="PHP"/><category scheme="taxonomy:Tags" term="ubuntu" label="ubuntu"/><category scheme="taxonomy:Tags" term="internet" label="Internet"/></entry><entry xml:base="installing-apc-and-memcached-for-php-sessions-on-ubuntu"><title type="html">Installing APC and Memcached for PHP Sessions on Ubuntu and Debi…</title><link href="https://www.simonholywell.com/post/2009/04/installing-apc-and-memcached-for-php-sessions-on-ubuntu/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2009/02/a-good-windows-development-environment-and-ubuntu-virtua/?utm_source=atom_feed" rel="related" type="text/html" title="A Good Windows Development Environment and Ubuntu Virtualbox"/><link href="https://www.simonholywell.com/post/2009/03/installing-apc-and-memcached-for-php-sessions-on-redhat/?utm_source=atom_feed" rel="related" type="text/html" title="Installing APC and Memcached for PHP Sessions on Redhat"/><link href="https://www.simonholywell.com/post/2009/03/using-phing-for-good-unfuddle-add-repository-and-svn-imp/?utm_source=atom_feed" rel="related" type="text/html" title="Using phing for good - Unfuddle Add Repository and SVN Import Ta…"/><link href="https://www.simonholywell.com/post/2009/01/enabling-sites-and-modules-in-apache-on-ubuntu-or-debian/?utm_source=atom_feed" rel="related" type="text/html" title="Enabling sites and modules in Apache on Ubuntu or Debian"/><link href="https://www.simonholywell.com/post/2009/03/crunchbang-linux-on-the-eee-pc/?utm_source=atom_feed" rel="related" type="text/html" title="CrunchBang Linux on the Eee Pc"/><id>https://www.simonholywell.com/post/2009/04/installing-apc-and-memcached-for-php-sessions-on-ubuntu/</id><author><name>Simon Holywell</name></author><published>2009-04-10T18:41:11+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Installing APC on Debian or Ubuntu is as simple as:
**user@server:/directory/$** sudo apt-get install php-apc
Now let us reboot the Apache process to enable our new cache:
**user@server:/directory/$** sudo /etc/init.d/apache2 restart
APC should now be ready to run on your server. Try running the following command to verify it is setup; you should get something in response like mine:
**user@server:/directory/$** php -r ‘phpinfo();’ | grep ‘apc’
apc MMAP File Mask =&amp;gt; /tmp/apc.</summary><content type="html"><![CDATA[<p>Installing APC on Debian or Ubuntu is as simple as:</p>
<blockquote>
<p><a href="mailto:**user@server">**user@server</a>:/directory/$** sudo apt-get install php-apc</p>
</blockquote>
<p>Now let us reboot the Apache process to enable our new cache:</p>
<blockquote>
<p><a href="mailto:**user@server">**user@server</a>:/directory/$** sudo /etc/init.d/apache2 restart</p>
</blockquote>
<p>APC should now be ready to run on your server.  Try running the following command to verify it is setup; you should get something in response like mine:</p>
<blockquote>
<p><a href="mailto:**user@server">**user@server</a>:/directory/$** php -r ‘phpinfo();’ | grep ‘apc’<br>
apc MMAP File Mask =&gt; /tmp/apc.s5jA6w apc.cache_by_default =&gt; On =&gt; On apc.coredump_unmap =&gt; Off =&gt; Off apc.enable_cli =&gt; On =&gt; On apc.enabled =&gt; On =&gt; On</p>
<p>&lt;…SNIP…&gt;</p>
</blockquote>
<p>Now lets move onto installing Memcached, which again is very simple:</p>
<blockquote>
<p><a href="mailto:**user@server">**user@server</a>:/directory/$<em>* sudo apt-get install memcached</em><a href="mailto:*user@server">*user@server</a>:/directory/$** /etc/init.d/memcached start</p>
</blockquote>
<p>The PHP Memcached module can be installed through Apt-Get as well:</p>
<blockquote>
<p><a href="mailto:**user@server">**user@server</a>:/directory/$** sudo apt-get install php5-memcache</p>
</blockquote>
<p>Now to configure PHP to use Memcached to store the session information we need to edit our /etc/php5/apache2/php.ini file and find the lines like the following:</p>
<blockquote>
<p>session.save_handler = files ;session.save_path =</p>
</blockquote>
<p>and change them so that they now look like this:</p>
<blockquote>
<p>session.save_handler = memcache session.save_path = “tcp://localhost:11211?persistent=1&amp;weight=1&amp;timeout=1&amp;retry_interval=15”</p>
</blockquote>
<p>That just leaves us to restart the Apache2 process:</p>
<blockquote>
<p><a href="mailto:**user@server">**user@server</a>:/directory/$** /etc/init.d/apache2 restart</p>
</blockquote>
<p>You are now up and running with Memcached PHP sessions and APC served PHP.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="apache" label="apache"/><category scheme="taxonomy:Tags" term="debian" label="debian"/><category scheme="taxonomy:Tags" term="linux" label="linux"/><category scheme="taxonomy:Tags" term="memcached" label="memcached"/><category scheme="taxonomy:Tags" term="modules" label="modules"/><category scheme="taxonomy:Tags" term="php" label="PHP"/><category scheme="taxonomy:Tags" term="ubuntu" label="ubuntu"/><category scheme="taxonomy:Tags" term="internet" label="Internet"/></entry><entry xml:base="haiku-os-progress"><title type="html">Haiku OS Progress</title><link href="https://www.simonholywell.com/post/2009/04/haiku-os-progress/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2009/03/using-phing-for-good-unfuddle-add-repository-and-svn-imp/?utm_source=atom_feed" rel="related" type="text/html" title="Using phing for good - Unfuddle Add Repository and SVN Import Ta…"/><link href="https://www.simonholywell.com/post/2009/03/installing-apc-and-memcached-for-php-sessions-on-redhat/?utm_source=atom_feed" rel="related" type="text/html" title="Installing APC and Memcached for PHP Sessions on Redhat"/><link href="https://www.simonholywell.com/post/2009/03/putty-and-control-s-or-ctrl-s/?utm_source=atom_feed" rel="related" type="text/html" title="PuTTY and Control + S or Ctrl + S"/><link href="https://www.simonholywell.com/post/2009/03/firefox-3-1-has-web-workers-threading-and-geolocation/?utm_source=atom_feed" rel="related" type="text/html" title="Firefox 3.1 has Web Workers (threading) and Geolocation"/><link href="https://www.simonholywell.com/post/2009/03/crunchbang-linux-on-the-eee-pc/?utm_source=atom_feed" rel="related" type="text/html" title="CrunchBang Linux on the Eee Pc"/><id>https://www.simonholywell.com/post/2009/04/haiku-os-progress/</id><author><name>Simon Holywell</name></author><published>2009-04-02T16:29:06+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>I have previously written about Haiku (formerly OpenBeOs) on my blog and I am pleased to say that I revisited this project last night and had a play with the latest nightly builds. It has moved on from the last time I look at it nearly 4 years ago now, but it still has some way to go before it will be a plug and play replacement for the old BeOS 5.</summary><content type="html"><![CDATA[<p><img src="/static/images/wp/2009/02/haiku.png" alt="Haiku OS Logo"></p>
<p>I have previously written about <a href="/post/2005/04/haiku-osopenbeos-an-open-source-beos-clone.html">Haiku</a> (formerly OpenBeOs) on my blog and I am pleased to say that I revisited this project last night and had a play with the latest nightly builds.  It has moved on from the last time I look at it nearly 4 years ago now, but it still has some way to go before it will be a plug and play replacement for the old BeOS 5.1 release.</p>
<p>Development is still moving ahead and I have managed to get it running on some older hardware I have so I can test it out. The codebase is about 70% complete according to the roadmap published on the Haiku website, which means that services I would consider vital for day to day use are yet to be completed.</p>
<p>I have always liked BeOs and since the recent and prolific release of netbooks onto the market I have been thinking ever more about it and how well it would serve these low spec machines. I have been running Ubuntu and Windows on netbooks and both are slow (with WindowsXP Home Edition gradually collapsing to a crawl).</p>
<p>One of the major blockers to this at the moment is the small set of drivers available for hardware on Haiku. There is a freeBSD driver compatibility layer in production, which should allow network drivers from BSD to run with little to no modification, but I am unsure of its progress. Wireless as yet is very limited and was not supported on the model I installed Haiku onto, which is very important for a netbook as you can imagine.</p>
<p>Haiku is looking very nice though and it also is now selfhosted, which means that you can checkout the latest copy of the source code and compile it from within your Haiku OS.  It has also been further improved by the inclusion of a native <a href="http://www.haiku-os.org/news/2009-01-31/haiku_finally_gets_a_native_gcc4_full_story_inside">GCC4+ compiler</a>, which should hopefully see faster implementation and porting of applications such as Firefox.</p>
<p>So a few major milestones have been hit but it is still not complete and unfortunately I am unable to recommend it as a complete desktop OS at this time, but I will definately be keeping my eye on it.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="beos" label="beos"/><category scheme="taxonomy:Tags" term="haiku" label="haiku"/></entry><entry xml:base="using-phing-for-good-unfuddle-add-repository-and-svn-imp"><title type="html">Using phing for good - Unfuddle Add Repository and SVN Import Ta…</title><link href="https://www.simonholywell.com/post/2009/03/using-phing-for-good-unfuddle-add-repository-and-svn-imp/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2009/02/a-good-windows-development-environment-and-ubuntu-virtua/?utm_source=atom_feed" rel="related" type="text/html" title="A Good Windows Development Environment and Ubuntu Virtualbox"/><link href="https://www.simonholywell.com/post/2009/03/installing-apc-and-memcached-for-php-sessions-on-redhat/?utm_source=atom_feed" rel="related" type="text/html" title="Installing APC and Memcached for PHP Sessions on Redhat"/><link href="https://www.simonholywell.com/post/2009/03/crunchbang-linux-on-the-eee-pc/?utm_source=atom_feed" rel="related" type="text/html" title="CrunchBang Linux on the Eee Pc"/><link href="https://www.simonholywell.com/post/2009/02/agavi-release-candidate-1/?utm_source=atom_feed" rel="related" type="text/html" title="Agavi Release Candidate 1"/><link href="https://www.simonholywell.com/post/2009/01/enabling-sites-and-modules-in-apache-on-ubuntu-or-debian/?utm_source=atom_feed" rel="related" type="text/html" title="Enabling sites and modules in Apache on Ubuntu or Debian"/><id>https://www.simonholywell.com/post/2009/03/using-phing-for-good-unfuddle-add-repository-and-svn-imp/</id><author><name>Simon Holywell</name></author><published>2009-03-24T20:13:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>As you may be aware I have recently been playing with the excellent Agavi framework and it introduced me to the interesting phing tool. Phing can be used to automate tasks with build files that are close to interoperable with Apache Ant, which uses XML files to configure builds. The advantage phing has for us PHP users is that it is entirely written in PHP so extending it is as simple as adding a new class.</summary><content type="html"><![CDATA[<p>As you may be aware I have recently been playing with the excellent <a href="http://www.agavi.org">Agavi framework</a> and it introduced me to the interesting <a href="http://www.phing.info">phing</a> tool.  Phing can be used to automate tasks with build files that are close to interoperable with <a href="http://ant.apache.org/">Apache Ant</a>, which uses XML files to configure builds.  The advantage phing has for us PHP users is that it is entirely written in PHP so extending it is as simple as adding a new class.</p>
<p>On a few recent projects I did just that when I need the ability to perform SVN Import and access <a href="http://www.unfuddle.com/">Unfuddle</a>’s API to create a new repository on the fly.  Essentially my build file was creating a new website using a CMS and then creates a new repository for it and imports the newly built CMS automatically.  This was all written to use Unfuddle’s SVN but the add repository task should be able to be used to create a new <a href="http://git-scm.com/">git</a> repository as well.  The Unfuddle side of things was completed with refactoring and building upon <a href="http://codeinthehole.com/archives/15-Phing-task-to-create-an-Unfuddle-message.html">David Winterbottom</a>’s work, which was originally intended to send Unfuddle messages.</p>
<p><strong>Please find the code hosted on <a href="http://www.github.com">github</a> in <a href="http://github.com/treffynnon/phing/tree/master">my phing repo</a>.</strong></p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="agavi" label="agavi"/><category scheme="taxonomy:Tags" term="apache" label="apache"/><category scheme="taxonomy:Tags" term="git" label="git"/><category scheme="taxonomy:Tags" term="linux" label="linux"/><category scheme="taxonomy:Tags" term="phing" label="phing"/><category scheme="taxonomy:Tags" term="php" label="PHP"/><category scheme="taxonomy:Tags" term="subversion" label="subversion"/><category scheme="taxonomy:Tags" term="ubuntu" label="ubuntu"/></entry><entry xml:base="installing-apc-and-memcached-for-php-sessions-on-redhat"><title type="html">Installing APC and Memcached for PHP Sessions on Redhat</title><link href="https://www.simonholywell.com/post/2009/03/installing-apc-and-memcached-for-php-sessions-on-redhat/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2009/02/a-good-windows-development-environment-and-ubuntu-virtua/?utm_source=atom_feed" rel="related" type="text/html" title="A Good Windows Development Environment and Ubuntu Virtualbox"/><link href="https://www.simonholywell.com/post/2009/02/agavi-release-candidate-1/?utm_source=atom_feed" rel="related" type="text/html" title="Agavi Release Candidate 1"/><link href="https://www.simonholywell.com/post/2009/01/linux-to-windows-server-migrating-and-securing-your-cron/?utm_source=atom_feed" rel="related" type="text/html" title="Linux to Windows Server - Migrating and securing your crontab"/><link href="https://www.simonholywell.com/post/2009/01/agavi-1-0-beta-on-xampp-1-7-0/?utm_source=atom_feed" rel="related" type="text/html" title="Agavi 1.0 Beta on XAMPP 1.7.0"/><link href="https://www.simonholywell.com/post/2008/12/freelancers-costing-your-work/?utm_source=atom_feed" rel="related" type="text/html" title="Freelancers: Costing your work"/><id>https://www.simonholywell.com/post/2009/03/installing-apc-and-memcached-for-php-sessions-on-redhat/</id><author><name>Simon Holywell</name></author><published>2009-03-23T17:42:18+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Installing APC on Redhat is as simple as:
[user@server directory]# yum install php-pecl-apc
APC should now be ready to run on your server. Try running the following command to verify it is setup; you should get something in response like mine:
[user@server directory]# php -r ‘phpinfo();’ | grep ‘apc’
apc MMAP File Mask =&amp;gt; /tmp/apc.s5jA6w apc.cache_by_default =&amp;gt; On =&amp;gt; On apc.coredump_unmap =&amp;gt; Off =&amp;gt; Off apc.enable_cli =&amp;gt; On =&amp;gt; On apc.</summary><content type="html"><![CDATA[<p>Installing APC on Redhat is as simple as:</p>
<blockquote>
<p><strong>[<a href="mailto:user@server">user@server</a> directory]#</strong> yum install php-pecl-apc</p>
</blockquote>
<p>APC should now be ready to run on your server.  Try running the following command to verify it is setup; you should get something in response like mine:</p>
<blockquote>
<p><strong>[<a href="mailto:user@server">user@server</a> directory]#</strong> php -r ‘phpinfo();’ | grep ‘apc’<br>
apc MMAP File Mask =&gt; /tmp/apc.s5jA6w apc.cache_by_default =&gt; On =&gt; On apc.coredump_unmap =&gt; Off =&gt; Off apc.enable_cli =&gt; On =&gt; On apc.enabled =&gt; On =&gt; On</p>
<p>&lt;…SNIP…&gt;</p>
</blockquote>
<p>Now lets move onto installing Memcached, which again is very simple:</p>
<blockquote>
<p><strong>[<a href="mailto:user@server">user@server</a> directory]#</strong> yum install memcached<br>
<strong>[<a href="mailto:user@server">user@server</a> directory]#</strong> /etc/init.d/memcached start</p>
<p>The PHP Memcached module can be installed through YUM as well:</p>
</blockquote>
<blockquote>
<p><strong>[<a href="mailto:user@server">user@server</a> directory]#</strong> yum install php-pecl-memcache</p>
</blockquote>
<p>Now to configure PHP to use Memcached to store the session information we need to edit our /etc/php.d/memcache.ini file and jump to the bottom of the file where we uncomment the following lines by removing the preceeding semicolon (‘;’):</p>
<blockquote>
<p>; Options to use the memcache session handler</p>
<p>; Use memcache as a session handler ; session.save_handler=memcache ; Defines a comma separated of server urls to use for session storage</p>
<p>;session.save_path=“tcp://localhost:11211?persistent=1&amp;weight=1&amp;timeout=1&amp;retry_interval=15”</p>
</blockquote>
<p>So that it now looks like this:</p>
<blockquote>
<p>; Options to use the memcache session handler</p>
<p>; Use memcache as a session handler session.save_handler=memcache ; Defines a comma separated of server urls to use for session storage</p>
<p>session.save_path=“tcp://localhost:11211?persistent=1&amp;weight=1&amp;timeout=1&amp;retry_interval=15”</p>
</blockquote>
<p>That just leaves us to restart the Apache/HTTPd process:</p>
<blockquote>
<p><strong>[<a href="mailto:user@server">user@server</a> directory]#</strong> /etc/init.d/httpd restart</p>
</blockquote>
<p>You are now up and running with Memcached PHP sessions and APC served PHP.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="linux" label="linux"/><category scheme="taxonomy:Tags" term="memcached" label="memcached"/><category scheme="taxonomy:Tags" term="modules" label="modules"/><category scheme="taxonomy:Tags" term="php" label="PHP"/><category scheme="taxonomy:Tags" term="redhat" label="redhat"/><category scheme="taxonomy:Tags" term="internet" label="Internet"/></entry><entry xml:base="putty-and-control-s-or-ctrl-s"><title type="html">PuTTY and Control + S or Ctrl + S</title><link href="https://www.simonholywell.com/post/2009/03/putty-and-control-s-or-ctrl-s/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2009/03/crunchbang-linux-on-the-eee-pc/?utm_source=atom_feed" rel="related" type="text/html" title="CrunchBang Linux on the Eee Pc"/><link href="https://www.simonholywell.com/post/2009/02/a-good-windows-development-environment-and-ubuntu-virtua/?utm_source=atom_feed" rel="related" type="text/html" title="A Good Windows Development Environment and Ubuntu Virtualbox"/><link href="https://www.simonholywell.com/post/2009/01/securing-ssh-with-key-based-authentication/?utm_source=atom_feed" rel="related" type="text/html" title="Securing SSH with Key Based Authentication"/><link href="https://www.simonholywell.com/post/2009/01/linux-to-windows-server-migrating-and-securing-your-cron/?utm_source=atom_feed" rel="related" type="text/html" title="Linux to Windows Server - Migrating and securing your crontab"/><link href="https://www.simonholywell.com/post/2008/05/suzuki-bandit-carburettor-clean/?utm_source=atom_feed" rel="related" type="text/html" title="Suzuki Bandit Carburettor Clean"/><id>https://www.simonholywell.com/post/2009/03/putty-and-control-s-or-ctrl-s/</id><author><name>Simon Holywell</name></author><published>2009-03-16T16:05:21+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>As you have found this page I am sure you have accidentally hit the control+s short cut whilst inside a PuTTY shell and following that no keystrokes appear to affect the session. Basically hitting ctrl+s causes PuTTY to stop executing the stream coming in from the keyboard. It does however still listen to your keystrokes and it basically adds them to a queue.
Hitting control+q will re-open the stream execution, but it is worthwhile noting that it will also execute all the queued up commands as well!</summary><content type="html">&lt;p>As you have found this page I am sure you have accidentally hit the control+s short cut whilst inside a PuTTY shell and following that no keystrokes appear to affect the session. Basically hitting ctrl+s causes PuTTY to stop executing the stream coming in from the keyboard. It does however still listen to your keystrokes and it basically adds them to a queue.&lt;/p>
&lt;p>Hitting control+q will re-open the stream execution, but it is worthwhile noting that it will also execute all the queued up commands as well!&lt;/p></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="linux" label="linux"/><category scheme="taxonomy:Tags" term="maintenance" label="maintenance"/><category scheme="taxonomy:Tags" term="ssh" label="ssh"/></entry><entry xml:base="firefox-3-1-has-web-workers-threading-and-geolocation"><title type="html">Firefox 3.1 has Web Workers (threading) and Geolocation</title><link href="https://www.simonholywell.com/post/2009/03/firefox-3-1-has-web-workers-threading-and-geolocation/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2009/02/agavi-release-candidate-1/?utm_source=atom_feed" rel="related" type="text/html" title="Agavi Release Candidate 1"/><link href="https://www.simonholywell.com/post/2009/02/a-good-windows-development-environment-and-ubuntu-virtua/?utm_source=atom_feed" rel="related" type="text/html" title="A Good Windows Development Environment and Ubuntu Virtualbox"/><link href="https://www.simonholywell.com/post/2009/01/securing-ssh-with-key-based-authentication/?utm_source=atom_feed" rel="related" type="text/html" title="Securing SSH with Key Based Authentication"/><link href="https://www.simonholywell.com/post/2009/01/linux-to-windows-server-migrating-and-securing-your-cron/?utm_source=atom_feed" rel="related" type="text/html" title="Linux to Windows Server - Migrating and securing your crontab"/><link href="https://www.simonholywell.com/post/2009/01/agavi-1-0-beta-on-xampp-1-7-0/?utm_source=atom_feed" rel="related" type="text/html" title="Agavi 1.0 Beta on XAMPP 1.7.0"/><id>https://www.simonholywell.com/post/2009/03/firefox-3-1-has-web-workers-threading-and-geolocation/</id><author><name>Simon Holywell</name></author><published>2009-03-11T18:42:27+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>The latest beta 2 release includes web workers, which are essentially threads allowing you to farm off Javascript heavy lifting to background processes so that the interface can continue to load without being impacted upon. The Mozilla developer center [sic] has an interesting article on implementing them; Using web workers, which includes a couple of worked examples based on the Fibonacci sequence.
Geolocation is an interesting one for services like Twitter, Jaiku and possibly Facebook as it would allow users an easy way of updating all the services with their current location simply by Firefox broadcasting the information.</summary><content type="html"><![CDATA[<p><img src="/static/images/wp/2009/03/logo-wordmark-version-verti.jpg" alt="Firefox 3 Logo"></p>
<p>The latest beta 2 release includes <a href="https://developer.mozilla.org/En/DOM/Worker">web workers</a>, which are essentially threads allowing you to farm off Javascript heavy lifting to background processes so that the interface can continue to load without being impacted upon.  The <a href="http://developer.mozilla.org">Mozilla developer center</a> [<em>sic</em>] has an interesting article on implementing them; <a href="https://developer.mozilla.org/En/Using_web_workers">Using web workers</a>, which includes a couple of worked examples based on the <a href="http://www.textism.com/bucket/fib.html">Fibonacci sequence</a>.</p>
<p>Geolocation is an interesting one for services like <a href="http://www.twitter.com/treffynnon">Twitter</a>, <a href="http://treffynnon.jaiku.com">Jaiku</a> and possibly <a href="http://www.facebook.com">Facebook</a> as it would allow users an easy way of updating all the services with their current location simply by Firefox broadcasting the information.  But even more interestly <a href="http://maps.yahoo.com">Yahoo!</a> and <a href="http://maps.google.com">Google</a> maps (or a custom implementation of them – I am tempted but do not have the time at the moment) could use it to real time track the location of a user.  So potentially you could use the maps like a satellite navigation application with the <a href="https://developer.mozilla.org/En/Using_geolocation#Watching_the_current_position">watchPosition()</a> function all the user would need is a GPS mouse with a Firefox plugin to read the position from it.  Oh yes and of course they would need a laptop with Firefox installed on it and a mobile internet connection. :-)</p>
<p>Obviously for any of this to work you will need to be running the <a href="http://www.mozilla.com/en-US/firefox/3.1b2/releasenotes/#whatsnew">latest beta</a> available from the Mozilla site.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="firefox" label="firefox"/><category scheme="taxonomy:Tags" term="javascript" label="Javascript"/><category scheme="taxonomy:Tags" term="mozilla" label="mozilla"/><category scheme="taxonomy:Tags" term="internet" label="Internet"/></entry><entry xml:base="crunchbang-linux-on-the-eee-pc"><title type="html">CrunchBang Linux on the Eee Pc</title><link href="https://www.simonholywell.com/post/2009/03/crunchbang-linux-on-the-eee-pc/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2009/02/a-good-windows-development-environment-and-ubuntu-virtua/?utm_source=atom_feed" rel="related" type="text/html" title="A Good Windows Development Environment and Ubuntu Virtualbox"/><link href="https://www.simonholywell.com/post/2009/01/enabling-sites-and-modules-in-apache-on-ubuntu-or-debian/?utm_source=atom_feed" rel="related" type="text/html" title="Enabling sites and modules in Apache on Ubuntu or Debian"/><link href="https://www.simonholywell.com/post/2009/01/securing-ssh-with-key-based-authentication/?utm_source=atom_feed" rel="related" type="text/html" title="Securing SSH with Key Based Authentication"/><link href="https://www.simonholywell.com/post/2009/01/linux-to-windows-server-migrating-and-securing-your-cron/?utm_source=atom_feed" rel="related" type="text/html" title="Linux to Windows Server - Migrating and securing your crontab"/><link href="https://www.simonholywell.com/post/2005/11/hardening-ssh/?utm_source=atom_feed" rel="related" type="text/html" title="Hardening SSH"/><id>https://www.simonholywell.com/post/2009/03/crunchbang-linux-on-the-eee-pc/</id><author><name>Simon Holywell</name></author><published>2009-03-10T18:09:51+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>So far I have tried out Ubuntu, eeeBuntu, EasyPeasy Linux and CrunchBang Linux (all of which are Debian based) on the Asus Eee PC. Ubuntu was a bit of an annoyance to get setup and it was troublesome trying to get all the buttons or the sound and microphone to work so I then tried EasyPeasy. It was easy to install (it already contains the Array.org kernal) and I liked the NBR interface with its easy to use tabbed system not to mention that after using Ubuntu it was nice to be able to see most of the system dialogues on screen (Ubuntu’s dialogues were so long they fell off screen!</summary><content type="html"><![CDATA[<p>So far I have tried out <a href="http://www.ubuntu.com/">Ubuntu</a>, <a href="http://www.eeebuntu.org/">eeeBuntu</a>, <a href="http://www.geteasypeasy.com/">EasyPeasy Linux</a> and <a href="http://crunchbanglinux.org/">CrunchBang Linux</a> (all of which are Debian based) on the Asus Eee PC.  Ubuntu was a bit of an annoyance to get setup and it was troublesome trying to get all the buttons or the sound and microphone to work so I then tried EasyPeasy.  It was easy to install (it already contains the Array.org kernal) and I liked the NBR interface with its easy to use tabbed system not to mention that after using Ubuntu it was nice to be able to see most of the system dialogues on screen (Ubuntu’s dialogues were so long they fell off screen! – Hint: hold down alt and click to move dialogues without titlebars).  The major problem I had with it was that it took way too long to boot and came preloaded with a whole host of applications I will never need.</p>
<p>So after some research I saw a lot of good things being said about eeeBuntu, which again in the version I chose uses the NBR interface.  Also whilst it was very nice to use not everything worked, which was very annoying.  The microphone and some of the shortcut buttons did not work, which is useless if you need to use Skype.  The selection of preloaded applications was also not to my tastes (although better than EasyPeasy) and boot time was also quite painful although not as bad as EasyPeasy.  Speaking of boot times make sure you remove any SD cards from the onboard slot before booting the machine as this will add significantly to the load time of the OS.</p>
<p>After using eeeBuntu for some time I finally grew tired of the lag and decided it was time to do some more research into the available packages for easy installing on the Eee PC.  This is when I came across CrunchBang (#!) Linux, which is a very light weight version of Ubuntu running the <a href="http://icculus.org/openbox/index.php/Main_Page">Openbox</a> shell.  This distro boots quickly, comes with a nice set of applications that I can easily build upon.  I am really pleased with the OS so far and I am even writing this post from within it.</p>
<p>Installation is very simple just use <a href="http://unetbootin.sourceforge.net/">UNetbootin</a> to transfer the Cruncheee image to a USB key and boot from the USB key to try out the ‘live disc’ version of the OS to see if it is for you.  If you like it then right click on the desktop and choose install from the resultant menu.</p>
<p>Not everything will work right of the box though.  The microphone does not record immediately and requires some tweeking to the Volume Control interface.  You can bring up the interface by pressing the shortcut Super + v (in my case the Super key is emblazoned with the Windows logo).  Now click the preferences button at the bottom of the dialogue and check the boxes beside Front Mic Boost, Capture and Input Source.  Now in the playback tab unmute Front Mic and raise the volume, on the recording tab unmute the microphone icon and raise the volume and finally on the options tab choose Front Mic from the drop down.</p>
<p>Unfortunately there is one further annoyance.  The volume buttons do not bring up the on screen display but Super + v will bring up the mixer which is fine for me at the moment.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="debian" label="debian"/><category scheme="taxonomy:Tags" term="linux" label="linux"/><category scheme="taxonomy:Tags" term="ubuntu" label="ubuntu"/></entry><entry xml:base="agavi-release-candidate-1"><title type="html">Agavi Release Candidate 1</title><link href="https://www.simonholywell.com/post/2009/02/agavi-release-candidate-1/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2009/01/agavi-1-0-beta-on-xampp-1-7-0/?utm_source=atom_feed" rel="related" type="text/html" title="Agavi 1.0 Beta on XAMPP 1.7.0"/><link href="https://www.simonholywell.com/post/2008/12/freelancers-costing-your-work/?utm_source=atom_feed" rel="related" type="text/html" title="Freelancers: Costing your work"/><link href="https://www.simonholywell.com/post/2008/05/installing-agavi-on-xampp-windows/?utm_source=atom_feed" rel="related" type="text/html" title="Installing Agavi on XAMPP Windows"/><link href="https://www.simonholywell.com/post/2006/12/geographic-calculations-in-php/?utm_source=atom_feed" rel="related" type="text/html" title="Geographic Calculations in PHP"/><link href="https://www.simonholywell.com/post/2006/03/form-spam-not-ham/?utm_source=atom_feed" rel="related" type="text/html" title='Form SPAM (not "HAM") fighting tips'/><id>https://www.simonholywell.com/post/2009/02/agavi-release-candidate-1/</id><author><name>Simon Holywell</name></author><published>2009-02-22T16:50:22+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>A bit slow off the mark with this one but Agavi 1RC1 has been released and it is of course looking very nice. The 1.0 feature set is complete and potential bug fixes are the only things standing between now and 1.0 in earnest. Features that I am particularly interested in include the recent refactoring of the configuration/routing files, the new validation interface and the addition of unit testing to the framework.</summary><content type="html"><![CDATA[<p><img src="/static/images/wp/2009/02/agavi.jpg" alt="Agavi Framework Logo"></p>
<p>A bit slow off the mark with this one but Agavi 1RC1 has been released and it is of course looking very nice. The 1.0 feature set is complete and potential bug fixes are the only things standing between now and 1.0 in earnest.  Features that I am particularly interested in include the recent refactoring of the configuration/routing files, the new validation interface and the addition of unit testing to the framework.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="agavi" label="agavi"/><category scheme="taxonomy:Tags" term="php" label="PHP"/><category scheme="taxonomy:Tags" term="internet" label="Internet"/></entry><entry xml:base="a-good-windows-development-environment-and-ubuntu-virtua"><title type="html">A Good Windows Development Environment and Ubuntu Virtualbox</title><link href="https://www.simonholywell.com/post/2009/02/a-good-windows-development-environment-and-ubuntu-virtua/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2009/01/enabling-sites-and-modules-in-apache-on-ubuntu-or-debian/?utm_source=atom_feed" rel="related" type="text/html" title="Enabling sites and modules in Apache on Ubuntu or Debian"/><link href="https://www.simonholywell.com/post/2009/01/securing-ssh-with-key-based-authentication/?utm_source=atom_feed" rel="related" type="text/html" title="Securing SSH with Key Based Authentication"/><link href="https://www.simonholywell.com/post/2009/01/linux-to-windows-server-migrating-and-securing-your-cron/?utm_source=atom_feed" rel="related" type="text/html" title="Linux to Windows Server - Migrating and securing your crontab"/><link href="https://www.simonholywell.com/post/2008/06/xampp-virtualhosts/?utm_source=atom_feed" rel="related" type="text/html" title="XAMPP VirtualHosts"/><link href="https://www.simonholywell.com/post/2005/08/serving-virtual-hosts/?utm_source=atom_feed" rel="related" type="text/html" title="Serving Virtual Hosts"/><id>https://www.simonholywell.com/post/2009/02/a-good-windows-development-environment-and-ubuntu-virtua/</id><author><name>Simon Holywell</name></author><published>2009-02-18T16:07:40+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Often Linux just does it better! Often I find myself developing a Windows machine without access to a Linux development server, but I still need to access to some of the Linux binaries and features such as cron jobs, the at command and binaries such as imagemagick, pdftotext, etc. Some things can be emulated with ported binaries or through Cygwin, but I feel a lot more comfortable developing on a platform that is representative of the live server the web site will run on.</summary><content type="html"><![CDATA[<p><img src="/static/images/wp/2009/02/how_to-virtualbox_logo.png" alt="Sun VirtualBox Logo"></p>
<p>Often Linux just does it better!  Often I find myself developing a Windows machine without access to a Linux development server, but I still need to access to some of the Linux binaries and features such as cron jobs, the at command and binaries such as imagemagick, pdftotext, etc.  Some things can be emulated with ported binaries or through Cygwin, but I feel a lot more comfortable developing on a platform that is representative of the live server the web site will run on.</p>
<p>I have not removed <a href="http://www.apachefriends.org/">XAMPP</a> as it is very useful for developing small scripts or sites without the overhead of running a virtual machine.  Therein lies the problem with this solution – it is virtual machine based and that will mean your local development machine will suffer when the virtual machine steals computing time from the CPU or more memory.  So whilst I can use XAMPP on my netbook I am not so sure a VM will run smoothly.</p>
<h1 id="setting-up-a-new-development-environment">Setting up a new development environment</h1>
<ol>
<li>
<p>Download VirtualBox 2.1 from <a href="http://www.virtualbox.org"><a href="http://www.virtualbox.org">http://www.virtualbox.org</a></a></p>
</li>
<li>
<p>Download the latest Ubuntu from <a href="http://www.ubuntu.com"><a href="http://www.ubuntu.com">http://www.ubuntu.com</a></a> Your choice of server or desktop. I chose desktop to give me another web browser testing environment.</p>
</li>
<li>
<p>Install VirtualBox and open it up</p>
<ol>
<li>
<p>Click create new VM (Virtual Machine)</p>
</li>
<li>
<p>Give your VM name (I called mine Development)</p>
</li>
<li>
<p>From the drop downs choose</p>
<ol>
<li>Linux</li>
<li>Ubuntu (only choose Ubuntu 64 bit if you are running 64 bit Windows)</li>
</ol>
</li>
<li>
<p>Choose how much of your machines physical memory the virtual machine is allowed to steal. I chose 512MB as I am running the desktop version of Ubuntu.</p>
</li>
<li>
<p>You will need to create a new virtual hard disk – a new hard disk wizard will open</p>
<ol>
<li>Choose dynamically expanding storage</li>
<li>Choose
<ol>
<li>Give the virtual hard disk a name (mine is called Development just like my virtual machine)</li>
<li>The location of the storage on your hard drive</li>
</ol>
</li>
</ol>
</li>
</ol>
</li>
<li>
<p>Now your new virtual machine should be setup so right click on it and choose Start</p>
<ol>
<li>
<p>The Virtual Machine will pop up a message asking you to go through its first run wizard</p>
</li>
<li>
<p>Choose your installation location</p>
<ol>
<li>CD/DVD ROM</li>
<li>Image file – point this to the location of your Ubuntu installation ISO you downloaded and saved earlier</li>
</ol>
</li>
<li>
<p>This will then mount your CD image and boot from it</p>
</li>
</ol>
</li>
<li>
<p>Install Ubuntu by going through its installation wizard which is very easy and does not require detail here (if you have chosen the desktop version this will be even easier because you can use the mouse!)</p>
</li>
<li>
<p>Once you have the virtual machine setup you will want the nice Linux drivers so you can have a larger screen size and for networking etc. For this you need to install the Virtual Guest Additions.</p>
<ol>
<li>Mount a new CD drive/ISO Image in your virtual machine whilst it is running from the top menu item called Devices</li>
<li>Add the new image which you will find in your VirtualBox program folder</li>
</ol>
</li>
<li>
<p>Back to your virtual machine and open up a terminal window</p>
<ol>
<li>In your terminal navigate to the CD Rom drive</li>
<li>Execute the following command sudo sh ./VBoxLinuxAdditions-x86.run</li>
<li>Once complete you need to reboot the machine so execute sudo reboot</li>
</ol>
</li>
<li>
<p>Once the machine reboots get back into the terminal and run the following commands</p>
<ol>
<li>sudo apt-get update</li>
<li>sudo apt-get upgrade</li>
<li>sudo apt-get install apache2 mysql-server-5.0 php5 php5-xdebug</li>
<li>Just to be on the safe side restart apache with sudo /etc/init.d/apache2 restart</li>
<li>Try accessing your web server by opening a web browser in the virtual machine and typing in localhost if you chose the desktop and you should see a message like It Works!</li>
</ol>
</li>
<li>
<p>We need to be able to see folders on our host machine inside the development machine quickly and easy so from the top menu bar choose Devices -&gt; Shared Folders</p>
<ol>
<li>Add a new folder</li>
<li>Tell it which folder to look in</li>
<li>Give it a memorable name</li>
<li>Tick make permanent</li>
</ol>
</li>
<li>
<p>Jump back into the virtual machine and execute the following commands to add your shared folder to the virtual machine, in a terminal</p>
<ol>
<li>
<p>sudo mkdir /mnt/yourFolderNameHere (mine is /mnt/htdocs/)</p>
</li>
<li>
<p>sudo mount -t vboxsf memorableFolderName /mnt/yourFolderNameHere</p>
<ol>
<li>Replace memorableFolderName with name you set in step 9.III</li>
<li>Replace /mnt/yourFolderNameHere with the folder you made in step 10.I</li>
</ol>
</li>
<li>
<p>If you navigate to /mnt/yourFolderNameHere and execute ls you should see a list of the files on your host systems shared folder</p>
</li>
<li>
<p>If that worked then we want to add our folder to the fstab file so that the mount point is loaded every time our virtual machine boots up</p>
<ol>
<li>
<p>sudo vim /etc/fstab</p>
</li>
<li>
<p>Add the following line to the bottom of the file:<br>
memorableFolderName /mnt/yourFolderNameHere vboxsf defaults 0 0</p>
<ol>
<li>Replace memorableFolderName with name you set in step 9.III</li>
<li>Replace /mnt/yourFolderNameHere with the folder you made in step 10.I</li>
</ol>
</li>
</ol>
</li>
</ol>
</li>
<li>
<p>Now to make this development machine available over the network shut the virtual machine down by going to top menu bar Machine -&gt; Close and choosing Power Off</p>
<ol>
<li>
<p>Right click on the virtual machine and choose settings</p>
</li>
<li>
<p>From the left hand menu choose Network</p>
<ol>
<li>Tick Enable Adapter</li>
<li>Adapter Type: Intel PRO/1000 T Server</li>
<li>Attached to: Host Interface</li>
<li>Tick Cable Connected</li>
<li>Choose the interface on your host machine that gives you access to the outside world. You can find out which one this is by looking in your control panel.</li>
</ol>
</li>
<li>
<p>Save the settings and start your virtual machine back up again</p>
</li>
<li>
<p>To find out the IP address of your virtual machine open a terminal execute ifconfig</p>
</li>
</ol>
</li>
<li>
<p>You should now be able to visit your web server from your host machine by entering that IP address into your web browser.</p>
</li>
</ol>
<h1 id="configuring-our-web-server">Configuring our web server</h1>
<ol>
<li>
<p>We need to enable mod_rewrite which involves making a simple symbolic link</p>
<ol>
<li>Navigate to /etc/apache2/mods-enabled</li>
<li>Execute sudo ln -s /etc/apache2/mods-available/rewrite.load rewrite.load</li>
</ol>
</li>
<li>
<p>Reboot the server sudo /etc/init.d/apache2 restart and test it is function ok.</p>
</li>
</ol>
<h1 id="setting-up-mass-virtual-hosts">Setting up Mass Virtual hosts</h1>
<p>The idea behind this step is to minimise the time it takes to setup a new host on the server. Basically all you have to do is create a new directory an away you go. (Don’t forget it will still need to appear in your hosts file).</p>
<ol>
<li>
<p>We need to enable mod_vhost_alias</p>
<ol>
<li>Navigate to /etc/apache2/mods-enabled</li>
<li>Execute sudo ln -s /etc/apache2/mods-available/vhost_alias.load vhost_alias.load</li>
</ol>
</li>
<li>
<p>Now to setup the rules it will create virtual hosts by</p>
<ol>
<li>
<p>Execute sudo vim /etc/apache2/apache2.conf</p>
</li>
<li>
<p>Go to the base of the file and add the following rules:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-apacheconf" data-lang="apacheconf"><span class="line"><span class="cl"><span class="c"># Mass Virtual Hosting</span>
</span></span><span class="line"><span class="cl"><span class="nb">UseCanonicalName</span> <span class="k">Off</span>
</span></span><span class="line"><span class="cl"><span class="nb">LogFormat</span> <span class="s2">&#34;%V %h %l %u %t \&#34;%r\&#34; %s %b&#34;</span> vcommon
</span></span><span class="line"><span class="cl"><span class="nb">CustomLog</span> <span class="sx">/var/log/apache2/access.log</span> vcommon
</span></span><span class="line"><span class="cl"><span class="nb">VirtualDocumentRoot</span> <span class="sx">/mnt/htdocs/</span>%1
</span></span><span class="line"><span class="cl"><span class="nt">&lt;Directory</span> <span class="s">/mnt/htdocs/</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nb">Options</span> Indexes FollowSymLinks MultiViews
</span></span><span class="line"><span class="cl">    <span class="nb">AllowOverride</span> <span class="k">All</span>
</span></span><span class="line"><span class="cl">    <span class="nb">Order</span> allow,deny
</span></span><span class="line"><span class="cl">    <span class="nb">Allow</span> from <span class="k">all</span>
</span></span><span class="line"><span class="cl"><span class="nt">&lt;/Directory&gt;</span>
</span></span></code></pre></div><p>VirtualDocumentRoot sets the directory that the VHosts public directory is contained in. This will basically convert <a href="http://subdomain.localhost/">http://subdomain.localhost/</a> to /mnt/htdocs/subdomain and pull the relevant files through.</p>
</li>
</ol>
</li>
<li>
<p>Now restart the apache process sudo /etc/init.d/apache2 restart</p>
</li>
</ol>
<p>A side note when using this method that you should be aware of. This will affect your rewrite rules if they are placed into a .htaccess file. To avoid any problems always declare the RewriteBase rule in your .htaccess.</p>
<p>For example:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-apacheconf" data-lang="apacheconf"><span class="line"><span class="cl"><span class="nt">&lt;IfModule</span> <span class="s">mod_rewrite.c</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nb">RewriteEngine</span> <span class="k">On</span>
</span></span><span class="line"><span class="cl">    <span class="nb">RewriteBase</span> /
</span></span><span class="line"><span class="cl">    <span class="nb">RewriteCond</span> %{REQUEST_FILENAME} !-d
</span></span><span class="line"><span class="cl">    <span class="nb">RewriteCond</span> %{REQUEST_FILENAME} !-f
</span></span><span class="line"><span class="cl">    <span class="nb">RewriteRule</span> ^(.*)$ index.php?url=$1 [QSA,L]
</span></span><span class="line"><span class="cl"><span class="nt">&lt;/IfModule&gt;</span>
</span></span></code></pre></div><h1 id="virtualbox-shared-folders-permissions">VirtualBox Shared Folders Permissions</h1>
<p>Currently you maybe having permissions issues with your shared folders because they might be being mounted as root:root.  To get them to load with a specified user and group you will need to edit your /etc/fstab file again and change ‘defaults‘ to be ‘uid=username,gid=groupname‘ – an example would be ‘uid=simon,gid=www-data‘.</p>
<p>A full line example would be from:<br>
<code>htdocs /mnt/htdocs vboxsf defaults 0 0</code> to <code>htdocs /mnt/htdocs vboxsf uid=simon,gid=www-data 0 0</code></p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="apache" label="apache"/><category scheme="taxonomy:Tags" term="debian" label="debian"/><category scheme="taxonomy:Tags" term="linux" label="linux"/><category scheme="taxonomy:Tags" term="modules" label="modules"/><category scheme="taxonomy:Tags" term="mysql" label="Mysql"/><category scheme="taxonomy:Tags" term="ubuntu" label="ubuntu"/><category scheme="taxonomy:Tags" term="virtualhosting" label="virtualhosting"/><category scheme="taxonomy:Tags" term="windows" label="windows"/><category scheme="taxonomy:Tags" term="xampp" label="xampp"/><category scheme="taxonomy:Tags" term="internet" label="Internet"/></entry><entry xml:base="enabling-sites-and-modules-in-apache-on-ubuntu-or-debian"><title type="html">Enabling sites and modules in Apache on Ubuntu or Debian</title><link href="https://www.simonholywell.com/post/2009/01/enabling-sites-and-modules-in-apache-on-ubuntu-or-debian/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2009/01/securing-ssh-with-key-based-authentication/?utm_source=atom_feed" rel="related" type="text/html" title="Securing SSH with Key Based Authentication"/><link href="https://www.simonholywell.com/post/2005/08/serving-virtual-hosts/?utm_source=atom_feed" rel="related" type="text/html" title="Serving Virtual Hosts"/><link href="https://www.simonholywell.com/post/2008/06/xampp-virtualhosts/?utm_source=atom_feed" rel="related" type="text/html" title="XAMPP VirtualHosts"/><link href="https://www.simonholywell.com/post/2005/11/hardening-ssh/?utm_source=atom_feed" rel="related" type="text/html" title="Hardening SSH"/><link href="https://www.simonholywell.com/post/2005/11/mod-security/?utm_source=atom_feed" rel="related" type="text/html" title="Mod Security"/><id>https://www.simonholywell.com/post/2009/01/enabling-sites-and-modules-in-apache-on-ubuntu-or-debian/</id><author><name>Simon Holywell</name></author><published>2009-01-24T20:42:09+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>I really like the way the Apache modules and virtualhosts are seperated out on Debian into folders containing those, which are available and those which are enabled. There is one small problem with this – it is more work than before! Luckily there are some helper scripts.
The Apache configuration files are layed out in the following way:
mods-available – the actual text files containing the modules configuration sites-available – the vhosts text file for the site</summary><content type="html"><![CDATA[<p>I really like the way the Apache modules and virtualhosts are seperated out on Debian into folders containing those, which are available and those which are enabled. There is one small problem with this – it is more work than before! Luckily there are some helper scripts.</p>
<p>The Apache configuration files are layed out in the following way:</p>
<blockquote>
<p>mods-available – the actual text files containing the modules configuration sites-available – the vhosts text file for the site</p>
<p>mods-enabled – a symlink to the actual text file in mods-available sites-enabled – a symlink to the actual text file in sites-available</p>
</blockquote>
<p>Anything listed in the enabled directories will be loaded when Apache is therefore enabling the respective site or module. Manually symlinking these up can be a right pain so I use the following scripts to assist me:</p>
<blockquote>
<p>“a2ensite sitename” – will create the symlink for you “a2dissite sitename” – will remove the symlink for you “a2enmod modulename” – will create the symlink for you “a2dismod modulename” – will remove the symlink for you</p>
</blockquote>
<p>When the symlink is place the module or site will be loaded and vice versa.</p>
<p>Do not forget that you still need to reload the configurations into Apache by running “/etc/init.d/apache2 reload”.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="apache" label="apache"/><category scheme="taxonomy:Tags" term="debian" label="debian"/><category scheme="taxonomy:Tags" term="modules" label="modules"/><category scheme="taxonomy:Tags" term="ubuntu" label="ubuntu"/><category scheme="taxonomy:Tags" term="virtualhosting" label="virtualhosting"/></entry><entry xml:base="securing-ssh-with-key-based-authentication"><title type="html">Securing SSH with Key Based Authentication</title><link href="https://www.simonholywell.com/post/2009/01/securing-ssh-with-key-based-authentication/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2005/11/hardening-ssh/?utm_source=atom_feed" rel="related" type="text/html" title="Hardening SSH"/><link href="https://www.simonholywell.com/post/2005/08/virtual-mail-servers/?utm_source=atom_feed" rel="related" type="text/html" title="Virtual Mail Servers"/><link href="https://www.simonholywell.com/post/2005/08/serving-virtual-hosts/?utm_source=atom_feed" rel="related" type="text/html" title="Serving Virtual Hosts"/><link href="https://www.simonholywell.com/post/2009/01/linux-to-windows-server-migrating-and-securing-your-cron/?utm_source=atom_feed" rel="related" type="text/html" title="Linux to Windows Server - Migrating and securing your crontab"/><link href="https://www.simonholywell.com/post/2009/01/agavi-1-0-beta-on-xampp-1-7-0/?utm_source=atom_feed" rel="related" type="text/html" title="Agavi 1.0 Beta on XAMPP 1.7.0"/><id>https://www.simonholywell.com/post/2009/01/securing-ssh-with-key-based-authentication/</id><author><name>Simon Holywell</name></author><published>2009-01-20T17:16:40+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Certificates are a useful way of restricting access to your SSH server because a user must have three things to log onto the server:
Username Password Certificate Normally they would only need to have a password and username, which can be guess at or (potentially) brute forced. Forcing the user to supply a certificate on log on means that they must also have a tangible source of identification (without the key file they cannot log in!</summary><content type="html"><![CDATA[<p>Certificates are a useful way of restricting access to your SSH server because a user must have three things to log onto the server:</p>
<ol>
<li>Username</li>
<li>Password</li>
<li>Certificate</li>
</ol>
<p>Normally they would only need to have a password and username, which can be guess at or (potentially) brute forced. Forcing the user to supply a certificate on log on means that they must also have a tangible source of identification (without the key file they cannot log in!).</p>
<h1 id="creating-the-key-pair">Creating the key pair</h1>
<p>Log onto the server and run ssh-keygen and you will get asked a few questions as follows (enter a passphrase):</p>
<blockquote>
<p><a href="mailto:user@host">user@host</a>$ sudo ssh-keygen<br>
Generating public/private rsa key pair. Enter file in which to save the key (/home/user/.ssh/id_rsa): Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /home/user/.ssh/id_rsa. Your public key has been saved in /home/user/.ssh/id_rsa.pub. The key fingerprint is: 95:60:c2:31:2e:94:cf:66:b6:fa:8b:b8:45:6c:dd:22 <a href="mailto:user@server">user@server</a> The key’s randomart image is: +–[ RSA 2048]—-+ | .o+.o | | ….+ . . | | .o. o | | . o*. . | | E+o.S | | o … | | .. | | o.. | | o…o. | +—————–+</p>
<p>This will generate two files:</p>
</blockquote>
<ol>
<li>id_rsa</li>
<li>id_rsa.pub</li>
</ol>
<p>in your home directory (if you chose the defaults). They are your private and public keys respectively. The public key is the one that goes on your server and the private key is the one you use when logging into the server.</p>
<h1 id="add-the-public-key">Add the public key</h1>
<p>Now on the server run</p>
<blockquote>
<p><a href="mailto:user@server">user@server</a>:~$ cat id_rsa.pub &gt;&gt; ~/.ssh/authorized_keys<br>
<a href="mailto:user@server">user@server</a>:~$ rm id_rsa</p>
<p>which adds the public key to the list of authorized keys for this user.</p>
</blockquote>
<h1 id="activate-the-key-based-authentication-on-the-server">Activate the key based authentication on the server</h1>
<p>To edit the config run</p>
<blockquote>
<p><a href="mailto:user@server">user@server</a>:~$ sudo vim /etc/ssh/sshd_config</p>
</blockquote>
<p>Ensure that you have the following lines uncommented and set correctly in your configuration file:</p>
<blockquote>
<p>RSAAuthentication yes<br>
PubkeyAuthentication yes</p>
<p>If you wish to lock non-certified logins from the server then also ensure you activate the following settings:</p>
</blockquote>
<blockquote>
<p>ChallengeResponseAuthentication no<br>
PasswordAuthentication no UsePAM no</p>
<p>Now reload the SSH configuration to get the new settings going:</p>
</blockquote>
<blockquote>
<p><a href="mailto:user@server">user@server</a>:~$ sudo /etc/init.d/ssh reload</p>
</blockquote>
<h1 id="conversion-to-putty">Conversion to PuTTY</h1>
<p>PuTTY has its own private key format and the private key you created earlier now needs to be converted, which is a very simple process. Firstly you need to download the key from the server and save it to your computer.</p>
<ol>
<li>Now open PuTTYgen, which comes when you install PuTTY (look in the PuTTY program files directory if there is no shortcut in the start menu).</li>
<li>Click the “Load” button and point it to the private key we downloaded earlier (depending on the file extension you gave the key file you may need to adjust the file extension filter on the PuTTY load key dialogue)</li>
<li>It will ask you for the passphrase you set when you were generating the certificates – enter it!</li>
<li>PuTTYgen should now tell you that you it has successfully imported the certificate – click ok.</li>
<li>Click the “Save private key” button and save it</li>
</ol>
<h1 id="getting-this-to-work-with-putty">Getting this to work with PuTTY</h1>
<p>Now the new key we just saved is compatible with PuTTY we can start a new PuTTY session as usual, but don’t forget to tell PuTTY where the key file is located by looking in the Category tree menu and clicking on Connection -&gt; SSH -&gt; Auth. You can now click the “Browse” button and point PuTTY to the key file you just created.</p>
<p>Click open and a new session will load:</p>
<ol>
<li>Enter your username as normal</li>
<li>When prompted; give the passphrase you gave when creating your key (do not make the mistake of using your linux user account password as it won’t work!)</li>
</ol>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="debian" label="debian"/><category scheme="taxonomy:Tags" term="ssh" label="ssh"/><category scheme="taxonomy:Tags" term="ubuntu" label="ubuntu"/><category scheme="taxonomy:Tags" term="internet" label="Internet"/></entry><entry xml:base="linux-to-windows-server-migrating-and-securing-your-cron"><title type="html">Linux to Windows Server - Migrating and securing your crontab</title><link href="https://www.simonholywell.com/post/2009/01/linux-to-windows-server-migrating-and-securing-your-cron/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2008/06/windows-cron-jobs-using-schtasks-or-at/?utm_source=atom_feed" rel="related" type="text/html" title="Windows Cron Jobs using Scheduled Tasks"/><link href="https://www.simonholywell.com/post/2009/01/agavi-1-0-beta-on-xampp-1-7-0/?utm_source=atom_feed" rel="related" type="text/html" title="Agavi 1.0 Beta on XAMPP 1.7.0"/><link href="https://www.simonholywell.com/post/2008/12/freelancers-costing-your-work/?utm_source=atom_feed" rel="related" type="text/html" title="Freelancers: Costing your work"/><link href="https://www.simonholywell.com/post/2008/11/displaying-syntax-highlighted-code-in-wordpress/?utm_source=atom_feed" rel="related" type="text/html" title="Displaying Syntax Highlighted Code in Wordpress"/><link href="https://www.simonholywell.com/post/2008/06/xampp-virtualhosts/?utm_source=atom_feed" rel="related" type="text/html" title="XAMPP VirtualHosts"/><id>https://www.simonholywell.com/post/2009/01/linux-to-windows-server-migrating-and-securing-your-cron/</id><author><name>Simon Holywell</name></author><published>2009-01-15T04:01:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>In the PHP development arena the LAMP (Linux, Apache, MySQL and PHP) stack is very common, but once in a while a client will come through the door with a Microsoft background. So what do you do if your CMS or framework was built with a Linux base layer in mind? Sounds easy, but what if you have jobs loaded into your Linux crontab for processing mail outs or after hours records processing?</summary><content type="html"><![CDATA[<p>In the PHP development arena the LAMP (Linux, Apache, MySQL and PHP) stack is very common, but once in a while a client will come through the door with a Microsoft background. So what do you do if your CMS or framework was built with a Linux base layer in mind? Sounds easy, but what if you have jobs loaded into your Linux crontab for processing mail outs or after hours records processing?</p>
<p>There are options for implementing cron jobs with a Windows server, one of which is to offload your cron jobs to a Linux server and use WGet to remotely activate the processing script on the Windows server. For more information on setting up cron jobs on a Linux box please see <a href="http://www.sitepoint.com/article/introducing-cron/">Introducing Cron</a>. Whilst this does work well, what if the Linux box goes down or its internet connection is severed and your scripts on the Windows server do not run? Or perhaps you do not have a Linux box to hand or you don’t feel comfortable sending cron job requests across the web.</p>
<p>Well you are in luck because Windows does offer a way to run cron jobs although its termed Scheduled Tasks by Microsoft. You will also need a small Windows binary that performs all the functions of the Linux WGet programme. I use the <a href="http://www.christopherlewis.com/WGet/WGetFiles.htm">WGet for Windows</a> utility compiled by Christopher Lewis. I usually stick it into the Windows Programs Files directory, but you can put it anywhere you like.</p>
<p>You might be thinking to yourself why use WGet when the box already has Internet Explorer and Mozilla Firefox installed; surely they can open a web address? Well, yes, they can but every time the task/cron job is invoked a new instance of the browser is created. Once the cron job is complete they do not self close either so your server would be left with many useless open processes running! No good at all.</p>
<p>Now we have the necessary software installed lets turn our attention to the setup of our Scheduled Task and as usual Windows has a nice wizard interface that can be found by accessing Start &gt; Programs &gt; Accessories &gt; System Tools &gt; Scheduled Tasks. However if you prefer the command line I go into detail further down the article about using schtasks.exe. When you open the utility you will see a Windows Explorer window containing any pre-existing tasks and an “Add Scheduled Task” icon which is the one we want to double click.</p>
<p>Let us step through the wizard setup process:</p>
<ol>
<li>Click next on the introduction page.</li>
<li>Choose the programme you would like run your PHP script. This is where the WGet binary comes into play. Use the browse button to locate it. Click next.</li>
<li>Give your task an easily identifiable name and choose the regularity with which you want the task to run. As an example you might use once a day for a mail out script and once a week for a database backup script. Yep you guessed it; click next.</li>
<li>You will be presented with a screen giving you more in depth scheduling options where you can choose start time and date and what days, weeks or months of the year you want the task to run on. Once again, after you are done, click next.</li>
<li>You must now choose a user that the task will run as and enter the username and password. I always setup a new Windows user solely for running Scheduled Tasks and I recommend you do the same for securities sake. As it is outside the scope of this article I will assume you know how to setup Windows users. You get the idea by now I am sure; click next.</li>
<li>A summary screen will then be displayed and we need to check the “Open advanced properties for this Task when I click finish” checkbox.</li>
<li>You will arrive on the Task tab of a window that looks much a like file properties window where we need to adjust the contents of the Run field to tell WGet which script we want it to run. Don’t delete the contents of the field just add the URL to your PHP script on the end. So you should end up with something like this: “C:Program Fileswgetwget.exe <a href="http://www.yourdomain.com/your_script.php">http://www.yourdomain.com/your\_script.php</a> –spider”. The ‘–spider’ switch on the WGet binary causes it to behave like a web spider effectively pinging the file to see if it is there without downloading it (don’t worry the spider request will cause your script to be run). For more information please see the <a href="http://www.gnu.org/software/wget/manual/wget.html">WGet manual</a>.</li>
<li>On the Schedule tab you can change the regularity of the Task with more granularity using the Advanced button and you can have multiple schedules for the same Task.</li>
<li>On the Settings tab I would set the Task to Stop if it runs for: 00 hour(s) 1 minute(s) unless you are running an intensive routine.</li>
<li>Click OK</li>
</ol>
<p>Once back viewing the Scheduled Tasks folder you can right click on the Task and choose Run to see if it works as expected.</p>
<p>OK so that is great if we know what tasks we want to setup, but what if your system needs make its own Tasks on the fly or you prefer setting up Tasks via the command line. Obviously you need to be exceptionally careful when you allow a web accessible script to setup Scheduled Tasks just as you would with cron jobs.</p>
<p>You must be running your server on a Windows system with Server 2003, Server 2008 or XP Professional otherwise you will not have the required schtasks.exe executable. To find out if you have it run schtasks on the command line. It should return a list of Scheduled Tasks currently on the system and if you see this read on otherwise you will need to investigate the windows at utility (type at /? on the command line).</p>
<p>The best place to start is by running schtasks /? which will bring up the help manual, but for further information on creating a Scheduled Task you should also read schtasks /Create /?. As there are lots of confusing options there I will break it down for you with a brief example.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="n">schtasks</span> <span class="p">/</span><span class="n">Create</span> <span class="p">/</span><span class="n">RU</span> <span class="n">username</span> <span class="p">/</span><span class="nb">RP </span><span class="n">password</span> <span class="p">/</span><span class="nb">SC </span><span class="n">MINUTE</span> <span class="p">/</span><span class="n">MO</span> <span class="mf">5</span> <span class="p">/</span><span class="n">TN</span> <span class="n">taskname</span> <span class="p">/</span><span class="n">TR</span> <span class="s2">&#34;C:\Program Files\wget\wget.exe http://www.webaddress.com/script.php --spider&#34;</span>
</span></span></code></pre></div><p>In the above statement we are creating a new Scheduled Task that is to run every five minutes and it executes WGet, which in turn calls our PHP script. /RU and /RP are the username and password (respectively) of the account that will be used to run the task and /SC is the definition of the iteration interval which can be from minutes to monthly. The /MO is the modifier which determines when it runs, in our example above its every 5 minutes, /TN is predictably the unique name of your Scheduled Task and /TR is the command to be run when the Scheduled Task is activated.</p>
<p>As another example if we wanted a script to be run every second month we would enter something like this:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="n">schtasks</span> <span class="p">/</span><span class="n">Create</span> <span class="p">/</span><span class="n">RU</span> <span class="n">username</span> <span class="p">/</span><span class="nb">RP </span><span class="n">password</span> <span class="p">/</span><span class="nb">SC </span><span class="n">MONTHLY</span> <span class="p">/</span><span class="n">MO</span> <span class="mf">2</span> <span class="p">/</span><span class="n">TN</span> <span class="n">taskname</span> <span class="p">/</span><span class="n">TR</span> <span class="s2">&#34;C:\Program Files\wget\wget.exe http://www.webaddress.com/script.php --spider&#34;</span>
</span></span></code></pre></div><p>So that should give you a basic idea of the command line utility and adjusting the examples with the help of the manual available by typing schtasks /? and schtasks /Create /? should get you on your way.</p>
<p>If you are like me you are now wondering if I am recommending security via obscurity; absolutely not! The problem with the examples I have given above is that if someone were to guess the URL of your processing php script (<a href="http://www.webaddress.com/script.php">http://www.webaddress.com/script.php</a> in the example above) they could access it via their web browser. Now think of the ramifications if your script is meant to send out emails once a day, but instead your script gets hit by a bot and sends your users 1,000+ emails a day!</p>
<p>So to lock your scripts down a bit I recommend the following:</p>
<ol>
<li>Always check the IP address and user agent of anyone trying to access your script</li>
<li>Add an HTTP header to our request so we can pass our processing script a secret key</li>
</ol>
<p>These checks combined should halt any bots in their tracks. So let us take a look at how this would work in real life with the following example code. Firstly the call we would issue to Scheduled Tasks and WGet:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="n">schtasks</span> <span class="p">/</span><span class="n">Create</span> <span class="p">/</span><span class="n">RU</span> <span class="n">username</span> <span class="p">/</span><span class="nb">RP </span><span class="n">password</span> <span class="p">/</span><span class="nb">SC </span><span class="n">MINUTE</span> <span class="p">/</span><span class="n">MO</span> <span class="mf">2</span> <span class="p">/</span><span class="n">TN</span> <span class="n">taskname</span> <span class="p">/</span><span class="n">TR</span> <span class="s2">&#34;C:\Program Files\wget\wget.exe --header=TASK_KEY:my-secret-key -U my-agent http://www.webaddress.com/script.php --spider&#34;</span>
</span></span></code></pre></div><p>–header=TASK_KEY:my-secret-key tells WGet to add an HTTP header called TASK_KEY which contains the value of “my-secret-key” to its request for the processing script. We can then compare the contents of this header with the copy of the secret key in our processing script – this will make more sense when I show you the PHP side of the coding. You will also notice that I have added -U my-agent, which changes the user agent that WGet identifies itself as – in this case to “my-agent”. Obviously you would want to change the key and user agent to make them harder for a bot maker (who could be reading this) to guess. I would use a SHA1 hash for your secret key just to make it even harder to guess – it is a lot harder to luck upon a94a8fe5ccb19ba61c4c0873d391e987982fbbd3, which is the word test hashed rather than simply the word test.</p>
<p>The PHP side of this is also very simple:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o">&lt;?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span><span class="p">(</span><span class="s1">&#39;my-agent&#39;</span> <span class="o">!==</span> <span class="nv">$_SERVER</span><span class="p">[</span><span class="s1">&#39;HTTP_USER_AGENT&#39;</span><span class="p">]</span> <span class="k">or</span>
</span></span><span class="line"><span class="cl">       <span class="nv">$_SERVER</span><span class="p">[</span><span class="s1">&#39;SERVER_ADDR&#39;</span><span class="p">]</span> <span class="o">!==</span> <span class="nv">$_SERVER</span><span class="p">[</span><span class="s1">&#39;REMOTE_ADDR&#39;</span><span class="p">]</span> <span class="k">or</span>
</span></span><span class="line"><span class="cl">       <span class="o">!</span><span class="nx">isset</span><span class="p">(</span><span class="nv">$_SERVER</span><span class="p">[</span><span class="s1">&#39;HTTP_TASK_KEY&#39;</span><span class="p">])</span> <span class="k">or</span>
</span></span><span class="line"><span class="cl">       <span class="k">empty</span><span class="p">(</span><span class="nv">$_SERVER</span><span class="p">[</span><span class="s1">&#39;HTTP_TASK_KEY&#39;</span><span class="p">])</span> <span class="k">or</span>
</span></span><span class="line"><span class="cl">       <span class="s1">&#39;my-secret-key&#39;</span> <span class="o">!==</span> <span class="nv">$_SERVER</span><span class="p">[</span><span class="s1">&#39;HTTP_TASK_KEY&#39;</span><span class="p">])</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">print</span> <span class="s1">&#39;You do not have permission to execute this script!&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="k">exit</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">print</span> <span class="s1">&#39;Executing operation.&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="o">/</span><span class="nx">insert</span> <span class="nx">your</span> <span class="nx">processing</span> <span class="nx">script</span> <span class="nx">here</span>
</span></span><span class="line"><span class="cl"><span class="cp">?&gt;</span><span class="err">
</span></span></span></code></pre></div><p>So again you can see here that you need to change the values of “my-agent” and “my-secret-key” to your own private values. Now to break down the code by looking at the operations in the if statement.</p>
<p>The first line ‘my-agent’ !== $_SERVER[‘HTTP_USER_AGENT’] checks to see whether the value of the user agent matches the specified value “my-agent”.</p>
<p>The second line $_SERVER[‘SERVER_ADDR’] !== $_SERVER[‘REMOTE_ADDR’] checks that the server requesting the script be processed is the same as the one the script is being executed on. Basically this means that only requests coming from the same IP address as the server will be run.</p>
<p>The third, fourth and fifth lines:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o">&lt;?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl"><span class="o">!</span><span class="nx">isset</span><span class="p">(</span><span class="nv">$_SERVER</span><span class="p">[</span><span class="s1">&#39;HTTP_TASK_KEY&#39;</span><span class="p">])</span> <span class="k">or</span>
</span></span><span class="line"><span class="cl"> <span class="k">empty</span><span class="p">(</span><span class="nv">$_SERVER</span><span class="p">[</span><span class="s1">&#39;HTTP_TASK_KEY&#39;</span><span class="p">])</span> <span class="k">or</span>
</span></span><span class="line"><span class="cl"> <span class="s1">&#39;my-secret-key&#39;</span> <span class="o">!==</span> <span class="nv">$_SERVER</span><span class="p">[</span><span class="s1">&#39;HTTP_TASK_KEY&#39;</span><span class="p">])</span>
</span></span></code></pre></div><p>Check that the HTTP header has been set then if the header contains something and finally if the header contents match our secret key; “my-secret-key” in this case.</p>
<p>If any of the criteria are found to be missing then the script will display the message “You do not have permission to execute this script!” and halt otherwise the code placed after the end of the if will be executed. So in this example upon a successful run the script would print out “Executing operation”.</p>
<p>Before I go I shall also very briefly show you how to setup a Scheduled Task from a PHP script. This can be very useful if you have a very large list of emails to send out to and the PHP script times out whilst your Scheduled Task is executing. What you can do is split it up into job lots of say 500 emails at a time and schedule the send out as multiple Scheduled Tasks dynamically from PHP. Of course this same principle would apply to large dataset changes that timeout during their operation as well.</p>
<p>To dynamically schedule the task we simply send it to the system via the PHP exec() function. As I said earlier you must ensure that you are very careful of what you put in an exec() call and I would advise that no user supplied data is allowed lest they maliciously insert a command like format C:! Here is the basic PHP to work from:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o">&lt;?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl"><span class="nx">exec</span><span class="p">(</span><span class="s1">&#39;schtasks /Delete /TN taskname /F&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">exec</span><span class="p">(</span><span class="s1">&#39;schtasks /Create /RU username /RP password /SC MINUTE /MO 2 /TN taskname /TR “C:\Program Files\wget\wget.exe --header=TASK_KEY:my-secret-key –U my-agent http://www.webaddress.com/script.php -r&#39;</span><span class="p">);</span>
</span></span></code></pre></div><p>The only new concept here is that I always make sure I delete any Scheduled Task that may already be in place with the same name before attempting to setup the new Scheduled Task.</p>
<p>To summarise we have now got a Scheduled Task up and running with some security to ensure only our server is able execute the processing script. You have learnt how to setup a new Scheduled Task either via the command line or the graphical user interface wizard or via the exec() function in PHP to dynamically setup new Scheduled Tasks on the fly. Experiment further and enjoy!</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="cron" label="cron"/><category scheme="taxonomy:Tags" term="linux" label="linux"/><category scheme="taxonomy:Tags" term="windows" label="windows"/><category scheme="taxonomy:Tags" term="internet" label="Internet"/></entry><entry xml:base="agavi-1-0-beta-on-xampp-1-7-0"><title type="html">Agavi 1.0 Beta on XAMPP 1.7.0</title><link href="https://www.simonholywell.com/post/2009/01/agavi-1-0-beta-on-xampp-1-7-0/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2008/05/installing-agavi-on-xampp-windows/?utm_source=atom_feed" rel="related" type="text/html" title="Installing Agavi on XAMPP Windows"/><link href="https://www.simonholywell.com/post/2008/12/freelancers-costing-your-work/?utm_source=atom_feed" rel="related" type="text/html" title="Freelancers: Costing your work"/><link href="https://www.simonholywell.com/post/2008/06/xampp-virtualhosts/?utm_source=atom_feed" rel="related" type="text/html" title="XAMPP VirtualHosts"/><link href="https://www.simonholywell.com/post/2006/12/geographic-calculations-in-php/?utm_source=atom_feed" rel="related" type="text/html" title="Geographic Calculations in PHP"/><link href="https://www.simonholywell.com/post/2006/03/form-spam-not-ham/?utm_source=atom_feed" rel="related" type="text/html" title='Form SPAM (not "HAM") fighting tips'/><id>https://www.simonholywell.com/post/2009/01/agavi-1-0-beta-on-xampp-1-7-0/</id><author><name>Simon Holywell</name></author><published>2009-01-02T03:39:14+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>To install the new XAMPP ensure you firstly uninstall and remove your current XAMPP folder. Upgrades are not supported with this version due to the differences one of which is the removal of PHP4 support from the XAMPP package.
I like to install agavi via the pear package that is available:
Open a command prompt and navigate to your XAMPP directory eg. D:\xampp\php
Execute:
pear channel-discover pear.agavi.org pear config-set auto_discover 1 pear config-set preferred_state beta pear install -a agavi/agavi Wait for a bit as it installs</summary><content type="html"><![CDATA[<p>To install the new XAMPP ensure you firstly uninstall and remove your current XAMPP folder. Upgrades are not supported with this version due to the differences one of which is the removal of PHP4 support from the XAMPP package.</p>
<p>I like to install agavi via the pear package that is available:</p>
<ol>
<li>
<p>Open a command prompt and navigate to your XAMPP directory eg. D:\xampp\php</p>
</li>
<li>
<p>Execute:</p>
<ol>
<li>pear channel-discover pear.agavi.org</li>
<li>pear config-set auto_discover 1</li>
<li>pear config-set preferred_state beta</li>
<li>pear install -a agavi/agavi</li>
</ol>
</li>
<li>
<p>Wait for a bit as it installs</p>
</li>
<li>
<p>Execute the command agavi and you will get a phing error</p>
</li>
</ol>
<p>To rectify the error we must complete a little bit of a hack to trick the agavi batch file into recognising our phings version is greater than 2.3.1. Navigate into your XAMPP PEAR folder (D:\xampp\php\PEAR\phing) and create a new directory called ‘etc’. Inside your ‘etc’ directory create a new text file called ‘VERSION.TXT’ containing the following text ‘Phing 2.3.3 BRANCH (2.3dev)’.</p>
<p>Try executing the agavi command on the command line again and you should have a successful response like:</p>
<pre tabindex="0"><code>D:\xampp\php &gt; agavi

Agavi &gt; status:

[echo] PHP:
[echo] Version: 5.2.8 [echo] Include path: .;D:\xampp\php\pear [echo] [echo] Phing: [echo] Version: Phing 2.3.3 BRANCH (2.3dev) [echo] [echo] Agavi: [echo] Installation directory: D:\xampp\php\pear\agavi [echo] Version: 1.0.0-beta6 [echo] URL: &lt;http://www.agavi.org&gt; [echo] [echo] Project: [echo] (not found) [echo] [echo] For a list of possible build targets, call this script with the -l argument.

D:\xampp\php &gt;
</code></pre><p>Hope that helps you out and you can continue to follow the <a href="http://www.agavi.org/documentation/tutorial/creating-agavi-project.html">official tutorial</a>.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="agavi" label="agavi"/><category scheme="taxonomy:Tags" term="xampp" label="xampp"/><category scheme="taxonomy:Tags" term="internet" label="Internet"/><category scheme="taxonomy:Tags" term="php" label="PHP"/></entry><entry xml:base="twitter-jaiku-rejaw-and-tumblr"><title type="html">Twitter, Jaiku, Rejaw and Tumblr</title><link href="https://www.simonholywell.com/post/2008/12/twitter-jaiku-rejaw-and-tumblr/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2008/12/carver-carver-one/?utm_source=atom_feed" rel="related" type="text/html" title="Carver Carver One"/><link href="https://www.simonholywell.com/post/2008/12/my-arrival-back-in-the-uk/?utm_source=atom_feed" rel="related" type="text/html" title="My arrival back in the UK"/><link href="https://www.simonholywell.com/post/2008/12/freelancers-costing-your-work/?utm_source=atom_feed" rel="related" type="text/html" title="Freelancers: Costing your work"/><link href="https://www.simonholywell.com/post/2008/11/displaying-syntax-highlighted-code-in-wordpress/?utm_source=atom_feed" rel="related" type="text/html" title="Displaying Syntax Highlighted Code in Wordpress"/><link href="https://www.simonholywell.com/post/2008/09/lancia-fulvia-hf/?utm_source=atom_feed" rel="related" type="text/html" title="Lancia Fulvia HF"/><id>https://www.simonholywell.com/post/2008/12/twitter-jaiku-rejaw-and-tumblr/</id><author><name>Simon Holywell</name></author><published>2008-12-18T14:29:24+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>It is clear from all usage reports that Twitter is definitely used by more people than the other services, but I am still not sure whether any of them are truly must have or useful. Rejaw and Jaiku are more in line with the Twitter model, but they allow users to make comments on posts. Jaiku goes further by allowing channels, which operate much like an IRC Channel. You follow the channel and when users post updates to it they are displayed in your feed.</summary><content type="html"><![CDATA[<p>It is clear from all usage reports that Twitter is definitely used by more people than the other services, but I am still not sure whether any of them are truly must have or useful. Rejaw and Jaiku are more in line with the Twitter model, but they allow users to make comments on posts. Jaiku goes further by allowing channels, which operate much like an IRC Channel. You follow the channel and when users post updates to it they are displayed in your feed. Tumblr is a very nifty little blogging application that allows you to post media and text fast. This is great for sharing an image or video you found on the web that you liked.</p>
<p>So that is very interesting, but what in the world is the point? I am still yet to work that out myself. Why follow someone on Twitter when you can just as easily subscribe to their blogs RSS feed on any number of sites such as Bloglines or Google. A lot of people are only using Twitter to let their followers know that they have released a new article on their blog for which RSS feeds are just as useable. Both push your article onto the top of your readers list.</p>
<p>You may argue that Twitter et al allows people to respond about articles and push them to their friends by reposting the link to their own feed, but this can just as easily be achieved with links to your blog from their site and by using the comments for on your site.</p>
<p>Much has been made of the use of Twitter during the Mumbai terrorist attacks, but I am unsure of the usefulness even for this purpose. None of what is being posted has been peer reviewed or fact checked as newspaper reports are supposed to be. You may be getting the most up to date reports, but what of their accuracy? I will stick to my BBC and Reuters RSS feeds I think.</p>
<p>I feel Jaiku is the better of all the services mentioned but because you must have an invite to sign up less people are using it and therefore it less engaging. Also I feel the channels feature is redundant as people are already using forums, mailing lists (Google Groups being a good example) and IRC for the same results. It does allow you to participate in the conversation away from your computer via MMS and WAP plus it also has an S60 compatible client, which is difficult to do on the more traditional communication mediums.</p>
<p>Even as I write this I am struggling to think of ways that any of these services might be useful. This is also partly due to the fact that all my friends are on Facebook so I can use that to send them presence/status updates and let them know what I am up to. What does anyone else on the web need to know about my latest thoughts on fried chicken or what magazine I am thinking of buying? Maybe your friends on the other side of the world might like to know so they feel they are keeping touch, but outsiders want considered thoughts and well written to the point articles not disorganised dross.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="reviews" label="reviews"/></entry><entry xml:base="carver-carver-one"><title type="html">Carver Carver One</title><link href="https://www.simonholywell.com/post/2008/12/carver-carver-one/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2008/09/lancia-fulvia-hf/?utm_source=atom_feed" rel="related" type="text/html" title="Lancia Fulvia HF"/><link href="https://www.simonholywell.com/post/2008/05/vauxhall-astra-front-brakes/?utm_source=atom_feed" rel="related" type="text/html" title="Vauxhall Astra Front Brakes"/><link href="https://www.simonholywell.com/post/2008/04/sql-server/?utm_source=atom_feed" rel="related" type="text/html" title="SQL SERVER"/><link href="https://www.simonholywell.com/post/2005/04/lancia-stratos/?utm_source=atom_feed" rel="related" type="text/html" title="Lancia Stratos"/><link href="https://www.simonholywell.com/post/2008/12/my-arrival-back-in-the-uk/?utm_source=atom_feed" rel="related" type="text/html" title="My arrival back in the UK"/><id>https://www.simonholywell.com/post/2008/12/carver-carver-one/</id><author><name>Simon Holywell</name></author><published>2008-12-14T12:47:48+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>I never thought I would see one of these little one seater cars running around largely due to their obscene price tag (£27k+), but the other day in Auckland I did. This was a photo I quickly snapped of it on Victoria Street outside the Sky Tower.
This little car has been loved by reviewers for its ability to be driven like a car but still give you the fun of banking into turns like a motorcycle.</summary><content type="html"><![CDATA[<p><img src="/static/images/wp/2008/12/3122343794_f4be5613fb_b-300x166.jpg" alt="Carver Carver One"></p>
<p>I never thought I would see one of these little one seater cars running around largely due to their obscene price tag (£27k+), but the other day in Auckland I did. This was a photo I quickly snapped of it on Victoria Street outside the Sky Tower.</p>
<p>This little car has been loved by reviewers for its ability to be driven like a car but still give you the fun of banking into turns like a motorcycle. Some day I hope to take one for a test drive and experience it for myself.</p>
<p>Visit the <a href="http://www.carver-worldwide.com/">official website</a> for more info and take a look on <a href="http://www.youtube.com/results?search_query=carver+one&amp;search_type=">Youtube</a> for video reviews of which there are many.</p>
]]></content><category scheme="taxonomy:Categories" term="motors" label="Motors"/><category scheme="taxonomy:Tags" term="cars" label="Cars"/><category scheme="taxonomy:Tags" term="photos" label="photos"/><category scheme="taxonomy:Tags" term="spotted" label="spotted"/></entry><entry xml:base="my-arrival-back-in-the-uk"><title type="html">My arrival back in the UK</title><link href="https://www.simonholywell.com/post/2008/12/my-arrival-back-in-the-uk/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2008/09/absence/?utm_source=atom_feed" rel="related" type="text/html" title="Absence"/><link href="https://www.simonholywell.com/post/2008/08/wedding/?utm_source=atom_feed" rel="related" type="text/html" title="Wedding"/><link href="https://www.simonholywell.com/post/2008/02/engagement/?utm_source=atom_feed" rel="related" type="text/html" title="Engagement"/><link href="https://www.simonholywell.com/post/2007/12/moves/?utm_source=atom_feed" rel="related" type="text/html" title="Moves"/><link href="https://www.simonholywell.com/post/2007/06/london/?utm_source=atom_feed" rel="related" type="text/html" title="London"/><id>https://www.simonholywell.com/post/2008/12/my-arrival-back-in-the-uk/</id><author><name>Simon Holywell</name></author><published>2008-12-04T09:38:05+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>I am now in a permanent role at Mosaic in Brighton and I am not looking for employment opportunities.
Just a short note to give you more detail on my return to the United Kingdom in December 2008. I will be landing just before Christmas and be ready for a new role with an exciting company in the new year.
A quick run down about me follows:
UK citizen so I can work for anyone Zend Certified PHP Engineer UK and Australian industry experience Worked with clients such as: the Virgin Group of companies Volkswagen (VW) Nickelodeon Merlin Entertainments Group (London Eye, Thorpe Park, etc.</summary><content type="html"><![CDATA[<p><img src="/static/images/wp/2008/12/3144643006_8cdc1c2761_b-225x300.jpg" alt="Bleak Economy"></p>
<p>I am now in a permanent role at Mosaic in Brighton and I am not looking for employment opportunities.</p>
<p>Just a short note to give you more detail on my return to the United Kingdom in December 2008. I will be landing just before Christmas and be ready for a new role with an exciting company in the new year.</p>
<p>A quick run down about me follows:</p>
<ul>
<li>UK citizen so I can work for anyone</li>
<li>Zend Certified PHP Engineer</li>
<li>UK and Australian industry experience</li>
<li>Worked with clients such as:
<ul>
<li>the Virgin Group of companies</li>
<li>Volkswagen (VW)</li>
<li>Nickelodeon</li>
<li>Merlin Entertainments Group (London Eye, Thorpe Park, etc.)</li>
<li>the Haymarket Magazine Group</li>
</ul>
</li>
<li>4 years industry experience
<ul>
<li><a href="http://www.wickedweb.co.uk"><a href="http://www.wickedweb.co.uk">http://www.wickedweb.co.uk</a></a></li>
<li><a href="http://www.underwired.com"><a href="http://www.underwired.com">http://www.underwired.com</a></a></li>
<li><a href="http://www.jellyfish.co.uk"><a href="http://www.jellyfish.co.uk">http://www.jellyfish.co.uk</a></a></li>
<li><a href="http://www.go4.com.au"><a href="http://www.go4.com.au">http://www.go4.com.au</a></a></li>
</ul>
</li>
<li>4 years freelance prior to that</li>
</ul>
<p>Some sample URLs I have worked on include:</p>
<ul>
<li><a href="http://www.thorpepark.com"><a href="http://www.thorpepark.com">http://www.thorpepark.com</a></a></li>
<li><a href="http://www.celsurplastics.com"><a href="http://www.celsurplastics.com">http://www.celsurplastics.com</a></a></li>
<li><a href="http://www.made.uk.com"><a href="http://www.made.uk.com">http://www.made.uk.com</a></a></li>
<li><a href="http://www.jamesmillard.co.uk"><a href="http://www.jamesmillard.co.uk">http://www.jamesmillard.co.uk</a></a></li>
<li><a href="http://www.salton.com.au"><a href="http://www.salton.com.au">http://www.salton.com.au</a></a></li>
<li><a href="http://www.advantechdesign.com.au"><a href="http://www.advantechdesign.com.au">http://www.advantechdesign.com.au</a></a></li>
<li><a href="http://www.syc.com.au"><a href="http://www.syc.com.au">http://www.syc.com.au</a></a></li>
<li><a href="http://www.osakacup.com"><a href="http://www.osakacup.com">http://www.osakacup.com</a></a></li>
<li><a href="http://www.go4.com.au"><a href="http://www.go4.com.au">http://www.go4.com.au</a></a></li>
</ul>
<p>Skills include:</p>
<ul>
<li>PHP</li>
<li>MySQL</li>
<li>(X)HTML</li>
<li>CSS</li>
<li>Javascript</li>
<li>AJAX</li>
<li>Python and ASP.NET</li>
<li>Linux, Windows and Mac</li>
<li>Web Servers</li>
<li>Domain Name Server</li>
<li>DOS/Shell/Bash scripting</li>
</ul>
<p>Plus training other staff and clients, attending and participating in client meetings and pitches, managing time and budget constraints, system and user documentation and general client assistance.</p>
<p>My resume is <a href="/cv.html">available online</a>. I am now in a permanent role at Mosaic in Brighton and I am not looking for employment opportunities.</p>
]]></content><category scheme="taxonomy:Tags" term="life" label="life"/><category scheme="taxonomy:Tags" term="me" label="Me"/></entry><entry xml:base="freelancers-costing-your-work"><title type="html">Freelancers: Costing your work</title><link href="https://www.simonholywell.com/post/2008/12/freelancers-costing-your-work/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2006/12/geographic-calculations-in-php/?utm_source=atom_feed" rel="related" type="text/html" title="Geographic Calculations in PHP"/><link href="https://www.simonholywell.com/post/2006/03/form-spam-not-ham/?utm_source=atom_feed" rel="related" type="text/html" title='Form SPAM (not "HAM") fighting tips'/><link href="https://www.simonholywell.com/post/2006/03/flickering-images/?utm_source=atom_feed" rel="related" type="text/html" title="Flickering Images"/><link href="https://www.simonholywell.com/post/2005/12/adodb/?utm_source=atom_feed" rel="related" type="text/html" title="ADODB"/><link href="https://www.simonholywell.com/post/2005/10/an-interesting-php-site/?utm_source=atom_feed" rel="related" type="text/html" title="An interesting PHP site"/><id>https://www.simonholywell.com/post/2008/12/freelancers-costing-your-work/</id><author><name>Simon Holywell</name></author><published>2008-12-01T10:18:27+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Recently I have been a fly-on-the-wall in an interesting discussion on the Auckland PHP User Group regarding the process of costing freelance work. So I thought I would toss my hat in the ring and give my opinion and summarise the interesting aspects.
Let me just say now that I cannot tell you how much you should be charging or what you are worth, but I can help you avoid some pitfalls.</summary><content type="html"><![CDATA[<p>Recently I have been a fly-on-the-wall in an interesting discussion on the Auckland PHP User Group regarding the process of costing freelance work. So I thought I would toss my hat in the ring and give my opinion and summarise the interesting aspects.</p>
<p>Let me just say now that I cannot tell you how much you should be charging or what you are worth, but I can help you avoid some pitfalls.</p>
<p>The lowest price submitted for a job will not necessarily get the job. Consider this example – say I would like to buy a washing machine. I would not opt to buy the cheapest one for any number of the following reasons:</p>
<!-- raw HTML omitted -->
<p>So there a few reasons off the top of my head that mean you do not want to be pricing yourself below the mark. Whilst those assumptions about you maybe way off the mark and you are the best coder under the sun and the moon you will never get the chance to prove it. You will be discounted as an inexperienced hack and your proposal will be pushed to the side if you are lucky and into the bin if you are not.</p>
<p>The next problem you can easily get yourself into is non-paying clients. There is no silver bullet for this problem because quite often they will look like a legitimate business. One way to avoid getting shafted is to request credit references from the client. This way you can easily find out how they have dealt with other companies in the past, but it can be very insulting to your client so be careful. Always meet the client on their premises before beginning work on the project. Not only will you have a better idea of their business and what they need, but you will make personal contact. People are a lot less likely to stiff you if they feel you are a friend so do your best to talk about their favourite sports team or the latest car they bought or whatever it is that makes them tick.</p>
<p>Furthermore you should maintain regular friendly contact with your clients during and after the completion of the project. This allows you to keep abreast of the clients expectations and let them know of any problems or blocks you may have encountered that could affect the go live date. Through this regular contact you can further ingrain yourself as a reliable and honest friend. Plus they will be sure to call you when they have their next budget round or project!</p>
<p>So what should you do if you really do not trust the client? Well my advice would be to walk away and look for better clients, but if you really must complete as you are on tight constraints then I would try something like the following arrangement. Charge the client the full price of the project up front and do not begin work until they have paid. To help them trust that your intentions are to complete the project; place a large completion bonus at the end of the contract. Then should they not pay you at the end at least you have been paid your hourly rate and it is just your bonus that you miss out on. But as I stated already I would not get involved in this scenario.</p>
<p>Of course you can also find yourself pitching well above the average, which will illicit one of two very strong responses. The first being outright refusal and the second can get you hired instantly. Once again it goes back to the client’s concept of quality. The most expensive TV has the most features so therefore the most expensive developer must also be the best. The point to take away from this is that pricing yourself too high is less likely to lose you the job than pricing yourself too low.</p>
<p>Pricing yourself too low also brings with it other issues further down the line. You attract clients who cannot pay you what you are worth and end up supporting old projects for much lower rates. Clients will quite often balk at a sudden price hike and phone you up to remind you how much of a good friend you are why they deserve a discount. It is the usual human reaction that I am sure you have experienced yourself – your telephone company sends you a letter informing you that calls are to go up by 20% and you will feel a little cheated. Your clients will feel the same way. Yet if you were to charge them the higher price in the beginning then they would likely still have taken you on for the project anyway.</p>
<p>The human psyche can be a strange beast and you will surely run across clients who are exceptions to the norm. Over time you will become adept at reading potential clients, but these notes will hopefully help you avoid the worst of it. It is tough out there being a freelancer so good luck!</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="costing" label="costing"/><category scheme="taxonomy:Tags" term="freelance" label="freelance"/><category scheme="taxonomy:Tags" term="internet" label="Internet"/><category scheme="taxonomy:Tags" term="php" label="PHP"/></entry><entry xml:base="displaying-syntax-highlighted-code-in-wordpress"><title type="html">Displaying Syntax Highlighted Code in Wordpress</title><link href="https://www.simonholywell.com/post/2008/11/displaying-syntax-highlighted-code-in-wordpress/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2008/06/switched-to-wordpress/?utm_source=atom_feed" rel="related" type="text/html" title="Switched to WordPress"/><link href="https://www.simonholywell.com/post/2008/06/xampp-virtualhosts/?utm_source=atom_feed" rel="related" type="text/html" title="XAMPP VirtualHosts"/><link href="https://www.simonholywell.com/post/2008/05/installing-agavi-on-xampp-windows/?utm_source=atom_feed" rel="related" type="text/html" title="Installing Agavi on XAMPP Windows"/><link href="https://www.simonholywell.com/post/2006/12/geographic-calculations-in-php/?utm_source=atom_feed" rel="related" type="text/html" title="Geographic Calculations in PHP"/><link href="https://www.simonholywell.com/post/2006/12/secondary-dns-for-free/?utm_source=atom_feed" rel="related" type="text/html" title="Secondary DNS for Free"/><id>https://www.simonholywell.com/post/2008/11/displaying-syntax-highlighted-code-in-wordpress/</id><author><name>Simon Holywell</name></author><published>2008-11-14T16:49:23+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>It is difficult to use both the TinyMCE WYSIWYG and post formatted code. TinyMCE will attempt to cleanup your HTML and it will therefore remove any tags it does not recognise so your XML code will be hacked up. To compound the problem further Wordpress has annoying habit of removing all your carefully laid out indentation and line breaks.
There are many solutions to the problem out there including plugins that use BBCode to wrap the posted code up in.</summary><content type="html"><![CDATA[<p>It is difficult to use both the TinyMCE WYSIWYG and post formatted code. TinyMCE will attempt to cleanup your HTML and it will therefore remove any tags it does not recognise so your XML code will be hacked up. To compound the problem further Wordpress has annoying habit of removing all your carefully laid out indentation and line breaks.</p>
<p>There are many solutions to the problem out there including plugins that use BBCode to wrap the posted code up in. Use of special pre tags and code to stop code between pre tags from being changed. All of these are bandaid fixes and not a clean way of approaching the problem.</p>
<p>Should you need to move to a new publish platform in the future then all the extra code and hacks that were executed across your post so that it could display properly will leave you with a mangled code sample in the database. I much prefer another technique, which is to section your code away into a separate input and storage mechanism. Handily there is already plugin available that allows you store a snippet of any kind and then call it into your post at the appropriate location using a short BBCode tag. It is called <a href="http://urbangiraffe.com/plugins/sniplets/">Sniplets</a>.</p>
<p>If you want you code to be highlighted in the same way as mine then it will take some hacking to get the googleSyntaxHighlighter to work with Sniplets. Handily however Sniplets does include a module system where you can add new ways of manipulating data contained in Sniplets. The process is quite simple so I will leave it up to you to decide how you want to implement it. Sniplets does include a copy of <a href="http://qbnz.com/highlighter/">Geshi</a> as its default syntax highlighter, which is more than capable should you not wish to integrate the googleSyntaxHighlighter.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="wordpress" label="Wordpress"/><category scheme="taxonomy:Tags" term="internet" label="Internet"/></entry><entry xml:base="lancia-fulvia-hf"><title type="html">Lancia Fulvia HF</title><link href="https://www.simonholywell.com/post/2008/09/lancia-fulvia-hf/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2005/04/lancia-stratos/?utm_source=atom_feed" rel="related" type="text/html" title="Lancia Stratos"/><link href="https://www.simonholywell.com/post/2008/05/vauxhall-astra-front-brakes/?utm_source=atom_feed" rel="related" type="text/html" title="Vauxhall Astra Front Brakes"/><link href="https://www.simonholywell.com/post/2008/04/sql-server/?utm_source=atom_feed" rel="related" type="text/html" title="SQL SERVER"/><link href="https://www.simonholywell.com/post/2008/09/absence/?utm_source=atom_feed" rel="related" type="text/html" title="Absence"/><link href="https://www.simonholywell.com/post/2008/08/wedding/?utm_source=atom_feed" rel="related" type="text/html" title="Wedding"/><id>https://www.simonholywell.com/post/2008/09/lancia-fulvia-hf/</id><author><name>Simon Holywell</name></author><published>2008-09-29T12:56:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>I spotted this wonderful Italian rally car whilst I was on our Honeymoon and visiting Amsterdam. I am a big fan of the Lancia rally cars including the Fulvia pictured here, Stratos, 037, Delta S4 and Delta HF Integrale.
Some interesting reading on the HF in Lancia Fulvia HF and Lancia Fulvia Gold Portfolio, 1963-76 (Gold Portfolio). I am so tempted to get myself a scale model like this though:</summary><content type="html"><![CDATA[<p><img src="/static/images/wp/2008/09/2889191335_702a6bce27_b-300x200.jpg" alt="Lancia Fulvia HF"></p>
<p>I spotted this wonderful Italian rally car whilst I was on our Honeymoon and visiting Amsterdam. I am a big fan of the Lancia rally cars including the Fulvia pictured here, Stratos, 037, Delta S4 and Delta HF Integrale.</p>
<p>Some interesting reading on the HF in <a href="http://www.amazon.co.uk/gp/product/8879110845?ie=UTF8&amp;tag=simonholywell-21&amp;linkCode=as2&amp;camp=1634&amp;creative=6738&amp;creativeASIN=8879110845">Lancia Fulvia HF</a> and <a href="http://www.amazon.co.uk/gp/product/1855201631?ie=UTF8&amp;tag=simonholywell-21&amp;linkCode=as2&amp;camp=1634&amp;creative=6738&amp;creativeASIN=1855201631">Lancia Fulvia Gold Portfolio, 1963-76 (Gold Portfolio)</a>. I am so tempted to get myself a scale model like this though:</p>
<p><img src="/static/images/2008-09-29_lancia_fulvia_model.jpg" alt="Lancia Fulvia HF Scale Model"></p>
<p><a href="http://www.amazon.co.uk/gp/product/B002IJC0QI?ie=UTF8&amp;tag=simonholywell-21&amp;linkCode=as2&amp;camp=1634&amp;creative=6738&amp;creativeASIN=B002IJC0QI">IXO 1/43 Lancia Fulvia 1.6 Coupe HF Rally du Maroc 1972</a></p>
]]></content><category scheme="taxonomy:Categories" term="motors" label="Motors"/><category scheme="taxonomy:Tags" term="cars" label="Cars"/><category scheme="taxonomy:Tags" term="fulvia" label="Fulvia"/><category scheme="taxonomy:Tags" term="lancia" label="Lancia"/><category scheme="taxonomy:Tags" term="photos" label="photos"/><category scheme="taxonomy:Tags" term="spotted" label="spotted"/></entry><entry xml:base="absence"><title type="html">Absence</title><link href="https://www.simonholywell.com/post/2008/09/absence/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2008/08/wedding/?utm_source=atom_feed" rel="related" type="text/html" title="Wedding"/><link href="https://www.simonholywell.com/post/2008/02/engagement/?utm_source=atom_feed" rel="related" type="text/html" title="Engagement"/><link href="https://www.simonholywell.com/post/2007/12/moves/?utm_source=atom_feed" rel="related" type="text/html" title="Moves"/><link href="https://www.simonholywell.com/post/2007/06/london/?utm_source=atom_feed" rel="related" type="text/html" title="London"/><link href="https://www.simonholywell.com/post/2006/12/wow-almost-six-months/?utm_source=atom_feed" rel="related" type="text/html" title="Wow, Almost Six Months"/><id>https://www.simonholywell.com/post/2008/09/absence/</id><author><name>Simon Holywell</name></author><published>2008-09-16T20:30:45+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>I have been travelling around Europe for the last month or so and I have been completely out of reach. [STRIKEOUT:Unfortunately it looks as though the solution I had implemented for code highlighting has died during this time,][FIXED] [STRIKEOUT:but I have also noticed that it is stripping backslashes which is affecting the code – especially the MS SQL import script I have supplied on one of my posts][FIXED]. It contains references to newline characters etc (n), which have been destroyed by the Wordpress plug in I am using called Sniplets.</summary><content type="html"><![CDATA[<p><img src="/static/images/wp/2008/09/2889192703_bcb529b564_b.jpg" alt="Al Duomo, Firenze"></p>
<p>I have been travelling around Europe for the last month or so and I have been completely out of reach. [STRIKEOUT:Unfortunately it looks as though the solution I had implemented for code highlighting has died during this time,][FIXED] [STRIKEOUT:but I have also noticed that it is stripping backslashes which is affecting the code – especially the MS SQL import script I have supplied on one of my posts][FIXED]. It contains references to newline characters etc (n), which have been destroyed by the Wordpress plug in I am using called Sniplets.</p>
<p>My travels are going to continue so I am unsure when I will have this fixed again. Hopefully soon.</p>
]]></content><category scheme="taxonomy:Tags" term="life" label="life"/><category scheme="taxonomy:Tags" term="me" label="Me"/><category scheme="taxonomy:Tags" term="site-updates" label="Site Updates"/></entry><entry xml:base="wedding"><title type="html">Wedding</title><link href="https://www.simonholywell.com/post/2008/08/wedding/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2008/02/engagement/?utm_source=atom_feed" rel="related" type="text/html" title="Engagement"/><link href="https://www.simonholywell.com/post/2007/12/moves/?utm_source=atom_feed" rel="related" type="text/html" title="Moves"/><link href="https://www.simonholywell.com/post/2007/06/london/?utm_source=atom_feed" rel="related" type="text/html" title="London"/><link href="https://www.simonholywell.com/post/2005/11/downtimehousing/?utm_source=atom_feed" rel="related" type="text/html" title="Downtime/Housing"/><link href="https://www.simonholywell.com/post/2008/04/sql-server/?utm_source=atom_feed" rel="related" type="text/html" title="SQL SERVER"/><id>https://www.simonholywell.com/post/2008/08/wedding/</id><author><name>Simon Holywell</name></author><published>2008-08-29T23:28:14+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Marion and I were wed with a lovely ceremony on the 26th of July at the Brighton Pavilion in Brighton, England.
We are now travelling around western Europe and enjoying every moment of it even if we had to slum it in a Hilton in Innsbruck! ;-)
In other news I have now left my job at Wickedweb in Edenbridge, Kent and I will be moving to Auckland, New Zealand in October.</summary><content type="html"><![CDATA[<p><img src="/static/images/wp/2008/08/2945008216_81e2021604_b.jpg" alt="Brighton Pavilion"></p>
<p>Marion and I were wed with a lovely ceremony on the 26th of July at the Brighton Pavilion in Brighton, England.</p>
<p>We are now travelling around western Europe and enjoying every moment of it even if we had to slum it in a Hilton in Innsbruck! ;-)</p>
<p>In other news I have now left my job at Wickedweb in Edenbridge, Kent and I will be moving to Auckland, New Zealand in October. I have thoroughly enjoyed my time here in England and at <a href="http://www.wickedweb.co.uk/">Wickedweb</a>, <a href="http://www.underwired.co.uk/">Underwired*</a> &amp; <a href="http://jellyfish.co.uk">JellyFish Search Engine Marketing</a>. I will certainly be back in the UK at some point in the future to catch up with friends down here and in Scotland.</p>
]]></content><category scheme="taxonomy:Tags" term="life" label="life"/><category scheme="taxonomy:Tags" term="me" label="Me"/></entry><entry xml:base="switched-to-wordpress"><title type="html">Switched to WordPress</title><link href="https://www.simonholywell.com/post/2008/06/switched-to-wordpress/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2006/12/wow-almost-six-months/?utm_source=atom_feed" rel="related" type="text/html" title="Wow, Almost Six Months"/><link href="https://www.simonholywell.com/post/2006/04/new-design/?utm_source=atom_feed" rel="related" type="text/html" title="New Design"/><link href="https://www.simonholywell.com/post/2006/03/server-migration/?utm_source=atom_feed" rel="related" type="text/html" title="Server Migration"/><link href="https://www.simonholywell.com/post/2008/06/windows-cron-jobs-using-schtasks-or-at/?utm_source=atom_feed" rel="related" type="text/html" title="Windows Cron Jobs using Scheduled Tasks"/><link href="https://www.simonholywell.com/post/2008/06/xampp-virtualhosts/?utm_source=atom_feed" rel="related" type="text/html" title="XAMPP VirtualHosts"/><id>https://www.simonholywell.com/post/2008/06/switched-to-wordpress/</id><author><name>Simon Holywell</name></author><published>2008-06-29T06:18:16+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Wordpress
I have now moved my website over to WordPress; it is more widely supported than TextPattern and it has a regular release schedule.</summary><content type="html"><![CDATA[<p><a href="http://www.wordpress.org/"><img src="/static/images/wp/2008/06/blue-xl.png" alt="Wordpress"></a></p>
<p>Wordpress</p>
<p>I have now moved my website over to WordPress; it is more widely supported than TextPattern and it has a regular release schedule.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="wordpress" label="Wordpress"/><category scheme="taxonomy:Tags" term="site-updates" label="Site Updates"/></entry><entry xml:base="windows-cron-jobs-using-schtasks-or-at"><title type="html">Windows Cron Jobs using Scheduled Tasks</title><link href="https://www.simonholywell.com/post/2008/06/windows-cron-jobs-using-schtasks-or-at/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2008/04/sql-server-2005-dump-to-sql-statements/?utm_source=atom_feed" rel="related" type="text/html" title="SQL Server 2005 Dump to SQL statements"/><link href="https://www.simonholywell.com/post/2008/06/xampp-virtualhosts/?utm_source=atom_feed" rel="related" type="text/html" title="XAMPP VirtualHosts"/><link href="https://www.simonholywell.com/post/2008/05/installing-agavi-on-xampp-windows/?utm_source=atom_feed" rel="related" type="text/html" title="Installing Agavi on XAMPP Windows"/><link href="https://www.simonholywell.com/post/2008/05/php-common-mistakes/?utm_source=atom_feed" rel="related" type="text/html" title="Common PHP Mistakes"/><link href="https://www.simonholywell.com/post/2008/05/suzuki-bandit-carburettor-clean/?utm_source=atom_feed" rel="related" type="text/html" title="Suzuki Bandit Carburettor Clean"/><id>https://www.simonholywell.com/post/2008/06/windows-cron-jobs-using-schtasks-or-at/</id><author><name>Simon Holywell</name></author><published>2008-06-17T10:49:02+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>UPDATED: I have written a new, more indepth, article on this subject here: &amp;lt;/post/2009/01/linux-to-windows-server-migrating-and-securing-your-cron.html&amp;gt;
Every now and then you end up having to develop on a Windows box. Here are some handy hints for getting your cron jobs up and running.
The user interface for the Scheduled Tasks in Windows can be found at Start &amp;gt; Programs &amp;gt; Accessories &amp;gt; System Tools &amp;gt; Scheduled Tasks.
For performing cron jobs on webpages I recommend that you get the following binary: WGET for Windows</summary><content type="html"><![CDATA[<p><strong>UPDATED:</strong> I have written a new, more indepth, article on this subject here: <a href="/post/2009/01/linux-to-windows-server-migrating-and-securing-your-cron.html">&lt;/post/2009/01/linux-to-windows-server-migrating-and-securing-your-cron.html&gt;</a></p>
<p>Every now and then you end up having to develop on a Windows box. Here are some handy hints for getting your cron jobs up and running.</p>
<p>The user interface for the Scheduled Tasks in Windows can be found at Start &gt; Programs &gt; Accessories &gt; System Tools &gt; Scheduled Tasks.</p>
<p>For performing cron jobs on webpages I recommend that you get the following binary: <a href="http://pages.interlog.com/~tcharron/wgetwin.html">WGET for Windows</a></p>
<p>Now to setup your cron job:</p>
<ol>
<li>Double click Add Scheduled Task</li>
<li>Click Next to skip past the intro</li>
<li>Browse to program you wish run. Now you can use FireFox, Internet Explorer or indeed any other programme here. You could even run a batch script – more on this later. For web based invocation (calling a webpage over http etc) I recommend you use Wget though as it will not remain open after execution and it will use less resources. Of course if you have a PHP CLI script then you can invoke the PHP binary. I am going to focus on Wget and FireFox for the moment. After choosing the application click next.</li>
<li>Give your task a name and choose the regularity with which you wish the task to be performed.</li>
<li>Pick the time, start date and additional break points ie should it run on weekdays only?</li>
<li>Now you need to enter the username and password of the user this application will be run as. It goes without mentioning that running FireFox as Administrator is a bad idea. Next.</li>
<li>Check the “Open advanced properties for this task when I click Finish” checkbox and click finish.</li>
</ol>
<p>You are now presented with what looks like a standard Windows file property dialogue but there are a few extra options. You will arrive on the Task tab.</p>
<ol>
<li>In the Run input box we can now specify the file we would like to be opened by our Application. This should be the full URL: <code>http://example.org/my_cron_job.php</code> for both FireFox and Wget. For Wget only add the following onto the end of the run command: ” -r”. This will cause Wget to clobber the file it downloads instead of making copies: <a href="http://www.gnu.org/software/wget/manual/wget.html#Download-Options">Wget Manual</a> see ‘-nc’ <code>–no-clobber</code> So once your done your Run should resemble this <code>C:wget.exe http://example.org/my_cron_job.php -r</code></li>
<li>On the Schedule tab you can change the regularity of the Task with more granularity using the Advanced button. And you can have multiple schedules for the same Task.</li>
<li>The Settings tab I would set the Stop the task if it runs for: 00 hour(s) 1 minute(s).</li>
<li>Click OK.</li>
</ol>
<p>Once back in the list of Scheduled Tasks folder you can right click on the Task and choose Run to see if it works as expected.</p>
<p>I would like to have a few batch scripts that I could run like you would have cron.daily and cron.hourly in Linux. Then you only need one scheduled task and you can run multiple jobs for each time break down. Maybe another time.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="cron" label="cron"/><category scheme="taxonomy:Tags" term="windows" label="windows"/></entry><entry xml:base="xampp-virtualhosts"><title type="html">XAMPP VirtualHosts</title><link href="https://www.simonholywell.com/post/2008/06/xampp-virtualhosts/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2008/05/installing-agavi-on-xampp-windows/?utm_source=atom_feed" rel="related" type="text/html" title="Installing Agavi on XAMPP Windows"/><link href="https://www.simonholywell.com/post/2005/08/serving-virtual-hosts/?utm_source=atom_feed" rel="related" type="text/html" title="Serving Virtual Hosts"/><link href="https://www.simonholywell.com/post/2006/12/geographic-calculations-in-php/?utm_source=atom_feed" rel="related" type="text/html" title="Geographic Calculations in PHP"/><link href="https://www.simonholywell.com/post/2006/12/secondary-dns-for-free/?utm_source=atom_feed" rel="related" type="text/html" title="Secondary DNS for Free"/><link href="https://www.simonholywell.com/post/2006/06/server-log-spamming/?utm_source=atom_feed" rel="related" type="text/html" title="Server Log Spamming"/><id>https://www.simonholywell.com/post/2008/06/xampp-virtualhosts/</id><author><name>Simon Holywell</name></author><published>2008-06-14T17:08:39+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Here are some hints for those of you that use a XAMPP install for testing your developments on your local machine.
I am using a Windows machine running XP Pro and this is how I setup my VirtualHosts. The conf file you need to amend is located at c:\xampp\apache\conf\extra\httpd-vhosts.conf Open it up in your favourite editor and un-comment the following line near the top of the file:
NameVirtualHost *:80
This will enable the creation of VirtualHosts in your XAMMP installation.</summary><content type="html"><![CDATA[<p>Here are some hints for those of you that use a XAMPP install for testing your developments on your local machine.</p>
<p>I am using a Windows machine running XP Pro and this is how I setup my VirtualHosts. The conf file you need to amend is located at c:\xampp\apache\conf\extra\httpd-vhosts.conf Open it up in your <a href="http://www.vim.org/">favourite editor</a> and un-comment the following line near the top of the file:</p>
<p><code>NameVirtualHost *:80</code></p>
<p>This will enable the creation of VirtualHosts in your XAMMP installation.</p>
<p>Firstly you need a VirtualHost setup for localhost so that you can access the XAMPP scripts and demo files and any projects you might already have in the default htdocs location. This will look something similar to this:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-apacheconf" data-lang="apacheconf"><span class="line"><span class="cl"><span class="nt">&lt;VirtualHost</span> <span class="s">*:80</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nb">ServerAdmin</span> name@domain.com
</span></span><span class="line"><span class="cl">    <span class="nb">DocumentRoot</span> c:\xampp\htdocs
</span></span><span class="line"><span class="cl">    <span class="nb">ServerName</span> localhost
</span></span><span class="line"><span class="cl"><span class="nt">&lt;/VirtualHost&gt;</span>
</span></span></code></pre></div><p>Now for your custom VirtualHost. This can be placed anywhere on your computer where there are read permissions setup. It does not have to fall under the standard XAMPP htdocs folder. It will look something like this:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-apacheconf" data-lang="apacheconf"><span class="line"><span class="cl"><span class="nt">&lt;VirtualHost</span> <span class="s">*:80</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nb">ServerAdmin</span> name@domain.com
</span></span><span class="line"><span class="cl">    <span class="nb">DocumentRoot</span> c:\xampp\simonholywell.com\pub
</span></span><span class="line"><span class="cl">    <span class="nb">ServerName</span> simonholywell.localhost
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;Directory</span> <span class="s">c:\xampp\simonholywell.com\pub</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="nb">Order</span> allow,deny
</span></span><span class="line"><span class="cl">        <span class="nb">Allow</span> from <span class="k">all</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;/Directory&gt;</span>
</span></span><span class="line"><span class="cl"><span class="nt">&lt;/VirtualHost&gt;</span>
</span></span></code></pre></div><p>You will notice that in the above example there is a directory directive applied to the VirtualHost where there wasn’t one in the standard localhost VirtualHost we setup first. This is because the default install of XAMMP does not allow us to have folders outside of the DocumentRoot (<code>c:\\xampp\\htdocs</code>). The VirtualHost I setup was in <code>c:\\xampp</code> however so I had to allow Apache access in the VirtualHost container.</p>
<p>Don’t forget to add your new ServerName to your hosts file. Usually found in <code>c:\\WINDOWS\\System32\\drivers\\etc\\hosts</code> and editable with any text editor. Of course it goes without saying that Apache must be restarted after any configuration changes and you may need to restart your browser after some changes to the hosts file.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="virtualhosting" label="virtualhosting"/><category scheme="taxonomy:Tags" term="xampp" label="xampp"/><category scheme="taxonomy:Tags" term="internet" label="Internet"/></entry><entry xml:base="installing-agavi-on-xampp-windows"><title type="html">Installing Agavi on XAMPP Windows</title><link href="https://www.simonholywell.com/post/2008/05/installing-agavi-on-xampp-windows/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2006/12/geographic-calculations-in-php/?utm_source=atom_feed" rel="related" type="text/html" title="Geographic Calculations in PHP"/><link href="https://www.simonholywell.com/post/2006/12/secondary-dns-for-free/?utm_source=atom_feed" rel="related" type="text/html" title="Secondary DNS for Free"/><link href="https://www.simonholywell.com/post/2006/06/server-log-spamming/?utm_source=atom_feed" rel="related" type="text/html" title="Server Log Spamming"/><link href="https://www.simonholywell.com/post/2006/03/form-spam-not-ham/?utm_source=atom_feed" rel="related" type="text/html" title='Form SPAM (not "HAM") fighting tips'/><link href="https://www.simonholywell.com/post/2006/03/flickering-images/?utm_source=atom_feed" rel="related" type="text/html" title="Flickering Images"/><id>https://www.simonholywell.com/post/2008/05/installing-agavi-on-xampp-windows/</id><author><name>Simon Holywell</name></author><published>2008-05-18T16:44:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Having recently heard of the Agavi project from a web framework showdown at a PHP conference in the UK I have decided to trial it. My setup is a WinXP computer with a default install of the latest XAMPP which has thrown up some issues with installing and building Agavi. Please see my hints below to overcome these issues.
Open a command prompt (type cmd in the run console) Navigate to your XAMMP PHP directory.</summary><content type="html"><![CDATA[<p>Having recently heard of the <a href="http://www.agavi.org">Agavi project</a> from a web framework showdown at a PHP conference in the UK I have decided to trial it. My setup is a WinXP computer with a default install of the latest <a href="http://www.apachefriends.org">XAMPP</a> which has thrown up some issues with installing and building Agavi. Please see my hints below to overcome these issues.</p>
<ol>
<li>Open a command prompt (type cmd in the run console)</li>
<li>Navigate to your XAMMP PHP directory. Mine is C:\xampp-test\php</li>
<li>Execute pear.bat channel-discover pear.agavi.org</li>
<li>Execute pear.bat install agavi/agavi</li>
</ol>
<p>Agavi is now installed! Now we just need a new default project to work from.</p>
<p>Agavi needs to be told where the phing batch file is stored.</p>
<ol>
<li>Edit the agavi.bat file in the XAMPP php directory. Mine is <code>C:\\xampp-test\\php\\agavi.bat</code></li>
<li>Change set PHING_COMMAND=phing to contain the full absolute path to phing.bat which is in the XAMPP php folder. Mine looks like this: <code>set PHING\_COMMAND=C:\\xampp-test\\php\\phing.bat</code></li>
</ol>
<p>Begin setting up your project directory.</p>
<ol>
<li>Create a new directory in your XAMPP directory. Mine is <code>C:\\xampp-test\\htdocs\\simonholywell.com</code></li>
<li>Create an empty text file called build.properties in the directory (this banishes a build error where phing fails if it cannot find the file)</li>
<li>Open a command prompt and navigate to the new directory</li>
<li>Execute agavi.bat project The agavi.bat file is stored in the XAMPP php folder. My command looked like this: <code>C:\\xampp-test\\php\\agavi.bat</code> project</li>
<li>Follow the prompts the installer gives you (hitting enter will supply the installer with the [default] value)</li>
</ol>
<p>Agavi should now be setup for your project. View it in your browser to verify.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="agavi" label="agavi"/><category scheme="taxonomy:Tags" term="xampp" label="xampp"/><category scheme="taxonomy:Tags" term="internet" label="Internet"/></entry><entry xml:base="php-common-mistakes"><title type="html">Common PHP Mistakes</title><link href="https://www.simonholywell.com/post/2008/05/php-common-mistakes/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2008/04/sql-server-2005-dump-to-sql-statements/?utm_source=atom_feed" rel="related" type="text/html" title="SQL Server 2005 Dump to SQL statements"/><link href="https://www.simonholywell.com/post/2006/12/geographic-calculations-in-php/?utm_source=atom_feed" rel="related" type="text/html" title="Geographic Calculations in PHP"/><link href="https://www.simonholywell.com/post/2006/03/form-spam-not-ham/?utm_source=atom_feed" rel="related" type="text/html" title='Form SPAM (not "HAM") fighting tips'/><link href="https://www.simonholywell.com/post/2006/03/flickering-images/?utm_source=atom_feed" rel="related" type="text/html" title="Flickering Images"/><link href="https://www.simonholywell.com/post/2005/12/adodb/?utm_source=atom_feed" rel="related" type="text/html" title="ADODB"/><id>https://www.simonholywell.com/post/2008/05/php-common-mistakes/</id><author><name>Simon Holywell</name></author><published>2008-05-18T11:08:11+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>A few common PHP mistakes:
Using require_once when a simple require would achieve the same result. Using require uses less system resources and therefore executes more quickly. You should engineer your code so you don’t need to use require_once. The same of course applies to include statements. Failing to declare variables before attempting to use them. Don’t use absolute paths and URLs where relative will suffice Not opening code for peer review.</summary><content type="html"><![CDATA[<p><img src="/static/images/wp/2008/05/brand.gif" alt="PHP (elePHPant)"></p>
<p>A few common PHP mistakes:</p>
<ul>
<li>Using require_once when a simple require would achieve the same result. Using require uses less system resources and therefore executes more quickly. You should engineer your code so you don’t need to use require_once. The same of course applies to include statements.</li>
<li>Failing to declare variables before attempting to use them.</li>
<li>Don’t use absolute paths and URLs where relative will suffice</li>
<li>Not opening code for peer review. Often others will have ingenuous just like you about how to optimise your code. Make use of the resources you have.</li>
<li>Using double quotes where an apostrophe will fit better. Only use “ where the string you are constructing contains ‘ or variables you wish to substituted. This saves the PHP parser from expanding text it doesn’t need to.</li>
<li>It is recommended that you place the value you wish to match before the variable you hope to find it in. Eg. if (‘test’ == $var) { } This prevents the value being assigned to the variable should you forget an =</li>
</ul>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="php" label="PHP"/></entry><entry xml:base="suzuki-bandit-carburettor-clean"><title type="html">Suzuki Bandit Carburettor Clean</title><link href="https://www.simonholywell.com/post/2008/05/suzuki-bandit-carburettor-clean/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2008/03/getting-back-on-the-bike/?utm_source=atom_feed" rel="related" type="text/html" title="Getting Back on the Bike"/><link href="https://www.simonholywell.com/post/2008/05/vauxhall-astra-front-brakes/?utm_source=atom_feed" rel="related" type="text/html" title="Vauxhall Astra Front Brakes"/><link href="https://www.simonholywell.com/post/2008/04/sql-server-2005-dump-to-sql-statements/?utm_source=atom_feed" rel="related" type="text/html" title="SQL Server 2005 Dump to SQL statements"/><link href="https://www.simonholywell.com/post/2008/04/sql-server/?utm_source=atom_feed" rel="related" type="text/html" title="SQL SERVER"/><link href="https://www.simonholywell.com/post/2007/07/biking-to-the-uk/?utm_source=atom_feed" rel="related" type="text/html" title="Biking to the UK"/><id>https://www.simonholywell.com/post/2008/05/suzuki-bandit-carburettor-clean/</id><author><name>Simon Holywell</name></author><published>2008-05-14T17:47:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Suzuki Bandit in the snow
When I went away on holiday the other year I left my Bandit standing for about 3 weeks and it must of had a bad batch of fuel in the tank. The bad fuel turned into jelly in the carburettors and of course the bike started running like a dog. In the back of my mind I had thought I should drain the float bowls before leaving, but it got forgotten in all the excitement of the trip.</summary><content type="html"><![CDATA[<p><img src="/static/images/wp/2008/05/2393458606_9cda8eb84a_b2.jpg" alt="Suzuki Bandit in the snow"></p>
<p>Suzuki Bandit in the snow</p>
<p>When I went away on holiday the other year I left my Bandit standing for about 3 weeks and it must of had a bad batch of fuel in the tank. The bad fuel turned into jelly in the carburettors and of course the bike started running like a dog. In the back of my mind I had thought I should drain the float bowls before leaving, but it got forgotten in all the excitement of the trip.</p>
<p><strong>If you suspect you have left your bike too long and that the fuel will have turned to jelly do not start it. Before getting into details I also strongly suggest you purchase the <a href="http://www.amazon.co.uk/gp/product/1844255964?ie=UTF8&amp;tag=simonholywell-21&amp;linkCode=as2&amp;camp=1634&amp;creative=6738&amp;creativeASIN=1844255964">Suzuki GSF600, 650 and 1200 Bandit Service and Repair Manual: 1995 to 2006</a> as it contains a lot of very useful information including the all important tightening torques.</strong></p>
<p>Anyway so the bike now would not run a week after returning and I desperately wanted to ride so I stripped the fairings off, drained the fuel tank by pulling the fuel lead and opening the petcock, removed the fuel tank, removed the battery, pulled the airbox out and finally released the carburettors. This involved disconnecting the throttle cable, the fuel hose and the fuel overflow hoses not forgetting the choke cable of course.</p>
<p>Once you have the four carbies out you need to set about pulling the float bowl covers off and inspecting them and cleaning with carb cleaner as needed. Also pull out the pilot screw/needle remembering how many turns it takes. Pop the diaphragm cover and remove the rubber diaphragm checking for any problems. Don’t forget to hang on to the spring that is under the cover and remove the fuel flow needle.</p>
<p>Give it a good blast of carb cleaner and then blow out with compressed air and you should see gunk come flying out. Use further cleaner and air blasts for stubborn rubbish.</p>
<p>Carefully reassemble and attach to the motorbike in reverse order.</p>
<p>The following video illustrates this process fairly well (bare in mind it was not made using Bandit carbs so they differ slightly). <a href="http://www.youtube.com/watch?v=USqw8tYDUbw">Video</a></p>
]]></content><category scheme="taxonomy:Categories" term="motors" label="Motors"/><category scheme="taxonomy:Tags" term="bandit" label="bandit"/><category scheme="taxonomy:Tags" term="bikes" label="Bikes"/><category scheme="taxonomy:Tags" term="maintenance" label="maintenance"/><category scheme="taxonomy:Tags" term="suzuki" label="suzuki"/></entry><entry xml:base="vauxhall-astra-front-brakes"><title type="html">Vauxhall Astra Front Brakes</title><link href="https://www.simonholywell.com/post/2008/05/vauxhall-astra-front-brakes/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2008/04/sql-server/?utm_source=atom_feed" rel="related" type="text/html" title="SQL SERVER"/><link href="https://www.simonholywell.com/post/2008/03/getting-back-on-the-bike/?utm_source=atom_feed" rel="related" type="text/html" title="Getting Back on the Bike"/><link href="https://www.simonholywell.com/post/2005/04/lancia-stratos/?utm_source=atom_feed" rel="related" type="text/html" title="Lancia Stratos"/><link href="https://www.simonholywell.com/post/2008/04/mobile-browsing/?utm_source=atom_feed" rel="related" type="text/html" title="Mobile Browsing"/><link href="https://www.simonholywell.com/post/2008/04/sql-server-2005-dump-to-sql-statements/?utm_source=atom_feed" rel="related" type="text/html" title="SQL Server 2005 Dump to SQL statements"/><id>https://www.simonholywell.com/post/2008/05/vauxhall-astra-front-brakes/</id><author><name>Simon Holywell</name></author><published>2008-05-14T17:05:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Vauxhall Astra
For those you who possess an Astra from 1990-1998 the following hints might prove useful along with the more long winded description provided by the Vauxhall Astra (1991-98) Service and Repair Manual. I bought a set of two vented rotors and four brake pads for about £40 on ebay so they are reasonably cheap.
Removing the calliper from the calliper carrier requires a 7mm allen key and to remove the calliper carrier from the hub you will need a 10mm allen key.</summary><content type="html"><![CDATA[<p><img src="/static/images/wp/2008/05/28711682__1221582579__1__1-97d13e860eb5dc2f7b61e91633364d22__big__.jpg" alt="Vauxhall Astra"></p>
<p>Vauxhall Astra</p>
<p>For those you who possess an Astra from 1990-1998 the following hints might prove useful along with the more long winded description provided by the <a href="http://www.amazon.co.uk/gp/product/1859605885?ie=UTF8&amp;tag=simonholywell-21&amp;linkCode=as2&amp;camp=1634&amp;creative=6738&amp;creativeASIN=1859605885">Vauxhall Astra (1991-98) Service and Repair Manual</a>. I bought a set of two vented rotors and four brake pads for about £40 on ebay so they are reasonably cheap.</p>
<p>Removing the calliper from the calliper carrier requires a 7mm allen key and to remove the calliper carrier from the hub you will need a 10mm allen key.</p>
<p>To make it easier you will need to remove the calliper from the carrier first and then drop the carrier off. The calliper bolts are hidden behind a rubber grommit so they are nicely protected from the elements and corrosion the bolts for the carrier however can be quite tough to shift because they are exposed so I recommend using an allen socket on the end of a breakers bar to get it moving.</p>
<p>The calliper is held in place with a wire spring type fitting kit. This is easy to remove with a screw driver and some leverage and just as easy to fit back up once the pads are changed and the calliper &amp; its carrier are refitted to the car.</p>
<p>A philips head screw driver will have the rotor retaining screw out and then it is simply a matter of reversing the process.</p>
<p>If you are just changing the pads then you should remember to have the rotor/disc surface machined flat again.</p>
<p>There is nothing complicated with a fairly simple single piston calliper so it should not be any problem for someone with any experience of brake maintenance.</p>
]]></content><category scheme="taxonomy:Categories" term="motors" label="Motors"/><category scheme="taxonomy:Tags" term="cars" label="Cars"/><category scheme="taxonomy:Tags" term="maintenance" label="maintenance"/></entry><entry xml:base="mobile-browsing"><title type="html">Mobile Browsing</title><link href="https://www.simonholywell.com/post/2008/04/mobile-browsing/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2008/04/sql-server-2005-dump-to-sql-statements/?utm_source=atom_feed" rel="related" type="text/html" title="SQL Server 2005 Dump to SQL statements"/><link href="https://www.simonholywell.com/post/2008/04/sql-server/?utm_source=atom_feed" rel="related" type="text/html" title="SQL SERVER"/><link href="https://www.simonholywell.com/post/2008/03/getting-back-on-the-bike/?utm_source=atom_feed" rel="related" type="text/html" title="Getting Back on the Bike"/><link href="https://www.simonholywell.com/post/2008/03/mysql-to-ms-sql-sql-server/?utm_source=atom_feed" rel="related" type="text/html" title="MySQL to MS SQL (SQL Server)"/><link href="https://www.simonholywell.com/post/2008/02/engagement/?utm_source=atom_feed" rel="related" type="text/html" title="Engagement"/><id>https://www.simonholywell.com/post/2008/04/mobile-browsing/</id><author><name>Simon Holywell</name></author><published>2008-04-14T17:44:08+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>I have recently been using the web from my mobile quite a bit. My email is hosted by Google for my domain name so I use their freely available mobile java app (with the blue icon) to view my mail. The best web browser on the mobile is of course Opera Mini. I make no secret of my love of Opera on the desktop. After having downloaded and used Opera Mini I am very impressed with the way it renders pages and the browsing experience it offers on such a small screen.</summary><content type="html"><![CDATA[<p><img src="/static/images/wp/2008/04/phonel.jpg" alt="Phone"></p>
<p>I have recently been using the web from my mobile quite a bit. My email is hosted by Google for my domain name so I use their freely available <a href="http://m.google.com/a">mobile java</a> app (with the blue icon) to view my mail. The best web browser on the mobile is of course Opera Mini. I make no secret of my love of Opera on the desktop. After having downloaded and used Opera Mini I am very impressed with the way it renders pages and the browsing experience it offers on such a small screen.</p>
<p>I am infact writing this blog post with the help of Opera Mini on my Sony Ericsson K800i mobile telephone.</p>
<p>This is one huge advantage of using Textile because I can easily mark up my post even in such a restricted environment such as a mobile. <a href="http://textism.com/tools/textile/">Textile</a> is the mark up language used by <a href="http://www.textpattern.com/">Textpattern</a></p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="mobile" label="mobile"/></entry><entry xml:base="sql-server-2005-dump-to-sql-statements"><title type="html">SQL Server 2005 Dump to SQL statements</title><link href="https://www.simonholywell.com/post/2008/04/sql-server-2005-dump-to-sql-statements/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2006/12/geographic-calculations-in-php/?utm_source=atom_feed" rel="related" type="text/html" title="Geographic Calculations in PHP"/><link href="https://www.simonholywell.com/post/2006/03/flickering-images/?utm_source=atom_feed" rel="related" type="text/html" title="Flickering Images"/><link href="https://www.simonholywell.com/post/2005/12/adodb/?utm_source=atom_feed" rel="related" type="text/html" title="ADODB"/><link href="https://www.simonholywell.com/post/2008/04/sql-server/?utm_source=atom_feed" rel="related" type="text/html" title="SQL SERVER"/><link href="https://www.simonholywell.com/post/2008/03/getting-back-on-the-bike/?utm_source=atom_feed" rel="related" type="text/html" title="Getting Back on the Bike"/><id>https://www.simonholywell.com/post/2008/04/sql-server-2005-dump-to-sql-statements/</id><author><name>Simon Holywell</name></author><published>2008-04-08T13:36:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Say you have a development environment setup using SQL Server 2005 Express Edition and your customer has a SQL Server 2000 database accessible only via ODBC and you can only run a DB import via a script. How would you do it? Easy you might think just run msdbdump.exe on the command line, well this isn’t MySQL so you are not so fortunate.
Backing up your DB is easy with SQL Server using the following commands:</summary><content type="html"><![CDATA[<p>Say you have a development environment setup using SQL Server 2005 Express Edition and your customer has a SQL Server 2000 database accessible only via ODBC and you can only run a DB import via a script. How would you do it? Easy you might think just run msdbdump.exe on the command line, well this isn’t MySQL so you are not so fortunate.</p>
<p>Backing up your DB is easy with SQL Server using the following commands:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="n">sp_addumpdevice</span><span class="w"> </span><span class="s1">&#39;disk&#39;</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;pseudoName&#39;</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;C:yourFilename.mdb&#39;</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">GO</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="n">DUMP</span><span class="w"> </span><span class="k">DATABASE</span><span class="w"> </span><span class="n">yourDatabaseName</span><span class="w"> </span><span class="k">TO</span><span class="w"> </span><span class="n">pseudoName</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">GO</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="n">sp_dropdevice</span><span class="w"> </span><span class="n">pseudoName</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div><p>But this just gives you a binary file that can be restored if you have access privileges to the live database for restoring. If you are in a shared hosting environment or one where the paranoid admins won’t give you remote desktop access and the only access you have is to run a PHP script to import the data and schema via SQL you will need to export the DB to T-SQL format. For more information on T-SQL I recommend the following two books <a href="http://www.amazon.co.uk/gp/product/0672328674?ie=UTF8&amp;tag=simonholywell-21&amp;linkCode=as2&amp;camp=1634&amp;creative=6738&amp;creativeASIN=0672328674">Sams Teach Yourself Microsoft SQL Server T-SQL in 10 Minutes</a> and <a href="http://www.amazon.co.uk/gp/product/0735626014?ie=UTF8&amp;tag=simonholywell-21&amp;linkCode=as2&amp;camp=1634&amp;creative=6738&amp;creativeASIN=0735626014">Microsoft SQL Server T-SQL Fundamentals</a>.</p>
<p>Microsoft have a little program to perform this very function: <a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=56E5B1C5-BF17-42E0-A410-371A838E570A&amp;displaylang=en">Microsoft SQL Server Database Publishing Wizard 1.1</a> It is difficult to find on the web so I aim to save you the time I spent hunting for it. When you run the wizard make sure to set:</p>
<ul>
<li>Drop existing objects in script to <strong>false</strong></li>
<li>Schema qualify to <strong>false</strong></li>
<li>Script for target database to <strong>SQL Server 2000</strong></li>
</ul>
<p>It does seem to chew on the cud for quite some time so grab a beverage.</p>
<p>Now for the PHP portion of the process. So you have uploaded your lovely T-SQL dump file to a PHP accessible location on your webserver and now you are wondering how to get into your DB via ODBC. Well you will need a PHP script like the one I have supplied below.</p>
<p>A couple of the complexities to be aware of before you continue. It seems that the T-SQL dump file comes out as UTF16 and we need it in UTF8 so you will need to convert it to UTF8 before you can import. I used a neat little function available from <a href="http://www.moddular.org/log/utf16-to-utf8">Modular.org</a> for this purpose. This may or may not meet your needs. If you need a more accurate conversion method then I recommend you start your search with the PHP module/function <a href="http://uk.php.net/mbstring">mbstring</a> . T-SQL contains reference and keywords that ODBC/MS SQL cannot understand. I have included some regex to strip these out.</p>
<p>My script is by no means perfect or factored down so feel free to make suggestions or improvements.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o">&lt;?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl"><span class="sd">/**
</span></span></span><span class="line"><span class="cl"><span class="sd"> * Import a MS SQL T-SQL dump file into
</span></span></span><span class="line"><span class="cl"><span class="sd"> * and ODBC connection via a PHP browser
</span></span></span><span class="line"><span class="cl"><span class="sd"> * script.
</span></span></span><span class="line"><span class="cl"><span class="sd"> *
</span></span></span><span class="line"><span class="cl"><span class="sd"> * I have not tested the script with binary DB fields so
</span></span></span><span class="line"><span class="cl"><span class="sd"> * I cannot confirm whether it works or not.
</span></span></span><span class="line"><span class="cl"><span class="sd"> *
</span></span></span><span class="line"><span class="cl"><span class="sd"> * @author Simon Holywell
</span></span></span><span class="line"><span class="cl"><span class="sd"> * @version 8/4/2008
</span></span></span><span class="line"><span class="cl"><span class="sd"> */</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">//Up the execution limits - you may need to tweak for
</span></span></span><span class="line"><span class="cl"><span class="c1">//larger database imports I have only tested up to 9MB
</span></span></span><span class="line"><span class="cl"><span class="c1">//which took 30seconds to process with this file.
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">ini_set</span><span class="p">(</span><span class="s1">&#39;max_execution_time&#39;</span><span class="p">,</span> <span class="mi">1000</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">ini_set</span><span class="p">(</span><span class="s1">&#39;max_input_time&#39;</span><span class="p">,</span> <span class="mi">1000</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">ini_set</span><span class="p">(</span><span class="s1">&#39;memory_limit&#39;</span><span class="p">,</span> <span class="s1">&#39;120M&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">//ODBC connection details
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nv">$server_dsn</span> <span class="o">=</span> <span class="s1">&#39;dsn&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nv">$user</span> <span class="o">=</span> <span class="s1">&#39;user&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nv">$pass</span> <span class="o">=</span> <span class="s1">&#39;pass&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">//path to T-SQL dump file
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nv">$dump_filename</span> <span class="o">=</span> <span class="s1">&#39;../dump.sql&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">//drop the tables that already
</span></span></span><span class="line"><span class="cl"><span class="c1">//exist in the DB?
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nv">$drop_prexisting</span> <span class="o">=</span> <span class="k">true</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">//How many queries should the script
</span></span></span><span class="line"><span class="cl"><span class="c1">//execute per database connection
</span></span></span><span class="line"><span class="cl"><span class="c1">//this is in place to stop the DB/ODBC
</span></span></span><span class="line"><span class="cl"><span class="c1">//connection from timing out on us.
</span></span></span><span class="line"><span class="cl"><span class="c1">//5 is a safe number if you have large
</span></span></span><span class="line"><span class="cl"><span class="c1">//database fields
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nv">$how_many_per_connection</span> <span class="o">=</span> <span class="mi">5</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">function</span> <span class="nf">utf16_to_utf8</span><span class="p">(</span><span class="nv">$str</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">//http://www.moddular.org/log/utf16-to-utf8
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="c1">//16th March 2006
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="nv">$c0</span> <span class="o">=</span> <span class="nx">ord</span><span class="p">(</span><span class="nv">$str</span><span class="p">[</span><span class="mi">0</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl">    <span class="nv">$c1</span> <span class="o">=</span> <span class="nx">ord</span><span class="p">(</span><span class="nv">$str</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="nv">$c0</span> <span class="o">==</span> <span class="mh">0xFE</span> <span class="o">&amp;&amp;</span> <span class="nv">$c1</span> <span class="o">==</span> <span class="mh">0xFF</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$be</span> <span class="o">=</span> <span class="k">true</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nv">$c0</span> <span class="o">==</span> <span class="mh">0xFF</span> <span class="o">&amp;&amp;</span> <span class="nv">$c1</span> <span class="o">==</span> <span class="mh">0xFE</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$be</span> <span class="o">=</span> <span class="k">false</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$str</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nv">$str</span> <span class="o">=</span> <span class="nx">substr</span><span class="p">(</span><span class="nv">$str</span><span class="p">,</span> <span class="mi">2</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nv">$len</span> <span class="o">=</span> <span class="nx">strlen</span><span class="p">(</span><span class="nv">$str</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nv">$dec</span> <span class="o">=</span> <span class="s1">&#39;&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="p">(</span><span class="nv">$i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nv">$i</span> <span class="o">&lt;</span> <span class="nv">$len</span><span class="p">;</span> <span class="nv">$i</span> <span class="o">+=</span> <span class="mi">2</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$c</span> <span class="o">=</span> <span class="p">(</span><span class="nv">$be</span><span class="p">)</span> <span class="o">?</span> <span class="nx">ord</span><span class="p">(</span><span class="nv">$str</span><span class="p">[</span><span class="nv">$i</span><span class="p">])</span> <span class="o">&lt;&lt;</span> <span class="mi">8</span> <span class="o">|</span> <span class="nx">ord</span><span class="p">(</span><span class="nv">$str</span><span class="p">[</span><span class="nv">$i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">])</span> <span class="o">:</span>
</span></span><span class="line"><span class="cl">                <span class="nx">ord</span><span class="p">(</span><span class="nv">$str</span><span class="p">[</span><span class="nv">$i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">])</span> <span class="o">&lt;&lt;</span> <span class="mi">8</span> <span class="o">|</span> <span class="nx">ord</span><span class="p">(</span><span class="nv">$str</span><span class="p">[</span><span class="nv">$i</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="nv">$c</span> <span class="o">&gt;=</span> <span class="mh">0x0001</span> <span class="o">&amp;&amp;</span> <span class="nv">$c</span> <span class="o">&lt;=</span> <span class="mh">0x007F</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nv">$dec</span> <span class="o">.=</span> <span class="nx">chr</span><span class="p">(</span><span class="nv">$c</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nv">$c</span> <span class="o">&gt;</span> <span class="mh">0x07FF</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nv">$dec</span> <span class="o">.=</span> <span class="nx">chr</span><span class="p">(</span><span class="mh">0xE0</span> <span class="o">|</span> <span class="p">((</span><span class="nv">$c</span> <span class="o">&gt;&gt;</span> <span class="mi">12</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mh">0x0F</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">            <span class="nv">$dec</span> <span class="o">.=</span> <span class="nx">chr</span><span class="p">(</span><span class="mh">0x80</span> <span class="o">|</span> <span class="p">((</span><span class="nv">$c</span> <span class="o">&gt;&gt;</span>  <span class="mi">6</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mh">0x3F</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">            <span class="nv">$dec</span> <span class="o">.=</span> <span class="nx">chr</span><span class="p">(</span><span class="mh">0x80</span> <span class="o">|</span> <span class="p">((</span><span class="nv">$c</span> <span class="o">&gt;&gt;</span>  <span class="mi">0</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mh">0x3F</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nv">$dec</span> <span class="o">.=</span> <span class="nx">chr</span><span class="p">(</span><span class="mh">0xC0</span> <span class="o">|</span> <span class="p">((</span><span class="nv">$c</span> <span class="o">&gt;&gt;</span>  <span class="mi">6</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mh">0x1F</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">            <span class="nv">$dec</span> <span class="o">.=</span> <span class="nx">chr</span><span class="p">(</span><span class="mh">0x80</span> <span class="o">|</span> <span class="p">((</span><span class="nv">$c</span> <span class="o">&gt;&gt;</span>  <span class="mi">0</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mh">0x3F</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nv">$dec</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">function</span> <span class="nf">microtime_float</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">//http://www.developertutorials.com/blog/php/php-measure-max-execution-time-script-execution-time-83/
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="c1">//Akash Mehta
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="c1">//March 15th, 2008
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="k">list</span><span class="p">(</span><span class="nv">$utime</span><span class="p">,</span> <span class="nv">$time</span><span class="p">)</span> <span class="o">=</span> <span class="nx">explode</span><span class="p">(</span><span class="s2">&#34; &#34;</span><span class="p">,</span> <span class="nx">microtime</span><span class="p">());</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="p">((</span><span class="nx">float</span><span class="p">)</span><span class="nv">$utime</span> <span class="o">+</span> <span class="p">(</span><span class="nx">float</span><span class="p">)</span><span class="nv">$time</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="cp">?&gt;</span><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err">&lt;p&gt;Dropping:&lt;/p&gt;
</span></span></span><span class="line"><span class="cl"><span class="err">&lt;?php
</span></span></span><span class="line"><span class="cl"><span class="err">//drop all pre-existing tables in the DB prior to importing
</span></span></span><span class="line"><span class="cl"><span class="err">if($drop_prexisting)
</span></span></span><span class="line"><span class="cl"><span class="err">    $table_drop_sql = &#39;&#39;;
</span></span></span><span class="line"><span class="cl"><span class="err">$link2 = odbc_connect($server_dsn, $user, $pass) or die(&#39;Unable to connect to the server: &#39;.odbc_errormsg());
</span></span></span><span class="line"><span class="cl"><span class="err">$tables = odbc_tables($link2);
</span></span></span><span class="line"><span class="cl"><span class="err">while (odbc_fetch_row($tables)){
</span></span></span><span class="line"><span class="cl"><span class="err">    if(odbc_result($tables,&#34;TABLE_TYPE&#34;)==&#34;TABLE&#34;) {
</span></span></span><span class="line"><span class="cl"><span class="err">        $table_name = odbc_result($tables,&#34;TABLE_NAME&#34;);
</span></span></span><span class="line"><span class="cl"><span class="err">        print $table_name.&#39;&lt;br /&gt;&#39;;
</span></span></span><span class="line"><span class="cl"><span class="err">        if($drop_prexisting)
</span></span></span><span class="line"><span class="cl"><span class="err">            $table_drop_sql .= &#34;DROP TABLE $table_name\n&#34;;
</span></span></span><span class="line"><span class="cl"><span class="err">    }
</span></span></span><span class="line"><span class="cl"><span class="err">}
</span></span></span><span class="line"><span class="cl"><span class="err">odbc_close($link2);
</span></span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err">if($drop_prexisting) {
</span></span></span><span class="line"><span class="cl"><span class="err">    $link2 = odbc_connect($server_dsn, $user, $pass) or die(&#39;Unable to connect to the server: &#39;.odbc_errormsg());
</span></span></span><span class="line"><span class="cl"><span class="err">    @odbc_exec($link2, $table_drop_sql);
</span></span></span><span class="line"><span class="cl"><span class="err">    odbc_close($link2);
</span></span></span><span class="line"><span class="cl"><span class="err">}
</span></span></span><span class="line"><span class="cl"><span class="err">?&gt;
</span></span></span><span class="line"><span class="cl"><span class="err">&lt;p&gt;Have patience - converting the DB file to UTF8 and removing guff&amp;hellip;&lt;/p&gt;
</span></span></span><span class="line"><span class="cl"><span class="err">&lt;?php
</span></span></span><span class="line"><span class="cl"><span class="err">$script_start = microtime_float();
</span></span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err">$file = file_get_contents($dump_filename);
</span></span></span><span class="line"><span class="cl"><span class="err">//convert from utf16 to utf8 character encoding
</span></span></span><span class="line"><span class="cl"><span class="err">$file = utf16_to_utf8($file);
</span></span></span><span class="line"><span class="cl"><span class="err">//strip out errant MS line endings
</span></span></span><span class="line"><span class="cl"><span class="err">$file = str_replace(array(&#34;\r&#34;,&#34;\r\n&#34;,&#34;\r\n&#34;,&#34;\n\n&#34;), &#34;\n&#34;, $file);
</span></span></span><span class="line"><span class="cl"><span class="err">//strip more guff that ODBC/MS SQL cannot understand
</span></span></span><span class="line"><span class="cl"><span class="err">//(the dbo object doesn&#39;t exist via ODBC)
</span></span></span><span class="line"><span class="cl"><span class="err">$file = preg_replace(&#34;/^IF NOT EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N&#39;[[a-z_]+]&#39;) AND OBJECTPROPERTY(id, N&#39;IsUserTable&#39;) = 1)$/im&#34;,&#39;&#39;,$file);
</span></span></span><span class="line"><span class="cl"><span class="err">//strip out print statements
</span></span></span><span class="line"><span class="cl"><span class="err">$file = preg_replace(&#34;/^print &#39;[a-z0-9 ]+&#39;$/im&#34;, &#39;&#39;, $file);
</span></span></span><span class="line"><span class="cl"><span class="err">//strip SQL Server comments
</span></span></span><span class="line"><span class="cl"><span class="err">$file = preg_replace(&#39;/^/[*]{6} [a-z0-9[] /:._]+ [*]{6}/$/im&#39;, &#39;&#39;, $file);
</span></span></span><span class="line"><span class="cl"><span class="err">//strip out SQL Server rubbish and any errant dbo refs
</span></span></span><span class="line"><span class="cl"><span class="err">$file = str_replace(array(&#34;GO\n&#34;,&#39;[dbo].&#39;,&#39;dbo.&#39;), &#39;&#39;, $file);
</span></span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err">//lets split up the queries by stepping through the file and breaking on insert statements
</span></span></span><span class="line"><span class="cl"><span class="err">$search_string = &#34;\nINSERT [&#34;;
</span></span></span><span class="line"><span class="cl"><span class="err">$file_length = strlen($file);
</span></span></span><span class="line"><span class="cl"><span class="err">$iteration = 0;
</span></span></span><span class="line"><span class="cl"><span class="err">$total_interations = 0;
</span></span></span><span class="line"><span class="cl"><span class="err">$total_exe_time = bcsub(microtime_float(), $script_start, 4);
</span></span></span><span class="line"><span class="cl"><span class="err">$queries = array();
</span></span></span><span class="line"><span class="cl"><span class="err">while(true) {
</span></span></span><span class="line"><span class="cl"><span class="err">    $script_start = microtime_float();
</span></span></span><span class="line"><span class="cl"><span class="err">    $end_yank = strpos($file, $search_string, strlen($search_string));
</span></span></span><span class="line"><span class="cl"><span class="err">    //store the query(s)
</span></span></span><span class="line"><span class="cl"><span class="err">    $queries[] = substr($file, 0, $end_yank);
</span></span></span><span class="line"><span class="cl"><span class="err">    //scrub the saved query(s) from the main T-SQL
</span></span></span><span class="line"><span class="cl"><span class="err">    $file = substr($file, $end_yank);
</span></span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err">    if(empty($file) or
</span></span></span><span class="line"><span class="cl"><span class="err">       strlen($file) &lt;= strlen($search_string) or
</span></span></span><span class="line"><span class="cl"><span class="err">       $end_yank == 0)
</span></span></span><span class="line"><span class="cl"><span class="err">        break;
</span></span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err">    if(1 == (++$iteration / $how_many_per_connection)) {
</span></span></span><span class="line"><span class="cl"><span class="err">        //process our accumulated queries
</span></span></span><span class="line"><span class="cl"><span class="err">        $link = odbc_connect($server_dsn, $user, $pass) or die(&#39;Unable to connect to the server: &#39;.odbc_errormsg());
</span></span></span><span class="line"><span class="cl"><span class="err">        odbc_exec($link, implode(&#34;n&#34;, $queries)) or die(&#39;Could not process SQL: &#39;.odbc_errormsg($link));
</span></span></span><span class="line"><span class="cl"><span class="err">        odbc_close($link);
</span></span></span><span class="line"><span class="cl"><span class="err">        $queries = array();
</span></span></span><span class="line"><span class="cl"><span class="err">        $total_interations += $iteration;
</span></span></span><span class="line"><span class="cl"><span class="err">        $script_end = microtime_float();
</span></span></span><span class="line"><span class="cl"><span class="err">        $portion_time = bcsub($script_end, $script_start, 4);
</span></span></span><span class="line"><span class="cl"><span class="err">        $total_exe_time += $portion_time;
</span></span></span><span class="line"><span class="cl"><span class="err">        print &#39;&lt;p&gt;&#39;.$total_interations.&#39; records processed.  Portion: &#39;.$portion_time.&#39; Total: &#39;.$total_exe_time.&#39;&lt;/p&gt;&#39;;
</span></span></span><span class="line"><span class="cl"><span class="err">        $iteration = 0;
</span></span></span><span class="line"><span class="cl"><span class="err">    }
</span></span></span><span class="line"><span class="cl"><span class="err">}
</span></span></span><span class="line"><span class="cl"><span class="err">?&gt;
</span></span></span><span class="line"><span class="cl"><span class="err">&lt;p&gt;Successfully Imported:&lt;/p&gt;
</span></span></span><span class="line"><span class="cl"><span class="err">&lt;?php
</span></span></span><span class="line"><span class="cl"><span class="err">$link2 = odbc_connect($server_dsn, $user, $pass) or die(&#39;Unable to connect to the server: &#39;.odbc_errormsg());
</span></span></span><span class="line"><span class="cl"><span class="err">$tables = odbc_tables($link2);
</span></span></span><span class="line"><span class="cl"><span class="err">while (odbc_fetch_row($tables)){
</span></span></span><span class="line"><span class="cl"><span class="err">    if(odbc_result($tables,&#34;TABLE_TYPE&#34;)==&#34;TABLE&#34;)
</span></span></span><span class="line"><span class="cl"><span class="err">        echo&#34;&lt;br&gt;&#34;.odbc_result($tables,&#34;TABLE_NAME&#34;);
</span></span></span><span class="line"><span class="cl"><span class="err">}
</span></span></span><span class="line"><span class="cl"><span class="err">odbc_close($link);
</span></span></span><span class="line"><span class="cl"><span class="err">?&gt;
</span></span></span></code></pre></div>]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="code" label="code"/><category scheme="taxonomy:Tags" term="mssql" label="mssql"/><category scheme="taxonomy:Tags" term="windows" label="windows"/><category scheme="taxonomy:Tags" term="bikes" label="Bikes"/><category scheme="taxonomy:Tags" term="php" label="PHP"/></entry><entry xml:base="sql-server"><title type="html">SQL SERVER</title><link href="https://www.simonholywell.com/post/2008/04/sql-server/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2008/03/getting-back-on-the-bike/?utm_source=atom_feed" rel="related" type="text/html" title="Getting Back on the Bike"/><link href="https://www.simonholywell.com/post/2008/02/engagement/?utm_source=atom_feed" rel="related" type="text/html" title="Engagement"/><link href="https://www.simonholywell.com/post/2007/12/moves/?utm_source=atom_feed" rel="related" type="text/html" title="Moves"/><link href="https://www.simonholywell.com/post/2007/07/biking-to-the-uk/?utm_source=atom_feed" rel="related" type="text/html" title="Biking to the UK"/><link href="https://www.simonholywell.com/post/2007/07/triumph-street-triple/?utm_source=atom_feed" rel="related" type="text/html" title="Triumph Street Triple"/><id>https://www.simonholywell.com/post/2008/04/sql-server/</id><author><name>Simon Holywell</name></author><published>2008-04-07T17:50:26+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Say you have a development environment setup using SQL Server 2005 Express Edition and your customer has a SQL Server 2000 database accessible only via ODBC and you can only run a DB import via a script. How would you do it? Easy you might think just run msdbdump.exe on the command line, well this isn’t MySQL so you are not so fortunate.
Backing up your DB is easy with SQL Server using the following commands:</summary><content type="html"><![CDATA[<p>Say you have a development environment setup using SQL Server 2005 Express Edition and your customer has a SQL Server 2000 database accessible only via ODBC and you can only run a DB import via a script. How would you do it? Easy you might think just run msdbdump.exe on the command line, well this isn’t MySQL so you are not so fortunate.</p>
<p>Backing up your DB is easy with SQL Server using the following commands:</p>
<p>But this just gives you a binary file that can be restored if you have access privileges to the live database for restoring. If you are in a shared hosting environment or one where the paranoid admins won’t give you remote desktop access and the only access you have is to run a PHP script to import the data and schema via SQL you will need to export the DB to T-SQL format.</p>
<p>Microsoft have a little program to perform this very function: <a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=56E5B1C5-BF17-42E0-A410-371A838E570A&amp;displaylang=en">Microsoft SQL Server Database Publishing Wizard 1.1</a> It is difficult to find on the web so I aim to save you the time I spent hunting for it. When you run the wizard make sure to set:</p>
<ul>
<li>Drop existing objects in script to <strong>false</strong></li>
<li>Schema qualify to <strong>false</strong></li>
<li>Script for target database to <strong>SQL Server 2000</strong></li>
</ul>
<p>It does seem to chew on the cud for quite some time so grab a beverage.</p>
<p>Now for the PHP portion of the process. So you have uploaded your lovely T-SQL dump file to a PHP accessible location on your webserver and now you are wondering how to get into your DB via ODBC. Well you will need a PHP script like the one I have supplied below.</p>
<p>A couple of the complexities to be aware of before you continue. It seems that the T-SQL dump file comes out as UTF16 and we need it in UTF8 so you will need to convert it to UTF8 before you can import. I used a neat little function available from <a href="http://www.moddular.org/log/utf16-to-utf8">Modular.org</a> for this purpose. This may or may not meet your needs. If you need a more accurate conversion method then I recommend you start your search with the PHP module/function <a href="http://uk.php.net/mbstring">mbstring</a> . T-SQL contains reference and keywords that ODBC/MS SQL cannot understand. I have included some regex to strip these out.</p>
<p>My script is by no means perfect or factored down so feel free to make suggestions or improvements.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="bikes" label="Bikes"/><category scheme="taxonomy:Tags" term="cars" label="Cars"/><category scheme="taxonomy:Tags" term="me" label="Me"/></entry><entry xml:base="getting-back-on-the-bike"><title type="html">Getting Back on the Bike</title><link href="https://www.simonholywell.com/post/2008/03/getting-back-on-the-bike/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2007/07/biking-to-the-uk/?utm_source=atom_feed" rel="related" type="text/html" title="Biking to the UK"/><link href="https://www.simonholywell.com/post/2007/07/triumph-street-triple/?utm_source=atom_feed" rel="related" type="text/html" title="Triumph Street Triple"/><link href="https://www.simonholywell.com/post/2008/03/mysql-to-ms-sql-sql-server/?utm_source=atom_feed" rel="related" type="text/html" title="MySQL to MS SQL (SQL Server)"/><link href="https://www.simonholywell.com/post/2008/02/engagement/?utm_source=atom_feed" rel="related" type="text/html" title="Engagement"/><link href="https://www.simonholywell.com/post/2007/12/moves/?utm_source=atom_feed" rel="related" type="text/html" title="Moves"/><id>https://www.simonholywell.com/post/2008/03/getting-back-on-the-bike/</id><author><name>Simon Holywell</name></author><published>2008-03-28T11:02:20+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>If you haven’t been riding through winter like me then take care getting back out there and wear good gear. Check all the essentials:
Oil Water (if applicable) Tyre pressures and wear Chain tension and wear Check all electrics (kill switch and all lights being the main ones) Also have a glance at your sprockets If the bike has been sitting for more than a month then you will probably want to drain the fuel tank as well as the petrol may have gone off.</summary><content type="html"><![CDATA[<p>If you haven’t been riding through winter like me then take care getting back out there and wear good gear. Check all the essentials:</p>
<ul>
<li>Oil</li>
<li>Water (if applicable)</li>
<li>Tyre pressures and wear</li>
<li>Chain tension and wear</li>
<li>Check all electrics (kill switch and all lights being the main ones)</li>
<li>Also have a glance at your sprockets</li>
</ul>
<p>If the bike has been sitting for more than a month then you will probably want to drain the fuel tank as well as the petrol may have gone off. When you leave it too long it can form a jelly like substance in the fuel lines or worse in the carburettors. If this has happened or you forgot to drain your float bowls you will need to strip down the carbies and clean them out with compressed air.</p>
<p>Electrics corrode so if it won’t start check that the connections are OK on the:</p>
<ul>
<li>Battery (you have already checked for charge right?!)</li>
<li>Kill switch</li>
<li>Clutch switch (if applicable)</li>
<li>Neutral switch (if applicable)</li>
<li>Kickstand switch (if applicable)</li>
</ul>
]]></content><category scheme="taxonomy:Categories" term="motors" label="Motors"/><category scheme="taxonomy:Tags" term="bikes" label="Bikes"/><category scheme="taxonomy:Tags" term="maintenance" label="maintenance"/></entry><entry xml:base="mysql-to-ms-sql-sql-server"><title type="html">MySQL to MS SQL (SQL Server)</title><link href="https://www.simonholywell.com/post/2008/03/mysql-to-ms-sql-sql-server/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2008/02/engagement/?utm_source=atom_feed" rel="related" type="text/html" title="Engagement"/><link href="https://www.simonholywell.com/post/2007/12/moves/?utm_source=atom_feed" rel="related" type="text/html" title="Moves"/><link href="https://www.simonholywell.com/post/2007/08/iso-3166-country-list/?utm_source=atom_feed" rel="related" type="text/html" title="ISO 3166 Country List"/><link href="https://www.simonholywell.com/post/2007/07/biking-to-the-uk/?utm_source=atom_feed" rel="related" type="text/html" title="Biking to the UK"/><link href="https://www.simonholywell.com/post/2007/07/triumph-street-triple/?utm_source=atom_feed" rel="related" type="text/html" title="Triumph Street Triple"/><id>https://www.simonholywell.com/post/2008/03/mysql-to-ms-sql-sql-server/</id><author><name>Simon Holywell</name></author><published>2008-03-27T13:58:33+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Recently I produced a website for hosting on a Linux box running with PHP5 and MySQL5. Well it now needs to move over to a Windows 2003 server with MS SQL as the DB and IIS as opposed to Apache.
Install MyODBC Install SQL Server 2005 Express Using MS SQL Server Management create a new database. (right click on databases in the Object Explorer)
Use the following SQL Server SQL to create a link to your MySQL DB:</summary><content type="html"><![CDATA[<p>Recently I produced a website for hosting on a Linux box running with PHP5 and MySQL5. Well it now needs to move over to a Windows 2003 server with MS SQL as the DB and IIS as opposed to Apache.</p>
<ul>
<li>Install <a href="http://www.mysql.com/products/myodbc/">MyODBC</a></li>
<li>Install <a href="http://www.microsoft.com/sql/editions/express/default.mspx">SQL Server 2005 Express</a></li>
</ul>
<ol>
<li>
<p>Using MS SQL Server Management create a new database. (right click on databases in the Object Explorer)</p>
</li>
<li>
<p>Use the following SQL Server SQL to create a link to your MySQL DB:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">EXEC</span><span class="w"> </span><span class="n">master</span><span class="p">.</span><span class="n">dbo</span><span class="p">.</span><span class="n">sp_addlinkedserver</span><span class="w"> </span><span class="o">@</span><span class="n">server</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">N</span><span class="s1">&#39;MYSQL&#39;</span><span class="p">,</span><span class="w"> </span><span class="o">@</span><span class="n">srvproduct</span><span class="o">=</span><span class="n">N</span><span class="s1">&#39;MySQL&#39;</span><span class="p">,</span><span class="w"> </span><span class="o">@</span><span class="n">provider</span><span class="o">=</span><span class="n">N</span><span class="s1">&#39;MSDASQL&#39;</span><span class="p">,</span><span class="w"> </span><span class="o">@</span><span class="n">provstr</span><span class="o">=</span><span class="n">N</span><span class="s1">&#39;DRIVER={MySQL ODBC 3.51 Driver}; SERVER=MySQLServerIP; DATABASE=Db_NAME; USER=MySQLUserName; PASSWORD=MySQLPassword; OPTION=3&#39;</span><span class="w">
</span></span></span></code></pre></div><p>Execute the above</p>
</li>
<li>
<p>Use the following PHP script to get a list of tables to import:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="nv">$conn</span> <span class="o">=</span> <span class="nx">mysql_connect</span><span class="p">(</span><span class="s1">&#39;host&#39;</span><span class="p">,</span><span class="s1">&#39;user&#39;</span><span class="p">,</span><span class="s1">&#39;pass&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">mysql_select_db</span><span class="p">(</span><span class="s1">&#39;database&#39;</span><span class="p">,</span><span class="nv">$conn</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nv">$SQL</span> <span class="o">=</span> <span class="s2">&#34;SHOW TABLES;&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nv">$result</span> <span class="o">=</span> <span class="nx">mysql_query</span><span class="p">(</span><span class="nv">$SQL</span><span class="p">,</span> <span class="nv">$conn</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="k">while</span><span class="p">(</span><span class="nv">$row</span> <span class="o">=</span> <span class="nx">mysql_fetch_array</span><span class="p">(</span><span class="nv">$result</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">    <span class="k">print</span> <span class="s2">&#34;SELECT * INTO SQLServerDBName.dbo.</span><span class="si">{</span><span class="nv">$row</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="si">}</span><span class="s2">&lt;br /&gt;
</span></span></span><span class="line"><span class="cl"><span class="s2">           FROM openquery(MySQL, &#39;SELECT * FROM `</span><span class="si">{</span><span class="nv">$row</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="si">}</span><span class="s2">`&#39;);&lt;br /&gt;
</span></span></span><span class="line"><span class="cl"><span class="s2">&#34;</span><span class="p">;</span>
</span></span></code></pre></div></li>
<li>
<p>Copy and paste the output from the above script into your SQL Server query window and execute it</p>
</li>
<li>
<p>All your data should now have been transferred across along with the table schemas</p>
</li>
</ol>
<p>Don’t forget to change all the references above to your correct database server settings.</p>
<p>Please note I have had some trouble with SQL Server not accepting 0000-00-00 00:00:00 in datetime fields set to not null in MySQL – set your datetime fields to accept null before exporting.</p>
<p>Also primary keys and auto_increment column attributes are not brought across either. So you will need to go into Server Management and manually re-add your auto_increment (Identity in SQL Server speak) and the primary key. It can also be done programmatically like this:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">BEGIN</span><span class="w"> </span><span class="k">TRANSACTION</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">GO</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">CREATE</span><span class="w"> </span><span class="k">TABLE</span><span class="w"> </span><span class="n">dbo</span><span class="p">.</span><span class="n">Tmp_admin_accounts</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="n">account_id</span><span class="w"> </span><span class="nb">int</span><span class="w"> </span><span class="k">NOT</span><span class="w"> </span><span class="k">NULL</span><span class="w"> </span><span class="k">IDENTITY</span><span class="w"> </span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="n">username</span><span class="w"> </span><span class="nb">varchar</span><span class="p">(</span><span class="mi">20</span><span class="p">)</span><span class="w"> </span><span class="k">NOT</span><span class="w"> </span><span class="k">NULL</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="n">passhash</span><span class="w"> </span><span class="nb">char</span><span class="p">(</span><span class="mi">40</span><span class="p">)</span><span class="w"> </span><span class="k">NOT</span><span class="w"> </span><span class="k">NULL</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">)</span><span class="w">  </span><span class="k">ON</span><span class="w"> </span><span class="p">[</span><span class="k">PRIMARY</span><span class="p">]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">GO</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">SET</span><span class="w"> </span><span class="n">IDENTITY_INSERT</span><span class="w"> </span><span class="n">dbo</span><span class="p">.</span><span class="n">Tmp_admin_accounts</span><span class="w"> </span><span class="k">ON</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">GO</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">IF</span><span class="w"> </span><span class="k">EXISTS</span><span class="p">(</span><span class="k">SELECT</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="n">dbo</span><span class="p">.</span><span class="n">admin_accounts</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">     </span><span class="k">EXEC</span><span class="p">(</span><span class="s1">&#39;INSERT INTO dbo.Tmp_admin_accounts (account_id, username, passhash)
</span></span></span><span class="line"><span class="cl"><span class="s1">        SELECT account_id, username, passhash FROM dbo.admin_accounts WITH (HOLDLOCK TABLOCKX)&#39;</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">GO</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">SET</span><span class="w"> </span><span class="n">IDENTITY_INSERT</span><span class="w"> </span><span class="n">dbo</span><span class="p">.</span><span class="n">Tmp_admin_accounts</span><span class="w"> </span><span class="k">OFF</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">GO</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">DROP</span><span class="w"> </span><span class="k">TABLE</span><span class="w"> </span><span class="n">dbo</span><span class="p">.</span><span class="n">admin_accounts</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">GO</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">EXECUTE</span><span class="w"> </span><span class="n">sp_rename</span><span class="w"> </span><span class="n">N</span><span class="s1">&#39;dbo.Tmp_admin_accounts&#39;</span><span class="p">,</span><span class="w"> </span><span class="n">N</span><span class="s1">&#39;admin_accounts&#39;</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;OBJECT&#39;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">GO</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">ALTER</span><span class="w"> </span><span class="k">TABLE</span><span class="w"> </span><span class="n">dbo</span><span class="p">.</span><span class="n">admin_accounts</span><span class="w"> </span><span class="k">ADD</span><span class="w"> </span><span class="k">CONSTRAINT</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="n">PK_admin_accounts</span><span class="w"> </span><span class="k">PRIMARY</span><span class="w"> </span><span class="k">KEY</span><span class="w"> </span><span class="n">CLUSTERED</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="n">account_id</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">)</span><span class="w"> </span><span class="k">WITH</span><span class="p">(</span><span class="w"> </span><span class="n">STATISTICS_NORECOMPUTE</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">OFF</span><span class="p">,</span><span class="w"> </span><span class="n">IGNORE_DUP_KEY</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">OFF</span><span class="p">,</span><span class="w"> </span><span class="n">ALLOW_ROW_LOCKS</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">ON</span><span class="p">,</span><span class="w"> </span><span class="n">ALLOW_PAGE_LOCKS</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">ON</span><span class="p">)</span><span class="w"> </span><span class="k">ON</span><span class="w"> </span><span class="p">[</span><span class="k">PRIMARY</span><span class="p">]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">GO</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">COMMIT</span><span class="w">
</span></span></span></code></pre></div><p>Because SQL Server doesn’t allow you to alter a pre-existing column to be an Identity (auto_increment) column you have to:</p>
<ol>
<li>Create a temporary table with an Identity column</li>
<li>Allow arbitrary numbers to be inserted into the Identity column (includes previously inserted IDs apparently so you could end up with duplicates!)</li>
<li>Move the data across to the temporary table</li>
<li>Disallow inserting into the Identity column</li>
<li>Drop the original table</li>
<li>Rename the temporary table to the same name as the original</li>
<li>Alter the Identity column to add the primary key</li>
</ol>
<p>Wow! What a pain.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="mssql" label="mssql"/><category scheme="taxonomy:Tags" term="mysql" label="Mysql"/><category scheme="taxonomy:Tags" term="sql" label="sql"/></entry><entry xml:base="engagement"><title type="html">Engagement</title><link href="https://www.simonholywell.com/post/2008/02/engagement/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2007/12/moves/?utm_source=atom_feed" rel="related" type="text/html" title="Moves"/><link href="https://www.simonholywell.com/post/2007/06/london/?utm_source=atom_feed" rel="related" type="text/html" title="London"/><link href="https://www.simonholywell.com/post/2005/11/downtimehousing/?utm_source=atom_feed" rel="related" type="text/html" title="Downtime/Housing"/><link href="https://www.simonholywell.com/post/2006/12/wow-almost-six-months/?utm_source=atom_feed" rel="related" type="text/html" title="Wow, Almost Six Months"/><link href="https://www.simonholywell.com/post/2007/08/iso-3166-country-list/?utm_source=atom_feed" rel="related" type="text/html" title="ISO 3166 Country List"/><id>https://www.simonholywell.com/post/2008/02/engagement/</id><author><name>Simon Holywell</name></author><published>2008-02-02T19:52:10+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>I recently asked my girlfriend for her hand in marriage; she said yes! We are both very excited and have begun to make arrangements. No date has been set yet but we aim to walk down the aisle before the end of the year. As we are from different countries we have decided to hold a ceremony in each of our countries and England to involve all of our friends and family.</summary><content type="html">&lt;p>I recently asked my girlfriend for her hand in marriage; she said yes! We are both very excited and have begun to make arrangements. No date has been set yet but we aim to walk down the aisle before the end of the year. As we are from different countries we have decided to hold a ceremony in each of our countries and England to involve all of our friends and family.&lt;/p>
&lt;p>I am so pleased and happy and look forward to the good times to come in our shared future.&lt;/p></content><category scheme="taxonomy:Tags" term="life" label="life"/><category scheme="taxonomy:Tags" term="me" label="Me"/></entry><entry xml:base="moves"><title type="html">Moves</title><link href="https://www.simonholywell.com/post/2007/12/moves/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2007/06/london/?utm_source=atom_feed" rel="related" type="text/html" title="London"/><link href="https://www.simonholywell.com/post/2005/11/downtimehousing/?utm_source=atom_feed" rel="related" type="text/html" title="Downtime/Housing"/><link href="https://www.simonholywell.com/post/2006/12/wow-almost-six-months/?utm_source=atom_feed" rel="related" type="text/html" title="Wow, Almost Six Months"/><link href="https://www.simonholywell.com/post/2007/08/iso-3166-country-list/?utm_source=atom_feed" rel="related" type="text/html" title="ISO 3166 Country List"/><link href="https://www.simonholywell.com/post/2007/07/biking-to-the-uk/?utm_source=atom_feed" rel="related" type="text/html" title="Biking to the UK"/><id>https://www.simonholywell.com/post/2007/12/moves/</id><author><name>Simon Holywell</name></author><published>2007-12-18T10:30:44+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>I have been a little slow to update my website of late due to a change of jobs and having recently moved house.
I am now working for WickedWeb (and have been since July), which is a web agency in the Kent countryside and with an office in London (Covent Garden). I am based in the Edenbridge office where I am a web developer working mainly in PHP with some ASP maintenance.</summary><content type="html"><![CDATA[<p>I have been a little slow to update my website of late due to a change of jobs and having recently moved house.</p>
<p>I am now working for <a href="http://www.wickedweb.co.uk/">WickedWeb</a> (and have been since July), which is a web agency in the Kent countryside and with an office in London (Covent Garden). I am based in the Edenbridge office where I am a web developer working mainly in PHP with some ASP maintenance.</p>
<p>In the last month I moved to Brighton, which is an ok commute into work everyday and it is a nice location. Looking forward to the runs on the motorbike next summer!</p>
]]></content><category scheme="taxonomy:Tags" term="life" label="life"/><category scheme="taxonomy:Tags" term="me" label="Me"/></entry><entry xml:base="iso-3166-country-list"><title type="html">ISO 3166 Country List</title><link href="https://www.simonholywell.com/post/2007/08/iso-3166-country-list/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2006/12/geographic-calculations-in-php/?utm_source=atom_feed" rel="related" type="text/html" title="Geographic Calculations in PHP"/><link href="https://www.simonholywell.com/post/2006/03/flickering-images/?utm_source=atom_feed" rel="related" type="text/html" title="Flickering Images"/><link href="https://www.simonholywell.com/post/2005/12/adodb/?utm_source=atom_feed" rel="related" type="text/html" title="ADODB"/><link href="https://www.simonholywell.com/post/2007/07/biking-to-the-uk/?utm_source=atom_feed" rel="related" type="text/html" title="Biking to the UK"/><link href="https://www.simonholywell.com/post/2007/07/triumph-street-triple/?utm_source=atom_feed" rel="related" type="text/html" title="Triumph Street Triple"/><id>https://www.simonholywell.com/post/2007/08/iso-3166-country-list/</id><author><name>Simon Holywell</name></author><published>2007-08-21T21:26:48+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Here is a small script that I put together to grab the XML list from the ISO website and convert it into an SQL statement. The idea is that the script can be used to just obtain a list for web projects or it can be setup to run periodically to make sure that a list is always kept up to date. Obviously none of the associated checks to make that work have been written into this code so you will need to add it yourself (ie.</summary><content type="html"><![CDATA[<p>Here is a small script that I put together to grab the XML list from the ISO website and convert it into an SQL statement. The idea is that the script can be used to just obtain a list for web projects or it can be setup to run periodically to make sure that a list is always kept up to date. Obviously none of the associated checks to make that work have been written into this code so you will need to add it yourself (ie. checking that if a country has been removed that you are not going to break referential integrity etc).</p>
<p>It is a really simple script so just use it as you wish, but make sure you reference the original source. It is not your work and you may not pass it off as such. This script requires PHP5 as it makes use of the SimpleXML functions. As you can tell this script is really more of a utility script and not for general consumption. There are some comments thrown in but it is a very simple script so you should not have too much trouble with it.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o">&lt;?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl"><span class="c1">//Get ISO list of countries
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nv">$iso_xml_zip_file_url</span> <span class="o">=</span> <span class="s1">&#39;http://www.iso.org/iso/&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nv">$iso_xml_zip_filename</span> <span class="o">=</span> <span class="s1">&#39;iso_3166-1_list_en.zip&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nv">$iso_xml_zip_new_filename</span> <span class="o">=</span> <span class="s1">&#39;iso_3166-1_list_en_&#39;</span><span class="o">.</span><span class="nx">date</span><span class="p">(</span><span class="s1">&#39;Y-m-d&#39;</span><span class="p">)</span><span class="o">.</span><span class="s1">&#39;.zip&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nv">$iso_xml_filename</span> <span class="o">=</span> <span class="s1">&#39;iso_3166-1_list_en.xml&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nv">$download_directory</span> <span class="o">=</span> <span class="s1">&#39;./temp/&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">//setup database variables
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nv">$table_name</span> <span class="o">=</span> <span class="s1">&#39;countries&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nv">$country_column_name</span> <span class="o">=</span> <span class="s1">&#39;original&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nv">$country_column_capitalised_name</span> <span class="o">=</span> <span class="s1">&#39;name&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nv">$country_column_alpha</span> <span class="o">=</span> <span class="s1">&#39;alpha&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">//download the file
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="nx">file_exists</span><span class="p">(</span><span class="nv">$download_directory</span><span class="o">.</span><span class="nv">$iso_xml_zip_new_filename</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">    <span class="nx">copy</span><span class="p">(</span><span class="nv">$iso_xml_zip_file_url</span><span class="o">.</span><span class="nv">$iso_xml_zip_filename</span><span class="p">,</span> <span class="nv">$download_directory</span><span class="o">.</span><span class="nv">$iso_xml_zip_new_filename</span><span class="p">)</span> <span class="k">or</span> <span class="k">die</span><span class="p">(</span><span class="s1">&#39;Could not copy &#39;</span><span class="o">.</span><span class="nv">$iso_xml_zip_file_url</span><span class="o">.</span><span class="nv">$iso_xml_zip_filename</span><span class="o">.</span><span class="s1">&#39; to &#39;</span><span class="o">.</span><span class="nv">$download_directory</span><span class="o">.</span><span class="nv">$iso_xml_zip_new_filename</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">$za</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">ZipArchive</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="nv">$za</span><span class="o">-&gt;</span><span class="na">open</span><span class="p">(</span><span class="nv">$download_directory</span><span class="o">.</span><span class="nv">$iso_xml_zip_new_filename</span><span class="p">)</span> <span class="k">or</span> <span class="k">die</span><span class="p">(</span><span class="s1">&#39;Cannot open ZIP file - possibly corrupt.&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nv">$xml</span> <span class="o">=</span> <span class="nv">$za</span><span class="o">-&gt;</span><span class="na">getFromName</span><span class="p">(</span><span class="nv">$iso_xml_filename</span><span class="p">)</span> <span class="k">or</span> <span class="k">die</span><span class="p">(</span><span class="s1">&#39;Cannot extract XML file (&#39;</span><span class="o">.</span><span class="nv">$iso_xml_filename</span><span class="o">.</span><span class="s1">&#39;) - perhaps the ZIP is corrupt.&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">//clean up the names of the elements so they will work as objects
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nv">$xml</span> <span class="o">=</span> <span class="nx">str_replace</span><span class="p">(</span><span class="k">array</span><span class="p">(</span><span class="s1">&#39;ISO_3166-1_&#39;</span><span class="p">,</span> <span class="s1">&#39;-2_Code_element&#39;</span><span class="p">,</span> <span class="s1">&#39;_name&#39;</span><span class="p">),</span> <span class="s1">&#39;&#39;</span><span class="p">,</span> <span class="nv">$xml</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nv">$xml</span> <span class="o">=</span> <span class="nx">simplexml_load_string</span><span class="p">(</span><span class="nv">$xml</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">$SQL</span> <span class="o">=</span> <span class="s1">&#39;&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">foreach</span><span class="p">(</span><span class="nv">$xml</span><span class="o">-&gt;</span><span class="na">Entry</span> <span class="k">as</span> <span class="nv">$entry</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nv">$SQL</span> <span class="o">.=</span> <span class="s2">&#34;INSERT INTO `</span><span class="si">$table_name</span><span class="s2">` SET
</span></span></span><span class="line"><span class="cl"><span class="s2">            `</span><span class="si">$country_column_name</span><span class="s2">` = &#39;&#34;</span><span class="o">.</span><span class="nx">mysql_escape_string</span><span class="p">(</span><span class="nv">$entry</span><span class="o">-&gt;</span><span class="na">Country</span><span class="p">)</span><span class="o">.</span><span class="s2">&#34;&#39;,
</span></span></span><span class="line"><span class="cl"><span class="s2">            `</span><span class="si">$country_column_capitalised_name</span><span class="s2">` = &#39;&#34;</span><span class="o">.</span><span class="nx">mysql_escape_string</span><span class="p">(</span><span class="nx">ucwords</span><span class="p">(</span><span class="nx">strtolower</span><span class="p">(</span><span class="nv">$entry</span><span class="o">-&gt;</span><span class="na">Country</span><span class="p">)))</span><span class="o">.</span><span class="s2">&#34;&#39;,
</span></span></span><span class="line"><span class="cl"><span class="s2">            `</span><span class="si">$country_column_alpha</span><span class="s2">` = &#39;&#34;</span><span class="o">.</span><span class="nx">mysql_escape_string</span><span class="p">(</span><span class="nv">$entry</span><span class="o">-&gt;</span><span class="na">Alpha</span><span class="p">)</span><span class="o">.</span><span class="s2">&#34;&#39;;</span><span class="se">\n\n</span><span class="s2">&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">print</span> <span class="s1">&#39;&lt;pre&gt;&#39;</span><span class="o">.</span><span class="nv">$SQL</span><span class="o">.</span><span class="s1">&#39;&lt;/pre&gt;&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="nx">file_exists</span><span class="p">(</span><span class="nv">$download_directory</span><span class="o">.</span><span class="nv">$iso_xml_zip_new_filename</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">    <span class="nx">copy</span><span class="p">(</span><span class="nv">$iso_xml_zip_file_url</span><span class="o">.</span><span class="nv">$iso_xml_zip_filename</span><span class="p">,</span> <span class="nv">$download_directory</span><span class="o">.</span><span class="nv">$iso_xml_zip_new_filename</span><span class="p">)</span> <span class="k">or</span> <span class="k">die</span><span class="p">(</span><span class="s1">&#39;Could not copy &#39;</span><span class="o">.</span><span class="nv">$iso_xml_zip_file_url</span><span class="o">.</span><span class="nv">$iso_xml_zip_filename</span><span class="o">.</span><span class="s1">&#39; to &#39;</span><span class="o">.</span><span class="nv">$download_directory</span><span class="o">.</span><span class="nv">$iso_xml_zip_new_filename</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="cp">?&gt;</span><span class="err">
</span></span></span></code></pre></div><p>There is some sample output from this script for download as well: <a href="/static/files/2007-08-21-iso-3166.sql">2007008221iiso33166ssql</a></p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="code" label="code"/></entry><entry xml:base="biking-to-the-uk"><title type="html">Biking to the UK</title><link href="https://www.simonholywell.com/post/2007/07/biking-to-the-uk/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2007/07/triumph-street-triple/?utm_source=atom_feed" rel="related" type="text/html" title="Triumph Street Triple"/><link href="https://www.simonholywell.com/post/2007/06/london/?utm_source=atom_feed" rel="related" type="text/html" title="London"/><link href="https://www.simonholywell.com/post/2006/12/geographic-calculations-in-php/?utm_source=atom_feed" rel="related" type="text/html" title="Geographic Calculations in PHP"/><link href="https://www.simonholywell.com/post/2006/12/wow-almost-six-months/?utm_source=atom_feed" rel="related" type="text/html" title="Wow, Almost Six Months"/><link href="https://www.simonholywell.com/post/2006/12/secondary-dns-for-free/?utm_source=atom_feed" rel="related" type="text/html" title="Secondary DNS for Free"/><id>https://www.simonholywell.com/post/2007/07/biking-to-the-uk/</id><author><name>Simon Holywell</name></author><published>2007-07-21T23:43:09+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Just a few tips for fellow bikers who might be considering a move to the UK from Victoria.
If you only have your L’s pass you test before you come so you can transfer your licence over. When you have a full licence (ie over 21 with a restricted motorcycle licence) this will be transferred to a full A licence in the UK meaning you can ride any capacity bike you like.</summary><content type="html"><![CDATA[<p>Just a few tips for fellow bikers who might be considering a move to the UK from Victoria.</p>
<p>If you only have your L’s pass you test before you come so you can transfer your licence over. When you have a full licence (ie over 21 with a restricted motorcycle licence) this will be transferred to a full A licence in the UK meaning you can ride any capacity bike you like. However insurance is going to set you back…it is significantly more expensive here.</p>
<p>To help reduce this cost make sure you bring a no claims bonus confirmation letter from your Australian insurer with you. This must state your NCB in years, your name, your bike and a policy number. The company will probably want to see the original so make sure you make copies before sending it through the good old Royal Mail. The only insurer that would accept my foreign NCB was <a href="http://www.bennetts.co.uk/">Bennetts</a> – you may find others.</p>
<p>NCB ratings are not taken from your car like they are in Australia so make sure you transfer any car NCB over to your bike before you come. 5 years is maximum NCB and it will make a real difference to your quote.</p>
<p>Before sending anything into the <a href="http://www.dvla.gov.uk/">DVLA</a> ensure you make computer scans or at least photocopies of your licence (both sides) and any other documentation. It could get lost in the post, but much more likely the <a href="http://www.dvla.gov.uk/">DVLA</a> will neglect to add your motorbike licence to the licence they send out to you!</p>
<p>When you receive your new licence immediately check it lists the correct categories. Another little quirk about licences here is that they come in two parts – it’s ridiculous but the plastic one like the one you keep in your wallet in Australia is not your actual licence. There is an A4 sheet of paper that must accompany it to be an official licence so don’t toss it like I was tempted to. This annoyingly means that if you are out riding and get pulled you will have to go into a cop shop to flash both parts of your licence.</p>
<p>If you decide to do some advanced/safer riding courses then I can recommend the <a href="http://www.bikesafe.co.uk/">BikeSafe</a> scheme where you ride out with a police observer who gives you tips on your riding. This I found was very helpful as riding here is completely different and more hectic I found. If you do decide to do this course take the ones organised for <a href="http://www.bikesafe-london.co.uk/">London</a> rather than the surrounding counties as the London courses are subsidised by <a href="http://www.tfl.gov.uk">Transport for London</a> and therefore cheaper for the same service! They run one from the Ace Café to the North West of London and one from the Police Academy in Bromley to the South East of London in Kent. I attended the Bromley one.</p>
<p>To help boost my confidence I am also an associate member of the <a href="http://www.iam.org.uk">Institute of Advanced Motorists</a> (IAM). I have only been to two observed runs so far but I can already feel I my riding improving and it is making riding more fun. They are very friendly. I am doing it through the <a href="http://www.l-a-m.org">London Advanced Motorcyclists</a> (LAM) group who run sessions from Banstead and Bromley. Basically you attend a Potluck session and scope it all out and meet people. If you decide it’s for you then you join IAM and attend potluck sessions from there on in.</p>
<p>By the way you need to bring your bike (roadworthy condition of course), proper gear, your MOT certificate (if applicable), your insurance certificate and both parts of your licence to both BikeSafe and your first LAM potluck sessions. You should also bring an open mind and remember they are there to steer you in the correct direction – they are not going to force you to do something you don’t want to do. They are there to help you improve not attack your riding.</p>
]]></content><category scheme="taxonomy:Categories" term="motors" label="Motors"/><category scheme="taxonomy:Tags" term="bikes" label="Bikes"/><category scheme="taxonomy:Tags" term="uk" label="uk"/></entry><entry xml:base="triumph-street-triple"><title type="html">Triumph Street Triple</title><link href="https://www.simonholywell.com/post/2007/07/triumph-street-triple/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2007/06/london/?utm_source=atom_feed" rel="related" type="text/html" title="London"/><link href="https://www.simonholywell.com/post/2006/12/geographic-calculations-in-php/?utm_source=atom_feed" rel="related" type="text/html" title="Geographic Calculations in PHP"/><link href="https://www.simonholywell.com/post/2006/12/wow-almost-six-months/?utm_source=atom_feed" rel="related" type="text/html" title="Wow, Almost Six Months"/><link href="https://www.simonholywell.com/post/2006/12/secondary-dns-for-free/?utm_source=atom_feed" rel="related" type="text/html" title="Secondary DNS for Free"/><link href="https://www.simonholywell.com/post/2006/06/ramones-museum/?utm_source=atom_feed" rel="related" type="text/html" title="Ramones Museum"/><id>https://www.simonholywell.com/post/2007/07/triumph-street-triple/</id><author><name>Simon Holywell</name></author><published>2007-07-20T13:46:19+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Yeah I know I am not that quick off the mark posting this up, but I have been admiring it for days. The new Street Triple is running a slightly retuned version of the Daytona’s 675cc triple cylinder engine. It also shares the same frame and swing arm as its much lauded super sport colleague from what I can tell. I have always loved the styling of the larger Speed Triples, but I am not keen to go to much over a 600cc until I have had more on road experience in this country.</summary><content type="html"><![CDATA[<p>Yeah I know I am not that quick off the mark posting this up, but I have been admiring it for days. The new Street Triple is running a slightly retuned version of the Daytona’s 675cc triple cylinder engine. It also shares the same frame and swing arm as its much lauded super sport colleague from what I can tell. I have always loved the styling of the larger Speed Triples, but I am not keen to go to much over a 600cc until I have had more on road experience in this country. So this is the perfect compromise – it has the go of a Daytona (well nearly), looks fantastic and sounds great. I will be very tempted to trade the Bandit in come August and try to get one of these (I reckon there maybe a wait involved given the stir this bike is creating).</p>
<p>I have been hunting around the web looking for all the information I can find about the bike so I thought I would share it with you.</p>
<p><a href="http://www.triumph675.net/streettriple.html">Triumph 675 rolling news article</a> – Best photo for a desktop background I could find.</p>
<p><a href="http://www.triumphstreettriple.com/">Triumph Street Triple site</a></p>
<p><a href="http://www.visordown.com/motorcyclenews/view/triumph_street_triple_675_official_launch_images/1068.html">VisorDown.com Article</a></p>
<p><a href="http://londonbikers.com/news/7f5920ee-4ed9-4779-9b41-dff7f5e8db0e">London Bikers Article</a></p>
<p>Bike gets delivered.<br>
Kevin tries to destroy it. Carmichael at it again! Yet more fantastic bike control.</p>
]]></content><category scheme="taxonomy:Categories" term="motors" label="Motors"/><category scheme="taxonomy:Tags" term="bikes" label="Bikes"/><category scheme="taxonomy:Tags" term="triumph" label="triumph"/></entry><entry xml:base="london"><title type="html">London</title><link href="https://www.simonholywell.com/post/2007/06/london/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2005/11/downtimehousing/?utm_source=atom_feed" rel="related" type="text/html" title="Downtime/Housing"/><link href="https://www.simonholywell.com/post/2006/12/wow-almost-six-months/?utm_source=atom_feed" rel="related" type="text/html" title="Wow, Almost Six Months"/><link href="https://www.simonholywell.com/post/2006/12/geographic-calculations-in-php/?utm_source=atom_feed" rel="related" type="text/html" title="Geographic Calculations in PHP"/><link href="https://www.simonholywell.com/post/2006/12/secondary-dns-for-free/?utm_source=atom_feed" rel="related" type="text/html" title="Secondary DNS for Free"/><link href="https://www.simonholywell.com/post/2006/06/ramones-museum/?utm_source=atom_feed" rel="related" type="text/html" title="Ramones Museum"/><id>https://www.simonholywell.com/post/2007/06/london/</id><author><name>Simon Holywell</name></author><published>2007-06-14T13:13:07+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>I am now based in London and I am working for a company called underwired* based near Farringdon train station.
A few observations:
The trains are slow, late, expensive and overcrowded Carrying a skateboard around town appears to be frowned upon The roads are rubbish, but entertaining on a motorbike They speak weirdly and sometimes smell funny ;-)</summary><content type="html"><![CDATA[<p>I am now based in London and I am working for a company called <a href="http://www.underwired.com/">underwired*</a> based near Farringdon train station.</p>
<p>A few observations:</p>
<ul>
<li>The trains are slow, late, expensive and overcrowded</li>
<li>Carrying a skateboard around town appears to be frowned upon</li>
<li>The roads are rubbish, but entertaining on a motorbike</li>
<li>They speak weirdly and sometimes smell funny ;-)</li>
</ul>
]]></content><category scheme="taxonomy:Tags" term="life" label="life"/><category scheme="taxonomy:Tags" term="me" label="Me"/></entry><entry xml:base="geographic-calculations-in-php"><title type="html">Geographic Calculations in PHP</title><link href="https://www.simonholywell.com/post/2006/12/geographic-calculations-in-php/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2006/03/flickering-images/?utm_source=atom_feed" rel="related" type="text/html" title="Flickering Images"/><link href="https://www.simonholywell.com/post/2005/12/adodb/?utm_source=atom_feed" rel="related" type="text/html" title="ADODB"/><link href="https://www.simonholywell.com/post/2006/03/form-spam-not-ham/?utm_source=atom_feed" rel="related" type="text/html" title='Form SPAM (not "HAM") fighting tips'/><link href="https://www.simonholywell.com/post/2005/10/an-interesting-php-site/?utm_source=atom_feed" rel="related" type="text/html" title="An interesting PHP site"/><link href="https://www.simonholywell.com/post/2005/10/developing-with-camtech/?utm_source=atom_feed" rel="related" type="text/html" title="Developing with CamTech"/><id>https://www.simonholywell.com/post/2006/12/geographic-calculations-in-php/</id><author><name>Simon Holywell</name></author><published>2006-12-10T05:27:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>warning
This library is now deprecated in favour of my new Navigator library. Please use it instead - its much better, tested and makes use of newer PHP features!
Recently I have been involved with a project that maps yachts during an ocean race, which got me thinking about basic calculations and conversions that would be useful to fellow developers. I envisage this being useful in projects leveraging Google or Yahoo maps.</summary><content type="html"><![CDATA[<blockquote>
<p><strong>warning</strong></p>
<p>This library is now deprecated in favour of my new <a href="/post/2013/01/navigator-geographic-calculations-library-for-php.html">Navigator library</a>. Please use it instead - its much better, tested and makes use of newer PHP features!</p>
</blockquote>
<p>Recently I have been involved with a project that maps yachts during an ocean race, which got me thinking about basic calculations and conversions that would be useful to fellow developers. I envisage this being useful in projects leveraging Google or Yahoo maps. For the moment the class performs the following functions:</p>
<ul>
<li>Calculate the distance between two coordinate points on the earth’s surface (using Vincenty, Haversine, Great Circle or The Cosine Law)</li>
<li>Conversion between units (metres to kilometres, nautical miles and miles).</li>
<li>Convert coordinate notation (decimals to degrees, minutes &amp; seconds and back again).</li>
</ul>
<p>That is all you get for the moment, but it is pretty powerful for getting a “as the crow flies” distance between two coordinates. Vincenty’s formula is the most accurate method for calculation, but it is also the most processor intensive.</p>
<p>The attached file package contains an extensive set of “api” documentation and PHPDoc comments throughout the class to make customisation and use easier. I have also included a demo php file in there so you can see how it is intended to be used. It should also be pointed out here that this class requires some of the new OO features only available in PHP5, but it could easily be edited to be backwards compatible with PHP4.</p>
<p>This code has now been moved to GitHub: <a href="http://github.com/treffynnon/Geographic-Calculations-in-PHP"><a href="http://github.com/treffynnon/Geographic-Calculations-in-PHP">http://github.com/treffynnon/Geographic-Calculations-in-PHP</a></a></p>
<p>A zip file of the code can be downloaded directly from GitHub <a href="http://github.com/treffynnon/Geographic-Calculations-in-PHP/zipball/master"><a href="http://github.com/treffynnon/Geographic-Calculations-in-PHP/zipball/master">http://github.com/treffynnon/Geographic-Calculations-in-PHP/zipball/master</a></a> as well but please be patient as it is compressed on request from the source files stored on GitHub.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="code" label="code"/><category scheme="taxonomy:Tags" term="maps" label="maps"/><category scheme="taxonomy:Tags" term="php" label="PHP"/><category scheme="taxonomy:Tags" term="internet" label="Internet"/></entry><entry xml:base="wow-almost-six-months"><title type="html">Wow, Almost Six Months</title><link href="https://www.simonholywell.com/post/2006/12/wow-almost-six-months/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2006/04/new-design/?utm_source=atom_feed" rel="related" type="text/html" title="New Design"/><link href="https://www.simonholywell.com/post/2006/03/server-migration/?utm_source=atom_feed" rel="related" type="text/html" title="Server Migration"/><link href="https://www.simonholywell.com/post/2005/11/downtimehousing/?utm_source=atom_feed" rel="related" type="text/html" title="Downtime/Housing"/><link href="https://www.simonholywell.com/post/2006/12/secondary-dns-for-free/?utm_source=atom_feed" rel="related" type="text/html" title="Secondary DNS for Free"/><link href="https://www.simonholywell.com/post/2006/06/ramones-museum/?utm_source=atom_feed" rel="related" type="text/html" title="Ramones Museum"/><id>https://www.simonholywell.com/post/2006/12/wow-almost-six-months/</id><author><name>Simon Holywell</name></author><published>2006-12-09T14:26:47+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>I did not realise it but it has been almost 6 months since the last update to this website. So I guess I have been busier than I thought of late! Anyway I created a new design for the site and added some features which I felt were lacking.
I had planned to write my own blogging engine, but when I tried the upgrade to Textpattern 4.0.4 I realised that most of the things that annoyed me about previous releases had been fixed and improved.</summary><content type="html"><![CDATA[<p>I did not realise it but it has been almost 6 months since the last update to this website. So I guess I have been busier than I thought of late! Anyway I created a new design for the site and added some features which I felt were lacking.</p>
<p>I had planned to write my own blogging engine, but when I tried the upgrade to <a href="http://www.textpattern">Textpattern 4.0.4</a> I realised that most of the things that annoyed me about previous releases had been fixed and improved. It is such a nice light weight programme that I could no longer see the point in creating my own even if it did use the latest PHP5 features. On top of that, this update may have taken more than six months more to arrive! :-)</p>
]]></content><category scheme="taxonomy:Tags" term="life" label="life"/><category scheme="taxonomy:Tags" term="site-updates" label="Site Updates"/></entry><entry xml:base="secondary-dns-for-free"><title type="html">Secondary DNS for Free</title><link href="https://www.simonholywell.com/post/2006/12/secondary-dns-for-free/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2006/06/server-log-spamming/?utm_source=atom_feed" rel="related" type="text/html" title="Server Log Spamming"/><link href="https://www.simonholywell.com/post/2006/03/form-spam-not-ham/?utm_source=atom_feed" rel="related" type="text/html" title='Form SPAM (not "HAM") fighting tips'/><link href="https://www.simonholywell.com/post/2006/03/flickering-images/?utm_source=atom_feed" rel="related" type="text/html" title="Flickering Images"/><link href="https://www.simonholywell.com/post/2005/12/optus-cable-port-25-smtp/?utm_source=atom_feed" rel="related" type="text/html" title="Optus Cable + Port 25 (SMTP)"/><link href="https://www.simonholywell.com/post/2005/12/adodb/?utm_source=atom_feed" rel="related" type="text/html" title="ADODB"/><id>https://www.simonholywell.com/post/2006/12/secondary-dns-for-free/</id><author><name>Simon Holywell</name></author><published>2006-12-09T14:09:19+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>I recently had a server go offline, taking with it the DNS for my main email domain. I had long suspected this would be a major potential problem in the setup. When the server went down the DNS settings where not backed up by the hosting company so all of a sudden people emailing me started to encounter bounce backs and I could not work out why. Then it dawned on me that when the server died something must have gone missing.</summary><content type="html"><![CDATA[<p>I recently had a server go offline, taking with it the DNS for my main email domain. I had long suspected this would be a major potential problem in the setup. When the server went down the DNS settings where not backed up by the hosting company so all of a sudden people emailing me started to encounter bounce backs and I could not work out why. Then it dawned on me that when the server died something must have gone missing.</p>
<p>As you can understand this was pretty annoying so I decided I needed to implement a better, more robust solution. Having used both <a href="http://www.zoneedit.com">ZoneEdit.com</a> and <a href="http://www.everydns.net">EveryDNS.net</a> before I wondered whether they supported Slave/Secondary DNS setups. Thankfully they do and to sweeten the deal further, they are both free!</p>
<p>To setup you will first need to head over and get yourself accounts at both of the providers and then begin setting your domain up at either of the two. This will be your Primary/Master DNS/record. I chose to go with EveryDNS as the primary so the instructions below reflect that.</p>
<p>Begin setting up your domain on EveryDNS by creating all your A, MX and CNAME records. You will then need to set AXFR to allow <em>all</em> access so that the ZoneEdit servers will have access to the settings and records at EveryDNS.</p>
<p>Now it is time setup the ZoneEdit side of things. Add the new zone for the same domain to your account and edit it. Go to the <em>Advanced Settings</em> for your zone, the link for which will be near the bottom of the page. In the list of links towards the bottom you will find <em>Make this Zone a Slave/Secondary</em> obviously choose confirm when it asks.</p>
<p>You need to put in the IP address of the EveryDNS nameserver you wish to set as the Primary Server. I chose ns1.everydns.net, which when pinged works out to be 38.99.14.207 as you can see in the image above.</p>
<p>Underneath this you will see the nameservers you have been assigned by ZoneEdit, make a quick note of these as you will need to put them in EveryDNS.</p>
<p>Back at EveryDNS we need to add a NS record to our domain for every slave server we have setup. Otherwise they will not respond authoritatively for the domain, which is no good. You can see my to ZoneEdit NS records in the EveryDNS screenshot above.</p>
<p>Now you will want to enter <strong>all</strong> (six in my case) of your new DNSs into your domain name registrar’s management interface. Then all you have to do is wait for the DNSs around the world to cache your new setup.</p>
<p>Once everything has propagated it is a good idea to run the handy diagnostic tool at <a href="http://www.dnsreport.com">DNSReport.com</a> and ensure there are no errors or problems. Sometimes the EveryDNS and ZoneEdit servers may show up as being out of synchronisation after a few changes but they will soon match up.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="dns" label="Dns"/><category scheme="taxonomy:Tags" term="internet" label="Internet"/></entry><entry xml:base="ramones-museum"><title type="html">Ramones Museum</title><link href="https://www.simonholywell.com/post/2006/06/ramones-museum/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2006/06/server-log-spamming/?utm_source=atom_feed" rel="related" type="text/html" title="Server Log Spamming"/><link href="https://www.simonholywell.com/post/2006/06/remote/?utm_source=atom_feed" rel="related" type="text/html" title="Canon SLR Remote Controls"/><link href="https://www.simonholywell.com/post/2006/04/new-design/?utm_source=atom_feed" rel="related" type="text/html" title="New Design"/><link href="https://www.simonholywell.com/post/2006/04/v-for-vendetta/?utm_source=atom_feed" rel="related" type="text/html" title="V for Vendetta"/><link href="https://www.simonholywell.com/post/2006/04/hilarious/?utm_source=atom_feed" rel="related" type="text/html" title="Hilarious"/><id>https://www.simonholywell.com/post/2006/06/ramones-museum/</id><author><name>Simon Holywell</name></author><published>2006-06-28T16:42:02+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>This goes straight onto the list of todos (http://www.ramonesmuseum.com/) just as soon as I get those tickets to Berlin! Awesome idea and congratulations to Florian for realising his dream!
I only wish I had seen this website/museum before now.</summary><content type="html"><![CDATA[<p>This goes straight onto the list of todos (<a href="http://www.ramonesmuseum.com/"><a href="http://www.ramonesmuseum.com/">http://www.ramonesmuseum.com/</a></a>) just as soon as I get those tickets to Berlin! Awesome idea and congratulations to Florian for realising his dream!</p>
<p>I only wish I had seen this website/museum before now.</p>
]]></content></entry><entry xml:base="server-log-spamming"><title type="html">Server Log Spamming</title><link href="https://www.simonholywell.com/post/2006/06/server-log-spamming/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2006/03/form-spam-not-ham/?utm_source=atom_feed" rel="related" type="text/html" title='Form SPAM (not "HAM") fighting tips'/><link href="https://www.simonholywell.com/post/2006/03/flickering-images/?utm_source=atom_feed" rel="related" type="text/html" title="Flickering Images"/><link href="https://www.simonholywell.com/post/2005/12/optus-cable-port-25-smtp/?utm_source=atom_feed" rel="related" type="text/html" title="Optus Cable + Port 25 (SMTP)"/><link href="https://www.simonholywell.com/post/2005/12/adodb/?utm_source=atom_feed" rel="related" type="text/html" title="ADODB"/><link href="https://www.simonholywell.com/post/2005/11/hardening-ssh/?utm_source=atom_feed" rel="related" type="text/html" title="Hardening SSH"/><id>https://www.simonholywell.com/post/2006/06/server-log-spamming/</id><author><name>Simon Holywell</name></author><published>2006-06-16T10:13:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>I have been looking through my hosts logs of late and I have noticed an ever increasing amount of referrer spam. Now whilst this is of no real concern to me as I do not use referrer logs or display them anywhere it is however really quite annoying to see this type of thing in your logs.
Apparently its not a new scam even though I have only started see it from the beginning of this year.</summary><content type="html"><![CDATA[<p>I have been looking through my hosts logs of late and I have noticed an ever increasing amount of referrer spam. Now whilst this is of no real concern to me as I do not use referrer logs or display them anywhere it is however really quite annoying to see this type of thing in your logs.</p>
<p>Apparently its <a href="http://www.spywareinfo.com/articles/referer_spam/">not a new scam</a> even though I have only started see it from the beginning of this year.</p>
<p>Those of you using referrers from the server logs to generate link lists on your websites should take note of the fixes available.</p>
<p>A <em>Referrer</em> is the url some one was on when they found a link to your site. Servers like Apache will log these urls along with users activity. This allows you to see what sites are linking to you and providing you with traffic.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="internet" label="Internet"/></entry><entry xml:base="remote"><title type="html">Canon SLR Remote Controls</title><link href="https://www.simonholywell.com/post/2006/06/remote/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2006/04/new-design/?utm_source=atom_feed" rel="related" type="text/html" title="New Design"/><link href="https://www.simonholywell.com/post/2006/04/v-for-vendetta/?utm_source=atom_feed" rel="related" type="text/html" title="V for Vendetta"/><link href="https://www.simonholywell.com/post/2006/04/hilarious/?utm_source=atom_feed" rel="related" type="text/html" title="Hilarious"/><link href="https://www.simonholywell.com/post/2006/03/lies/?utm_source=atom_feed" rel="related" type="text/html" title="Lies"/><link href="https://www.simonholywell.com/post/2006/03/form-spam-not-ham/?utm_source=atom_feed" rel="related" type="text/html" title='Form SPAM (not "HAM") fighting tips'/><id>https://www.simonholywell.com/post/2006/06/remote/</id><author><name>Simon Holywell</name></author><published>2006-06-07T05:32:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Information below can be used to make remotes for Canon EOS SLR cameras. I built a time delay remote that allows me to take time-delay/interval photographs.
Canon wired remote (DIY):
http://www.chantalcurrid.com/remoteControl.htm
http://www.peeters.com/300d.html
Using a Canon TC-80N3 remote on 2.5mm plug cameras (best but expensive):
[http://sean.wenzel.net/lists/digi\_astro/18/9438.html](http://sean.wenzel.net/lists/digi_astro/18/9438.html)
http://eosdoc.com/manuals/other/TC-80N3/
http://www.deep-sky.co.uk/dslr/dslr.htm
[http://www.licha.de/astro\_review\_canon\_300d.php](http://www.licha.de/astro_review_canon_300d.php)
Tutorials:
http://www.tpub.com/neets/book2/3d.htm
http://www.uoguelph.ca/~antoon/gadgets/555/555.html
Delay/Timer circuits (mostly 555 IC based):
http://www.benlo.com/kap/shutter.html
http://home.cogeco.ca/~rpaisley4/LM555.html#4
http://www.davidbridgen.com/555.htm
http://robroy.dyndns.info/KAP/rig1.html
http://www.uoguelph.ca/~antoon/gadgets/555/555.html
http://www.ladyada.net/make/sudc4kap/make.html
http://www.mikmo.dk/cblfo.html
[http://www.siliconchip.com.au/cms/A\_30337/article.html](http://www.siliconchip.com.au/cms/A_30337/article.html)
[http://www.rocketreviews.com/reviews/scratch/tiny\_timer.html](http://www.rocketreviews.com/reviews/scratch/tiny_timer.html)
http://www.zen22142.zen.co.uk/Circuits/Timing/ivt.htm
[http://uk.geocities.com/ronj\_1217/rts.html](http://uk.geocities.com/ronj_1217/rts.html)
http://circuitos.cl.tripod.com/schem/r34.gif
http://www.aaroncake.net/circuits/relaytim.htm</summary><content type="html"><![CDATA[<p>Information below can be used to make remotes for Canon EOS SLR cameras. I built a time delay remote that allows me to take time-delay/interval photographs.</p>
<p><strong>Canon wired remote (DIY)</strong>:</p>
<p><a href="http://www.chantalcurrid.com/remoteControl.htm"><a href="http://www.chantalcurrid.com/remoteControl.htm">http://www.chantalcurrid.com/remoteControl.htm</a></a><br>
<a href="http://www.peeters.com/300d.html"><a href="http://www.peeters.com/300d.html">http://www.peeters.com/300d.html</a></a></p>
<p><strong>Using a Canon TC-80N3 remote on 2.5mm plug cameras (best but expensive)</strong>:</p>
<p>[<a href="http://sean.wenzel.net/lists/digi_astro/18/9438.html">http://sean.wenzel.net/lists/digi\_astro/18/9438.html</a>](<a href="http://sean.wenzel.net/lists/digi_astro/18/9438.html">http://sean.wenzel.net/lists/digi_astro/18/9438.html</a>)</p>
<p><a href="http://eosdoc.com/manuals/other/TC-80N3/"><a href="http://eosdoc.com/manuals/other/TC-80N3/">http://eosdoc.com/manuals/other/TC-80N3/</a></a></p>
<p><a href="http://www.deep-sky.co.uk/dslr/dslr.htm"><a href="http://www.deep-sky.co.uk/dslr/dslr.htm">http://www.deep-sky.co.uk/dslr/dslr.htm</a></a></p>
<p>[<a href="http://www.licha.de/astro_review_canon_300d.php">http://www.licha.de/astro\_review\_canon\_300d.php</a>](<a href="http://www.licha.de/astro_review_canon_300d.php">http://www.licha.de/astro_review_canon_300d.php</a>)</p>
<p><strong>Tutorials</strong>:</p>
<p><a href="http://www.tpub.com/neets/book2/3d.htm"><a href="http://www.tpub.com/neets/book2/3d.htm">http://www.tpub.com/neets/book2/3d.htm</a></a></p>
<p><a href="http://www.uoguelph.ca/~antoon/gadgets/555/555.html"><a href="http://www.uoguelph.ca/~antoon/gadgets/555/555.html">http://www.uoguelph.ca/~antoon/gadgets/555/555.html</a></a></p>
<p><strong>Delay/Timer circuits (mostly 555 IC based)</strong>:</p>
<p><a href="http://www.benlo.com/kap/shutter.html"><a href="http://www.benlo.com/kap/shutter.html">http://www.benlo.com/kap/shutter.html</a></a></p>
<p><a href="http://home.cogeco.ca/~rpaisley4/LM555.html#4"><a href="http://home.cogeco.ca/~rpaisley4/LM555.html#4">http://home.cogeco.ca/~rpaisley4/LM555.html#4</a></a></p>
<p><a href="http://www.davidbridgen.com/555.htm"><a href="http://www.davidbridgen.com/555.htm">http://www.davidbridgen.com/555.htm</a></a></p>
<p><a href="http://robroy.dyndns.info/KAP/rig1.html"><a href="http://robroy.dyndns.info/KAP/rig1.html">http://robroy.dyndns.info/KAP/rig1.html</a></a></p>
<p><a href="http://www.uoguelph.ca/~antoon/gadgets/555/555.html"><a href="http://www.uoguelph.ca/~antoon/gadgets/555/555.html">http://www.uoguelph.ca/~antoon/gadgets/555/555.html</a></a></p>
<p><a href="http://www.ladyada.net/make/sudc4kap/make.html"><a href="http://www.ladyada.net/make/sudc4kap/make.html">http://www.ladyada.net/make/sudc4kap/make.html</a></a><br>
<a href="http://www.mikmo.dk/cblfo.html"><a href="http://www.mikmo.dk/cblfo.html">http://www.mikmo.dk/cblfo.html</a></a></p>
<p>[<a href="http://www.siliconchip.com.au/cms/A_30337/article.html">http://www.siliconchip.com.au/cms/A\_30337/article.html</a>](<a href="http://www.siliconchip.com.au/cms/A_30337/article.html">http://www.siliconchip.com.au/cms/A_30337/article.html</a>)</p>
<p>[<a href="http://www.rocketreviews.com/reviews/scratch/tiny_timer.html">http://www.rocketreviews.com/reviews/scratch/tiny\_timer.html</a>](<a href="http://www.rocketreviews.com/reviews/scratch/tiny_timer.html">http://www.rocketreviews.com/reviews/scratch/tiny_timer.html</a>)</p>
<p><a href="http://www.zen22142.zen.co.uk/Circuits/Timing/ivt.htm"><a href="http://www.zen22142.zen.co.uk/Circuits/Timing/ivt.htm">http://www.zen22142.zen.co.uk/Circuits/Timing/ivt.htm</a></a></p>
<p>[<a href="http://uk.geocities.com/ronj_1217/rts.html">http://uk.geocities.com/ronj\_1217/rts.html</a>](<a href="http://uk.geocities.com/ronj_1217/rts.html">http://uk.geocities.com/ronj_1217/rts.html</a>)</p>
<p><a href="http://circuitos.cl.tripod.com/schem/r34.gif"><a href="http://circuitos.cl.tripod.com/schem/r34.gif">http://circuitos.cl.tripod.com/schem/r34.gif</a></a></p>
<p><a href="http://www.aaroncake.net/circuits/relaytim.htm"><a href="http://www.aaroncake.net/circuits/relaytim.htm">http://www.aaroncake.net/circuits/relaytim.htm</a></a></p>
<p>[<a href="http://www.electronicsforu.com/efylinux/circuit/feb2003/mar99_wiper.pdf">http://www.electronicsforu.com/efylinux/circuit/feb2003/mar99\_wiper.pdf</a>](<a href="http://www.electronicsforu.com/efylinux/circuit/feb2003/mar99_wiper.pdf">http://www.electronicsforu.com/efylinux/circuit/feb2003/mar99_wiper.pdf</a>)</p>
<p><strong>LED</strong>:</p>
<p>[<a href="http://metku.net/index.html?sect=view&amp;n=1&amp;path=mods/ledcalc/index_eng">http://metku.net/index.html?sect=view&amp;n=1&amp;path=mods/ledcalc/index\_eng</a>](<a href="http://metku.net/index.html?sect=view&amp;n=1&amp;path=mods/ledcalc/index_eng">http://metku.net/index.html?sect=view&amp;n=1&amp;path=mods/ledcalc/index_eng</a>)</p>
<p><strong>Potentiometers</strong>:</p>
<p><a href="http://en.wikipedia.org/wiki/Potentiometer"><a href="http://en.wikipedia.org/wiki/Potentiometer">http://en.wikipedia.org/wiki/Potentiometer</a></a></p>
<p><a href="http://sound.westhost.com/pots.htm"><a href="http://sound.westhost.com/pots.htm">http://sound.westhost.com/pots.htm</a></a></p>
]]></content></entry><entry xml:base="new-design"><title type="html">New Design</title><link href="https://www.simonholywell.com/post/2006/04/new-design/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2006/03/server-migration/?utm_source=atom_feed" rel="related" type="text/html" title="Server Migration"/><link href="https://www.simonholywell.com/post/2006/04/v-for-vendetta/?utm_source=atom_feed" rel="related" type="text/html" title="V for Vendetta"/><link href="https://www.simonholywell.com/post/2006/04/hilarious/?utm_source=atom_feed" rel="related" type="text/html" title="Hilarious"/><link href="https://www.simonholywell.com/post/2006/03/lies/?utm_source=atom_feed" rel="related" type="text/html" title="Lies"/><link href="https://www.simonholywell.com/post/2006/03/form-spam-not-ham/?utm_source=atom_feed" rel="related" type="text/html" title='Form SPAM (not "HAM") fighting tips'/><id>https://www.simonholywell.com/post/2006/04/new-design/</id><author><name>Simon Holywell</name></author><published>2006-04-29T21:31:07+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>I have updated the sites backend code. Thought I would change the looks at the same time. So a nice simple new layout. Enjoy.</summary><content type="html">&lt;p>I have updated the sites backend code. Thought I would change the looks at the same time. So a nice simple new layout. Enjoy.&lt;/p></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="site-updates" label="Site Updates"/></entry><entry xml:base="v-for-vendetta"><title type="html">V for Vendetta</title><link href="https://www.simonholywell.com/post/2006/04/v-for-vendetta/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2006/03/lies/?utm_source=atom_feed" rel="related" type="text/html" title="Lies"/><link href="https://www.simonholywell.com/post/2006/03/mangled/?utm_source=atom_feed" rel="related" type="text/html" title="Mangled"/><link href="https://www.simonholywell.com/post/2005/07/pop-goes-the-psu/?utm_source=atom_feed" rel="related" type="text/html" title="Pop Goes the PSU"/><link href="https://www.simonholywell.com/post/2005/04/msn-messenger/?utm_source=atom_feed" rel="related" type="text/html" title="MSN Messenger"/><link href="https://www.simonholywell.com/post/2006/04/hilarious/?utm_source=atom_feed" rel="related" type="text/html" title="Hilarious"/><id>https://www.simonholywell.com/post/2006/04/v-for-vendetta/</id><author><name>Simon Holywell</name></author><published>2006-04-28T19:00:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>How does this tripe get 75% at rottentomatoes.com
It was obvious from the very beginning that this was going to be a very ordinary movie. The references to the actions of Guy Fawkes were over stylised.
Through out the movie I felt like I was being treated like an idiot. Natalie Portman’s character (Evie) is rescued, by a masked man, from the local police (line men) and she follows him onto a roof top!</summary><content type="html"><![CDATA[<p>How does this tripe get 75% at <a href="http://www.rottentomatoes.com/m/v_for_vendetta/">rottentomatoes.com</a></p>
<p>It was obvious from the very beginning that this was going to be a very ordinary movie. The references to the actions of Guy Fawkes were over stylised.</p>
<p>Through out the movie I felt like I was being treated like an idiot. Natalie Portman’s character (Evie) is rescued, by a masked man, from the local police (line men) and she follows him onto a roof top! She was just about to be raped, some weirdo rescues her and she follows him! Nonsense.</p>
<p>The rest of the movie pretty much follows rather slowly in the same vein of shit. It was so boring I was constantly willing the end to come early.</p>
<p>I will not delve into the protagonist’s terrorist status because it is pretty much irrelevant. It adds nothing to the story. There have also been highly obvious injections of contemporary issues, which add nothing. It is just glaringly obvious.</p>
<p>Leaving the cinema I overheard a conversation, and this is the best part of the movie, someone was questioning the actions of governments. If it can spark healthy debate then at least there is one iota of value in the ticket price. But for those of us not living under rocks or walking around with our ears and eyes blocked and covered there is nothing new here, just inevitability.</p>
<p>There are more interesting films on similar topics, but I think one that sticks with me is <a href="http://www.rottentomatoes.com/m/1007003-fahrenheit_451/">Fahrenheit</a> <a href="http://imdb.com/title/tt0060390/">451</a> A Much better movie.</p>
]]></content><category scheme="taxonomy:Tags" term="rants" label="Rants"/></entry><entry xml:base="hilarious"><title type="html">Hilarious</title><link href="https://www.simonholywell.com/post/2006/04/hilarious/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2006/03/lies/?utm_source=atom_feed" rel="related" type="text/html" title="Lies"/><link href="https://www.simonholywell.com/post/2006/03/form-spam-not-ham/?utm_source=atom_feed" rel="related" type="text/html" title='Form SPAM (not "HAM") fighting tips'/><link href="https://www.simonholywell.com/post/2006/03/flickering-images/?utm_source=atom_feed" rel="related" type="text/html" title="Flickering Images"/><link href="https://www.simonholywell.com/post/2006/03/pictures-of-walls/?utm_source=atom_feed" rel="related" type="text/html" title="Pictures of Walls"/><link href="https://www.simonholywell.com/post/2006/03/server-migration/?utm_source=atom_feed" rel="related" type="text/html" title="Server Migration"/><id>https://www.simonholywell.com/post/2006/04/hilarious/</id><author><name>Simon Holywell</name></author><published>2006-04-24T03:59:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>These videos are fantastic:
Average Homeboy Fight scene from Undefeatable Garbage Day</summary><content type="html"><![CDATA[<p>These videos are fantastic:</p>
<blockquote>
<p><a href="http://www.poetv.com/video.php?vid=2338">Average Homeboy</a> <a href="http://www.poetv.com/video.php?vid=1676">Fight scene from Undefeatable</a> <a href="http://www.poetv.com/video.php?vid=600">Garbage Day</a></p>
</blockquote>
]]></content></entry><entry xml:base="lies"><title type="html">Lies</title><link href="https://www.simonholywell.com/post/2006/03/lies/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2006/03/mangled/?utm_source=atom_feed" rel="related" type="text/html" title="Mangled"/><link href="https://www.simonholywell.com/post/2005/07/pop-goes-the-psu/?utm_source=atom_feed" rel="related" type="text/html" title="Pop Goes the PSU"/><link href="https://www.simonholywell.com/post/2005/04/msn-messenger/?utm_source=atom_feed" rel="related" type="text/html" title="MSN Messenger"/><link href="https://www.simonholywell.com/post/2006/03/form-spam-not-ham/?utm_source=atom_feed" rel="related" type="text/html" title='Form SPAM (not "HAM") fighting tips'/><link href="https://www.simonholywell.com/post/2006/03/flickering-images/?utm_source=atom_feed" rel="related" type="text/html" title="Flickering Images"/><id>https://www.simonholywell.com/post/2006/03/lies/</id><author><name>Simon Holywell</name></author><published>2006-03-20T17:02:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>They lied to us then.
They continue to lie to us now.
They did not even bother to plan.
They will continue to lie to us in the future.
I need say no more.</summary><content type="html"><![CDATA[<p>They lied to us then.</p>
<p>They continue to lie to us now.</p>
<p>They did not even bother to plan.</p>
<p>They <em>will</em> continue to lie to us in the future.</p>
<p>I need say no more.</p>
]]></content><category scheme="taxonomy:Tags" term="rants" label="Rants"/></entry><entry xml:base="form-spam-not-ham"><title type="html">Form SPAM (not "HAM") fighting tips</title><link href="https://www.simonholywell.com/post/2006/03/form-spam-not-ham/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2006/03/flickering-images/?utm_source=atom_feed" rel="related" type="text/html" title="Flickering Images"/><link href="https://www.simonholywell.com/post/2005/12/adodb/?utm_source=atom_feed" rel="related" type="text/html" title="ADODB"/><link href="https://www.simonholywell.com/post/2005/10/an-interesting-php-site/?utm_source=atom_feed" rel="related" type="text/html" title="An interesting PHP site"/><link href="https://www.simonholywell.com/post/2005/10/developing-with-camtech/?utm_source=atom_feed" rel="related" type="text/html" title="Developing with CamTech"/><link href="https://www.simonholywell.com/post/2005/12/optus-cable-port-25-smtp/?utm_source=atom_feed" rel="related" type="text/html" title="Optus Cable + Port 25 (SMTP)"/><id>https://www.simonholywell.com/post/2006/03/form-spam-not-ham/</id><author><name>Simon Holywell</name></author><published>2006-03-18T04:23:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>A site that I have up called Alfa Romeo Sprint QV has recently been the target of malicious spammers and/or their robots. The messages mainly consisted of porn and poker sites.
Now the script used to generate the Your Sprints section of the site was written a long time ago when spamming forms and blogs was not a common occurrence and my site had a relative small readership and no Google rank or anything like that.</summary><content type="html"><![CDATA[<p>A site that I have up called <a href="http://www.alfasprint.com.ru">Alfa Romeo Sprint QV</a> has recently been the target of malicious spammers and/or their robots. The messages mainly consisted of porn and poker sites.</p>
<p>Now the script used to generate the <a href="http://www.alfasprint.com.ru/yoursprints.php">Your Sprints</a> section of the site was written a long time ago when spamming forms and blogs was not a common occurrence and my site had a relative small readership and no Google rank or anything like that. So I thought I would be safe to allow these cars to be posted un-moderated to the site. I knew I could trust the Alfa owners out there to do the right thing and I did not expect anybody else to visit the site. But as we all know obscurity is no defence against spammers or script kiddies.</p>
<p>So the other night I spent quite a large amount of time trying to secure the forms in the site. First of all, it is now a moderated affair without anything going live until I have approved it. Although robots don’t understand this and will submit the form anyway creating a lot of spam to sort through so this is only beginning of the measures I took.</p>
<p>I then made it so the form had rolling names on all the input fields. Whilst it is not good for accessibility (sorry) it does make it a lot harder for a script to get hold of the from via commonly used names like email_address or name. For accessibility purposes I strongly suggest you make use of the label element of html. If you are interested in creating good forms then I highly recommend this series of articles: <a href="http://www.webstandards.org/learn/tutorials/accessible-forms/">Accessible HTML/XHTML Forms</a> by Ian Lloyd of the Web Standards Group.</p>
<p>Every time the page loads new names are generated for the inputs so you cannot take a source snapshot and use that to submit the form either. I store the field names in a session array which is deleted upon submission, but allows me to extract the data from the post array. So if you try posting something with different names the script will not access it and of course if no session is set then you will be sent back to form, which obviously regenerates the field names at the same time.</p>
<p>Now that may sound complex but it really boils down to this:</p>
<ol>
<li>Generate field name: <code>$_SESSION['form']['field1'] = rand(0, 9999999);</code> <!-- raw HTML omitted -->you\ will\ need\ to\ make\ sure\ that\ you\ have\ some\ way\ of\ ensuring
that\ the\ input\ names\ are\ unique<!-- raw HTML omitted --></li>
<li>Label for accessibility: <code>&lt;label for=?&lt;?=$_SESSION['form']['field1']?&gt;?&gt;Field 1&lt;/label&gt;</code></li>
<li>Apply to form: <code>&lt;input name=&quot;&lt;?=$_SESSION['form']['field1']?&gt;&quot; type=&quot;text&quot; size=&quot;20&quot; /&gt;</code></li>
<li>After submission grab the data: <code>$data1 = $_POST[$_SESSION['form']['field1']];</code></li>
<li>Sanitise the data (strip_tags etc.)</li>
<li><code>unset($_SESSION['form']);</code></li>
</ol>
<p>Now to help slow down people who are posting rubbish and separate them from those genuinely trying to post I added a simple mathematical problem that must be completed. The script randomly chooses two numbers between 0 and 10 which the user must correctly add together for the form data to be inserted into the database.</p>
<p>I should also add a note here; although I have used disabled textboxes to hold the numbers that must be added together, when the form is submitted I only use the values stored in the session to determine if they were correct. This way it stops someone from creating their own form and supplying their own numbers. If you took the values from the form then it would be very easy to circumvent the protection.</p>
<p>Anyway these are just some ideas I have had to help deal with the problem of form spam. Obviously you cannot use some of the protections in some forms and you have to weigh up the pros and cons of the additions. But for my little personal site becoming inundated with spam these little changes have made a big difference. So I hope you find some of the ideas useful.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="internet" label="Internet"/><category scheme="taxonomy:Tags" term="php" label="PHP"/></entry><entry xml:base="flickering-images"><title type="html">Flickering Images</title><link href="https://www.simonholywell.com/post/2006/03/flickering-images/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2005/12/adodb/?utm_source=atom_feed" rel="related" type="text/html" title="ADODB"/><link href="https://www.simonholywell.com/post/2005/10/an-interesting-php-site/?utm_source=atom_feed" rel="related" type="text/html" title="An interesting PHP site"/><link href="https://www.simonholywell.com/post/2005/10/developing-with-camtech/?utm_source=atom_feed" rel="related" type="text/html" title="Developing with CamTech"/><link href="https://www.simonholywell.com/post/2005/12/optus-cable-port-25-smtp/?utm_source=atom_feed" rel="related" type="text/html" title="Optus Cable + Port 25 (SMTP)"/><link href="https://www.simonholywell.com/post/2005/11/hardening-ssh/?utm_source=atom_feed" rel="related" type="text/html" title="Hardening SSH"/><id>https://www.simonholywell.com/post/2006/03/flickering-images/</id><author><name>Simon Holywell</name></author><published>2006-03-17T20:06:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>I have been asked numerous times in the past how I create this effect in some forum signatures so now I am releasing the code so you can see. It could equally be used as a background image in CSS (like the photo of the excavator above) so you could have a circulating series of background or in this case header images. I am sure you can think of many other neat uses for this script.</summary><content type="html"><![CDATA[<p>I have been asked numerous times in the past how I create this effect in some forum signatures so now I am releasing the code so you can see. It could equally be used as a background image in CSS (like the photo of the excavator above) so you could have a circulating series of background or in this case header images. I am sure you can think of many other neat uses for this script.</p>
<p>Demo rar’d archive (includes demo ‘Disgraceful Alfa’ gallery images) can be found at the end of the article.</p>
<ol>
<li>Extract into a new directory</li>
<li>Open image.jpg in your favourite editor</li>
<li>Change the BASE_DIR to reflect the absolute path to the directory containing the image.php file eg. /home/simon/flickering/</li>
<li>chmod the storage.dat file to 777</li>
<li>Then open the url in your browser….enjoy!</li>
</ol>
<p>This is the PHP script (image.jpg is the file name):</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o">&lt;?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl"><span class="cm">/*
</span></span></span><span class="line"><span class="cl"><span class="cm">   Original script written by
</span></span></span><span class="line"><span class="cl"><span class="cm">   Simon Holywell (simonholywell.com)
</span></span></span><span class="line"><span class="cl"><span class="cm">   17/3/2006
</span></span></span><span class="line"><span class="cl"><span class="cm">
</span></span></span><span class="line"><span class="cl"><span class="cm">   You may use this script for any purpose.  You can
</span></span></span><span class="line"><span class="cl"><span class="cm">   make changes to the code.  You may NOT redistribute
</span></span></span><span class="line"><span class="cl"><span class="cm">   the code, link back to my site.  All derivatives
</span></span></span><span class="line"><span class="cl"><span class="cm">   must be released and opensource.
</span></span></span><span class="line"><span class="cl"><span class="cm">
</span></span></span><span class="line"><span class="cl"><span class="cm">   THIS NOTICE MUST ALWAYS APPEAR AT THE VERY TOP
</span></span></span><span class="line"><span class="cl"><span class="cm">   OF THE SCRIPT NO MATTER HOW MODIFIED IT IS.
</span></span></span><span class="line"><span class="cl"><span class="cm">*/</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="cm">/*  Setup vars below
</span></span></span><span class="line"><span class="cl"><span class="cm">  ------------------------------------------ */</span>
</span></span><span class="line"><span class="cl"><span class="nx">define</span><span class="p">(</span><span class="s1">&#39;BASE_DIR&#39;</span><span class="p">,</span> <span class="s1">&#39;/path/to/base/&#39;</span><span class="p">);</span>  <span class="c1">//base absolute path to this script
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">define</span><span class="p">(</span><span class="s1">&#39;FILE_NAME&#39;</span><span class="p">,</span> <span class="s1">&#39;alfa&#39;</span><span class="p">);</span> <span class="c1">//filename w/o the extension or number
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">define</span><span class="p">(</span><span class="s1">&#39;IMAGE_PATH&#39;</span><span class="p">,</span> <span class="nx">BASE_DIR</span><span class="o">.</span><span class="s1">&#39;images/&#39;</span><span class="o">.</span><span class="nx">FILE_NAME</span><span class="p">);</span> <span class="c1">//where images are stored
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">define</span><span class="p">(</span><span class="s1">&#39;FILE_SUFFIX&#39;</span><span class="p">,</span> <span class="s1">&#39;.jpg&#39;</span><span class="p">);</span> <span class="c1">//suffix (usually the extension of the images)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">define</span><span class="p">(</span><span class="s1">&#39;IMAGE_COUNT&#39;</span><span class="p">,</span> <span class="mi">20</span><span class="p">);</span> <span class="c1">//number of images
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">define</span><span class="p">(</span><span class="s1">&#39;DATA_FILE&#39;</span><span class="p">,</span> <span class="nx">BASE_DIR</span><span class="o">.</span><span class="s1">&#39;storage.dat&#39;</span><span class="p">);</span> <span class="c1">//the file where the data is stored
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="cm">/* File management
</span></span></span><span class="line"><span class="cl"><span class="cm">  ------------------------------------------ */</span>
</span></span><span class="line"><span class="cl"><span class="k">if</span><span class="p">(</span><span class="nx">file_exists</span><span class="p">(</span><span class="nx">DATA_FILE</span><span class="p">)</span> <span class="o">&amp;&amp;</span> <span class="nx">is_readable</span><span class="p">(</span><span class="nx">DATA_FILE</span><span class="p">)</span> <span class="o">&amp;&amp;</span> <span class="nx">is_writable</span><span class="p">(</span><span class="nx">DATA_FILE</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">    <span class="nv">$storage</span> <span class="o">=</span> <span class="nx">fopen</span><span class="p">(</span><span class="nx">DATA_FILE</span><span class="p">,</span> <span class="s2">&#34;r+&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="k">else</span>
</span></span><span class="line"><span class="cl">    <span class="nv">$storage</span> <span class="o">=</span> <span class="o">@</span><span class="nx">fopen</span><span class="p">(</span><span class="nx">DATA_FILE</span><span class="p">,</span> <span class="s2">&#34;w+&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="nv">$storage</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">print</span> <span class="s1">&#39;Error: You must make the data file readable (chmod 777) and it must exist!&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">exit</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// get the serialized array
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nv">$image_data</span> <span class="o">=</span> <span class="k">array</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="nv">$data</span> <span class="o">=</span> <span class="nx">implode</span><span class="p">(</span><span class="s2">&#34;&#34;</span><span class="p">,</span> <span class="o">@</span><span class="nx">file</span><span class="p">(</span><span class="nx">DATA_FILE</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"><span class="nv">$image_data</span> <span class="o">=</span> <span class="nx">unserialize</span><span class="p">(</span><span class="nv">$data</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// add one to move to the next image
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">if</span><span class="p">(</span><span class="nv">$image_data</span><span class="p">[</span><span class="s1">&#39;position&#39;</span><span class="p">]</span><span class="o">++</span> <span class="o">&gt;=</span> <span class="nx">IMAGE_COUNT</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="nv">$image_data</span><span class="p">[</span><span class="s1">&#39;position&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// hit counter
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nv">$image_data</span><span class="p">[</span><span class="s1">&#39;hit_counter&#39;</span><span class="p">]</span><span class="o">++</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// wipe files contents
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="o">@</span><span class="nx">fseek</span><span class="p">(</span><span class="nv">$storage</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span> <span class="c1">// move back to the beginning of the file
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="o">@</span><span class="nx">ftruncate</span><span class="p">(</span><span class="nv">$storage</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>  <span class="c1">//leave 0 bytes in the file from this point
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="c1">// stick the data back in the file
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nv">$data</span> <span class="o">=</span> <span class="nx">serialize</span><span class="p">(</span><span class="nv">$image_data</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nv">$data</span> <span class="o">=</span> <span class="o">@</span><span class="nx">fputs</span><span class="p">(</span><span class="nv">$storage</span><span class="p">,</span> <span class="nv">$data</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="o">@</span><span class="nx">fclose</span><span class="p">(</span><span class="nv">$storage</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="nv">$data</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">    <span class="k">print</span> <span class="s1">&#39;Error: Could not write the data back to the file.  Please make sure that it exists and is chmod\&#39;d to 777.&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">exit</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// verify the required image exists
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="nx">file_exists</span><span class="p">(</span><span class="nx">IMAGE_PATH</span><span class="o">.</span><span class="nv">$image_data</span><span class="p">[</span><span class="s1">&#39;position&#39;</span><span class="p">]</span><span class="o">.</span><span class="nx">FILE_SUFFIX</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">print</span> <span class="s1">&#39;Error: Image (&#39;</span><span class="o">.</span><span class="nx">IMAGE_PATH</span><span class="o">.</span><span class="nv">$image_data</span><span class="p">[</span><span class="s1">&#39;position&#39;</span><span class="p">]</span><span class="o">.</span><span class="nx">FILE_SUFFIX</span><span class="o">.</span><span class="s1">&#39;) cannot be found.  Please ensure that you have set the correct number of images and that image directory is readable.&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">exit</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// tell the user&#39;s browser that it is an image
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">header</span><span class="p">(</span><span class="s2">&#34;Content-type: image/jpeg&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="cm">/* Image Manipulation
</span></span></span><span class="line"><span class="cl"><span class="cm">  ------------------------------------------ */</span>
</span></span><span class="line"><span class="cl"><span class="c1">// load the image from your selection of images
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nv">$image</span> <span class="o">=</span> <span class="nx">imagecreatefromjpeg</span><span class="p">(</span><span class="nx">IMAGE_PATH</span><span class="o">.</span><span class="nv">$image_data</span><span class="p">[</span><span class="s1">&#39;position&#39;</span><span class="p">]</span><span class="o">.</span><span class="nx">FILE_SUFFIX</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nv">$size</span> <span class="o">=</span> <span class="nx">getimagesize</span><span class="p">(</span><span class="nx">IMAGE_PATH</span><span class="o">.</span><span class="nv">$image_data</span><span class="p">[</span><span class="s1">&#39;position&#39;</span><span class="p">]</span><span class="o">.</span><span class="nx">FILE_SUFFIX</span><span class="p">);</span> <span class="c1">// Read the size
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="c1">// allocate the text colours
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nv">$white</span> <span class="o">=</span> <span class="nx">imagecolorallocate</span><span class="p">(</span><span class="nv">$image</span><span class="p">,</span> <span class="mi">255</span><span class="p">,</span> <span class="mi">255</span><span class="p">,</span> <span class="mi">255</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nv">$black</span> <span class="o">=</span> <span class="nx">imagecolorallocate</span><span class="p">(</span><span class="nv">$image</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// define the font, x position, y postition
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nv">$font</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nv">$x</span> <span class="o">=</span> <span class="mi">5</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nv">$y</span> <span class="o">=</span> <span class="nv">$size</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">-</span> <span class="mi">17</span><span class="p">;</span>  <span class="c1">// equivalent to 17px from the base of the image
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="c1">// write hit counter (shadow first and then the white)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">imagestring</span><span class="p">(</span><span class="nv">$image</span><span class="p">,</span> <span class="nv">$font</span><span class="p">,</span> <span class="nv">$x</span> <span class="o">+</span> <span class="mi">2</span><span class="p">,</span> <span class="nv">$y</span> <span class="o">+</span> <span class="mi">2</span><span class="p">,</span> <span class="s1">&#39;Views: &#39;</span><span class="o">.</span><span class="nv">$image_data</span><span class="p">[</span><span class="s1">&#39;hit_counter&#39;</span><span class="p">],</span> <span class="nv">$black</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">imagestring</span><span class="p">(</span><span class="nv">$image</span><span class="p">,</span> <span class="nv">$font</span><span class="p">,</span> <span class="nv">$x</span><span class="p">,</span> <span class="nv">$y</span><span class="p">,</span> <span class="s1">&#39;Views: &#39;</span><span class="o">.</span><span class="nv">$image_data</span><span class="p">[</span><span class="s1">&#39;hit_counter&#39;</span><span class="p">],</span> <span class="nv">$white</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// write the current position of the slideshow to the image
</span></span></span><span class="line"><span class="cl"><span class="c1">// obviously you will have to take more off of x if you have more
</span></span></span><span class="line"><span class="cl"><span class="c1">// than 100 images other wise the zero will be off &#34;screen&#34;
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">imagestring</span><span class="p">(</span><span class="nv">$image</span><span class="p">,</span> <span class="nv">$font</span><span class="p">,</span> <span class="nv">$size</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">-</span> <span class="mi">50</span><span class="p">,</span> <span class="nv">$y</span> <span class="o">+</span> <span class="mi">2</span><span class="p">,</span> <span class="nv">$image_data</span><span class="p">[</span><span class="s1">&#39;position&#39;</span><span class="p">]</span><span class="o">.</span><span class="s1">&#39; of &#39;</span><span class="o">.</span><span class="nx">IMAGE_COUNT</span><span class="p">,</span> <span class="nv">$black</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">imagestring</span><span class="p">(</span><span class="nv">$image</span><span class="p">,</span> <span class="nv">$font</span><span class="p">,</span> <span class="nv">$size</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">-</span> <span class="mi">52</span><span class="p">,</span> <span class="nv">$y</span><span class="p">,</span> <span class="nv">$image_data</span><span class="p">[</span><span class="s1">&#39;position&#39;</span><span class="p">]</span><span class="o">.</span><span class="s1">&#39; of &#39;</span><span class="o">.</span><span class="nx">IMAGE_COUNT</span><span class="p">,</span> <span class="nv">$white</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="cm">/* Output image
</span></span></span><span class="line"><span class="cl"><span class="cm">  ------------------------------------------ */</span>
</span></span><span class="line"><span class="cl"><span class="nx">imagejpeg</span><span class="p">(</span><span class="nv">$image</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">imagedestroy</span><span class="p">(</span><span class="nv">$image</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="cp">?&gt;</span><span class="err">
</span></span></span></code></pre></div><p>You also need to add a line to .htaccess:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-apacheconf" data-lang="apacheconf"><span class="line"><span class="cl"><span class="nb">ForceType</span> application/x-httpd-php
</span></span></code></pre></div><p>Due to the change in the .htaccess file Apache now treats .jpg files as PHP in this directory. This then allows us to execute some php code which ultimately outputs a JPEG header and JPEG data, which shows up as an image when its linked to. The browser is none the wiser as it does not look like remote script invocation like some previous methods that have been released. So this can be used anywhere an image can without anyone knowing until they see it changing!</p>
<p><a href="/static/files/flickering_images.zip">Flickering Images (zip file)</a></p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="code" label="code"/><category scheme="taxonomy:Tags" term="php" label="PHP"/><category scheme="taxonomy:Tags" term="internet" label="Internet"/></entry><entry xml:base="pictures-of-walls"><title type="html">Pictures of Walls</title><link href="https://www.simonholywell.com/post/2006/03/pictures-of-walls/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2006/03/server-migration/?utm_source=atom_feed" rel="related" type="text/html" title="Server Migration"/><link href="https://www.simonholywell.com/post/2006/03/mangled/?utm_source=atom_feed" rel="related" type="text/html" title="Mangled"/><link href="https://www.simonholywell.com/post/2005/12/optus-cable-port-25-smtp/?utm_source=atom_feed" rel="related" type="text/html" title="Optus Cable + Port 25 (SMTP)"/><link href="https://www.simonholywell.com/post/2005/12/adodb/?utm_source=atom_feed" rel="related" type="text/html" title="ADODB"/><link href="https://www.simonholywell.com/post/2005/11/downtimehousing/?utm_source=atom_feed" rel="related" type="text/html" title="Downtime/Housing"/><id>https://www.simonholywell.com/post/2006/03/pictures-of-walls/</id><author><name>Simon Holywell</name></author><published>2006-03-15T08:23:11+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Pictures of Walls is a great site with some very interesting photos of walls (with graffiti).</summary><content type="html">&lt;p>&lt;a href="http://www.picturesofwalls.com/">Pictures of Walls&lt;/a> is a great site with some very interesting photos of walls (with graffiti).&lt;/p></content></entry><entry xml:base="server-migration"><title type="html">Server Migration</title><link href="https://www.simonholywell.com/post/2006/03/server-migration/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2006/03/mangled/?utm_source=atom_feed" rel="related" type="text/html" title="Mangled"/><link href="https://www.simonholywell.com/post/2005/12/optus-cable-port-25-smtp/?utm_source=atom_feed" rel="related" type="text/html" title="Optus Cable + Port 25 (SMTP)"/><link href="https://www.simonholywell.com/post/2005/12/adodb/?utm_source=atom_feed" rel="related" type="text/html" title="ADODB"/><link href="https://www.simonholywell.com/post/2005/11/downtimehousing/?utm_source=atom_feed" rel="related" type="text/html" title="Downtime/Housing"/><link href="https://www.simonholywell.com/post/2005/11/hardening-ssh/?utm_source=atom_feed" rel="related" type="text/html" title="Hardening SSH"/><id>https://www.simonholywell.com/post/2006/03/server-migration/</id><author><name>Simon Holywell</name></author><published>2006-03-04T19:44:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Well I would like to say it went smoothly, but… At least its all transferred over and backed up now. This new server should be faster as well as more reliable than the old one. I even managed to get something up on FullOctane.com</summary><content type="html">&lt;p>Well I would like to say it went smoothly, but… At least its all transferred over and backed up now. This new server should be faster as well as more reliable than the old one. I even managed to get something up on &lt;a href="http://www.fulloctane.com">FullOctane.com&lt;/a>&lt;/p></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="site-updates" label="Site Updates"/></entry><entry xml:base="mangled"><title type="html">Mangled</title><link href="https://www.simonholywell.com/post/2006/03/mangled/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2005/07/pop-goes-the-psu/?utm_source=atom_feed" rel="related" type="text/html" title="Pop Goes the PSU"/><link href="https://www.simonholywell.com/post/2005/04/msn-messenger/?utm_source=atom_feed" rel="related" type="text/html" title="MSN Messenger"/><link href="https://www.simonholywell.com/post/2005/12/optus-cable-port-25-smtp/?utm_source=atom_feed" rel="related" type="text/html" title="Optus Cable + Port 25 (SMTP)"/><link href="https://www.simonholywell.com/post/2005/12/adodb/?utm_source=atom_feed" rel="related" type="text/html" title="ADODB"/><link href="https://www.simonholywell.com/post/2005/11/downtimehousing/?utm_source=atom_feed" rel="related" type="text/html" title="Downtime/Housing"/><id>https://www.simonholywell.com/post/2006/03/mangled/</id><author><name>Simon Holywell</name></author><published>2006-03-02T09:10:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>I must preface this with a statement: I do not profess to be an expert on the English language. I am, in fact, quite sure you will find errors in this piece and the many others that I have and will post on this site.
However it somewhat irks me that supposedly well educated people cannot adhere to even some of the most basic principles of the language. A quite ridiculous mistake I hear quite often around people who claim to have completed tertiary studies of some kind is the overuse of the word me.</summary><content type="html"><![CDATA[<p>I must preface this with a statement: I do not profess to be an expert on the English language. I am, in fact, quite sure you will find errors in this piece and the many others that I have and will post on this site.</p>
<p>However it somewhat irks me that supposedly well educated people cannot adhere to even some of the most basic principles of the language. A quite ridiculous mistake I hear quite often around people who claim to have completed tertiary studies of some kind is the overuse of the word me. For example; me and you, this is so grotesquely wrong that I could barely bring myself to type it. In fact I had to come back to edit the sentence upon proof reading because I had written it correctly! The second person comes first (you), not only out of politeness but adherence to the grammatical constructs of English. It is a simple enough requirement so just go along with it! You and I. Or if you are addressing a particular person; Jennifer and I.</p>
<p>Another horrendous misuse of the language is to incorrectly describe the letter H even though it clearly guides you how to do so in any English dictionary. For those of you still wondering: <!-- raw HTML omitted -->a<!-- raw HTML omitted --> ch You may note the lack of an H at the beginning, so stop saying hay-ch when you mean H. You are incorrect and look really quite foolish.</p>
<p>Yous is a highly incorrect method of referring to a group of people. Need I say anymore?</p>
<p>Now you may be thinking to yourself one of two things:</p>
<ol>
<li>What does an upstart Australian think he can teach me about English?</li>
<li>The English language was not made in a day and has slowly mutated to become the language we now know, so why should I care if these transgressions find their way into the language?</li>
</ol>
<p>Question two is a valid point and I have thought about it before now. So in true hypocritical spirit I will answer it with another question! Why add something that is of no value? Why should the incorrect and highly rude manner of referring to oneself and those around them (illustrated above) be added to the language? It detracts from the language and for those lazy people (generally those who use such slack talk) out there it even adds an extra letter to the statement! So why do it?</p>
]]></content><category scheme="taxonomy:Tags" term="rants" label="Rants"/></entry><entry xml:base="optus-cable-port-25-smtp"><title type="html">Optus Cable + Port 25 (SMTP)</title><link href="https://www.simonholywell.com/post/2005/12/optus-cable-port-25-smtp/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2005/12/adodb/?utm_source=atom_feed" rel="related" type="text/html" title="ADODB"/><link href="https://www.simonholywell.com/post/2005/11/hardening-ssh/?utm_source=atom_feed" rel="related" type="text/html" title="Hardening SSH"/><link href="https://www.simonholywell.com/post/2005/11/mod-security/?utm_source=atom_feed" rel="related" type="text/html" title="Mod Security"/><link href="https://www.simonholywell.com/post/2005/10/an-interesting-php-site/?utm_source=atom_feed" rel="related" type="text/html" title="An interesting PHP site"/><link href="https://www.simonholywell.com/post/2005/10/developing-with-camtech/?utm_source=atom_feed" rel="related" type="text/html" title="Developing with CamTech"/><id>https://www.simonholywell.com/post/2005/12/optus-cable-port-25-smtp/</id><author><name>Simon Holywell</name></author><published>2005-12-21T08:38:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>I have been setting up a mail server of which smtp is an integral part. I could access it through my old net connection at home and I can through work but I am currently staying somewhere with Optus Cable. They block port 25! I called their tech support to confirm, he did say it was possible to have to port re-opened for this individual connection. But I am not the account holder.</summary><content type="html"><![CDATA[<p>I have been setting up a mail server of which smtp is an integral part. I could access it through my old net connection at home and I can through work but I am currently staying somewhere with Optus Cable. They block port 25! I called their tech support to confirm, he did say it was possible to have to port re-opened for this individual connection. But I am not the account holder. <a href="http://forums.whirlpool.net.au/forum-replies.cfm?t=168371">whirlpool forums</a> also suggest an online method of removing the block.</p>
<p>So my advice to people in a similar predicament is to use the <a href="http://www.zoneedit.com/smtp.html">tools provided by zoneedit.com</a> I can only hope you find this before wasting too much time like me.</p>
<p>Here is a handy list of Optus’ other blocked ports:</p>
<blockquote>
<p>25 SMTP 80 http 135 – windows RPC worm/exploit 13 [789] windows file sharing/netbios 16 [01] snmp 445 windows 2k/xp filesharing 593 RPC as 135 1080 socks src: <a href="http://forums.whirlpool.net.au/forum-replies-archive.cfm/179530.html">whirlpool</a></p>
</blockquote>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="internet" label="Internet"/></entry><entry xml:base="adodb"><title type="html">ADODB</title><link href="https://www.simonholywell.com/post/2005/12/adodb/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2005/10/an-interesting-php-site/?utm_source=atom_feed" rel="related" type="text/html" title="An interesting PHP site"/><link href="https://www.simonholywell.com/post/2005/10/developing-with-camtech/?utm_source=atom_feed" rel="related" type="text/html" title="Developing with CamTech"/><link href="https://www.simonholywell.com/post/2005/11/hardening-ssh/?utm_source=atom_feed" rel="related" type="text/html" title="Hardening SSH"/><link href="https://www.simonholywell.com/post/2005/11/mod-security/?utm_source=atom_feed" rel="related" type="text/html" title="Mod Security"/><link href="https://www.simonholywell.com/post/2005/08/virtual-mail-servers/?utm_source=atom_feed" rel="related" type="text/html" title="Virtual Mail Servers"/><id>https://www.simonholywell.com/post/2005/12/adodb/</id><author><name>Simon Holywell</name></author><published>2005-12-19T21:13:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>During a recent project I ended up using ADODB and found it very effective. Especially the wrapper it places around PHPs sessions, it stores them in the DB instead of in the temp directory, which can be less secure. It also handles encryption of the session variables contents, but only using MD5 originally and I prefer to use SHA1. So I hacked the following to allow me to do so and I contributed it to ADODB.</summary><content type="html"><![CDATA[<p>During a recent project I ended up using ADODB and found it very effective. Especially the wrapper it places around PHPs sessions, it stores them in the DB instead of in the temp directory, which can be less secure. It also handles encryption of the session variables contents, but only using MD5 originally and I prefer to use SHA1. So I hacked the following to allow me to do so and I contributed it to ADODB.</p>
<p>adodb-encrypt-sha1.php (new file):</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o">&lt;?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">defined</span><span class="p">(</span><span class="s1">&#39;ADODB_SESSION&#39;</span><span class="p">))</span> <span class="k">die</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="k">include_once</span> <span class="nx">ADODB_SESSION</span> <span class="o">.</span> <span class="s1">&#39;/crypt.inc.php&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">ADODB_Encrypt_SHA1</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">function</span> <span class="nf">write</span><span class="p">(</span><span class="nv">$data</span><span class="p">,</span> <span class="nv">$key</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$sha1crypt</span> <span class="o">=&amp;</span> <span class="k">new</span> <span class="nx">SHA1Crypt</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$sha1crypt</span><span class="o">-&gt;</span><span class="na">encrypt</span><span class="p">(</span><span class="nv">$data</span><span class="p">,</span> <span class="nv">$key</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">function</span> <span class="nf">read</span><span class="p">(</span><span class="nv">$data</span><span class="p">,</span> <span class="nv">$key</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$sha1crypt</span> <span class="o">=&amp;</span> <span class="k">new</span> <span class="nx">SHA1Crypt</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$sha1crypt</span><span class="o">-&gt;</span><span class="na">decrypt</span><span class="p">(</span><span class="nv">$data</span><span class="p">,</span> <span class="nv">$key</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="k">return</span> <span class="mi">1</span><span class="p">;</span>
</span></span></code></pre></div><p>Add to crypt.inc.php:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o">&lt;?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">SHA1Crypt</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">function</span> <span class="nf">keyED</span><span class="p">(</span><span class="nv">$txt</span><span class="p">,</span><span class="nv">$encrypt_key</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$encrypt_key</span> <span class="o">=</span> <span class="nx">sha1</span><span class="p">(</span><span class="nv">$encrypt_key</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$ctr</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$tmp</span> <span class="o">=</span> <span class="s2">&#34;&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="k">for</span> <span class="p">(</span><span class="nv">$i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span><span class="nv">$i</span><span class="o">&lt;</span><span class="nx">strlen</span><span class="p">(</span><span class="nv">$txt</span><span class="p">);</span><span class="nv">$i</span><span class="o">++</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="p">(</span><span class="nv">$ctr</span><span class="o">==</span><span class="nx">strlen</span><span class="p">(</span><span class="nv">$encrypt_key</span><span class="p">))</span> <span class="nv">$ctr</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="nv">$tmp</span><span class="o">.=</span> <span class="nx">substr</span><span class="p">(</span><span class="nv">$txt</span><span class="p">,</span><span class="nv">$i</span><span class="p">,</span><span class="mi">1</span><span class="p">)</span> <span class="o">^</span> <span class="nx">substr</span><span class="p">(</span><span class="nv">$encrypt_key</span><span class="p">,</span><span class="nv">$ctr</span><span class="p">,</span><span class="mi">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="nv">$ctr</span><span class="o">++</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$tmp</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">function</span> <span class="nf">Encrypt</span><span class="p">(</span><span class="nv">$txt</span><span class="p">,</span><span class="nv">$key</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">srand</span><span class="p">((</span><span class="nx">double</span><span class="p">)</span><span class="nx">microtime</span><span class="p">()</span><span class="o">*</span><span class="mi">1000000</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$encrypt_key</span> <span class="o">=</span> <span class="nx">sha1</span><span class="p">(</span><span class="nx">rand</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">32000</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$ctr</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$tmp</span> <span class="o">=</span> <span class="s2">&#34;&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="k">for</span> <span class="p">(</span><span class="nv">$i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span><span class="nv">$i</span><span class="o">&lt;</span><span class="nx">strlen</span><span class="p">(</span><span class="nv">$txt</span><span class="p">);</span><span class="nv">$i</span><span class="o">++</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="p">(</span><span class="nv">$ctr</span><span class="o">==</span><span class="nx">strlen</span><span class="p">(</span><span class="nv">$encrypt_key</span><span class="p">))</span> <span class="nv">$ctr</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="nv">$tmp</span><span class="o">.=</span> <span class="nx">substr</span><span class="p">(</span><span class="nv">$encrypt_key</span><span class="p">,</span><span class="nv">$ctr</span><span class="p">,</span><span class="mi">1</span><span class="p">)</span> <span class="o">.</span>
</span></span><span class="line"><span class="cl">            <span class="p">(</span><span class="nx">substr</span><span class="p">(</span><span class="nv">$txt</span><span class="p">,</span><span class="nv">$i</span><span class="p">,</span><span class="mi">1</span><span class="p">)</span> <span class="o">^</span> <span class="nx">substr</span><span class="p">(</span><span class="nv">$encrypt_key</span><span class="p">,</span><span class="nv">$ctr</span><span class="p">,</span><span class="mi">1</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">            <span class="nv">$ctr</span><span class="o">++</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nx">base64_encode</span><span class="p">(</span><span class="nv">$this</span><span class="o">-&gt;</span><span class="na">keyED</span><span class="p">(</span><span class="nv">$tmp</span><span class="p">,</span><span class="nv">$key</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">function</span> <span class="nf">Decrypt</span><span class="p">(</span><span class="nv">$txt</span><span class="p">,</span><span class="nv">$key</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$txt</span> <span class="o">=</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">keyED</span><span class="p">(</span><span class="nx">base64_decode</span><span class="p">(</span><span class="nv">$txt</span><span class="p">),</span><span class="nv">$key</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$tmp</span> <span class="o">=</span> <span class="s2">&#34;&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="k">for</span> <span class="p">(</span><span class="nv">$i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span><span class="nv">$i</span><span class="o">&lt;</span><span class="nx">strlen</span><span class="p">(</span><span class="nv">$txt</span><span class="p">);</span><span class="nv">$i</span><span class="o">++</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">            <span class="nv">$sha1</span> <span class="o">=</span> <span class="nx">substr</span><span class="p">(</span><span class="nv">$txt</span><span class="p">,</span><span class="nv">$i</span><span class="p">,</span><span class="mi">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="nv">$i</span><span class="o">++</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="nv">$tmp</span><span class="o">.=</span> <span class="p">(</span><span class="nx">substr</span><span class="p">(</span><span class="nv">$txt</span><span class="p">,</span><span class="nv">$i</span><span class="p">,</span><span class="mi">1</span><span class="p">)</span> <span class="o">^</span> <span class="nv">$sha1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$tmp</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">function</span> <span class="nf">RandPass</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$randomPassword</span> <span class="o">=</span> <span class="s2">&#34;&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="nx">srand</span><span class="p">((</span><span class="nx">double</span><span class="p">)</span><span class="nx">microtime</span><span class="p">()</span><span class="o">*</span><span class="mi">1000000</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">for</span><span class="p">(</span><span class="nv">$i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span><span class="nv">$i</span><span class="o">&lt;</span><span class="mi">8</span><span class="p">;</span><span class="nv">$i</span><span class="o">++</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nv">$randnumber</span> <span class="o">=</span> <span class="nx">rand</span><span class="p">(</span><span class="mi">48</span><span class="p">,</span><span class="mi">120</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="k">while</span> <span class="p">((</span><span class="nv">$randnumber</span> <span class="o">&gt;=</span> <span class="mi">58</span> <span class="o">&amp;&amp;</span> <span class="nv">$randnumber</span> <span class="o">&lt;=</span> <span class="mi">64</span><span class="p">)</span> <span class="o">||</span> <span class="p">(</span><span class="nv">$randnumber</span> <span class="o">&gt;=</span> <span class="mi">91</span> <span class="o">&amp;&amp;</span> <span class="nv">$randnumber</span> <span class="o">&lt;=</span> <span class="mi">96</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">            <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="nv">$randnumber</span> <span class="o">=</span> <span class="nx">rand</span><span class="p">(</span><span class="mi">48</span><span class="p">,</span><span class="mi">120</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">            <span class="nv">$randomPassword</span> <span class="o">.=</span> <span class="nx">chr</span><span class="p">(</span><span class="nv">$randnumber</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nv">$randomPassword</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>This code has now been added to the stable release of ADODB.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="code" label="code"/><category scheme="taxonomy:Tags" term="php" label="PHP"/><category scheme="taxonomy:Tags" term="internet" label="Internet"/></entry><entry xml:base="downtimehousing"><title type="html">Downtime/Housing</title><link href="https://www.simonholywell.com/post/2005/11/downtimehousing/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2005/11/hardening-ssh/?utm_source=atom_feed" rel="related" type="text/html" title="Hardening SSH"/><link href="https://www.simonholywell.com/post/2005/11/mod-security/?utm_source=atom_feed" rel="related" type="text/html" title="Mod Security"/><link href="https://www.simonholywell.com/post/2005/10/an-interesting-php-site/?utm_source=atom_feed" rel="related" type="text/html" title="An interesting PHP site"/><link href="https://www.simonholywell.com/post/2005/10/developing-with-camtech/?utm_source=atom_feed" rel="related" type="text/html" title="Developing with CamTech"/><link href="https://www.simonholywell.com/post/2005/09/akg-headphones/?utm_source=atom_feed" rel="related" type="text/html" title="AKG Headphones"/><id>https://www.simonholywell.com/post/2005/11/downtimehousing/</id><author><name>Simon Holywell</name></author><published>2005-11-26T11:58:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>As some of you will know I have finished uni and now work as php developer for Go4 Multimedia and as such I am currently between houses and I do not have regular access to the net where I am staying.</summary><content type="html">&lt;p>As some of you will know I have finished uni and now work as php developer for &lt;a href="http://www.go4.com.au">Go4 Multimedia&lt;/a> and as such I am currently between houses and I do not have regular access to the net where I am staying.&lt;/p></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="life" label="life"/><category scheme="taxonomy:Tags" term="me" label="Me"/></entry><entry xml:base="hardening-ssh"><title type="html">Hardening SSH</title><link href="https://www.simonholywell.com/post/2005/11/hardening-ssh/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2005/08/virtual-mail-servers/?utm_source=atom_feed" rel="related" type="text/html" title="Virtual Mail Servers"/><link href="https://www.simonholywell.com/post/2005/08/serving-virtual-hosts/?utm_source=atom_feed" rel="related" type="text/html" title="Serving Virtual Hosts"/><link href="https://www.simonholywell.com/post/2005/11/mod-security/?utm_source=atom_feed" rel="related" type="text/html" title="Mod Security"/><link href="https://www.simonholywell.com/post/2005/10/an-interesting-php-site/?utm_source=atom_feed" rel="related" type="text/html" title="An interesting PHP site"/><link href="https://www.simonholywell.com/post/2005/10/developing-with-camtech/?utm_source=atom_feed" rel="related" type="text/html" title="Developing with CamTech"/><id>https://www.simonholywell.com/post/2005/11/hardening-ssh/</id><author><name>Simon Holywell</name></author><published>2005-11-12T13:35:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>A very nice article: Keeping SSH access secure
I use the following in /etc/ssh/sshd_config:
AllowUsers username PermitRootLogin no
Which kills root login access to the server meaning you will need to login as the username provided in AllowUsers and then su to root (eg. su root) or sudo the commands if you have sudo setup (apt-get install sudo).
You may also wish to change the port through which SSH occurs by adding:</summary><content type="html"><![CDATA[<p>A very nice article: <a href="http://www.debian-administration.org/articles/87">Keeping SSH access secure</a></p>
<p>I use the following in /etc/ssh/sshd_config:<br>
AllowUsers username PermitRootLogin no</p>
<p>Which kills root login access to the server meaning you will need to login as the username provided in AllowUsers and then su to root (eg. su root) or sudo the commands if you have sudo setup (apt-get install sudo).</p>
<p>You may also wish to change the port through which SSH occurs by adding:<br>
Port 2345</p>
<p>Where 2345 is the new port number. This will stop people from attacking through the standard port 22, which can help against script kiddies and those using pre-packaged scripts. It will however not stop someone from finding the new port via ICMP sweeps.</p>
<p>Kick over SSHd:<br>
/etc/init.d/ssh restart</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="debian" label="debian"/><category scheme="taxonomy:Tags" term="ssh" label="ssh"/><category scheme="taxonomy:Tags" term="internet" label="Internet"/></entry><entry xml:base="mod-security"><title type="html">Mod Security</title><link href="https://www.simonholywell.com/post/2005/11/mod-security/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2005/10/an-interesting-php-site/?utm_source=atom_feed" rel="related" type="text/html" title="An interesting PHP site"/><link href="https://www.simonholywell.com/post/2005/10/developing-with-camtech/?utm_source=atom_feed" rel="related" type="text/html" title="Developing with CamTech"/><link href="https://www.simonholywell.com/post/2005/08/virtual-mail-servers/?utm_source=atom_feed" rel="related" type="text/html" title="Virtual Mail Servers"/><link href="https://www.simonholywell.com/post/2005/08/serving-virtual-hosts/?utm_source=atom_feed" rel="related" type="text/html" title="Serving Virtual Hosts"/><link href="https://www.simonholywell.com/post/2005/08/thebat/?utm_source=atom_feed" rel="related" type="text/html" title="TheBat!"/><id>https://www.simonholywell.com/post/2005/11/mod-security/</id><author><name>Simon Holywell</name></author><published>2005-11-12T13:16:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>A great little addition to all Apache server installations.
Install it via:
apt-get install libapache2-mod-security
Then create a symbolic link so that the mod is enabled:
ln -s /etc/apache2/mods-available/mod-security.load mod-security.load
Setup the config for the module in /etc/apache2/httpd.conf
Mine looks like the file attached at the end of the article.
Then kick over Apache2:
/etc/init.d/apache2 restart
You can now run the tests to see how well mod security is working for you:</summary><content type="html"><![CDATA[<p>A great little addition to all Apache server installations.</p>
<p>Install it via:</p>
<p>apt-get install libapache2-mod-security</p>
<p>Then create a symbolic link so that the mod is enabled:</p>
<p>ln -s /etc/apache2/mods-available/mod-security.load mod-security.load</p>
<p>Setup the config for the module in /etc/apache2/httpd.conf</p>
<p>Mine looks like the file attached at the end of the article.</p>
<p>Then kick over Apache2:</p>
<p>/etc/init.d/apache2 restart</p>
<p>You can now run the tests to see how well mod security is working for you:</p>
<p>cd /usr/share/mod-security/tests</p>
<p>./run-test.pl domain.com *</p>
<p>The asterisk will make it run all the tests for you. You can run particular tests individually if you like. eg. ./run-test.pl domain.com 55-cookie-1.test, 70-bug-bad-ARGS.test</p>
<p>(replace domain.com with the address to your server)</p>
<p>You will need to restart Apache2 after every change to the mod security settings for them take effect.</p>
<p><a href="/static/files/httpd.txt">httpd (TXT file)</a></p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="apache" label="apache"/><category scheme="taxonomy:Tags" term="internet" label="Internet"/></entry><entry xml:base="an-interesting-php-site"><title type="html">An interesting PHP site</title><link href="https://www.simonholywell.com/post/2005/10/an-interesting-php-site/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2005/10/developing-with-camtech/?utm_source=atom_feed" rel="related" type="text/html" title="Developing with CamTech"/><link href="https://www.simonholywell.com/post/2005/08/virtual-mail-servers/?utm_source=atom_feed" rel="related" type="text/html" title="Virtual Mail Servers"/><link href="https://www.simonholywell.com/post/2005/08/serving-virtual-hosts/?utm_source=atom_feed" rel="related" type="text/html" title="Serving Virtual Hosts"/><link href="https://www.simonholywell.com/post/2005/08/thebat/?utm_source=atom_feed" rel="related" type="text/html" title="TheBat!"/><link href="https://www.simonholywell.com/post/2005/07/us-military-cannot-operate-adobe-acrobat/?utm_source=atom_feed" rel="related" type="text/html" title="U.S. Military Cannot Operate Adobe Acrobat"/><id>https://www.simonholywell.com/post/2005/10/an-interesting-php-site/</id><author><name>Simon Holywell</name></author><published>2005-10-15T16:14:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Some hints and tips for producing secure PHP code. Some tips are gems others are less so.
http://securephp.damonkohler.com/</summary><content type="html"><![CDATA[<p>Some hints and tips for producing secure PHP code. Some tips are gems others are less so.</p>
<p><a href="http://securephp.damonkohler.com/"><a href="http://securephp.damonkohler.com/">http://securephp.damonkohler.com/</a></a></p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="php" label="PHP"/><category scheme="taxonomy:Tags" term="internet" label="Internet"/></entry><entry xml:base="developing-with-camtech"><title type="html">Developing with CamTech</title><link href="https://www.simonholywell.com/post/2005/10/developing-with-camtech/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2005/08/virtual-mail-servers/?utm_source=atom_feed" rel="related" type="text/html" title="Virtual Mail Servers"/><link href="https://www.simonholywell.com/post/2005/08/serving-virtual-hosts/?utm_source=atom_feed" rel="related" type="text/html" title="Serving Virtual Hosts"/><link href="https://www.simonholywell.com/post/2005/08/thebat/?utm_source=atom_feed" rel="related" type="text/html" title="TheBat!"/><link href="https://www.simonholywell.com/post/2005/07/us-military-cannot-operate-adobe-acrobat/?utm_source=atom_feed" rel="related" type="text/html" title="U.S. Military Cannot Operate Adobe Acrobat"/><link href="https://www.simonholywell.com/post/2005/05/setting-up-a-world-visible-host-with-a-netcomm-nb1300-ad/?utm_source=atom_feed" rel="related" type="text/html" title="Setting up a world visible host with a Netcomm NB1300 ADSL modem…"/><id>https://www.simonholywell.com/post/2005/10/developing-with-camtech/</id><author><name>Simon Holywell</name></author><published>2005-10-05T10:42:43+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>For a project I am working on at the moment we are using the CamTech Merchant Gateway. A handy note to all is that it will not function on anything but Java 1.4.x. Java 5 does not work.</summary><content type="html">&lt;p>For a project I am working on at the moment we are using the CamTech Merchant Gateway. A handy note to all is that it will not function on anything but Java 1.4.x. Java 5 does not work.&lt;/p></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="php" label="PHP"/><category scheme="taxonomy:Tags" term="internet" label="Internet"/></entry><entry xml:base="akg-headphones"><title type="html">AKG Headphones</title><link href="https://www.simonholywell.com/post/2005/09/akg-headphones/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2005/09/apple-macintosh-history/?utm_source=atom_feed" rel="related" type="text/html" title="Apple Macintosh History"/><link href="https://www.simonholywell.com/post/2005/08/virtual-mail-servers/?utm_source=atom_feed" rel="related" type="text/html" title="Virtual Mail Servers"/><link href="https://www.simonholywell.com/post/2005/08/serving-virtual-hosts/?utm_source=atom_feed" rel="related" type="text/html" title="Serving Virtual Hosts"/><link href="https://www.simonholywell.com/post/2005/08/2005-08-21-gmt/?utm_source=atom_feed" rel="related" type="text/html" title="GMT"/><link href="https://www.simonholywell.com/post/2005/08/setting-up-a-debian-sarge-server/?utm_source=atom_feed" rel="related" type="text/html" title="Setting up a Debian Sarge Server"/><id>https://www.simonholywell.com/post/2005/09/akg-headphones/</id><author><name>Simon Holywell</name></author><published>2005-09-10T07:12:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>When headphones are mentioned I immediately start thinking about Grado, Beyer and AKG. Most people only make it as far as Sennheiser, which in my opinion is a shame. Sure they do make fantastic equipment but the pricing is poor if you want a good set of what are called “monitor” or reference headphones. To the average user this may be neither here nor there however it makes a big difference to what you actually hear.</summary><content type="html"><![CDATA[<p>When headphones are mentioned I immediately start thinking about Grado, Beyer and AKG. Most people only make it as far as Sennheiser, which in my opinion is a shame. Sure they do make fantastic equipment but the pricing is poor if you want a good set of what are called “monitor” or reference headphones. To the average user this may be neither here nor there however it makes a big difference to what you actually hear. Pick the wrong cans and they will colour the sound of the music by accentuating particular aspects of the sound spectrum, which if you don’t know already is bad. Sure enough some people will prefer the coloured sounds, but personally I like to hear it as the artist intended, which is usually the way it sounds the best anyway.</p>
<p>Having been given a $40 JB HiFi gift voucher for Christmas by a relation I thought there would be the best place to begin my search for my new headphones. They had Sennheisers on display there with a listening post, the phones (HD465 I think) I liked the look of were about $125. But even before they had touched my ears I was disgusted by their muddy sound so I tossed them back onto the shelf. I then tried on the HD555 ($200) and HD550 ($175) both of which were quite nice and a vast improvement upon the pair I tried on earlier. But I did not really want to spend that much money of a pair of headphones that could get left somewhere or get nicked because they look really nice.</p>
<p>The next day I hunted down an AKG agent because I really wanted to try out the K44s everybody on forums and in some magazines had been raving about. Having read a review on <a href="http://www.hifichoice.co.uk">HiFiChoice.co.uk</a> as was not going to buy them without trying them out as they are reportedly uncomfortable for some people. Different ears cope differently with having padding against them for long periods of time. So I went for a 40 minute drive to Drum Power in Bayswater (<a href="http://www.drumpower.com.au/"><a href="http://www.drumpower.com.au/">http://www.drumpower.com.au/</a></a>) to checkout their range of AKG head phones as they seemed to be the closest agent and friendly on the phone.</p>
<p>They had some K44s hooked up for me to try out on a Sennheiser tower similar to the one at JB but with the studio range of Sennheiser cans. Whilst I was suitably impressed by the sound they produced they were very uncomfortable against my ears as the cup was slightly too small to fit around my ears. So it crushed the lobes and became almost painful after 10 minutes of listening. They also had the K55 and K66 in the store, however none that I could audition, looking at the cups I thought I could detect a larger size on the higher range models. So still impressed by the great bang for buck sound of the K44s ($44, rrp ~$59) I bought a pair of K55s ($55, rrp ~$70), which have been used for monitoring in the past by some studios on a budget. The K66s have a coloured sound according to Darren the very friendly and helpful bloke who helped me out at the shop so I decided that they were off the cards. He was however adamant that the K44, K55 and K66 all had the same cup size. So having decided that I could give them to my sister if they were uncomfortable I took a chance and bought the K55s unheard and without even seeing them out of the box.</p>
<p>After another 40 minutes I arrived home and hooked the K55s up to my PC to test them out on my large collection of music. When I put them over my head I was soon glad that I had taken a chance, if the cups are not bigger then they certainly feel it and are far more comfortable than the K44s. However one thing to note about all of the K series mentioned so far is that the cups are really quite shallow so if your ears stick out a bit then these most likely will become excruciatingly uncomfortable before very long. Now I have only been testing the new headphones for about 1.5 hours so I cannot definitively say that they will not start to hurt my ears after prolonged use but so far for the small amount they cost they are very comfortable. Like everyone else I suggest you try before you buy, but this time I was lucky enough to get away without trying out the exact model I ended up buying.</p>
<p>The headphones do not have looks on their side but then what does it matter when they sound really nice? Besides most people will look at them and think that they are a pair of cheepies (which you can easily argue they are) and not bother nicking them if you accidentally leave them somewhere. The build quality is of the standard you would expect for the price, plastic, but they feel durable enough and are quite flexible so will take to being put into a bag full other stuff without being snapped in two like some solid but brittle headphones. They are a closed design so they do cut out some external noise and make a minimal attempt of not disturbing the person next to you. Up until now they have not become too hot to wear but by summer that may have changed!</p>
<p>So what am I saying in this long winded way? If your in the market for some terrific sounding headphones but donâ€™t have a $400 budget then I recommend the AKG K55s. Obviously there are better headphones out there, but for the money ($55) you cannot do better in my experience. If you are in the UK or USA then perhaps with some of the deals you can get (eg. Richer Sounds) then there are other similarly good headphones in the same price bracket, but in Australia I am yet to see anything. Go have a chat with Luke or Darren at Drum Power who are very accommodating and pickup some new phones at very close to wholesale price.</p>
]]></content></entry><entry xml:base="apple-macintosh-history"><title type="html">Apple Macintosh History</title><link href="https://www.simonholywell.com/post/2005/09/apple-macintosh-history/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2005/08/virtual-mail-servers/?utm_source=atom_feed" rel="related" type="text/html" title="Virtual Mail Servers"/><link href="https://www.simonholywell.com/post/2005/08/serving-virtual-hosts/?utm_source=atom_feed" rel="related" type="text/html" title="Serving Virtual Hosts"/><link href="https://www.simonholywell.com/post/2005/08/2005-08-21-gmt/?utm_source=atom_feed" rel="related" type="text/html" title="GMT"/><link href="https://www.simonholywell.com/post/2005/08/setting-up-a-debian-sarge-server/?utm_source=atom_feed" rel="related" type="text/html" title="Setting up a Debian Sarge Server"/><link href="https://www.simonholywell.com/post/2005/08/thebat/?utm_source=atom_feed" rel="related" type="text/html" title="TheBat!"/><id>https://www.simonholywell.com/post/2005/09/apple-macintosh-history/</id><author><name>Simon Holywell</name></author><published>2005-09-03T13:56:05+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>A very interesting site created by a Macintosh team member, Andy Hertzfeld, with amusing stories about the hardware, software and people who created the first Macintosh computer.
http://www.folklore.org</summary><content type="html"><![CDATA[<p>A very interesting site created by a Macintosh team member, Andy Hertzfeld, with amusing stories about the hardware, software and people who created the first Macintosh computer.</p>
<p><a href="http://www.folklore.org"><a href="http://www.folklore.org">http://www.folklore.org</a></a></p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/></entry><entry xml:base="virtual-mail-servers"><title type="html">Virtual Mail Servers</title><link href="https://www.simonholywell.com/post/2005/08/virtual-mail-servers/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2005/08/serving-virtual-hosts/?utm_source=atom_feed" rel="related" type="text/html" title="Serving Virtual Hosts"/><link href="https://www.simonholywell.com/post/2005/08/setting-up-a-debian-sarge-server/?utm_source=atom_feed" rel="related" type="text/html" title="Setting up a Debian Sarge Server"/><link href="https://www.simonholywell.com/post/2005/08/thebat/?utm_source=atom_feed" rel="related" type="text/html" title="TheBat!"/><link href="https://www.simonholywell.com/post/2005/07/us-military-cannot-operate-adobe-acrobat/?utm_source=atom_feed" rel="related" type="text/html" title="U.S. Military Cannot Operate Adobe Acrobat"/><link href="https://www.simonholywell.com/post/2005/05/setting-up-a-world-visible-host-with-a-netcomm-nb1300-ad/?utm_source=atom_feed" rel="related" type="text/html" title="Setting up a world visible host with a Netcomm NB1300 ADSL modem…"/><id>https://www.simonholywell.com/post/2005/08/virtual-mail-servers/</id><author><name>Simon Holywell</name></author><published>2005-08-28T17:44:50+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>http://workaround.org/articles/ispmail-sarge
VPSs are nice but how do you host multiple domain email addresses? Well the above tutorial a fantastic guide on Debian Sarge.
An item worthy of note is creation of the Courier SSL certificates. By default there will be a couple automatically created by Courier at install time. This are useless as your email client WILL reject them because localhost is not the same domain as domain1.com etc…
You need to edit both /etc/courier/pop3d.</summary><content type="html"><![CDATA[<p><a href="http://workaround.org/articles/ispmail-sarge"><a href="http://workaround.org/articles/ispmail-sarge">http://workaround.org/articles/ispmail-sarge</a></a></p>
<p>VPSs are nice but how do you host multiple domain email addresses? Well the above tutorial a fantastic guide on Debian Sarge.</p>
<p>An item worthy of note is creation of the Courier SSL certificates. By default there will be a couple automatically created by Courier at install time. This are useless as your email client WILL reject them because localhost is not the same domain as domain1.com etc…</p>
<p>You need to edit both /etc/courier/pop3d.cnf and /etc/courier/imapd.cnf and change the details to reflect your company or name.</p>
<blockquote>
<p>CN – Fully qualified hostname (eg. mail.domain.com) C – Country (2 letter code eg. AU) ST – State or province L – Location/City O – Organisation OU – Organisation Unit/Division</p>
</blockquote>
<p>CN must be set to your mail servers hostname!</p>
<p>Now you need to remove the old certificates because the new ones cannot be generated with them in place:</p>
<blockquote>
<p>cd /etc/courier rm imapd.pem pop3d.pem</p>
</blockquote>
<p>Now to make the new certificates, which will last for 365 days at which point you need to re-generate them. If you need them to last longer then you can adjust the /usr/sbin/mk*****cert shell script.</p>
<blockquote>
<p>mkimapdcert mkpop3dcert</p>
</blockquote>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="debian" label="debian"/><category scheme="taxonomy:Tags" term="mail" label="mail"/><category scheme="taxonomy:Tags" term="internet" label="Internet"/></entry><entry xml:base="serving-virtual-hosts"><title type="html">Serving Virtual Hosts</title><link href="https://www.simonholywell.com/post/2005/08/serving-virtual-hosts/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2005/08/setting-up-a-debian-sarge-server/?utm_source=atom_feed" rel="related" type="text/html" title="Setting up a Debian Sarge Server"/><link href="https://www.simonholywell.com/post/2005/08/thebat/?utm_source=atom_feed" rel="related" type="text/html" title="TheBat!"/><link href="https://www.simonholywell.com/post/2005/07/us-military-cannot-operate-adobe-acrobat/?utm_source=atom_feed" rel="related" type="text/html" title="U.S. Military Cannot Operate Adobe Acrobat"/><link href="https://www.simonholywell.com/post/2005/05/setting-up-a-world-visible-host-with-a-netcomm-nb1300-ad/?utm_source=atom_feed" rel="related" type="text/html" title="Setting up a world visible host with a Netcomm NB1300 ADSL modem…"/><link href="https://www.simonholywell.com/post/2005/04/save-toby/?utm_source=atom_feed" rel="related" type="text/html" title="Save Toby"/><id>https://www.simonholywell.com/post/2005/08/serving-virtual-hosts/</id><author><name>Simon Holywell</name></author><published>2005-08-22T07:41:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>To begin with I am using Apache2 so this will not apply to Apache1.3. Apache2 uses an interesting technique for setting up Virtual Hosts, they are no longer stored in the huge httpd.conf file. They are stored in two folders, sites-available and sites-enabled.
I am basing this setup on the following structure:
/home/www/ -- www.sitename1.com -- htdocs -- stats -- logs -- www.sitename2.com -- htdocs -- stats -- logs To make a new Virtual Host you make a new file in the sites-available directory.</summary><content type="html"><![CDATA[<p>To begin with I am using Apache2 so this will not apply to Apache1.3. Apache2 uses an interesting technique for setting up Virtual Hosts, they are no longer stored in the huge httpd.conf file. They are stored in two folders, sites-available and sites-enabled.</p>
<p>I am basing this setup on the following structure:</p>
<pre><code>/home/www/
-- www.sitename1.com

   -- htdocs
      -- stats
   -- logs
-- www.sitename2.com
    -- htdocs
       -- stats
    -- logs
</code></pre>
<p>To make a new Virtual Host you make a new file in the sites-available directory. Sitename = your new site. <em>Don’t forget to sudo if your not logged in as root</em></p>
<pre><code>cd /etc/apache2/sites-available
vi sitename
</code></pre>
<p>Then enter the following into your new file:</p>
<pre><code>&lt;VirtualHost *&gt;

    ServerAdmin email@address.com
    ServerName sitename.com
    ServerAlias *.sitename.com
    DocumentRoot /var/www/sitename/htdocs
    ErrorLog /var/www/sitename/logs/error.log
    TransferLog /var/www/sitename/logs/access.log
&lt;/VirtualHost&gt;
</code></pre>
<p>The asterisk in the initial VirtualHost tag can be replaced by a particular IP address if your server has more than one.</p>
<p>You need to add a symlink to the sites-enabled directory for apache2 to add your new VirtualHost to its serving directories.</p>
<pre><code>cd ../sites-enabled
ln -s ../sites-available/sitename
</code></pre>
<p>Now you need to create the folders mentioned in the structure above:</p>
<pre><code>mkdir /var/www/sitename
mkdir /var/www/sitename/htdocs
mkdir /var/www/sitename/htdocs/stats
mkdir /var/www/sitename/logs
/etc/init.d/apache2 restart
</code></pre>
<p>So you have your nice little virtual servers setup, but how do you know who is accessing them? Well the following article is good starting point: <a href="http://www.debian-administration.org/articles/85"><a href="http://www.debian-administration.org/articles/85">http://www.debian-administration.org/articles/85</a></a></p>
<p><strong>However there are a few helpful extras that you need to know.</strong></p>
<p>When installing and Debian asks you for the location of the log files you need to modify the path from /var/logs/apache/ to /var/logs/apache2 because you are running Apache2.</p>
<p>When creating that cron job in /etc/cron.daily you must set permissions for it:</p>
<pre><code>chmod +x mycmds.sh
</code></pre>
<p>If you wish to run the script now to test it then you need to type:</p>
<pre><code>./mycmds.sh
</code></pre>
<p>Also when you run webalizer it may chuck an error saying something like it could not find /var/logs/apache2/access.log.1 This is because the log has not been rotated yet so if you don’t want to wait for the cron job to do it for you you can:</p>
<pre><code>logrotate --force apache2
</code></pre>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="debian" label="debian"/><category scheme="taxonomy:Tags" term="virtualhosting" label="virtualhosting"/><category scheme="taxonomy:Tags" term="internet" label="Internet"/></entry><entry xml:base=""><title type="html">GMT</title><link href="https://www.simonholywell.com/post/2005/08/2005-08-21-gmt/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2005/08/setting-up-a-debian-sarge-server/?utm_source=atom_feed" rel="related" type="text/html" title="Setting up a Debian Sarge Server"/><link href="https://www.simonholywell.com/post/2005/08/thebat/?utm_source=atom_feed" rel="related" type="text/html" title="TheBat!"/><link href="https://www.simonholywell.com/post/2005/07/pop-goes-the-psu/?utm_source=atom_feed" rel="related" type="text/html" title="Pop Goes the PSU"/><link href="https://www.simonholywell.com/post/2005/07/us-military-cannot-operate-adobe-acrobat/?utm_source=atom_feed" rel="related" type="text/html" title="U.S. Military Cannot Operate Adobe Acrobat"/><link href="https://www.simonholywell.com/post/2005/07/lebedev-optimus-keyboard/?utm_source=atom_feed" rel="related" type="text/html" title="Lebedev Optimus Keyboard"/><id>https://www.simonholywell.com/post/2005/08/2005-08-21-gmt/</id><author><name>Simon Holywell</name></author><published>2005-08-21T16:04:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>A very interesting article written by Richard B. Langley of the University of New Brunswick about GMT and UTC and how they dictate world time. Well worth a read if you have always wondered.
GMT UTC (TXT file)</summary><content type="html"><![CDATA[<p>A very interesting article written by Richard B. Langley of the University of New Brunswick about GMT and UTC and how they dictate world time. Well worth a read if you have always wondered.</p>
<p><a href="/static/files/gmtutandthergo.txt">GMT UTC (TXT file)</a></p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/></entry><entry xml:base="setting-up-a-debian-sarge-server"><title type="html">Setting up a Debian Sarge Server</title><link href="https://www.simonholywell.com/post/2005/08/setting-up-a-debian-sarge-server/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2005/08/thebat/?utm_source=atom_feed" rel="related" type="text/html" title="TheBat!"/><link href="https://www.simonholywell.com/post/2005/07/pop-goes-the-psu/?utm_source=atom_feed" rel="related" type="text/html" title="Pop Goes the PSU"/><link href="https://www.simonholywell.com/post/2005/07/us-military-cannot-operate-adobe-acrobat/?utm_source=atom_feed" rel="related" type="text/html" title="U.S. Military Cannot Operate Adobe Acrobat"/><link href="https://www.simonholywell.com/post/2005/07/lebedev-optimus-keyboard/?utm_source=atom_feed" rel="related" type="text/html" title="Lebedev Optimus Keyboard"/><link href="https://www.simonholywell.com/post/2005/05/setting-up-a-world-visible-host-with-a-netcomm-nb1300-ad/?utm_source=atom_feed" rel="related" type="text/html" title="Setting up a world visible host with a Netcomm NB1300 ADSL modem…"/><id>https://www.simonholywell.com/post/2005/08/setting-up-a-debian-sarge-server/</id><author><name>Simon Holywell</name></author><published>2005-08-19T15:36:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Perfect Debian Setup is a very handy little article.
One item of note however is that Debian Sarge doesn’t support PHP5 even in the unstable packages so you will need to use the following technique to get the PHP5 goodies from a Debian developers repository. You can browse his directory and see what is on offer at: http://people.debian.org/~dexter There is also another source with less recent and a less complete collection of packages DotDeb, but as it is out of date I would not bother with it.</summary><content type="html"><![CDATA[<p><a href="http://www.falkotimme.com/howtos/perfect_setup_debian_sarge/index.php">Perfect Debian Setup</a> is a very handy little article.</p>
<p>One item of note however is that Debian Sarge doesn’t support PHP5 even in the unstable packages so you will need to use the following technique to get the PHP5 goodies from a Debian developers repository. You can browse his directory and see what is on offer at: <a href="http://people.debian.org/~dexter"><a href="http://people.debian.org/~dexter">http://people.debian.org/~dexter</a></a> There is also another source with less recent and a less complete collection of packages <a href="http://www.dotdeb.org">DotDeb</a>, but as it is out of date I would not bother with it.</p>
<p>Add to /etc/apt/sources.list<br>
deb <a href="http://people.debian.org/~dexter"><a href="http://people.debian.org/~dexter">http://people.debian.org/~dexter</a></a> php5 sarge</p>
<p>Update your package list<br>
apt-get update</p>
<p>Install the modules you need (below is a base install add other modules as you see fit)<br>
apt-get install php5 libapache2-mod-php5</p>
<p>Kick over Apache<br>
/etc/init.d/apache2 restart</p>
<p>If you wish to see the packages available from bash then<br>
apt-cache search php5</p>
<p>Other useful Debian server setup advice:</p>
<p><a href="http://rimuhosting.com/support/howtolist.jsp"><a href="http://rimuhosting.com/support/howtolist.jsp">http://rimuhosting.com/support/howtolist.jsp</a></a></p>
<p><a href="http://www.aboutdebian.com/internet.htm"><a href="http://www.aboutdebian.com/internet.htm">http://www.aboutdebian.com/internet.htm</a></a></p>
<p>[<a href="http://www.servepath.com/support/debian_securitychecklist.htm">http://www.servepath.com/support/debian\_securitychecklist.htm</a>](<a href="http://www.servepath.com/support/debian_securitychecklist.htm">http://www.servepath.com/support/debian_securitychecklist.htm</a>)</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="debian" label="debian"/></entry><entry xml:base="thebat"><title type="html">TheBat!</title><link href="https://www.simonholywell.com/post/2005/08/thebat/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2005/07/us-military-cannot-operate-adobe-acrobat/?utm_source=atom_feed" rel="related" type="text/html" title="U.S. Military Cannot Operate Adobe Acrobat"/><link href="https://www.simonholywell.com/post/2005/05/setting-up-a-world-visible-host-with-a-netcomm-nb1300-ad/?utm_source=atom_feed" rel="related" type="text/html" title="Setting up a world visible host with a Netcomm NB1300 ADSL modem…"/><link href="https://www.simonholywell.com/post/2005/04/save-toby/?utm_source=atom_feed" rel="related" type="text/html" title="Save Toby"/><link href="https://www.simonholywell.com/post/2005/04/neowin/?utm_source=atom_feed" rel="related" type="text/html" title="neowin"/><link href="https://www.simonholywell.com/post/2005/04/msn-messenger/?utm_source=atom_feed" rel="related" type="text/html" title="MSN Messenger"/><id>https://www.simonholywell.com/post/2005/08/thebat/</id><author><name>Simon Holywell</name></author><published>2005-08-14T14:54:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>I have reverted back to Ritlabs The Bat email client having previously used Thunderbird. When I left The Bat its HTML support was very limited and this has now been rectified in this release. Given its quicker searching of emails and faster template based email composition I had to move back over. For novice users there will be too many options but it makes life so much easier than any other client I have ever come across.</summary><content type="html"><![CDATA[<p>I have reverted back to Ritlabs The Bat email client having previously used Thunderbird. When I left The Bat its HTML support was very limited and this has now been rectified in this release. Given its quicker searching of emails and faster template based email composition I had to move back over. For novice users there will be too many options but it makes life so much easier than any other client I have ever come across.</p>
<p>If you recieve hundreds of emails a week then this is the client for you. Correspondents names and greetings are automatically placed according to your templates making replies a doddle.</p>
<p>There is also a nice discount offered for student users so there is no excuse!</p>
<p><a href="http://www.ritlabs.com">RitLabs</a></p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="internet" label="Internet"/></entry><entry xml:base="pop-goes-the-psu"><title type="html">Pop Goes the PSU</title><link href="https://www.simonholywell.com/post/2005/07/pop-goes-the-psu/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2005/04/msn-messenger/?utm_source=atom_feed" rel="related" type="text/html" title="MSN Messenger"/><link href="https://www.simonholywell.com/post/2005/07/us-military-cannot-operate-adobe-acrobat/?utm_source=atom_feed" rel="related" type="text/html" title="U.S. Military Cannot Operate Adobe Acrobat"/><link href="https://www.simonholywell.com/post/2005/07/lebedev-optimus-keyboard/?utm_source=atom_feed" rel="related" type="text/html" title="Lebedev Optimus Keyboard"/><link href="https://www.simonholywell.com/post/2005/05/setting-up-a-world-visible-host-with-a-netcomm-nb1300-ad/?utm_source=atom_feed" rel="related" type="text/html" title="Setting up a world visible host with a Netcomm NB1300 ADSL modem…"/><link href="https://www.simonholywell.com/post/2005/04/save-toby/?utm_source=atom_feed" rel="related" type="text/html" title="Save Toby"/><id>https://www.simonholywell.com/post/2005/07/pop-goes-the-psu/</id><author><name>Simon Holywell</name></author><published>2005-07-26T12:04:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>The power supply unit in my Shuttle PC has died, which is really annoying as I need to be getting on with assignments. Ok so I can browse the web and check my email with the Linux box but the assignment is in VisualBasic .NET so I need Windows to run VisualStudio .NET. A really friggin annoying side to this is not being able download images from my camera.
Anyway my new PSU should arrive soon, which is the new and improved quiet 250W PSU that comes in the new Shuttles.</summary><content type="html"><![CDATA[<p>The power supply unit in my Shuttle PC has died, which is really annoying as I need to be getting on with assignments. Ok so I can browse the web and check my email with the Linux box but the assignment is in VisualBasic .NET so I need Windows to run VisualStudio .NET. A really friggin annoying side to this is not being able download images from my camera.</p>
<p>Anyway my new PSU should arrive soon, which is the new and improved quiet 250W PSU that comes in the new Shuttles. Hopefully it will quieten down my irritating loud Shuttle. I hate PC noise! Oh yeah the old one died because it was full of dust. Shuttles should really come with filters as a matter of course as should any case produced since at least 1999.</p>
<p><a href="http://www.auspcmarket.com.au/index.php?redir=http://www.auspcmarket.com.au/show_product_info.php?input%5Bproduct_code%5D=AL-PC40&amp;input%5Bcategory_id%5D=96">PC40 PSU</a></p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="rants" label="Rants"/></entry><entry xml:base="us-military-cannot-operate-adobe-acrobat"><title type="html">U.S. Military Cannot Operate Adobe Acrobat</title><link href="https://www.simonholywell.com/post/2005/07/us-military-cannot-operate-adobe-acrobat/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2005/05/setting-up-a-world-visible-host-with-a-netcomm-nb1300-ad/?utm_source=atom_feed" rel="related" type="text/html" title="Setting up a world visible host with a Netcomm NB1300 ADSL modem…"/><link href="https://www.simonholywell.com/post/2005/04/save-toby/?utm_source=atom_feed" rel="related" type="text/html" title="Save Toby"/><link href="https://www.simonholywell.com/post/2005/04/neowin/?utm_source=atom_feed" rel="related" type="text/html" title="neowin"/><link href="https://www.simonholywell.com/post/2005/04/msn-messenger/?utm_source=atom_feed" rel="related" type="text/html" title="MSN Messenger"/><link href="https://www.simonholywell.com/post/2005/07/lebedev-optimus-keyboard/?utm_source=atom_feed" rel="related" type="text/html" title="Lebedev Optimus Keyboard"/><id>https://www.simonholywell.com/post/2005/07/us-military-cannot-operate-adobe-acrobat/</id><author><name>Simon Holywell</name></author><published>2005-07-16T12:32:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>There have been two recent cases of U.S. Military negligence when operating the Adobe Acrobat suite for creation of PDF files. One such incident ocurred in a report released from Iraq about an Italian agent named Nicola Calipari who was killed by the U.S. Military at checkpoint whilst attempting to rescue an Italian journalist. The PDF document contained both sensitive and unclassified information, the former of which was covered with black boxes.</summary><content type="html"><![CDATA[<p>There have been two recent cases of U.S. Military negligence when operating the Adobe Acrobat suite for creation of PDF files. One such incident ocurred in a report released from Iraq about an Italian agent named Nicola Calipari who was killed by the U.S. Military at checkpoint whilst attempting to rescue an Italian journalist. The PDF document contained both sensitive and unclassified information, the former of which was covered with black boxes. Merely covering the data is not enough however as a user can just select the text in Adobe Acrobat and copy &amp; paste it into a text document/application.</p>
<p>An alleged English crackers (hacker for the non-technical) case file was recently presented on the web by the military with, once again, classified text covered with black boxes. In this instance they are IP addresses of military computers, which Gary McKinnon apparently attacked. You can see the IP addresses below along with an example PNG demonstrating how easily this “security” can be overcome. The U.S. Military are currently seeking his extradition to face an American court.</p>
<p>IP Address Location<br>
160.145.18.111 Fort Myer, VA 160.145.30.89 Fort Myer, VA 160.145.33.52 Fort Myer, VA 160.145.40.22 Fort Myer, VA 160.145.40.31 Fort Myer, VA 160.145.40.51 Fort Myer, VA 160.145.214.25 Fort McNair, Washington, DC</p>
<p><img src="/static/images/5.png" alt="PDF copying of classified material example"></p>
<p><a href="http://news.zdnet.co.uk/internet/security/0,39020375,39197313,00.htm"><a href="http://news.zdnet.co.uk/internet/security/0,39020375,39197313,00.htm">http://news.zdnet.co.uk/internet/security/0,39020375,39197313,00.htm</a></a></p>
<p>[<a href="http://www.spy.org.uk/freegary/archives/2005/06/the_indictment.html#more">http://www.spy.org.uk/freegary/archives/2005/06/the\_indictment.html#more</a>](<a href="http://www.spy.org.uk/freegary/archives/2005/06/the_indictment.html#more">http://www.spy.org.uk/freegary/archives/2005/06/the_indictment.html#more</a>)</p>
<p>[<a href="http://www.boingboing.net/2005/06/08/uk_superhacker_who_0.html">http://www.boingboing.net/2005/06/08/uk\_superhacker\_who\_0.html</a>](<a href="http://www.boingboing.net/2005/06/08/uk_superhacker_who_0.html">http://www.boingboing.net/2005/06/08/uk_superhacker_who_0.html</a>)</p>
<p><a href="http://news.findlaw.com/hdocs/docs/cyberlaw/usmck1102vaind.pdf"><a href="http://news.findlaw.com/hdocs/docs/cyberlaw/usmck1102vaind.pdf">http://news.findlaw.com/hdocs/docs/cyberlaw/usmck1102vaind.pdf</a></a></p>
<p><a href="http://cryptome.org/ips-bared.htm"><a href="http://cryptome.org/ips-bared.htm">http://cryptome.org/ips-bared.htm</a></a></p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="internet" label="Internet"/></entry><entry xml:base="lebedev-optimus-keyboard"><title type="html">Lebedev Optimus Keyboard</title><link href="https://www.simonholywell.com/post/2005/07/lebedev-optimus-keyboard/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2005/05/setting-up-a-world-visible-host-with-a-netcomm-nb1300-ad/?utm_source=atom_feed" rel="related" type="text/html" title="Setting up a world visible host with a Netcomm NB1300 ADSL modem…"/><link href="https://www.simonholywell.com/post/2005/04/save-toby/?utm_source=atom_feed" rel="related" type="text/html" title="Save Toby"/><link href="https://www.simonholywell.com/post/2005/04/the-hoary-hedgehog/?utm_source=atom_feed" rel="related" type="text/html" title="The Hoary Hedgehog?"/><link href="https://www.simonholywell.com/post/2005/04/neowin/?utm_source=atom_feed" rel="related" type="text/html" title="neowin"/><link href="https://www.simonholywell.com/post/2005/04/foobar2000/?utm_source=atom_feed" rel="related" type="text/html" title="foobar2000"/><id>https://www.simonholywell.com/post/2005/07/lebedev-optimus-keyboard/</id><author><name>Simon Holywell</name></author><published>2005-07-16T11:57:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>The Optimus keyboard is a new idea many have been waiting for; a keyboard with a layout that changes depending upon its use. For example it can display the usual QWERTY keyboard in Word but just as easily switch to a French AZERTY layout if need be. This would also extend into games where you could have a different setup of keys and functions depending on the game being played.</summary><content type="html"><![CDATA[<p>The Optimus keyboard is a new idea many have been waiting for; a keyboard with a layout that changes depending upon its use. For example it can display the usual QWERTY keyboard in Word but just as easily switch to a French AZERTY layout if need be. This would also extend into games where you could have a different setup of keys and functions depending on the game being played.</p>
<p>This new design will make working in applications such as Photoshop much quicker because it can display the shortcuts and changes the keys to represent the typeface you’re using; terrific for Dingbat fonts.</p>
<p>It works by placing an OLED screen on each key which can be independently changed to offer different keyboard layouts.</p>
<p><a href="http://www.artlebedev.com/portfolio/optimus/"><a href="http://www.artlebedev.com/portfolio/optimus/">http://www.artlebedev.com/portfolio/optimus/</a></a></p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/></entry><entry xml:base="setting-up-a-world-visible-host-with-a-netcomm-nb1300-ad"><title type="html">Setting up a world visible host with a Netcomm NB1300 ADSL modem…</title><link href="https://www.simonholywell.com/post/2005/05/setting-up-a-world-visible-host-with-a-netcomm-nb1300-ad/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2005/04/save-toby/?utm_source=atom_feed" rel="related" type="text/html" title="Save Toby"/><link href="https://www.simonholywell.com/post/2005/04/neowin/?utm_source=atom_feed" rel="related" type="text/html" title="neowin"/><link href="https://www.simonholywell.com/post/2005/04/msn-messenger/?utm_source=atom_feed" rel="related" type="text/html" title="MSN Messenger"/><link href="https://www.simonholywell.com/post/2005/04/the-hoary-hedgehog/?utm_source=atom_feed" rel="related" type="text/html" title="The Hoary Hedgehog?"/><link href="https://www.simonholywell.com/post/2005/04/foobar2000/?utm_source=atom_feed" rel="related" type="text/html" title="foobar2000"/><id>https://www.simonholywell.com/post/2005/05/setting-up-a-world-visible-host-with-a-netcomm-nb1300-ad/</id><author><name>Simon Holywell</name></author><published>2005-05-07T16:40:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Due to the reluctance of many hosts on the internet to update their server software I have decided that I will use my spare computer at home as a small server for testing my PHP5 scripts and so on. But I ran into a few niggling problems along the way. Firstly alot of the modems functions are not properly documented in the user manual, which is pathetic, they assume that you know a lot about ADSL modems and procedures to do with them.</summary><content type="html"><![CDATA[<p>Due to the reluctance of many hosts on the internet to update their server software I have decided that I will use my spare computer at home as a small server for testing my PHP5 scripts and so on. But I ran into a few niggling problems along the way. Firstly alot of the modems functions are not properly documented in the user manual, which is pathetic, they assume that you know a lot about ADSL modems and procedures to do with them.</p>
<p>First go to <a href="http://www.dyndns.org"><a href="http://www.dyndns.org">http://www.dyndns.org</a></a> and get yourself a Dynamic (if you have a Dynamic IP address assigned by your ISP) account setup.</p>
<p>To setup your server you need to go into the advanced settings and click on the DDNS link. Enable it and choose Dynamic DNS as the service type. Enter the username and password you setup at dyndns.org. Lastly you will need to include your dyndns.org address, which takes the form of name.dyndns.org usually.</p>
<p><img src="/static/images/3.gif" alt="DDNS Configuration"></p>
<p>This will then automatically update your IP address on the dyndns.org site whenever it changes. This usually happens on reconnection. Then click on submit.</p>
<p>Next you need to setup Port Forwarding so that the incoming traffic is directed to the right computer on the network. So to do this you will need the local IP address of your serving computer. Your port configuration should then look something like this, you may not require FTP:</p>
<p><img src="/static/images/4.gif" alt="Port Forwarding"></p>
<p>With this setup you could just reboot the modem now and save the settings if you only wish to serve pages but if you would like remote FTP access then there is another setting you must adjust.</p>
<p>Down under Security you will see a Misc Configuration link, click it. Make sure to disable the FTP server and TFTP server. If you don’t then you will only be FTPing into the modem itself from what I can figure out. Don’t forget to click submit and then reboot the modem saving your settings as you go.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="internet" label="Internet"/></entry><entry xml:base="save-toby"><title type="html">Save Toby</title><link href="https://www.simonholywell.com/post/2005/04/save-toby/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2005/04/neowin/?utm_source=atom_feed" rel="related" type="text/html" title="neowin"/><link href="https://www.simonholywell.com/post/2005/04/msn-messenger/?utm_source=atom_feed" rel="related" type="text/html" title="MSN Messenger"/><link href="https://www.simonholywell.com/post/2005/04/the-hoary-hedgehog/?utm_source=atom_feed" rel="related" type="text/html" title="The Hoary Hedgehog?"/><link href="https://www.simonholywell.com/post/2005/04/foobar2000/?utm_source=atom_feed" rel="related" type="text/html" title="foobar2000"/><link href="https://www.simonholywell.com/post/2005/04/amip-song-title-server/?utm_source=atom_feed" rel="related" type="text/html" title="AMIP Song title server"/><id>https://www.simonholywell.com/post/2005/04/save-toby/</id><author><name>Simon Holywell</name></author><published>2005-04-20T16:39:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Toby is a wee rabbit who is going to be eaten unless his site creator is paid $50k USD in the next month. Fantastic little web legend if you ask me, please go and check SaveToby.com out for yourself. The updates page has some hidden gems.</summary><content type="html">&lt;p>Toby is a wee rabbit who is going to be eaten unless his site creator is paid $50k USD in the next month. Fantastic little web legend if you ask me, please go and check &lt;a href="http://www.savetoby.com">SaveToby.com&lt;/a> out for yourself. The updates page has some hidden gems.&lt;/p></content><category scheme="taxonomy:Tags" term="internet" label="Internet"/></entry><entry xml:base="the-hoary-hedgehog"><title type="html">The Hoary Hedgehog?</title><link href="https://www.simonholywell.com/post/2005/04/the-hoary-hedgehog/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2005/04/neowin/?utm_source=atom_feed" rel="related" type="text/html" title="neowin"/><link href="https://www.simonholywell.com/post/2005/04/foobar2000/?utm_source=atom_feed" rel="related" type="text/html" title="foobar2000"/><link href="https://www.simonholywell.com/post/2005/04/amip-song-title-server/?utm_source=atom_feed" rel="related" type="text/html" title="AMIP Song title server"/><link href="https://www.simonholywell.com/post/2005/04/konfabulator/?utm_source=atom_feed" rel="related" type="text/html" title="Konfabulator"/><link href="https://www.simonholywell.com/post/2005/04/lancia-stratos/?utm_source=atom_feed" rel="related" type="text/html" title="Lancia Stratos"/><id>https://www.simonholywell.com/post/2005/04/the-hoary-hedgehog/</id><author><name>Simon Holywell</name></author><published>2005-04-20T16:38:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Strange name for the latest incarnation of a linux distribution, but then Ubuntu is a very different beast. First of all the best thing about Ubuntu is that initially you only need to download one iso image from their site and you can get a desktop or server up and running a CD burner later. You can then download binaries for other programs you may need via an inbuilt and remove programs interface.</summary><content type="html"><![CDATA[<p>Strange name for the latest incarnation of a linux distribution, but then Ubuntu is a very different beast. First of all the best thing about Ubuntu is that initially you only need to download one iso image from their site and you can get a desktop or server up and running a CD burner later. You can then download binaries for other programs you may need via an inbuilt and remove programs interface. For all of us out there who have been getting frustrated with the bad downloads of Mandrake and SuSE this is the solution. No longer will your download be littered with errors and crash part way through the linux installation process. That is quite possibly the most frustrating thing for new comers to the operating system; one bad iso in collection of seven and their new OS won’t get through its installation procedure.</p>
<p>This also means that for those on a slower connection like me you can actually download it in a reasonable amount of time. Gone are the days of waiting for weeks with only a 56kbps dialup connection.</p>
<p>So far it has been a vary stable and reliable installation, but I have not put it to real production use it yet.</p>
<p><a href="http://www.ubuntu.com">Ubuntu.com</a></p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/></entry><entry xml:base="neowin"><title type="html">neowin</title><link href="https://www.simonholywell.com/post/2005/04/neowin/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2005/04/msn-messenger/?utm_source=atom_feed" rel="related" type="text/html" title="MSN Messenger"/><link href="https://www.simonholywell.com/post/2005/04/foobar2000/?utm_source=atom_feed" rel="related" type="text/html" title="foobar2000"/><link href="https://www.simonholywell.com/post/2005/04/amip-song-title-server/?utm_source=atom_feed" rel="related" type="text/html" title="AMIP Song title server"/><link href="https://www.simonholywell.com/post/2005/04/konfabulator/?utm_source=atom_feed" rel="related" type="text/html" title="Konfabulator"/><link href="https://www.simonholywell.com/post/2005/04/lancia-stratos/?utm_source=atom_feed" rel="related" type="text/html" title="Lancia Stratos"/><id>https://www.simonholywell.com/post/2005/04/neowin/</id><author><name>Simon Holywell</name></author><published>2005-04-10T16:37:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>If you don’t already know about this site then you have not been on the web in the last five years. It has become the biggest place to discuss Windows related news and problems. It now has a very large member base and is ever expanding.
The news is well worth a look for details about the latest updates to your favourite programs, but the forums are the greatest resource on there.</summary><content type="html"><![CDATA[<p>If you don’t already know about this site then you have not been on the web in the last five years. It has become the biggest place to discuss Windows related news and problems. It now has a very large member base and is ever expanding.</p>
<p>The news is well worth a look for details about the latest updates to your favourite programs, but the forums are the greatest resource on there. Even if your just looking for some silly jokes neowin will have it.</p>
<p>Check it out: <a href="http://www.neowin.net/">neowin.net</a></p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="internet" label="Internet"/></entry><entry xml:base="foobar2000"><title type="html">foobar2000</title><link href="https://www.simonholywell.com/post/2005/04/foobar2000/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2005/04/amip-song-title-server/?utm_source=atom_feed" rel="related" type="text/html" title="AMIP Song title server"/><link href="https://www.simonholywell.com/post/2005/04/konfabulator/?utm_source=atom_feed" rel="related" type="text/html" title="Konfabulator"/><link href="https://www.simonholywell.com/post/2005/04/lancia-stratos/?utm_source=atom_feed" rel="related" type="text/html" title="Lancia Stratos"/><link href="https://www.simonholywell.com/post/2005/04/msn-messenger/?utm_source=atom_feed" rel="related" type="text/html" title="MSN Messenger"/><link href="https://www.simonholywell.com/post/2005/04/haiku-osopenbeos-an-open-source-beos-clone/?utm_source=atom_feed" rel="related" type="text/html" title="Haiku OS/OpenBeOS - An open source BeOS clone"/><id>https://www.simonholywell.com/post/2005/04/foobar2000/</id><author><name>Simon Holywell</name></author><published>2005-04-10T16:36:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Quite simply the best player I have come across. It is lightweight and starts up exceptionally quickly and maintains a minimal footprint. It sounds great and the interface is nice and simple. Skinned players are for losers. I like to listen to my music not look at the player. This player does what it says on the box and it is not bloated. Download it and use it now. Nothing else to say!</summary><content type="html"><![CDATA[<p>Quite simply the best player I have come across. It is lightweight and starts up exceptionally quickly and maintains a minimal footprint. It sounds great and the interface is nice and simple. Skinned players are for losers. I like to listen to my music not look at the player. This player does what it says on the box and it is not bloated. Download it and use it now. Nothing else to say!</p>
<p><a href="http://www.foobar2000.org/">foobar2000.org</a> where the application can be obtained. I took the special package and I recommend you do the same.</p>
<p>A very similar player can be seen in Billy: <a href="http://www.sheepfriends.com/?page=billy"><a href="http://www.sheepfriends.com/?page=billy">http://www.sheepfriends.com/?page=billy</a></a>.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/></entry><entry xml:base="amip-song-title-server"><title type="html">AMIP Song title server</title><link href="https://www.simonholywell.com/post/2005/04/amip-song-title-server/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2005/04/konfabulator/?utm_source=atom_feed" rel="related" type="text/html" title="Konfabulator"/><link href="https://www.simonholywell.com/post/2005/04/lancia-stratos/?utm_source=atom_feed" rel="related" type="text/html" title="Lancia Stratos"/><link href="https://www.simonholywell.com/post/2005/04/msn-messenger/?utm_source=atom_feed" rel="related" type="text/html" title="MSN Messenger"/><link href="https://www.simonholywell.com/post/2005/04/haiku-osopenbeos-an-open-source-beos-clone/?utm_source=atom_feed" rel="related" type="text/html" title="Haiku OS/OpenBeOS - An open source BeOS clone"/><link href="https://www.simonholywell.com/post/2004/10/mms2802-assignment-2/?utm_source=atom_feed" rel="related" type="text/html" title="MMS2802: Assignment 2"/><id>https://www.simonholywell.com/post/2005/04/amip-song-title-server/</id><author><name>Simon Holywell</name></author><published>2005-04-10T16:18:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>AMIP is a program that gets the currently playing song title from your music player and broadcasts it to your email client and MSN messenger among others. I now use it for my email signatures and in MSN Messenger7 where it does a very good job.
It has many builds and you need to pick the one for the player you currently use. In my case foobar2000, which is quite possibly the best player available.</summary><content type="html"><![CDATA[<p>AMIP is a program that gets the currently playing song title from your music player and broadcasts it to your email client and MSN messenger among others. I now use it for my email signatures and in MSN Messenger7 where it does a very good job.</p>
<p>It has many builds and you need to pick the one for the player you currently use. In my case foobar2000, which is quite possibly the best player available. :-)</p>
<p>I got the latest BETA release from here: <a href="http://amip.tools-for.net/config/"><a href="http://amip.tools-for.net/config/">http://amip.tools-for.net/config/</a></a>. The lastest stable release among other things is available here: <a href="http://amip.tools-for.net/"><a href="http://amip.tools-for.net/">http://amip.tools-for.net/</a></a></p>
<p>You’ll also need to grab the latest Configurator to make all the setup easy.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/></entry><entry xml:base="konfabulator"><title type="html">Konfabulator</title><link href="https://www.simonholywell.com/post/2005/04/konfabulator/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2005/04/lancia-stratos/?utm_source=atom_feed" rel="related" type="text/html" title="Lancia Stratos"/><link href="https://www.simonholywell.com/post/2005/04/msn-messenger/?utm_source=atom_feed" rel="related" type="text/html" title="MSN Messenger"/><link href="https://www.simonholywell.com/post/2005/04/haiku-osopenbeos-an-open-source-beos-clone/?utm_source=atom_feed" rel="related" type="text/html" title="Haiku OS/OpenBeOS - An open source BeOS clone"/><link href="https://www.simonholywell.com/post/2004/10/mms2802-assignment-2/?utm_source=atom_feed" rel="related" type="text/html" title="MMS2802: Assignment 2"/><link href="https://www.simonholywell.com/post/2004/10/mms2402-dynamic-flash-web-gallery/?utm_source=atom_feed" rel="related" type="text/html" title="MMS2402: Dynamic Flash Web Gallery"/><id>https://www.simonholywell.com/post/2005/04/konfabulator/</id><author><name>Simon Holywell</name></author><published>2005-04-10T16:00:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>I have been using Konfabulator on my Windows machine for a little while and I am very impressed with it. I also tried out ObjectDesk but I didn’t feel it was as good. Konfabulator just works and does its job perfectly. ObjectDesk kept falling over which was quite irritating. There are also plenty of Widgets available for Konfabulator and unlike ObjectDesk the news widgets don’t all link to bullshit like CNN!</summary><content type="html"><![CDATA[<p>I have been using Konfabulator on my Windows machine for a little while and I am very impressed with it. I also tried out ObjectDesk but I didn’t feel it was as good. Konfabulator just works and does its job perfectly. ObjectDesk kept falling over which was quite irritating. There are also plenty of Widgets available for Konfabulator and unlike ObjectDesk the news widgets don’t all link to bullshit like CNN!</p>
<p>I currently use five widgets on my desktop (in the right hand screen of the two):</p>
<ul>
<li>The Weather (comes with the initial installation) for a five day forecast of Melbourne</li>
<li>mini Weather so I can see the weather in Edinburgh</li>
<li>Calendar (comes with the initial installation) nice to see the date occassionally</li>
<li>BBC news</li>
<li>Reuters news</li>
</ul>
<p>Konfabulator can be had <a href="http://www.konfabulator.com/">here</a>.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/></entry><entry xml:base="lancia-stratos"><title type="html">Lancia Stratos</title><link href="https://www.simonholywell.com/post/2005/04/lancia-stratos/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2005/04/msn-messenger/?utm_source=atom_feed" rel="related" type="text/html" title="MSN Messenger"/><link href="https://www.simonholywell.com/post/2005/04/haiku-osopenbeos-an-open-source-beos-clone/?utm_source=atom_feed" rel="related" type="text/html" title="Haiku OS/OpenBeOS - An open source BeOS clone"/><link href="https://www.simonholywell.com/post/2004/10/mms2802-assignment-2/?utm_source=atom_feed" rel="related" type="text/html" title="MMS2802: Assignment 2"/><link href="https://www.simonholywell.com/post/2004/10/mms2402-dynamic-flash-web-gallery/?utm_source=atom_feed" rel="related" type="text/html" title="MMS2402: Dynamic Flash Web Gallery"/><link href="https://www.simonholywell.com/post/2004/09/mms2802-assignment-1/?utm_source=atom_feed" rel="related" type="text/html" title="MMS2802: Assignment 1"/><id>https://www.simonholywell.com/post/2005/04/lancia-stratos/</id><author><name>Simon Holywell</name></author><published>2005-04-08T16:28:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Ever since I first saw Phill Eather’s Lancia Stratos at the Targa Tasmania race event when I was a kid I have wanted a one. They have classic styling that has not dated at all, well not much for a car of its age. Most of its competitors are all but forgotten. Yes Bertone did a wonderful job on the coachwork for Lancia’s rally monster. Despite not having any money I have been looking into the Stratos replica options.</summary><content type="html"><![CDATA[<p>Ever since I first saw Phill Eather’s Lancia Stratos at the Targa Tasmania race event when I was a kid I have wanted a one. They have classic styling that has not dated at all, well not much for a car of its age. Most of its competitors are all but forgotten. Yes Bertone did a wonderful job on the coachwork for Lancia’s rally monster. Despite not having any money I have been looking into the Stratos replica options. There are two companies involved in the production of these wonderful cars: <a href="http://www.hawkcars.co.uk">Hawk Kit Cars (UK)</a> and <a href="http://www.superstratos.com">Napiersport (UK)</a>.</p>
<p>Hawk seem to have sold the most kits of the two and they produce the most accurate replica of the Stratos, panels may even be used on an original Stratos! But some of the complexities and irritations of the orginal Stratos have been copied verbatim into the Hawk design. Napiersport have taken a different approach, keep the looks but improve upon comfort and ease of setup with a better suspension geometry. The Corse (Napiersport’s replica) has however been produced by many owners over the years and I would be a litte cautious to pay in full before I have received the car kit from them in its totallity.</p>
<p><img src="/static/images/wp/2005/04/2.jpg" alt="Phill Eathers Genuine Stratos"></p>
<p>Phill Eather’s Genuine Stratos</p>
<p><a href="http://www.hermes.net.au/stratos/">The Australian and New Zealand Lancia Stratos and Stratos Replica Register</a></p>
<p><a href="http://www.stratossupersite.com/">The biggest Stratos and Stratos replica forum</a>.</p>
<p>A couple of Lancia Stratos books that I found very interesting <a href="http://www.amazon.co.uk/gp/product/1845840410?ie=UTF8&amp;tag=simonholywell-21&amp;linkCode=as2&amp;camp=1634&amp;creative=6738&amp;creativeASIN=1845840410">Lancia Stratos (Rally Giants Series)</a> and <a href="http://www.amazon.co.uk/gp/product/0948207027?ie=UTF8&amp;tag=simonholywell-21&amp;linkCode=as2&amp;camp=1634&amp;creative=6738&amp;creativeASIN=0948207027">Lancia Stratos, 1972-85 (Brooklands Books Road Tests Series)</a>.</p>
]]></content><category scheme="taxonomy:Categories" term="motors" label="Motors"/><category scheme="taxonomy:Tags" term="lancia" label="Lancia"/><category scheme="taxonomy:Tags" term="stratos" label="Stratos"/><category scheme="taxonomy:Tags" term="cars" label="Cars"/></entry><entry xml:base="msn-messenger"><title type="html">MSN Messenger</title><link href="https://www.simonholywell.com/post/2005/04/msn-messenger/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2005/04/haiku-osopenbeos-an-open-source-beos-clone/?utm_source=atom_feed" rel="related" type="text/html" title="Haiku OS/OpenBeOS - An open source BeOS clone"/><link href="https://www.simonholywell.com/post/2004/10/mms2802-assignment-2/?utm_source=atom_feed" rel="related" type="text/html" title="MMS2802: Assignment 2"/><link href="https://www.simonholywell.com/post/2004/10/mms2402-dynamic-flash-web-gallery/?utm_source=atom_feed" rel="related" type="text/html" title="MMS2402: Dynamic Flash Web Gallery"/><link href="https://www.simonholywell.com/post/2004/09/mms2802-assignment-1/?utm_source=atom_feed" rel="related" type="text/html" title="MMS2802: Assignment 1"/><link href="https://www.simonholywell.com/post/2004/06/mms2801-assignment-3/?utm_source=atom_feed" rel="related" type="text/html" title="MMS2801: Assignment 3"/><id>https://www.simonholywell.com/post/2005/04/msn-messenger/</id><author><name>Simon Holywell</name></author><published>2005-04-08T16:27:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Most people use it as their instant messaging program of choice and it is the most fully featured and frequently updated one out there at the moment, at least of all the main stream programs out there. Microsoft claim to receive 100 million unique connections through their messaging service per day, which is quite phenomenal. So with this in mind I began to wonder why exactly this application was such a piece of shit.</summary><content type="html"><![CDATA[<p>Most people use it as their instant messaging program of choice and it is the most fully featured and frequently updated one out there at the moment, at least of all the main stream programs out there. Microsoft claim to receive 100 million unique connections through their messaging service per day, which is quite phenomenal. So with this in mind I began to wonder why exactly this application was such a piece of shit. To begin with it randomly drops out at various irritating intervals causing my chat windows to close! Perhaps you could ask me first? Making applications for the user does however seem beyond the grasp of Microsoft at this point; they are more concerned with releasing as much bloatware as possible.</p>
<p>If it were not for the fact that all my contacts are on MSN Messenger then I would be on the ever reliable Yahoo service right away for text instant messaging. Recently I had to delete all my contacts from the MSN contact list and re-add them, which was a very tedious task. All due to the fact that they cancelled my Hotmail account because I don’t use, but hey I was logging in with Messenger everyday! After re-instating the account all my MSN contacts returned, but half of them no longer came online. I stupidly assumed that they were busy, but looking on a friend’s machine I could see they were online. What a crock of shit! So I had to re-add all the contacts just to have them show up correctly.</p>
<p>And don’t come bitching to me about how its only freeware after all so what right do I have to complain! Every bloody right I am user of the software and as such my views are as valid as the next guy. Just because the application is free does not make it OK for the developer to neglect its users or receive criticism badly.</p>
<p>So if you can change away from MSN before you become trapped like me. It is highly likely you already are, I know your pain.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="internet" label="Internet"/><category scheme="taxonomy:Tags" term="rants" label="Rants"/></entry><entry xml:base="haiku-osopenbeos-an-open-source-beos-clone"><title type="html">Haiku OS/OpenBeOS - An open source BeOS clone</title><link href="https://www.simonholywell.com/post/2005/04/haiku-osopenbeos-an-open-source-beos-clone/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2004/10/mms2802-assignment-2/?utm_source=atom_feed" rel="related" type="text/html" title="MMS2802: Assignment 2"/><link href="https://www.simonholywell.com/post/2004/10/mms2402-dynamic-flash-web-gallery/?utm_source=atom_feed" rel="related" type="text/html" title="MMS2402: Dynamic Flash Web Gallery"/><link href="https://www.simonholywell.com/post/2004/09/mms2802-assignment-1/?utm_source=atom_feed" rel="related" type="text/html" title="MMS2802: Assignment 1"/><link href="https://www.simonholywell.com/post/2004/06/mms2801-assignment-3/?utm_source=atom_feed" rel="related" type="text/html" title="MMS2801: Assignment 3"/><link href="https://www.simonholywell.com/post/2004/05/mms2801-assignment-1-and-2/?utm_source=atom_feed" rel="related" type="text/html" title="MMS2801: Assignment 1 and 2"/><id>https://www.simonholywell.com/post/2005/04/haiku-osopenbeos-an-open-source-beos-clone/</id><author><name>Simon Holywell</name></author><published>2005-04-08T16:25:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Being reminded of my first encounter with the BeOS operating system by a housemate the other I thought I would take a look to see whatever happend to this great little multimedia OS. Whilst doing so I came across the OpenBeOS project that has since been renamed Haiku OS. Although its not a complete replica of BeOS R5 yet it is getting there and should come into its own when the new features are added after Haiku R1 (yet to be released).</summary><content type="html"><![CDATA[<p>Being reminded of my first encounter with the BeOS operating system by a housemate the other I thought I would take a look to see whatever happend to this great little multimedia OS. Whilst doing so I came across the OpenBeOS project that has since been renamed Haiku OS. Although its not a complete replica of BeOS R5 yet it is getting there and should come into its own when the new features are added after Haiku R1 (yet to be released). One of the main problems with BeOS was the lack of hardware support and not enough programs for the tasks that users wished to perform. A quick look at <a href="http://www.bebits.com">BeBits.com</a> told me that this was no longer the case and that there are infact quite a few good drivers and applications now available for this wonderful old operating system. It seems that at some point Be Inc. decided to stop production of the Be operating system and concentrate on their web technologies and that the BeOS source and licence was eventually purchased by Palm Inc. It now appears that a company in Germany called <a href="http://www.yellowtab.com/">YellowTab</a> (a reference to the yellow tabs in BeOS I am sure) has the source code for BeOS and have released a version called Zeta. Zeta is not however compatible with old BeOS drivers or software in some regards.</p>
<p>BeBits.com also has the last official release of <a href="http://www.bebits.com/app/2680">BeOS Personal R5</a> available. Developer edition link available below.</p>
<p><a href="http://haiku-os.org/">Haiku OS homepage.</a></p>
<p>Other links I came across while hunting for BeOS information: <a href="http://www.beosonline.de/">beosonline.de</a> – BeOS community with BeOS developer edition available for free download. <a href="http://www.bebug.be/">BeBug</a> – BeOS news (use the drop down box to change language) <a href="http://www.bedrivers.com/">BeOS Drivers</a> – Dedicated to drives for BeOS. <a href="http://www.beunited.org/">BeUnited.org</a> – Open Standards BeOS-compatible Operating Systems information. <a href="http://www.cosmoe.com/">Cosmoe</a> – It runs on Linux and has an API very similar to BeOS. <a href="http://www.mockup.org/">Mockup</a> – Pretty much as above.</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/></entry><entry xml:base="mms2802-assignment-2"><title type="html">MMS2802: Assignment 2</title><link href="https://www.simonholywell.com/post/2004/10/mms2802-assignment-2/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2004/10/mms2402-dynamic-flash-web-gallery/?utm_source=atom_feed" rel="related" type="text/html" title="MMS2402: Dynamic Flash Web Gallery"/><link href="https://www.simonholywell.com/post/2004/09/mms2802-assignment-1/?utm_source=atom_feed" rel="related" type="text/html" title="MMS2802: Assignment 1"/><link href="https://www.simonholywell.com/post/2004/06/mms2801-assignment-3/?utm_source=atom_feed" rel="related" type="text/html" title="MMS2801: Assignment 3"/><link href="https://www.simonholywell.com/post/2004/05/mms2801-assignment-1-and-2/?utm_source=atom_feed" rel="related" type="text/html" title="MMS2801: Assignment 1 and 2"/><link href="https://www.simonholywell.com/post/2003/10/mms1803-assignment-2-and-3/?utm_source=atom_feed" rel="related" type="text/html" title="MMS1803: Assignment 2 and 3"/><id>https://www.simonholywell.com/post/2004/10/mms2802-assignment-2/</id><author><name>Simon Holywell</name></author><published>2004-10-18T12:27:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Semester: 2
Group Work: No Mark: 94 A PHP forum with an Oracle backend.
ass2_mms2802.zip</summary><content type="html"><![CDATA[<p>Semester: 2<br>
Group Work: No Mark: 94 A PHP forum with an Oracle backend.</p>
<p><a href="/static/files/ass2_mms2802.zip">ass2_mms2802.zip</a></p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="uni" label="Uni"/></entry><entry xml:base="mms2402-dynamic-flash-web-gallery"><title type="html">MMS2402: Dynamic Flash Web Gallery</title><link href="https://www.simonholywell.com/post/2004/10/mms2402-dynamic-flash-web-gallery/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2004/09/mms2802-assignment-1/?utm_source=atom_feed" rel="related" type="text/html" title="MMS2802: Assignment 1"/><link href="https://www.simonholywell.com/post/2004/06/mms2801-assignment-3/?utm_source=atom_feed" rel="related" type="text/html" title="MMS2801: Assignment 3"/><link href="https://www.simonholywell.com/post/2004/05/mms2801-assignment-1-and-2/?utm_source=atom_feed" rel="related" type="text/html" title="MMS2801: Assignment 1 and 2"/><link href="https://www.simonholywell.com/post/2003/10/mms1803-assignment-2-and-3/?utm_source=atom_feed" rel="related" type="text/html" title="MMS1803: Assignment 2 and 3"/><link href="https://www.simonholywell.com/post/2003/09/mms1803-assignment-1/?utm_source=atom_feed" rel="related" type="text/html" title="MMS1803: Assignment 1"/><id>https://www.simonholywell.com/post/2004/10/mms2402-dynamic-flash-web-gallery/</id><author><name>Simon Holywell</name></author><published>2004-10-10T12:16:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Semester: 2
Group Work: No Mark: 80 A Flash image gallery that gets image data from a MySQL database. This web gallery was produced for the Universities web page. The interface colours and movement are entirely random through ActionScript.
Gallery demo site</summary><content type="html"><![CDATA[<p>Semester: 2<br>
Group Work: No Mark: 80 A Flash image gallery that gets image data from a MySQL database. This web gallery was produced for the Universities web page. The interface colours and movement are entirely random through ActionScript.</p>
<p><a href="http://gallery.simonholywell.com">Gallery demo site</a></p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="uni" label="Uni"/></entry><entry xml:base="mms2802-assignment-1"><title type="html">MMS2802: Assignment 1</title><link href="https://www.simonholywell.com/post/2004/09/mms2802-assignment-1/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2004/06/mms2801-assignment-3/?utm_source=atom_feed" rel="related" type="text/html" title="MMS2801: Assignment 3"/><link href="https://www.simonholywell.com/post/2004/05/mms2801-assignment-1-and-2/?utm_source=atom_feed" rel="related" type="text/html" title="MMS2801: Assignment 1 and 2"/><link href="https://www.simonholywell.com/post/2003/10/mms1803-assignment-2-and-3/?utm_source=atom_feed" rel="related" type="text/html" title="MMS1803: Assignment 2 and 3"/><link href="https://www.simonholywell.com/post/2003/09/mms1803-assignment-1/?utm_source=atom_feed" rel="related" type="text/html" title="MMS1803: Assignment 1"/><link href="https://www.simonholywell.com/post/2003/09/mms1408-database-driven-site/?utm_source=atom_feed" rel="related" type="text/html" title="MMS1408: Database Driven Site"/><id>https://www.simonholywell.com/post/2004/09/mms2802-assignment-1/</id><author><name>Simon Holywell</name></author><published>2004-09-14T12:25:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Semester: 2
Group Work: No Mark: 93 A Perl script for a simple forum providing threaded and unthreaded viewing styles of discussions from an Oracle database.
ass1_mms2802.zip</summary><content type="html"><![CDATA[<p>Semester: 2<br>
Group Work: No Mark: 93 A Perl script for a simple forum providing threaded and unthreaded viewing styles of discussions from an Oracle database.</p>
<p><a href="/static/files/ass1_mms2802.zip">ass1_mms2802.zip</a></p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="uni" label="Uni"/></entry><entry xml:base="mms2801-assignment-3"><title type="html">MMS2801: Assignment 3</title><link href="https://www.simonholywell.com/post/2004/06/mms2801-assignment-3/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2004/05/mms2801-assignment-1-and-2/?utm_source=atom_feed" rel="related" type="text/html" title="MMS2801: Assignment 1 and 2"/><link href="https://www.simonholywell.com/post/2003/10/mms1803-assignment-2-and-3/?utm_source=atom_feed" rel="related" type="text/html" title="MMS1803: Assignment 2 and 3"/><link href="https://www.simonholywell.com/post/2003/09/mms1803-assignment-1/?utm_source=atom_feed" rel="related" type="text/html" title="MMS1803: Assignment 1"/><link href="https://www.simonholywell.com/post/2003/09/mms1408-database-driven-site/?utm_source=atom_feed" rel="related" type="text/html" title="MMS1408: Database Driven Site"/><link href="https://www.simonholywell.com/post/2003/07/mms1408-weblog/?utm_source=atom_feed" rel="related" type="text/html" title="MMS1408: Weblog"/><id>https://www.simonholywell.com/post/2004/06/mms2801-assignment-3/</id><author><name>Simon Holywell</name></author><published>2004-06-03T12:22:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Semester: 1
Group Work: Yes Mark: 85 ColdFusion is used to connect to an Oracle database. ERD, DDS, schema and script files all included. This a sample traffic offence agency script.
ass3_mms2801.zip</summary><content type="html"><![CDATA[<p>Semester: 1<br>
Group Work: Yes Mark: 85 ColdFusion is used to connect to an Oracle database. ERD, DDS, schema and script files all included. This a sample traffic offence agency script.</p>
<p><a href="/static/files/ass3_mms2801.zip">ass3_mms2801.zip</a></p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="uni" label="Uni"/></entry><entry xml:base="mms2801-assignment-1-and-2"><title type="html">MMS2801: Assignment 1 and 2</title><link href="https://www.simonholywell.com/post/2004/05/mms2801-assignment-1-and-2/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2003/10/mms1803-assignment-2-and-3/?utm_source=atom_feed" rel="related" type="text/html" title="MMS1803: Assignment 2 and 3"/><link href="https://www.simonholywell.com/post/2003/09/mms1803-assignment-1/?utm_source=atom_feed" rel="related" type="text/html" title="MMS1803: Assignment 1"/><link href="https://www.simonholywell.com/post/2003/09/mms1408-database-driven-site/?utm_source=atom_feed" rel="related" type="text/html" title="MMS1408: Database Driven Site"/><link href="https://www.simonholywell.com/post/2003/07/mms1408-weblog/?utm_source=atom_feed" rel="related" type="text/html" title="MMS1408: Weblog"/><link href="https://www.simonholywell.com/post/2003/06/mms1402-djfigjam/?utm_source=atom_feed" rel="related" type="text/html" title="MMS1402: DJ.FIGJAM"/><id>https://www.simonholywell.com/post/2004/05/mms2801-assignment-1-and-2/</id><author><name>Simon Holywell</name></author><published>2004-05-12T12:19:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Semester: 1
Group Work: No Mark: 89 A complete ERD, DSD, schema and Oracle insert files are inlcuded for a sample Auto-Rentals company.
ar.zip</summary><content type="html"><![CDATA[<p>Semester: 1<br>
Group Work: No Mark: 89 A complete ERD, DSD, schema and Oracle insert files are inlcuded for a sample Auto-Rentals company.</p>
<p><a href="/static/files/ar.zip">ar.zip</a></p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="uni" label="Uni"/></entry><entry xml:base="mms1803-assignment-2-and-3"><title type="html">MMS1803: Assignment 2 and 3</title><link href="https://www.simonholywell.com/post/2003/10/mms1803-assignment-2-and-3/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2003/09/mms1803-assignment-1/?utm_source=atom_feed" rel="related" type="text/html" title="MMS1803: Assignment 1"/><link href="https://www.simonholywell.com/post/2003/09/mms1408-database-driven-site/?utm_source=atom_feed" rel="related" type="text/html" title="MMS1408: Database Driven Site"/><link href="https://www.simonholywell.com/post/2003/07/mms1408-weblog/?utm_source=atom_feed" rel="related" type="text/html" title="MMS1408: Weblog"/><link href="https://www.simonholywell.com/post/2003/06/mms1402-djfigjam/?utm_source=atom_feed" rel="related" type="text/html" title="MMS1402: DJ.FIGJAM"/><link href="https://www.simonholywell.com/post/2003/06/mms1802-assignment-3/?utm_source=atom_feed" rel="related" type="text/html" title="MMS1802: Assignment 3"/><id>https://www.simonholywell.com/post/2003/10/mms1803-assignment-2-and-3/</id><author><name>Simon Holywell</name></author><published>2003-10-21T00:13:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Semester: 2
Group Work: No Mark: 84 Demonstrates recursion and the use of a TreeMap. GUI menus and custom gridlayout also used. It also uses binary output to write and open the values the user enters to a flatfile database.
ass2_2.zip</summary><content type="html"><![CDATA[<p>Semester: 2<br>
Group Work: No Mark: 84 Demonstrates recursion and the use of a TreeMap. GUI menus and custom gridlayout also used. It also uses binary output to write and open the values the user enters to a flatfile database.</p>
<p><a href="/static/files/ass2_2.zip">ass2_2.zip</a></p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="uni" label="Uni"/></entry><entry xml:base="mms1803-assignment-1"><title type="html">MMS1803: Assignment 1</title><link href="https://www.simonholywell.com/post/2003/09/mms1803-assignment-1/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2003/09/mms1408-database-driven-site/?utm_source=atom_feed" rel="related" type="text/html" title="MMS1408: Database Driven Site"/><link href="https://www.simonholywell.com/post/2003/07/mms1408-weblog/?utm_source=atom_feed" rel="related" type="text/html" title="MMS1408: Weblog"/><link href="https://www.simonholywell.com/post/2003/06/mms1402-djfigjam/?utm_source=atom_feed" rel="related" type="text/html" title="MMS1402: DJ.FIGJAM"/><link href="https://www.simonholywell.com/post/2003/06/mms1802-assignment-3/?utm_source=atom_feed" rel="related" type="text/html" title="MMS1802: Assignment 3"/><link href="https://www.simonholywell.com/post/2003/05/mms1802-assignment-2/?utm_source=atom_feed" rel="related" type="text/html" title="MMS1802: Assignment 2"/><id>https://www.simonholywell.com/post/2003/09/mms1803-assignment-1/</id><author><name>Simon Holywell</name></author><published>2003-09-07T12:10:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Semester: 2
Group Work: No Mark: 81 A Java memory test game. It functions much like a card matching game.
ass1_2.zip</summary><content type="html"><![CDATA[<p>Semester: 2<br>
Group Work: No Mark: 81 A Java memory test game. It functions much like a card matching game.</p>
<p><a href="/static/files/ass1_2.zip">ass1_2.zip</a></p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="uni" label="Uni"/></entry><entry xml:base="mms1408-database-driven-site"><title type="html">MMS1408: Database Driven Site</title><link href="https://www.simonholywell.com/post/2003/09/mms1408-database-driven-site/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2003/07/mms1408-weblog/?utm_source=atom_feed" rel="related" type="text/html" title="MMS1408: Weblog"/><link href="https://www.simonholywell.com/post/2003/06/mms1402-djfigjam/?utm_source=atom_feed" rel="related" type="text/html" title="MMS1402: DJ.FIGJAM"/><link href="https://www.simonholywell.com/post/2003/06/mms1802-assignment-3/?utm_source=atom_feed" rel="related" type="text/html" title="MMS1802: Assignment 3"/><link href="https://www.simonholywell.com/post/2003/05/mms1802-assignment-2/?utm_source=atom_feed" rel="related" type="text/html" title="MMS1802: Assignment 2"/><link href="https://www.simonholywell.com/post/2003/04/mms1802-assignment-1/?utm_source=atom_feed" rel="related" type="text/html" title="MMS1802: Assignment 1"/><id>https://www.simonholywell.com/post/2003/09/mms1408-database-driven-site/</id><author><name>Simon Holywell</name></author><published>2003-09-04T09:02:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Semester: 2
Group Work: Yes Mark: 85 This is an html css php mysql website that is aimed at demonstrating the ability to make an ecommerce site.
Organics demo site - NO LONGER ONLINE :(</summary><content type="html"><![CDATA[<p>Semester: 2<br>
Group Work: Yes Mark: 85 This is an html css php mysql website that is aimed at demonstrating the ability to make an ecommerce site.</p>
<p>Organics demo site - NO LONGER ONLINE :(</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="uni" label="Uni"/></entry><entry xml:base="mms1408-weblog"><title type="html">MMS1408: Weblog</title><link href="https://www.simonholywell.com/post/2003/07/mms1408-weblog/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2003/06/mms1402-djfigjam/?utm_source=atom_feed" rel="related" type="text/html" title="MMS1402: DJ.FIGJAM"/><link href="https://www.simonholywell.com/post/2003/06/mms1802-assignment-3/?utm_source=atom_feed" rel="related" type="text/html" title="MMS1802: Assignment 3"/><link href="https://www.simonholywell.com/post/2003/05/mms1802-assignment-2/?utm_source=atom_feed" rel="related" type="text/html" title="MMS1802: Assignment 2"/><link href="https://www.simonholywell.com/post/2003/04/mms1802-assignment-1/?utm_source=atom_feed" rel="related" type="text/html" title="MMS1802: Assignment 1"/><link href="https://www.simonholywell.com/about-me/?utm_source=atom_feed" rel="related" type="text/html" title="About me"/><id>https://www.simonholywell.com/post/2003/07/mms1408-weblog/</id><author><name>Simon Holywell</name></author><published>2003-07-29T09:06:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Semester: 2
Group Work: No Mark: 89 A pretty nice assignment task if you ask me and I coded it all myself in PHP MySQL. It also has entries added frequently.
Blog demo site - NO LONGER ONLINE :(</summary><content type="html"><![CDATA[<p>Semester: 2<br>
Group Work: No Mark: 89 A pretty nice assignment task if you ask me and I coded it all myself in PHP MySQL. It also has entries added frequently.</p>
<p>Blog demo site - NO LONGER ONLINE :(</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="uni" label="Uni"/></entry><entry xml:base="mms1402-djfigjam"><title type="html">MMS1402: DJ.FIGJAM</title><link href="https://www.simonholywell.com/post/2003/06/mms1402-djfigjam/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2003/06/mms1802-assignment-3/?utm_source=atom_feed" rel="related" type="text/html" title="MMS1802: Assignment 3"/><link href="https://www.simonholywell.com/post/2003/05/mms1802-assignment-2/?utm_source=atom_feed" rel="related" type="text/html" title="MMS1802: Assignment 2"/><link href="https://www.simonholywell.com/post/2003/04/mms1802-assignment-1/?utm_source=atom_feed" rel="related" type="text/html" title="MMS1802: Assignment 1"/><link href="https://www.simonholywell.com/about-me/?utm_source=atom_feed" rel="related" type="text/html" title="About me"/><link href="https://www.simonholywell.com/projects/?utm_source=atom_feed" rel="related" type="text/html" title="Projects"/><id>https://www.simonholywell.com/post/2003/06/mms1402-djfigjam/</id><author><name>Simon Holywell</name></author><published>2003-06-05T08:58:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Semester: 1
Group Work: No Mark: 79 A Flash website demonstrating mixing sounds and my current Flash skills.
DJ FIGJAM demo site - NO LONGER ONLINE :(</summary><content type="html"><![CDATA[<p>Semester: 1<br>
Group Work: No Mark: 79 A Flash website demonstrating mixing sounds and my current Flash skills.</p>
<p>DJ FIGJAM demo site - NO LONGER ONLINE :(</p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="uni" label="Uni"/></entry><entry xml:base="mms1802-assignment-3"><title type="html">MMS1802: Assignment 3</title><link href="https://www.simonholywell.com/post/2003/06/mms1802-assignment-3/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2003/05/mms1802-assignment-2/?utm_source=atom_feed" rel="related" type="text/html" title="MMS1802: Assignment 2"/><link href="https://www.simonholywell.com/post/2003/04/mms1802-assignment-1/?utm_source=atom_feed" rel="related" type="text/html" title="MMS1802: Assignment 1"/><link href="https://www.simonholywell.com/about-me/?utm_source=atom_feed" rel="related" type="text/html" title="About me"/><link href="https://www.simonholywell.com/projects/?utm_source=atom_feed" rel="related" type="text/html" title="Projects"/><link href="https://www.simonholywell.com/unsubscribe-success/?utm_source=atom_feed" rel="related" type="text/html" title="Sorry to see you go"/><id>https://www.simonholywell.com/post/2003/06/mms1802-assignment-3/</id><author><name>Simon Holywell</name></author><published>2003-06-02T12:06:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Semester: 1
Group Work: No Mark: 82 This is a Java assignment completed for OOP1.
ass3.zip</summary><content type="html"><![CDATA[<p>Semester: 1<br>
Group Work: No Mark: 82 This is a Java assignment completed for OOP1.</p>
<p><a href="/static/files/ass3.zip">ass3.zip</a></p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="uni" label="Uni"/></entry><entry xml:base="mms1802-assignment-2"><title type="html">MMS1802: Assignment 2</title><link href="https://www.simonholywell.com/post/2003/05/mms1802-assignment-2/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/post/2003/04/mms1802-assignment-1/?utm_source=atom_feed" rel="related" type="text/html" title="MMS1802: Assignment 1"/><link href="https://www.simonholywell.com/about-me/?utm_source=atom_feed" rel="related" type="text/html" title="About me"/><link href="https://www.simonholywell.com/projects/?utm_source=atom_feed" rel="related" type="text/html" title="Projects"/><link href="https://www.simonholywell.com/unsubscribe-success/?utm_source=atom_feed" rel="related" type="text/html" title="Sorry to see you go"/><link href="https://www.simonholywell.com/subscribe-thank-you/?utm_source=atom_feed" rel="related" type="text/html" title="Thank you for subscribing"/><id>https://www.simonholywell.com/post/2003/05/mms1802-assignment-2/</id><author><name>Simon Holywell</name></author><published>2003-05-15T12:04:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Semester: 1
Group Work: No Mark: 76 A Java Applet that reads and writes to a flatfile database.
ass2.zip</summary><content type="html"><![CDATA[<p>Semester: 1<br>
Group Work: No Mark: 76 A Java Applet that reads and writes to a flatfile database.</p>
<p><a href="/static/files/ass2.zip">ass2.zip</a></p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="uni" label="Uni"/></entry><entry xml:base="mms1802-assignment-1"><title type="html">MMS1802: Assignment 1</title><link href="https://www.simonholywell.com/post/2003/04/mms1802-assignment-1/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://www.simonholywell.com/about-me/?utm_source=atom_feed" rel="related" type="text/html" title="About me"/><link href="https://www.simonholywell.com/projects/?utm_source=atom_feed" rel="related" type="text/html" title="Projects"/><link href="https://www.simonholywell.com/unsubscribe-success/?utm_source=atom_feed" rel="related" type="text/html" title="Sorry to see you go"/><link href="https://www.simonholywell.com/subscribe-thank-you/?utm_source=atom_feed" rel="related" type="text/html" title="Thank you for subscribing"/><id>https://www.simonholywell.com/post/2003/04/mms1802-assignment-1/</id><author><name>Simon Holywell</name></author><published>2003-04-11T11:59:00+00:00</published><updated>2024-11-19T12:47:01+10:00</updated><summary>Semester: 1
Group Work: No Mark: 80 A number guessing game. Written as a Java applet.
ass1.zip</summary><content type="html"><![CDATA[<p>Semester: 1<br>
Group Work: No Mark: 80 A number guessing game. Written as a Java applet.</p>
<p><a href="/static/files/ass1.zip">ass1.zip</a></p>
]]></content><category scheme="taxonomy:Categories" term="computing" label="Computing"/><category scheme="taxonomy:Tags" term="uni" label="Uni"/></entry></feed>