tag:blogger.com,1999:blog-11697656244679453872024-03-06T01:41:52.109+00:00Becoming JulieBecause I refuse to accept that 45/46 is a failureJuliehttp://www.blogger.com/profile/00911269487953748146noreply@blogger.comBlogger59125tag:blogger.com,1999:blog-1169765624467945387.post-28330833798756873672020-07-17T22:49:00.000+01:002020-07-17T22:49:32.558+01:00Multiplying on the 6502, but faster<div>There's a much faster way to do multiplication, and it all comes down to handling the business of adding up the shifted copies of the multiplicand.<br /></div><div>Let's look at 7 * 5 in binary again:<br /></div><pre>0 1 1 1 * 0 1 0 1
0 1 1 1
0 1 0 1 *
----------------<br />0 0 1 0 0 0 1 1<br /><br /> <br />0 0 0 0 0 1 0 1<br />0 1 1 1 ^ Add if 1<br />-------<br />0 1 1 1 0 1 0 1 -> shift right -> 0 0 1 1 1 0 1 0<br /><br />0 0 1 1 1 0 1 0<br />0 1 1 1 ^ Don't add if 0<br />-------<br />0 0 1 1 1 0 1 0 -> shift right -> 0 0 0 1 1 1 0 1<br /><br />0 0 0 1 1 1 0 1<br />0 1 1 1 ^ Add if 1<br />-------<br />1 0 0 0 1 1 0 1 -> shift right -> 0 1 0 0 0 1 1 0<br /><br />0 1 0 0 0 1 1 0<br />0 1 1 1 ^ Don't add if 0<br />-------<br />0 1 0 0 0 1 1 0 -> shift right -> 0 0 1 0 0 0 1 1<br />
</pre><div>
Here we begin with zeros in the high bits of the product register, and a copy of the multiplier in the low bits of the product register. Our model is only using 4 bit words, but of course the real 6502 uses 8 bits.<br /></div><div><br /></div><div>We loop for as many times as there are bits in the multiplier.</div><div><br /></div><div>Each time around the loop, we examine the lowest bit of the product (which will actually be a bit from the multiplier; the units the first time around, the twos the second time around, and so forth).</div><div><br /></div><div>If the lowest bit is a 1, we add the multiplicand to the high bits of the product.</div><div><br /></div><div>Whether or not we performed an addition, we shift the product one bit to the right; discarding a bit from the multiplier.</div><div><br /></div><div>After we are done going round the loop, we have the product in its rightful place.</div><div><br /></div>
<div>This works because we have shifted the product a whole word to the right, so the units bit of the product is aligned to the units bit of a word in memory. The copy of the multiplicand we might have added depending on the units bit of the multiplier has been shifted all the way down to the units position. The copy that we might have added depending on the twos bit of the multiplier has been shifted right one time fewer, down to the twos position, and so forth.<br /></div><div><br /></div><div>Here is the process (assuming 8 bit multiplicand and multiplier and 16 bit product; but it can easily be extended) in pseudocode:</div>
<div><br /></div>
<pre>Begin with the multiplier in the bottom 8 bits of the product
Do the following 8 times:
If bit 0 of the product is 1 then:
Add the multiplicand to the top 8 bits of the product
In any case:
Shift the whole 16-bit product right</pre>
<div>And here it is in 6502 assembly language!<br /></div>
<pre>.multiply \ Expects multiplier in product
TYA \ stash Y register on the stack
PHA
LDY #8 \ loop counter
LDA #0 \ initialise product
STA product+1
.mult_1
LDA product
AND #1 \ examine bit from multiplier
BEQ mult_2 \ skip adding if zero
CLC
LDA product+1
ADC multiplicand \ if this sets a carry, it will just
STA product+1 \ get shifted into the product <br />.mult_2 \ shift whole product one bit right<br />ROR product+1 \ bring in carry from addition
ROR product \ discard used bit
DEY \ decrease counter
BNE mult_1
PLA
TAY \ restore Y
RTS<br />.product<br />EQUW 0<br />.multiplicand<br />EQUB 0 <br /></pre>
<div><br /></div><div>It's faster than my earlier idea because the addition is restricted to just the width of the multiplicand, not the full width of the product. <br /></div><br />Juliehttp://www.blogger.com/profile/00911269487953748146noreply@blogger.com2tag:blogger.com,1999:blog-1169765624467945387.post-36683343969114231912020-07-16T23:12:00.000+01:002020-07-16T23:12:42.584+01:00Creating "universal" .deb packages<div>This is a way to create a "universal" .deb package suitable for installing on Debian, Ubuntu and similar distributions such as Linux Mint; and on any machine architecture (64-bit, 32-bit, even Raspberry Pi).</div><div><br /></div><div>The package actually installs the source files under /usr/src/ and performs the compilation and installation of the actual binary in the post-installation phase. The package manager will make sure all dependencies are installed <i>before</i> running the post-install script. As long as all dependencies are correctly specified (remember, if you need libfoo to run something, you will also need libfoo-dev to build it) then the overall effect will be exactly the same as if they had installed a pre-compiled binary package; but you only have to .deb-ify it once, and you won't be expecting random strangers to install unknown binaries on their systems.</div>
<br />
We are going to create a package called "wibble", which will contain this simple program:<br />
<br />
<span style="font-size: x-small;"><span style="font-family: "courier new", "courier", monospace;">#include <stdio.h></span></span><br />
<span style="font-size: x-small;"><span style="font-family: "courier new", "courier", monospace;">int main() {</span></span><br />
<span style="font-size: x-small;"><span style="font-family: "courier new", "courier", monospace;"> printf("Wibble\n");</span></span><br />
<span style="font-size: x-small;"><span style="font-family: "courier new", "courier", monospace;"> return 0;</span></span><br />
<span style="font-size: x-small;"><span style="font-family: "courier new", "courier", monospace;">};</span></span><br />
<br /><div>
All it does is display "Wibble", but the same principles obviously are applicable to anything more ambitious.</div><span><a name='more'></a></span>
<div><p style="text-align: left;"><br /></p><h2 style="text-align: left;">Building It</h2></div><div></div>
Open a terminal window, create a folder and navigate to it.<br />
<br />
Our package is going to be called "wibble", version 1.0-0 and it will be suitable for all architectures. So the canonical package name would be wibble_1.0-0_all. Make a folder to contain the files that will go into the package, and a skeleton folder structure beneath this:<br />
<br />
<span style="font-size: x-small;"><span style="font-family: "courier new", "courier", monospace;">$ mkdir wibble_1.0-0_all</span></span><br />
<span style="font-size: x-small;"><span style="font-family: "courier new", "courier", monospace;">$ cd wibble_1.0-0_all </span></span><br />
<span style="font-size: x-small;"><span style="font-family: "courier new", "courier", monospace;">$ mkdir usr</span></span><br />
<span style="font-size: x-small;"><span style="font-family: "courier new", "courier", monospace;">$ mkdir usr/share</span></span><br />
<span style="font-size: x-small;"><span style="font-family: "courier new", "courier", monospace;">$ mkdir usr/share/doc</span></span><br />
<span style="font-size: x-small;"><span style="font-family: "courier new", "courier", monospace;">$ mkdir usr/share/doc/wibble</span></span><br />
<span style="font-size: x-small;"><span style="font-family: "courier new", "courier", monospace;">$ mkdir usr/src</span></span><br />
<span style="font-size: x-small;"><span style="font-family: "courier new", "courier", monospace;">$ mkdir usr/src/wibble</span></span><br />
<span style="font-size: x-small;"><span style="font-family: "courier new", "courier", monospace;">$ mkdir DEBIAN</span></span><br />
<div><br /></div><div>Everything but the DEBIAN folder will be unpacked under the root directory. The DEBIAN folder contains a control file, and some scripts which will be run by the package manager at various stages of the installation and removal processes.</div><div><br /></div>
Now we will create some files to go in those folders, as follows:<br /><h3 style="text-align: left;">
usr/share/doc/wibble/COPYING</h3>
<span style="font-size: x-small;"><span style="font-family: "courier new", "courier", monospace;">NO RIGHTS RESERVED. THIS CODE IS DEDICATED TO THE PUBLIC DOMAIN.</span></span><br />
<span style="font-size: x-small;"><span style="font-family: "courier new", "courier", monospace;"><br /></span></span>
<span style="font-size: x-small;"><span style="font-family: "courier new", "courier", monospace;">YOU MAY USE IT, ABUSE IT, ENJOY IT, DESTROY IT, STUDY IT, SHARE IT AND</span></span><br />
<span style="font-size: x-small;"><span style="font-family: "courier new", "courier", monospace;">ADAPT IT WITHOUT RESTRICTION.</span></span><br />
<br /><h3>
usr/share/doc/wibble/README.jm</h3>
<span style="font-size: x-small;"><span style="font-family: "courier new", "courier", monospace;">This package is not quite as simple as it looks.</span></span><br />
<br />
(/usr/share/doc/wibble/ is where a package's information files conventionally reside -- READMEs, changelogs and so forth, perhaps even an "examples" subfolder.)<br />
<br /><h3 style="text-align: left;">
usr/src/wibble/wibble.c<br /></h3>
<span style="font-size: x-small;"><span style="font-family: "courier new", "courier", monospace;">#include <stdio.h></span></span><br />
<span style="font-size: x-small;"><span style="font-family: "courier new", "courier", monospace;">int main() {</span></span><br />
<span style="font-size: x-small;"><span style="font-family: "courier new", "courier", monospace;"> printf("Wibble\n");</span></span><br />
<span style="font-size: x-small;"><span style="font-family: "courier new", "courier", monospace;"> return 0;</span></span><br />
<span style="font-size: x-small;"><span style="font-family: "courier new", "courier", monospace;">};</span></span><br />
<br /><h3>
DEBIAN/control</h3>
<span style="font-size: x-small;"><span style="font-family: "courier new", "courier", monospace;">Package: wibble<br />Version: 1.0-1<br />Section: base<br />Priority: optional<br />Architecture: all<br />Depends: build-essential<br />Maintainer: Julie Montoya <bluerizlagirl@gmail.com><br />Description: Wibble demo<br /> A simple demo that does not do very much, except prove it is possible<br /> to do what it does.</span></span><br />
<br />
This
file tells the package manager about the package. Note the Depends:
line. Use this to specify any dependencies (and don't forget the -dev
packages, since you are going to be building stuff). The package build-essential is actually a metapackage; that is to say, it does not contain any files of its own except a documentation folder, but crucially it depends on a bunch of other packages, so you can force them all to install in one fell swoop. Note also that
continuation lines of the description begin with a space.<br />
<br />
This is all well and good, but all this will do is unpack the source "tree" (here, just one little file) into a folder under /usr/src/ . We still need to build the code. Fortunately, the Debian package format allows for us to do some finishing-off after the installation is completed, and again just before removal commences, by means of scripts which, if they exist within the package, will automatically be run at certain stages.<br />
<br /><h3>
DEBIAN/postinst</h3>
<span style="font-size: x-small;"><span style="font-family: "courier new", "courier", monospace;">#!/bin/sh<br /><br />############################## POSTINST script ##############################<br /><br /># By the time this runs, dpkg will already have unpacked the Source Code</span></span><br />
<span style="font-size: x-small;"><span style="font-family: "courier new", "courier", monospace;"># under /usr/src/ -- this is where we build and install it.<br />#<br /># This may be as simple as ./configure && make install but probably isn't<br /><br /><br />OLD_FOLDER=$(pwd)<br /><br />cd /usr/src/wibble/<br />gcc -owibble wibble.c<br />install -c wibble /usr/bin/<br /><br />cd $OLD_FOLDER<br /><br /><br />exit</span></span><br />
<div><br /></div><div>This script runs after all the files that make up the package have been installed to their proper locations, and all dependencies have been installed. So now we just have to build our Source Code, and install the binary we have just created to its intended location.<br /></div><div><br /></div>
With this simple bit of code, we don't need to use make. But a more complex project probably will use a configure script and makefile. You also will need to remember to pass appropriate options to configure to persuade it to use /usr/bin/ , /usr/lib/ , /etc/ and /usr/share/as opposed to /usr/local/wherever -- you are building a system package, and are <i>allowed</i> -- indeed, encouraged -- to step in those places. The package manager has an idea of what it has done for itself and how to undo it. We have to take care of anything the package manager does not know we have done. For this, we need the following script:<br />
<br /><h3 style="text-align: left;">
DEBIAN/prerm<br /></h3>
<span style="font-size: x-small;"><span style="font-family: "courier new", "courier", monospace;">#!/bin/sh<br /><br />################################ PRERM script ################################<br /><br /># We need to remove any files we created during installation that were<br /># not on the manifest, so folders to be removed are empty.<br />#<br /># NB, this includes the actual executables we installed!<br /># This may be as simple as make uninstall && make clean but probably isn't<br /><br />if [ -e /usr/src/wibble/wibble ]<br />then<br /> rm -f /usr/src/wibble/wibble<br />fi<br /><br />if [ -e /usr/bin/wibble ]<br />then<br /> rm -f /usr/bin/wibble<br />fi<br /><br />exit</span></span><br />
<br /><div>
This is a script that runs before the files installed during installation are removed. The package manager will only remove files that were on the
original manifest, and will complain if a folder it wants to remove is
not empty (as might be the case if some sort of upgrade had been done
outside of dpkg). So this is where we can remove the files we created (not
forgetting the actual binary!)</div><div><br /></div><div>With a real package with a Makefile, you probably will be able to run make uninstall to remove the binaries and make clean to get rid of all extraneous files.<br /></div>
<br />
Set permissions on the scripts:<br />
<br />
<span style="font-size: x-small;"><span style="font-family: "courier new", "courier", monospace;">$ chmod 775 DEBIAN/prerm DEBIAN/postinst</span></span><br />
<br />
And build the package:<br />
<span style="font-family: "courier new", "courier", monospace;"><br />
<font size="2">$ dpkg-deb -b wibble_1.0-0_all</font></span><br />
<br />
If all goes well, you will end up with a .deb package! You can inspect this with various GUI and command-line tools and see the individual files inside it, if you like.<br /><h2 style="text-align: left;">Testing It</h2>
You can test the package by just running the DEBIAN/postinst script. The final installation will fail for want of write permission, but if it gets that far then the build was successful.<br />
<br />
The next test will be to install it with dpkg:<br />
<br />
<font size="2"><span style="font-family: "courier new", "courier", monospace;">$ sudo dpkg -i wibble_1.0-0_all.deb</span></font><br />
<br />
Now remove it, to make sure that works too:<br />
<br />
<font size="2"><span style="font-family: "courier new", "courier", monospace;">$ sudo dpkg -r wibble</span></font><br />
<br />
But what you have not tested yet is the dependencies. To do this properly, you will need a pristine system with only a bare minimum of packages installed -- probably the second-best way to get one, if you can't just fire up a brand new virtual machine ;) , is just to boot up a live Ubuntu system from a USB drive. This should let you install packages from an Internet repository using apt-get. Or if you have a spare Raspberry Pi, you can even burn a fresh SD card image and use that (which will also prove it really is packaged for all architectures).<br />
<br />
If it works, well done! Otherwise, make a note of any dependencies you missed, and add them to the DEBIAN/control file. Your test environment need not be reinstalled from scratch, as long as you are sure you did not remove anything from the list of dependencies (though if the test environment is just your main laptop booted from USB, that can't really be helped).<br />
<br />
<br />
Note it's also entirely possible to install a package with no files at all except DEBIAN/control . You might think that is not much use, but you can specify a whole bunch of packages in Depends: which will be installed automatically. You can use this to install the same software packages (possibly even from a local repository) on a bunch of machines together. <br />Juliehttp://www.blogger.com/profile/00911269487953748146noreply@blogger.com0tag:blogger.com,1999:blog-1169765624467945387.post-74349781454404146112019-04-09T22:59:00.001+01:002019-04-09T23:13:08.968+01:00Multiplying on the 6502The 6502 does not have a hardware multiply instruction, so we need to write us a multiply routine in software. Here we need to multiply an 8-bit value by an 8-bit value giving a 16-bit product, but the principle can be extended up to a 256-bit multiplicand, 256-bit multiplier and 512-bit product.<br />
<br />
Multiplication in binary is exactly the same as the decimal multiplication you learned in primary school, but using only ones and zeros. For instance, here is how we would perform 7 * 5 in binary:<br />
<br />
<pre>0 1 1 1 * 0 1 0 1
0 1 1 1
0 1 0 1 *
-------------------
0 1 1 1 (from the 1 in the units position)
0 1 1 1 0 0 (from the 1 in the fours position)
-------------------
1 1 1 (carry between bits)
0 0 1 0 0 0 1 1
===================</pre>
<br />
We look at the multiplier, working from right to left. If there is a 0 at that bit, we do nothing. If there is a 1, we write down a copy of the multiplicand, lining its units digit up with the multiplier digit in question. When we have all our partial product rows, we just add them up to get our final answer. (In practice, we will keep adding as we go along.)<br />
<br />
The 6502 has bit-shifting instructions ROL and ROR, which shift the accumulator or addressed memory location left or right respectively; importing the previous value of the carry flag onto one end as a new digit, and catching the bit that falls out the other end in the carry flag. There are also ASL and LSR instructions, which do the same but clear the carry flag first so the newly-imported bit will always be zero. Typically you would use LSR on the high byte and ROR on the lower bytes in turn, or ASL on the low byte and ROL on the higher bytes in turn; but if you wish to import a one, you could do SEC followed by ROL or ROR.<br />
<br />
The code:<br />
<pre>.mult8
TXA \ we are going to stomp on X
PHA
LDA #0
STA mulA+1 \ extend A register to 16 bits
STA product \ zero product register
STA product+1
LDX #8 \ 8 bits
.mult8_1 \ BEGINNING OF LOOP
LSR mulB \ shift B right
BCC mult8_2 \ if 0 fell out, skip all this
LDA mulB \ set the high bit of B, so we regenerate
ORA #128 \ the original value after eight shifts
STA mulB \
LDA product \ add shifted-A to the product
CLC
ADC mulA
STA product
LDA product+1 \ now the high byte
ADC mulA+1
STA product+1
.mult8_2 \ paths merge again
ASL mulA \ shift A left
ROL mulA+1
DEX
BNE mult8_1 \ move on to the next bit
LDA mulA+1 \ effectively, shift A right 8 places
STA mulA
PLA
TAX \ restore X
RTS \ ..... and we're outta here</pre>
<pre> </pre>
<pre>.mulA EQUD 0 \ reserve 32 bits, in case we need a 16-bit multiply
.mulB EQUW 0 \ reserve 16 bits
.product EQUD 0 \ reserve 32 bits
</pre>
We begin by transferring the X register into the accumulator and pushing it onto the stack, so we can retrieve it later. Then we zero out the byte immediately after A, so we have a clean 16-bit workspace with an 8-bit value at the bottom end, along which we can shift A; and the two bytes to hold the product. The last step of the initialisation phase is to load the X register with 8 (the number of times we are going to go round).<br />
<br />
Each time around the loop, we shift B to the right each time; the rightmost bit will fall off the end and be caught in the carry flag. We can then use a BCC instruction to skip right over the addition if the bit that fell out was a 0. If it was a 1, we first set the high bit of B -- which will have the effect of regenerating the original value after 8 shifts -- and then add A (suitably shifted to line up with the original bit position out of B that was a 1) to the product. We know that the carry flag is set, but can't make use of this as we are not adding a constant. (Otherwise, we could add one less than what we wanted to add, and save a byte and two cycles clearing the carry.)<br />
<br />
Whatever bit shifted out of B, we eventually arrive at the same point. We shift A left 1 bit and decrease X. If the result is not zero, we go around the loop again.<br />
<br />
After eight rounds, A has been shifted left 8 bits; and thanks to our setting the high bit whenever the low bit was 1, B is exactly as it originally was. We copy A back to where it started out, pull the value we pushed earlier from the stack, transfer it back to X and return whence we came.<br />
<br />
Note, I have purposely reserved double the required space for A, B and the
product; on the basis that the same workspace could be used by both an
8-bit and a 16-bit multiply subroutine, and/or a generic, any-length multiply. Juliehttp://www.blogger.com/profile/00911269487953748146noreply@blogger.com0tag:blogger.com,1999:blog-1169765624467945387.post-2622056926440128652019-03-16T10:07:00.000+00:002019-03-16T10:10:16.324+00:00A Retro Programming ProjectSo I saw a post on a forum somewhere, awhile ago, and it set a train of thought in motion. Which has led me to take on a programming project. I can't reveal too many of the details here, in case the original poster is reading this and twigs to what I am doing. But, the hardware platform is the <a href="https://en.wikipedia.org/wiki/BBC_Micro" rel="nofollow" target="_blank">BBC Micro</a>, a popular 8-bit machine in the 1980s, and the project -- described in its most abstract terms -- consists of a relational database with three main tables; a visual editor; and a report generator.<br />
<br />
One of the tables will be populated by some external means (because I can't be bothered to design a visual editor for it right now) by translating an input file from a standard format. Another will be fairly static, and will govern the visual representations of items that may be described in the input table. The third table will store the user's creative input which, in accordance with rules defined in the first table, govern the arrangement and interactions of items which are represented visually according to the second table.<br />
<br />
(Don't worry if you don't understand any of that. It will probably get a bit more obvious.)<br />
<br />
Rather than get an actual BBC Micro at this stage, and have to put up with slow cassette and disc loading times and possibly replace the machine if I can't fit it into the model B into which I was initially determined to shoehorn it, have to get a Master 128 instead and get into a last-minute bidding war, I've decided to use an emulator. In this case, the excellent <a href="https://muffinresearch.co.uk/ubuntu-installing-the-beebem-bbc-micro-emulator/" rel="nofollow" target="_blank">BeebEm</a> (instructions given for Ubuntu; but as a build-from-source, the second half should work on anything once you have the relevant packages <i>and their -dev or -devel companions</i> -- yes, you are a developer.)<br />
<br />
Of course, it helps that I grew up with a BBC Model B and know enough BASIC and 6502 assembly language to get the job done. I've also got a slight advantage as my visual editing isn't going to require fast-moving multi-coloured sprites or anything else that cannot be rendered using universally-acceptable OS calls. It can all be made completely out of the lines and triangles (yes, 32KB of ROM and the most complicated shape a Model B can draw is a triangle) that the operating system can already produce. I'd get no benefit out of hitting the display memory directly; it's not as though I could write a faster triangle-drawing routine than Sophie Wilson and Steve Furber already did. So by keeping to "legal moves", if I can't fit it into a 32K B, I can retarget it seamlessly at the 128.<br />
<br />
First off, I'm going to start with the visualisation, because that will give me some important clues for structuring the data in Table Two. Juliehttp://www.blogger.com/profile/00911269487953748146noreply@blogger.com0tag:blogger.com,1999:blog-1169765624467945387.post-72808847028800013682018-08-21T19:43:00.001+01:002018-08-21T20:30:33.302+01:00Eid-ul-Adha: Celebrating an ObscenityToday is the Muslim feast of Eid-ul-Adha. This celebrates an event in both the Jewish / Christian and Islamic mythologies. You can read it in <a href="http://skepticsannotatedbible.com/gen/22.html">Genesis 22</a> or <a href="http://skepticsannotatedbible.com/quran/37/#100">Surah 37</a>. It's not for the squeamish.<br />
<br />
Basically, God told Abraham (or Ibrahim) to sacrifice his son Isaac (or Ishmael), to prove he loved God more than even his own family.<br />
<br />
So 'Bram told God in no uncertain terms to fuck off, and spent the rest of his days as a happy humanist, right?<br />
<a name='more'></a><br />
No, he actually went along with the whole sick show. It was only at the fifty-ninth second of the fifty-ninth minute of the twenty-third hour, when the blade of Abraham's knife was mere millimetres from the terrified Isaac's throat, that an angel appeared; and told Abraham that actually, God was satisfied that Abraham loved him after all, and he could spare Isaac's life.<br />
<br />
This is just wrong on so many levels.<br />
<br />
For a start, if somebody asks you to do something that you know is wrong, <i>you don't do it</i>, irrespective who that somebody is. Even deities are not exempt.<br />
<br />
For another thing, what kind of love is Abraham / Ibrahim even supposed to be demonstrating anyway? What kind of love can there even be for a vicious bastard who wants you to murder a member of your own family? Doing what you are asked, no matter how terrible, out of some misguided fear of adverse consequences? Bollocks is that love. What could God even have done to Abraham anyway, that would have been worse than losing his son?<br />
<b><br /></b>
<b>Obedience is not a virtue.</b> We can make machines that do exactly what they are told to do -- in fact, they can't do anything else -- and even that is not always a good thing. If you were to open a terminal window on your computer and type<br />
<code> $ sudo shutdown -h now</code><br />
it would do exactly what you told it; even although that almost certainly is not what you want, and in fact you probably would prefer the computer to exercise its power of insubordination if it had one.<br />
<br />
To me, this whole story is just further confirmation that the God of the Bible and the Qur'an is the villain. <br />
<br />
<i>(Note: The original command has been replaced with something that would be more benign, if anyone actually did type it into a real computer.)</i>Juliehttp://www.blogger.com/profile/00911269487953748146noreply@blogger.com1tag:blogger.com,1999:blog-1169765624467945387.post-83175759474538657722017-04-18T22:11:00.001+01:002017-04-18T22:11:58.066+01:00This year, I will definitely remember my mother's birthdayThis year, I will definitely remember my mother's birthday. For she was born on the 8 June, one year I am not allowed to mention.<br />
<br />
That is also the last day anything is going to make sense, ever.<br />
<br />
<a name='more'></a><br />
Theresa May has called a General Election on that date. Obviously I won't be touching my slice of cake till <i>after</i> I have been to the polls, but I know more or less what I expect to happen. The vote -- among those who can be bothered, after the Scottish Independence Referendum, the 2015 General Election, the Brexit referendum and the Local Elections in May -- is going to be split between Labour (<i>only we can beat the Tories</i>), the Lib Dems (<i>only we can reverse Article 50 and restore our place at the EU table</i>) and the Greens (<i>what the hell, may as well, they can't be as bad as any of the others</i>), against which the Conservatives will romp comfortably home to victory. The remainder of the EU will almost certainly seek to impose some sort of punitive trade tariffs, as a warning to anybody else thinking of leaving; and our former trading partners elsewhere in the world, who were taking advantage of our easy trade links with Europe, might well revise their own tariffs.<br />
<br />
This country will be asset-stripped, and the carcass left to rot.Juliehttp://www.blogger.com/profile/00911269487953748146noreply@blogger.com1tag:blogger.com,1999:blog-1169765624467945387.post-39094189367741981112016-10-27T22:03:00.001+01:002016-10-27T22:08:11.441+01:00Ransomware (no, not that sort)Yes, there is malicious software out there that encrypts files on your computer and directs you to a web page where, for a fee, you can buy the decryption key. Or just restore from a recent backup (you do make backups, right?) But that's not what I'm here to talk about tonight.<br />
<br />
Closed-source software vendors are holding their customers to ransom. If you don't buy the latest version of their products, you won't be able to read anyone else's documents if they have upgraded to the latest version. But what is especially galling is where electronically-identical hardware appliances have features enabled or disabled purely by software.<br />
<br />
<a name='more'></a>Imagine it's the early days of colour TV broadcasting, and a TV shop is selling two similar sets; they have the same size CRTs, but one is monochrome and the other is (a) colour and (b) twice the price. Now of course you want a colour set, to take advantage of the new broadcasts. Then your neighbour comes into the shop and buys one of the mono sets. This finally convinces you to pay the extra for the colour set.<br />
<br />
A few days later, you pop round to visit your neighbour. And you have a look at their telly. It looks a lot like yours -- except it's mono. Your neighbour returns from the kitchen. <i>Would you like to have a look inside?</i> And so they pop the back off, for you to appreciate the works.<br />
<br />
Inside it is a full colour set. Colour decoder, delay line, the full Monty. But it has been modified by adding just two short wire links, shorting together the drives to the red, green and blue electron guns; so that whichever one is trying to turn its own beam on, ends up turning on all three together, producing white light.<br />
<br />
The manufacturers can obviously turn a profit selling the sets at the lower price. And yet, for no reason save greed and meanness of spirit, they deliberately introduce a fault so that sell perfectly-functioning sets at a premium.<br />
<br />
This is exactly what often happens with proprietary software-driven devices. All the bits are present in a cheap one, that would be required to do the job of a more expensive one; yet the software has been told not to allow them to do it. Only, the manufacturers' vandalism in this case is rather less obvious than just a few extra bits of wire soldered in.<br />
<br />
We are being held to ransom. And now the mindset that believes this behaviour to be acceptable has, unfortunately, become ingrained in our politicians, things seem unlikely to change in the immediate future.<br />
<br />
Only true hackers can save us now.Juliehttp://www.blogger.com/profile/00911269487953748146noreply@blogger.com0tag:blogger.com,1999:blog-1169765624467945387.post-57222710839927330322016-06-18T08:22:00.001+01:002016-06-18T08:23:53.169+01:00What I Wore #1I wore an outfit for work yesterday that just made me feel enormously sexy! This is me trying to strike a provocative pose over the pool table:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgvqes6DerP75dzL7BzALxVrA13IZ4zak4kExeNX_BPAOdgdzFOAFXD30FMdUVgax7n_rGSyO7RDfk184isQu1RWD7MswAxrT7HdPdopfV8EvCGxnCDfztySJKuqxukom2-Zvme-4fYyBLB/s1600/20160617_130917.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgvqes6DerP75dzL7BzALxVrA13IZ4zak4kExeNX_BPAOdgdzFOAFXD30FMdUVgax7n_rGSyO7RDfk184isQu1RWD7MswAxrT7HdPdopfV8EvCGxnCDfztySJKuqxukom2-Zvme-4fYyBLB/s320/20160617_130917.jpg" width="180" /></a></div>
<br />
I have decided, I am going to take full advantage of the relaxed Friday dress code to explore sexy ...... <br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
Juliehttp://www.blogger.com/profile/00911269487953748146noreply@blogger.com0tag:blogger.com,1999:blog-1169765624467945387.post-47772249129387460502016-05-13T00:28:00.001+01:002016-05-13T00:28:54.724+01:00Why would you Pay More and Get Less?Open Source software comes with the freedom to inspect its internals and make modifications, the better to suit the way you work.<br />
<br />
Proprietary software usually does not include such freedoms -- and usually has to be paid for.<br />
<br />
So, serious question: Why would anyone choose to pay good money for Proprietary software, when Open Source alternatives are available on so much more favourable terms?Juliehttp://www.blogger.com/profile/00911269487953748146noreply@blogger.com0tag:blogger.com,1999:blog-1169765624467945387.post-7548240886275083772015-08-05T08:24:00.003+01:002015-08-05T08:29:36.990+01:00The Great Taxi Rip-OffLast night I travelled in a taxi. Among the table of fares was the following:<br />
<blockquote class="tr_bq">
First mile £3.00<br />
Each subsequent 146 yards £0.10</blockquote>
I asked the driver how many yards were in a mile (which I think is not an unreasonable question: if it's on the sign in his cab, he ought to know), and he did not know. Therefore, there is a meaningless disconnect between the figures: If I don't know how many yards there are in a mile, then I can't know how many 146-yard units there are in a mile, and therefore I can't work out how much I should be paying.<br />
<br />
Now, if it had read something like<br />
<blockquote class="tr_bq">
First kilometre £2.00<br />
Each subsequent 100 metres £0.10</blockquote>
then the correlation between distance travelled and amount paid would have been nice and obvious. Because there's a clue right in the name that tells you exactly how many metres are in a kilometre. Even if it was something like "Each subsequent 114.3 metres £0.10", the sum would still be possible -- though I might need a calculator, if needed better precision than "about 9p for 100 metres".<br />
<br />
I am convinced that this is another example of rip-off Britain, if we are actively prevented from working out independently how much we should be paying for a journey and instead have to trust the meter.Juliehttp://www.blogger.com/profile/00911269487953748146noreply@blogger.com0tag:blogger.com,1999:blog-1169765624467945387.post-53802766376319359342015-07-22T23:37:00.000+01:002015-07-22T23:39:13.684+01:00This time, it even looks like Perl!I <a href="http://becomingjulie.blogspot.co.uk/2015/07/raspberry-pi-flavoured-shenanigans.html" rel="nofollow" target="_blank">said before</a> that my first attempt to get controlling the Raspberry Pi's GPIO pins from Perl looked ugly. This time, I've added some methods to my JKLMwiringPi package, in an attempt to make the program look more like Perl.<br />
<br />
<a name='more'></a><br />
<pre>#!/usr/bin/perl -w
use strict;
package JKLMwiringPi;
use strict;
use Inline C => Config =>
ENABLE => AUTOWRAP =>
LIBS => "-lwiringPi ";
use Inline C => <<"--END-C--";
int wiringPiSetup() ;
void pinMode(int pin, int mode) ;
int digitalRead(int pin) ;
void digitalWrite(int pin, int value) ;
void delay(unsigned int howLong);
--END-C--
sub setup {
my $proto = shift; # MAGIC - DO NOT TRY TO UNDERSTAND THIS
my $class = ref($proto) || $proto; # MAGIC - DO NOT TRY TO UNDERSTAND THIS
my $self = undef;
my $success = wiringPiSetup;
if ($success >= 0) {
$self = {"success" => $success};
bless $self, $class; # MAGIC - DO NOT TRY TO UNDERSTAND THIS
return $self;
};
return undef;
};
sub pin_mode {
my $self = shift;
return undef unless $self;
my ($pin, $mode, $mode1);
while (@_ > 1) {
$pin = shift;
$mode = shift;
$mode1 = 0;
if ($mode =~ /[1oO]/) {
$mode1 = 1;
};
pinMode $pin + 0, $mode1;
};
return $self;
};
sub ms_delay {
my $self = shift;
return undef unless $self;
my $ms = shift;
delay $ms + 0;
return $self;
};
sub digital_read {
my $self = shift;
return undef unless $self;
my @ans = ();
foreach (@_) {
push @ans, digitalRead($_ + 0);
};
return wantarray ? @ans : $ans[0];
};
sub digital_write {
my $self = shift;
return undef unless $self;
my ($pin, $state, $state1);
while (@_ > 1) {
$pin = shift;
$state = shift;
$state1 = 0;
if ($state =~ /[1nN]/) {
$state1 = 1;
};
digitalWrite $pin + 0, $state1;
};
return $self;
};</pre>
<pre> </pre>
<pre>1;</pre>
<pre> </pre>
<pre>package Main;
use strict;
$| = 1;
my ($pin, $state, $wait, $array_ref, @array, $button);
# Each element is an array reference constructor:
# [ pin to affect, state to set it to, milliseconds to wait ]
my @seq = ([0, 1, 500], [1, 1, 500], [2, 1, 0], [0, 0, 500], [3, 1, 0], [1, 0, 500],
[4, 1, 0], [2, 0, 500], [5, 1, 0], [3, 0, 500], [6, 1, 0], [4, 0, 500],
[7, 1, 0], [5, 0, 500], [6, 0, 500], [7, 0, 1500],
[7, 1, 500], [6, 1, 500], [5, 1, 0], [7, 0, 500], [4, 1, 0], [6, 0, 500],
[3, 1, 0], [5, 0, 500], [2, 1, 0], [4, 0, 500], [1, 1, 0], [3, 0, 500],
[0, 1, 0], [2, 0, 500], [1, 0, 500], [0, 0, 1500]);
# Initialise GPIO
my $gpio = JKLMwiringPi->setup;
die "Something wrong with JKLMwiringPi->setup" unless $gpio;
# Set ports 0 - 7 as outputs and port 8 as an input; note this channel has a
# pull-up resistor
$gpio->pin_mode(0 => "out", 1 => "out", 2 => "out", 3 => "out", 4 => "out",
5 => "out", 6 => "out", 7 => "out", 8 => "in");
# Main loop: Keep going around as long as button is unpressed (due to wiring,
# button shows 0 when pressed)
while ($button =$gpio->digital_read(8)) {
push @seq, $array_ref = shift @seq;
($pin, $state, $wait) = @{$array_ref};
print "Turning pin $pin ";
print $state ? "on" : "off";
$gpio->digital_write($pin, $state);
$gpio->ms_delay($wait * .15);
print "\n";
};
# Tidy up after ourselves, leaving all outputs off
$gpio->digital_write(0 => "off", 1 => "off", 2 => "off", 3 => "off",
4 => "off", 5 => "off", 6 => "off", 7 => "off");
exit 0;
</pre>
<br />
Now, that looks a lot more Perl-like. "Asking" methods such as <tt>digital_read()</tt> return the thing being asked for. "Telling" methods return the JKLMwiringPi object, so they can be concatenated. So we could write the guts of our main loop as<br />
<br />
<tt>$gpio->digital_write($pin, $state)->ms_delay($wait * .15);</tt>
<br />
<br />
if we really wanted to. But because of the way I've written <tt>pin_mode()</tt> and <tt>digital_write()</tt> to be able to accept arrays, there isn't a great deal of need to.Juliehttp://www.blogger.com/profile/00911269487953748146noreply@blogger.com0tag:blogger.com,1999:blog-1169765624467945387.post-55168853766795831252015-07-22T17:40:00.001+01:002015-07-22T17:43:30.519+01:00Raspberry Pi Flavoured ShenanigansThe raspberry Pi folks make so much mention of Python that you might think support for other languages might be wanting.<br />
<br />
I certainly had difficulty persuading Perl to control the GPIO pins. I tried using the Perl bindings to WiringPi, but it seems that the underlying WiringPi library has changed since the Perl wrapper stuff was written, and now it either doesn't work, or segfaults. The actual C library is fine, as I proved to myself during my testing phase; but I'm always a little bit wary of stuff going on fire when I try to program it in C.<br />
<br />
I might redo it myself, if nobody else does, but I really wanted to get my Raspberry Pi up and running as quickly as possible.<br />
<br />
Fortunately, there's a trick we can use: <a href="http://search.cpan.org/~ingy/Inline-C-0.76/lib/Inline/C.pod" rel="nofollow" target="_blank">Inline::C</a>. This is a Perl module that does some high-level magic and lets you call functions in a C library as though they were Perl functions.<br />
<br />
Here's my version of a "Knight Rider" display using eight LEDs:<br />
<a name='more'></a><br />
<pre>#!/usr/bin/perl -w
use strict;
package JKLMwiringPi;
use strict;
use Inline C => Config =>
ENABLE => AUTOWRAP =>
LIBS => "-lwiringPi ";
use Inline C => <<"--END-C--";
int wiringPiSetup() ;
void pinMode(int pin, int mode) ;
int digitalRead(int pin) ;
void digitalWrite(int pin, int value) ;
void delay(unsigned int howLong);
--END-C--
1;
package Main;
use strict;
$| = 1;
my ($pin, $state, $wait, $array_ref, @array, $button);
# Each element is an array reference constructor:
# [ pin to affect, state to set it to, milliseconds to wait ]
my @seq = ([0, 1, 500], [1, 1, 500], [2, 1, 0], [0, 0, 500], [3, 1, 0], [1, 0, 500],
[4, 1, 0], [2, 0, 500], [5, 1, 0], [3, 0, 500], [6, 1, 0], [4, 0, 500],
[7, 1, 0], [5, 0, 500], [6, 0, 500], [7, 0, 1500],
[7, 1, 500], [6, 1, 500], [5, 1, 0], [7, 0, 500], [4, 1, 0], [6, 0, 500],
[3, 1, 0], [5, 0, 500], [2, 1, 0], [4, 0, 500], [1, 1, 0], [3, 0, 500],
[0, 1, 0], [2, 0, 500], [1, 0, 500], [0, 0, 1500]);
# Initialise GPIO
my $success = JKLMwiringPi::wiringPiSetup;
die "Something wrong with JKLMwiringPi::wiringPiSetup" if $success < 0;
# Set ports 0 - 7 as outputs
foreach $pin(0 .. 7) {
JKLMwiringPi::pinMode $pin, 1;
};
# Set port 8 as an input, note this channel has a pull-up resistor
JKLMwiringPi::pinMode 8, 0;
# Main loop: Keep going around as long as button is unpressed (due to wiring,
# button shows 0 when pressed)
while ($button = (JKLMwiringPi::digitalRead 8)) {
# Circulate the array @seq by shifting an item from the beginning and pushing
# the same value back onto the end
push @seq, $array_ref = shift @seq;
# The value is an array reference; let's fetch it and open it up
($pin, $state, $wait) = @{$array_ref};
print "Turning pin $pin ";
print $state ? "on" : "off";
JKLMwiringPi::digitalWrite $pin, $state;
JKLMwiringPi::delay $wait * .15;
print "\n";
};
# Tidy up after ourselves, leaving all outputs off
foreach $pin(0 .. 7) {
JKLMwiringPi::digitalWrite $pin, 0;
};
exit 0; </pre>
<br />
And here's a video of it in action:<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/i8aaR6j6t9Y/0.jpg" frameborder="0" height="266" src="https://www.youtube.com/embed/i8aaR6j6t9Y?feature=player_embedded" width="320"></iframe></div>
<br />
We create a package called <tt>JKLMwiringPi</tt>. This defines functions <tt>wiringPiSetup()</tt>, <tt>pinMode()</tt>, <tt>digitalRead()</tt>, <tt>digitalWrite()</tt> and <tt>delay()</tt> which simply call the same-named C functions in the wiringPi library. Then we use pins 0 - 7 as outputs to drive LEDs, and pin 8 as an input to read a button which, when pushed, will turn off all the outputs and exit from the program.<br />
<br />
Inside the main loop (which terminates when the value read from the switch is 0; the way it is wired means the switch reads 1 while not pressed), we keep shifting an item from the beginning of the array @seq and then pushing it back onto the end. What we shifted off is an array reference with three elements: a pin to write, the state to set it to and a delay. So we write the value to the pin and wait for the delay period (scaled appropriately).<br />
<br />
This code is still a bit ugly, but we can improve that next time by creating some proper methods within the <tt>JKLMWiringPi</tt> package.Juliehttp://www.blogger.com/profile/00911269487953748146noreply@blogger.com0tag:blogger.com,1999:blog-1169765624467945387.post-90293813917886809212015-07-22T07:50:00.000+01:002015-07-22T17:40:28.794+01:00Easiest Raspberry Pi fix ever!I thought I had killed my brand new Raspberry Pi 2, which was showing just a steady power light and that was it -- just like the state the machine is in after typing <tt>$ sudo poweroff</tt> and before disconnecting the power pack. The mouse sensor was unlit, and the CAPS LOCK and num lock lights on the keyboard were dead.<br />
<br />
However, it turned out to be a false alarm.<br />
<br />
I disconnected the Internet, HDMI, keyboard and mouse cables, leaving only the GPIO connections (which there were a lot of, and I really did not fancy disconnecting them unnecessarily). Then, on a whim, I decided to try powering it up again -- and this time, I noticed the "disk" activity light flashing, and the lights on the Internet socket also flashed briefly.<br />
<br />
Encouraged by this, I tried reconnecting just the keyboard, and noticed the caps lock and num lock lights were working. So I tried logging in blind (it's not all that difficult, actually; remember that ctrl+U erases everything you typed since the last time you pressed Return, so you don't even have to remember how many times you need to press backspace) and running my little test program.<br />
<br />
And it worked!<br />
<br />
So I shut it down cleanly; reconnected the mouse, Internet and TV; and powered it again. And was back in business, just in time for Pi Day (22/7)!<br />
<br />
<a name='more'></a><br />
Thinking about it, the problem must have been caused by the TV, network switch or (less believably, because they don't have any external power supply) the keyboard or mouse applying out-of-range voltages to pins and <a href="https://en.wikipedia.org/wiki/Latchup" rel="nofollow" target="_blank">latching up</a> the Pi's processor.<br />
<br />
Anyway, the moral of the story is: Some faults are recoverable. Try disconnecting everything before you condemn anything.Juliehttp://www.blogger.com/profile/00911269487953748146noreply@blogger.com0tag:blogger.com,1999:blog-1169765624467945387.post-72910514820662112482015-03-08T21:27:00.000+00:002015-03-08T21:27:32.523+00:00Putting Bigger Disks in a Server ..... Without RebootingYes, you read that right. It really is possible to swap the disks, in a running server, without rebooting. I know, because I was that soldier. This is how I did it.<br />
<br />
What you will need:<br />
<ul>
<li>A server with one or more RAID-1 arrays.</li>
<li>Enough RAM to run without a swap area.</li>
<li>Quick-release drive carriers, preferrably including one spare.</li>
<li>Enough new drives, preferrably identical, to replace the little ones.</li>
<li>Another computer with at least two SATA ports.</li>
<li>A USB stick with <a href="http://sysresccd.org/" rel="nofollow" target="_blank">System Rescue CD</a> installed.</li>
<li>The usual tools, spare parts &c.</li>
</ul>
<div>
<a name='more'></a>Most tutorials of this nature begin with a dire warning to <b>back up all your data</b>. You don't actually need to do this here, because the whole point of a RAID-1 setup is that both (all?) the disks are copies of each other. And the system tries its damnedest to make sure that this is the case. Nonetheless, if you don't feel confident ..... Well, back up all your data anyway.<br />
<br />
NOTE: # is the root prompt on the server; % is the prompt on the work computer (which will be running SystemRescueCD, and that uses <tt>zsh</tt> as its default shell instead of bash.) </div>
<div>
<br /></div>
<div>
Run <tt>top</tt> to check memory usage. If the machine has not used any swap space, you're good to go. If it has, you may as well take it down for awhile anyway and stick more RAM in it. Otherwise</div>
<div>
<br /></div>
<div>
<tt># swapoff -a</tt></div>
<div>
<br /></div>
<div>
Now <tt>cat /proc/mdstat</tt> . This will tell you which drives are part of which RAID arrays.</div>
<div>
<br /></div>
<div>
Disconnect one of the drives from the RAID array:</div>
<div>
<br /></div>
<div>
<tt># mdadm --manage /dev/md0 --fail /dev/sdb1</tt></div>
<div>
<tt># mdadm --manage /dev/md0 --remove /dev/sdb1</tt></div>
<div>
<br /></div>
<div>
Now for the first scary bit. You are going to physically remove the drive from the server. Take a deep breath, release the caddy and withdraw it in one smooth motion, while trying not to think about what might happen if you have got it wrong and pulled out the wrong drive. Run</div>
<div>
<br /></div>
<div>
<tt># cat /proc/mdstat</tt></div>
<div>
<br /></div>
<div>
again to make sure all is still well.</div>
<div>
<br /></div>
<div>
Label this drive at once. There <i>will</i> be confusion later on, and you don't want to get things mixed up. Now go to the computer you will be using for the donkey work. Connect the ex-server drive to SATA port 0, and a brand new drive to SATA 1. Plug in your SystemRescueCD USB stick, and boot up into the sysresccd shell (and don't forget to select a keymap when prompted, otherwise you will find all your punctuation marks in the wrong places. Maybe some letters, too, if you are French or German.)</div>
<div>
<br /></div>
<div>
Now run</div>
<div>
<br /></div>
<div>
<tt>% fdisk -l</tt></div>
<div>
<br /></div>
<div>
and read and digest the output carefully. You will know which disk is which, by the sizes: the smaller one -- which should be <tt>sda</tt>, because you plugged it into port 0 -- is the one you took out of the server, and the larger one with no partitions on it should be <tt>sdb</tt>. There will also be an <tt>sdc</tt>, and maybe even an <tt>sdd</tt> if you left the DVD±RW drive connected. Assuming things are right here, all you need do now is</div>
<div>
<br /></div>
<div>
<tt>% dd if=/dev/sda of=/dev/sdb bs=65536</tt></div>
<div>
<br /></div>
<div>
to copy the contents of sda, in 65536-byte chunks, over to sdb. This will bring the boot sector, partition table and everything else across.<br />
<br />
(You did get it the right way around, didn't you? If it stops with "not enough space left on device", you just tried to copy the factory-fresh HDD onto the one out of your server. Oops. I can't even give you any instructions here, because this did not happen to me. But it's not the end of the world; you still have a copy of your data on the disk that's still in the server .....) </div>
<div>
<br /></div>
<div>
(Why didn't she just say <tt>% sfdisk -d /dev/sda | sfdisk /dev/sdb</tt> to copy over just the partition table? That would have been much quicker, for sure. And the server is going to stomp all over the disk contents anyway. But then you wouldn't be able to time how long the copying takes. Disk I/O will be the major limiting factor for this operation, so you can be reasonably sure that the server will take about the same amount of time to recreate the RAID array as it took you to copy the disk.)</div>
<div>
<br /></div>
<div>
Now you have a clone of your original sdb. But it isn't <i>quite</i> ready yet. If there was a swap partition on the disk, we need to move that to the end of the free space, so we can grow the main partition. <br />
<br />
Messing around with partitions is a great way to trash a drive if you are not careful. So power down the work computer and disconnect the original drive. Then there is no way you can inadvertently change its contents. Restart the work computer. SystemRescueCD includes <tt>gparted</tt>, so start the GUI with</div>
<div>
<br /></div>
<div>
<tt>% startx</tt></div>
<div>
<br /></div>
<div>
and then get to work. Basically, you want the partition for your RAID member to be as big as it can be. Exactly how you have to do this bit will depend on your original partitioning scheme. Mine was easy -- just one primary partition for the RAID1 array that will hold the root file system, and a logical partition to act as swap space.<br />
<br />
Note that moving a logical partition first requires you to grow the extended partition which contains it; then you can move the logical partition, and last of all shrink the extended partition (I got bitten by this at first, but Google was very helpful). Also, if it protests that a partition is in use, what probably has happened is that the kernel has seen that it looks like part of a RAID array -- and so the underlying partitions will be in use by the mdraid driver. Try<br />
<br />
<tt>% cat /proc/mdstat</tt><br />
<br />
If a (degraded) RAID array shows up, you need to stop it with<br />
<br />
<tt>% mdadm --stop /dev/md0</tt><br />
<br />
and then you should be able to resize the partition.</div>
<div>
<br /></div>
<div>
Shut down the work computer, swap the new drive into the caddy, put the original sdb somewhere safe and insert the new drive into the server. Wait a minute or so, for the server to recognise that a new disk has been plugged in. If when you type</div>
<div>
<br /></div>
<div>
<tt># fdisk -l</tt></div>
<div>
<br /></div>
<div>
you can see the new, large drive, you're ready! So add it to the RAID array:</div>
<div>
<br /></div>
<div>
<tt># mdadm --manage /dev/md0 --add /dev/sdb1</tt></div>
<div>
<br /></div>
<div>
and keep doing <tt># cat /proc/mdstat</tt> a few times to convince yourself that stuff is happening. At this point, you may as well brew a cup of tea, write a blog post or something. You can't really go anywhere until the RAID system has done its stuff. You know roughly how long it's going to take to copy that amount of data from one drive to another, because you've already done it.<br />
<br />
Now it's time for a bit of a diversion. Run<br />
<br />
<tt># blkid</tt><br />
<br />
and make a note of the UUIDs of any swap partitions on <tt>sda</tt> .</div>
<div>
<br /></div>
<div>
When the array is no longer resyncing, then it's time for the second stage. So this time, disconnect the other drive from the array:</div>
<div>
<br /></div>
<div>
<tt># mdadm --manage /dev/md0 --fail /dev/sda1</tt></div>
<div>
<tt># mdadm --manage /dev/md0 --remove /dev/sda1</tt></div>
<div>
<br /></div>
<div>
and pop out the caddy with sda in it. Label the drive; plug it and your other new disk into your work computer; and boot up SystemRescueCD. Now I'm going to assume the small drive is sda and the large drive is sdb. Make sure they really are that way around. If needs be, power off and swap the cables. You don't want to be attempting substitutions.</div>
<div>
<br /></div>
<div>
This time, we can use the quick way of copying.</div>
<div>
<br /></div>
<div>
As this is the boot device, it needs its boot sector copying across:</div>
<div>
<br /></div>
<div>
<tt>% dd if=/dev/sda of=/dev/sdb bs=512 count=1</tt></div>
<div>
<br /></div>
<div>
And then you can copy the partition table:</div>
<div>
<br /></div>
<div>
<tt>% sfdisk -d /dev/sda | sfdisk /dev/sdb</tt></div>
<div>
<br /></div>
<div>
<tt>% fdisk -l</tt></div>
<div>
<br /></div>
<div>
and check that the partitions are the same on both drives. Recreate any swap partition that may have been on the original drive (I had a swap partition at sda5, so % mkswap /dev/sdb5 ) Don't forget to give it the same UUID as was in <tt>/etc/fstab</tt>. Start the GUI and use gparted to fix the partitions. At this stage, it would do no harm to run <tt>blkid</tt> and make sure the UUID for the swap partition is correct.</div>
<div>
<br /></div>
<div>
Power down the work computer, and swap the new sda into the caddy. Re-insert it into the server, let it get recognised, and then</div>
<div>
<br /></div>
<div>
<tt># mdadm --manage /dev/md0 --add /dev/sda1</tt></div>
<div>
<br /></div>
<div>
As ever, keep an eye on <tt>/proc/mdstat</tt> until it finishes resyncing.</div>
<div>
<br /></div>
<div>
You now have a clone of your original system on two new drives -- and the original two drives in a safe place in case anything goes wrong. But you are still not quite done yet. There is all that empty space to be taken care of.</div>
<div>
<br /></div>
<div>
First you need to grow the RAID array to fit in its new-size partitions:</div>
<div>
<br /></div>
<div>
<tt># mdadm --grow /dev/md0 --size=max</tt></div>
<div>
<br /></div>
<div>
And when that's done, you can grow the file system to fit in the RAID array:</div>
<div>
<br /></div>
<div>
<tt># resize2fs /dev/md0</tt></div>
<div>
<br /></div>
<div>
(Yes, this does work. You can resize a filesystem while it is still mounted, and nothing terrible will happen.) You can estimate how long this process is going to take, based on the difference between the new and old drive sizes; but this probably will be a bit optimistic, and it is likely to take longer in real life. Note that at first, /proc/mdstat will be estimating days for completion; it will speed up over time.<br />
<br />
The very last thing you need to do is to re-enable swap, with<br />
<br />
<tt># swapon -a</tt><br />
<br /></div>
<div>
..... And that's really all there is to it! Not only did you swap out both drives, but you now have more free space. And no reboot required -- although you really should think about doing so, just to prove that the array is still bootable. Have your SystemRescueCD USB stick with you while doing this</div>
<div>
<br /></div>
<div>
<br />
<i>Many thanks to the Open Source community, in particular those upon whose efforts this builds.</i></div>
Juliehttp://www.blogger.com/profile/00911269487953748146noreply@blogger.com0tag:blogger.com,1999:blog-1169765624467945387.post-65472668647794783782014-11-12T21:07:00.001+00:002014-11-12T21:07:10.461+00:00Freaking Awesome Scientificy Spacey Stuff!
<div class="content">
<div id="post_message_12685183">
<blockquote class="postcontent restore ">
Today, we landed a probe about the size of a washing machine on
the surface of a comet about the size of the main populated bit of Derby, 500 million km.
away. At that distance, the radio signals carrying instructions up and
pictures down take 28 minutes each way.<br />
<br />
That's pretty freaking awesome.<br />
<br />
If you scale the distances down to something more manageable, it's like
the equivalent of standing in London and firing a gun and hitting a
moving target, 1/20 of the width of a human hair, in Paris.<br />
<br />
Meanwhile, some kid watching the news on the TV or Internet is going to
be fired up by the sheer freaking awesomeness of it all, and decide
right there and then that they want to be a scientist when they grow up
because science is so freaking awesome. Hopefully <i>lots</i> of kids. And
they'll go to university and get their MScs and their PhDs and end up
doing something that will be so even more freaking awesome that it will
make landing Philae on P67 look about as impressive as reversing a car
into a garage.<br />
<br />
This must be the way people were feeling on the day the first human
stepped on the Moon, two years and eight days before Yours Truly was
born.<br />
<br />
(And the <i>real</i> experiment, drilling into the comet and analysing whatever is found in there, hasn't even started yet .....)
</blockquote>
</div>
</div>
Juliehttp://www.blogger.com/profile/00911269487953748146noreply@blogger.com0tag:blogger.com,1999:blog-1169765624467945387.post-38354676694780755562014-09-02T14:56:00.002+01:002014-09-02T15:05:21.339+01:00The Great Vacuum Cleaner Rip-OffRecent legislation has banned the manufacture or import of vacuum cleaners with a motor power over 1600 watts. And predictably, idiots who don't understand physics are complaining.<br />
<br />
The simple fact is, that <i>manufacturers have been ripping you off</i>.<br />
<br />
Let me explain.<br />
<br />
A vacuum cleaner turns electricity from the mains into kinetic energy which it imparts to the stream of moving air (which is what you want it to do). It also turns electricity into heat (which you don't want it to do) and sound (which you can't avoid, but it isn't much anyway; a screaming toddler is producing about a watt of sound energy. Yes, loudspeakers really are that inefficient).<br />
<br />
You can measure how fast KE is being imparted to the air stream by multiplying the volume flow rate by the pressure change. Assuming you use the fundamental units throughout, you get metres cubed per second, times Newtons per metre squared = Newtons-metres per second = Joules per second = Watts. <b>That figure is all the dirt in your carpet cares about</b>. The difference between air-watts and electrical watts is what is getting wasted.<br />
<br />
From the vacuum cleaner manufacturer's point of view, since you already have a moving air stream, you can use this for cooling the motor; so overheating really isn't a huge deal. You can therefore make your motor inefficient -- using copper wire that is too thin, and/or not enough steel to leave any molecules un-magnetised right through the crests and troughs of each cycle of the mains -- so it turns some electricity into heat that otherwise would have been turned into KE. Also from the vacuum cleaner manufacturer's point of view, a bigger number on the advertisement attracts more buyers. So it's actually in the manufacturers' interest to make vacuum cleaners <i>as inefficient as possible</i>, just so as to be able to claim big numbers!<br />
<br />
And people have fallen for this hook, line and sinker. I despair.<br />
<br />
(My proposed solution would be to require standardised testing of vacuum cleaners, including ability to extract different types of dirt from different surfaces, percentage efficiency as air-watts / electrical watts and expected lifetime of product. Of course this will make additional work for the manufacturers; but we consumers outnumber them, and the law is supposed to work for us .....)Juliehttp://www.blogger.com/profile/00911269487953748146noreply@blogger.com0tag:blogger.com,1999:blog-1169765624467945387.post-40266571608030136492014-07-24T18:01:00.000+01:002014-07-24T18:01:06.509+01:00Finally, as promised, eventually: Fixing Akionadi over NFSFirstly, apologies for the great lateness of this post. I could say it was due to personal circumstances &c.; but I'll tell the truth for once, and say it was just me being a dizzy mare.<br />
<br />
Anyway. The scenario is this. We have several clients running KDE, and using an NFS share for their home folder. By default, Akonadi wants to run its own MySQL server, as the individual user, with data in the user's home folder. Which means that every time a record needs to be modified, we have to lock a file (to make sure only one process is going to modify it at once); alter it; and then unlock it. This is creating <i>a lot</i> of network traffic, as compared to just sending a query over the network, and it also has potential problems if the timing of all these messages gets messed up.<br />
<br />
So the logical conclusion is, we need to have a central MySQL server for every user's Akonadi data, so the traffic is just queries and responses and we aren't relying on locking files on a remote server. (If you read <a href="http://becomingjulie.blogspot.co.uk/2014/06/decisions-that-bite-269.html" rel="nofollow" target="_blank">the first part of this story</a>, you'll remember that this particular use case is actually violating assumption #3; this is a more complicated case than a simple home user, and there is someone in charge who ought to know better.)<br />
<br />
<a name='more'></a><br />
As the NFS and NIS servers are already running on the same machine, we can easily set up a MySQL server there as well. In fact, I already installed MySQL anyway when I built the box, because I suspected it might be necessary for something. There's almost no good reason not to; MySQL hardly consumes any resources when idling.<br />
<br />
I'm going to suppose the NIS / NFS /MySQL server is <b>192.168.0.2</b>. We'll create a single MySQL user "<b>fred</b>" for all the Akonadi databases (there will be one per user) and this user obviously requires a password as they are logging in remotely. <i>This is a tiny bit lax</i>, as it means a savvy user could see other people's Akonadi data; but none of our users have any secrets from each other anyway. If your network needs more sophistication, so be it. You will just need to create a separate MySQL user for each Akonadi user, and keep track of their passwords.<br />
<br />
First we need to make some changes to the server configuration, so as to match what Akonadi is expecting. Open a terminal and login to the server;<br />
<br />
<code>$ ssh root@192.168.0.2</code><br />
<code># nano /etc/mysql/my.cnf</code><br />
<br />
Insert the following somewhere after <tt>[mysqld]</tt> but before the next opening square bracket character;<br />
<br />
<code># Make table names capitalisation-insensitive</code><br />
<code>lower_case_table_names=1</code><br />
<code># Avoid "MySQL server has gone away" errors</code><br />
<code>wait_timeout=31536000</code><br />
<br />
Save the file, and restart the MySQL server with the modified configuration;<br />
<br />
<code># service mysqld restart</code><br />
<code># mysql</code><br />
<code>mysql> CREATE DATABASE akonadi_julie;</code><br />
<code>mysql> GRANT ALL ON akonadi_julie TO "fred"@"192.168.%" IDENTIFIED BY "b00bies";</code><br />
<br />
Create as many databases as you need, and grant privileges on them. The last command you need to give is<br />
<br />
<code>mysql> FLUSH PRIVILEGES;</code><br />
<br />
to make sure that remote clients can connect properly. Press ctrl-D to exit MySQL, and again to break the SSH connection to the server. You're now back to being you, on your workstation.<br />
<br />
First of all, make a copy of a file that is about to get trashed;<br />
<br />
<code>$ cp .config/akonadi/akonadiserverrc .config/akonadi/akonadiserverrc.0</code><br />
<br />
Now you need to start the "akonaditray" application;<br />
<br />
<code>$ akonaditray &</code><br />
<br />
Wait for it to finish launching, and look for a new entry in the system tray (it might be hidden behind the "show hidden icons" arrow). Right-click it and select "Configure". Then click on the right-hand tab (Akonadi Server Configuration). Don't change anything just yet.<br />
<br />
Now search for a MySQL process with a <tt>--socket=/home/something</tt> option in its command line;<br />
<br />
<code>$ ps aux | grep mysql</code><br />
<br />
Highlight the whole <tt>--socket=.....</tt> string by left-clicking and dragging. Then you can middle-click to paste it into the next command;<br />
<br />
<code>$ mysqldump --socket=..... akonadi | mysql -h192.168.0.2 -ufred -p akonadi_julie</code><br />
<br />
Give the password <tt>b00bies</tt> when prompted. This will take a dump of the existing "akonadi" database, and pipe it into the "akonadi_julie" database on 192.168.0.2. Now all we need to do, is reconfigure Akonadi to use the remote database. So, in "Akonadi Server Configuration", change the settings as follows:<br />
<br />
<table border="0" style="margin-left: 2em;">
<tbody>
<tr>
<td colspan="2">Use internal MySQL server -- <strong>untick this</strong></td>
</tr>
<tr><td>Database Name</td><td>akonadi_julie</td></tr>
<tr><td>Host</td><td>192.168.0.2</td></tr>
<tr><td>Username</td><td>fred</td></tr>
<tr><td>Password</td><td>b00bies</td></tr>
<tr><td>Options</td><td>MYSQL_OPT_RECONNECT=1</td></tr>
</tbody>
</table>
<br />
(the "options" line should also help avoid the risk of "MySQL server has gone away" errors.) Restart the Akonadi server and make sure it does not give any errors -- you may have to do this a couple of times but it will work in the end. In the terminal, do
<br />
<br />
<code>$ ps aux | grep mysql</code><br />
<br />
again and make sure the original MySQL process has gone away. Right-click the akonaditray icon and close it down.<br />
<br />
You now need to repeat this procedure for every user.<br />
<br />
You <i>could</i> edit <tt>/home/*/.config/akonadi/akonadiserverrc</tt> directly, and use <tt>akonadictl restart</tt> to restart the Akonadi server; but the GUI method isn't really much slower.Juliehttp://www.blogger.com/profile/00911269487953748146noreply@blogger.com0tag:blogger.com,1999:blog-1169765624467945387.post-68507719527226443372014-06-14T11:15:00.002+01:002014-06-15T00:54:06.666+01:00Decisions that Bite, #269Sometimes, a bunch of decisions, each of which – considered in isolation – is perfectly sound and rational, can come together to bite you in a really nasty place.<br />
<br />
1. Database servers are usually configured with their own local disk drives, so they can get the maximum throughput supported by the motherboard, rather than storing data on a remotely-mounted network share. Acquiring and releasing file locks, which is something that databases have to do a lot, is also faster and more reliable using local hardware to which the kernel is talking directly, rather than by sending requests and acknowledgements across the network where it contributes to the overhead.<br />
<br />
2. You don't always want to have to think about file formats in too much depth. Sometimes, what you have to store lends itself naturally to a database. Someone else has already done the hard work, implementing the storage engine. All you need to concentrate on is getting the data in and out of the application.<br />
<br />
(Database servers also tend to be surprisingly light on resources; because traditionally, they have had no alternative but to have been.)<br />
<br />
Using a ready-made database server to store your data can make better sense than devising your own ad-hoc file format that may limit you in future in ways that, by defnition, you haven't thought of.<br />
<br />
3. Desktop users shouldn't need to be intimately familiar with the under-bonnet workings of a database merely in order to use their computers. If a database server is used by an application, its configuration should be managed by the application itself. This is especially so if the application makes use of esoteric configuration options.<br />
<br />
Starting a specific instance of the database server, just for that one user, with a configuration decided by the application and so specifically suited to it, can make better sense than trying to use an existing system-wide server. (You don't have to be root to run a server, if you listen on a non-privileged port and take care not to write anywhere you aren't allowed.)<br />
<br />
4. A network with multiple users running a limited range of desktop applications (mainly a web browser and an e-mail client) would be really, really great if it had the ability for any user to log in at any workstation and have their own home folder. You can rotate more staff than you have workstations, through any combination of shifts; and know that, as long as there are enough workstations for every team member, everyone will be able to access their own home folder.<br />
<br />
So, it makes sense in such a situation to use NIS to handle user logins, and mount <tt>/home</tt> on an NFS share.<br />
<br />
<br />
Four eminently sensible decisions, taken in isolation. But put them all together and what you get is, multiple databases in users' home folders on the same NFS share.<br />
<br />
This only became apparent when I upgraded a bunch of desktops to Debian Wheezy. (I'd resisted Squeeze for long enough already, because of the move to KDE4. KDE3 was good enough for most of what we needed – it's just that awkward "most of" that's the problem.)<br />
<br />
Now, Wheezy uses KDE4, as did Squeeze. KDE4 includes Akonadi, which uses a MySQL database to store data. And it starts an instance per user, configured especially to use a data store under that user's home folder. The newer applications in Wheezy make heavier use of Akonadi's database functionality.<br />
<br />
But Wheezy also has MySQL 5.5, whose default database engine is InnoDB – as opposed to Squeeze's 5.1 using MyISAM by default.<br />
<br />
And this is where the trouble begins; because InnoDB tables don't play nicely over network shares. NFS is too busy locking and unlocking files to serve much data; and very occasionally, messages get out-of-order and a lock or unlock is missed, resulting in slowdown waiting for the lock to timeout or – worse – data corruption if a write occurred while a file was supposed to have been locked.<br />
<br />
So when four or five users on the same network share all try to start up their Akonadi servers at exactly the same time, the result is a packet jam not quite of VoIP-degrading proportions, but certainly getting on for it. All because of an unfortunate concatenation of otherwise seemingly-innocuous circumstances.<br />
<br />
Fortunately, there is a happy ending. I'll explain all in the next post .....Juliehttp://www.blogger.com/profile/00911269487953748146noreply@blogger.com0tag:blogger.com,1999:blog-1169765624467945387.post-11570866298199667122014-03-26T23:09:00.001+00:002014-03-26T23:09:29.055+00:00An Anniversary!<p>Today is the anniversary of the installation of solar panels at Montoya Mansions!</p>
<p>In my first year, I have generated 1636 kWh. This is comfortably more than the predicted 1400 kWh for my first year's production, and alters the payback threshhold in my favour: if the price of electricity exceeds <ins>14.042 p per unit</ins>, my solar setup has cost less than the electricity it will generate over 25 years (accounting for deterioration).</p>
<p>The timing of my feed-in tariff payments has fallen nicely, such that each payment is due almost exactly halfway between an equinox and a solstice; thus, they correspond to the seasons as counted by duration of daylight. My first payment was £117.75 on 3 August; then £73.88 on 3 November. The sun could barely be bothered to rise in Winter, leading to a dire £29.12 on 3 February (although it still more than covered the £1.82 per week standing charge). Come 3 May, I expect to receive another £70 or 80 for the Spring (this payment and the Autumn one should be fairly similar, by symmetry: the graph of day length vs. day of the year is sinusoidal).</p>
<p>When I get my storage batteries and UPS plumbed in, I should be able to save even more, as I won't need to pay for all the electricity I will be using in the evening .....</p>
Juliehttp://www.blogger.com/profile/00911269487953748146noreply@blogger.com0tag:blogger.com,1999:blog-1169765624467945387.post-36044807681275564352014-03-16T11:02:00.000+00:002014-03-16T11:02:12.467+00:00Great news from the Independent on Sunday<p>The <em>Independent on Sunday</em> have announced a new policy of refusing to review children's books which are aimed <em>only</em> at boys, or <em>only</em> at girls:</p>
<p><a href="http://www.independent.co.uk/voices/comment/genderspecific-books-demean-all-our-children-so-the-independent-on-sunday-will-no-longer-review-anything-marketed-to-exclude-either-sex-9194694.html">http://www.independent.co.uk/voices/comment/genderspecific-books-demean-all-our-children-so-the-independent-on-sunday-will-no-longer-review-anything-marketed-to-exclude-either-sex-9194694.html</a></p>
<p>Which is A Good Thing. We don't need any more glittery pink books telling girls they should aspire to be princesses or fashion models; nor trashy, dumbed-down books for boys that ultimately only reinforce the idea that reading is for girls.</p>
Thanks to <a href="http://twitter.com/LetToysBeToys">Let Toys Be Toys</a> for breaking this news.Juliehttp://www.blogger.com/profile/00911269487953748146noreply@blogger.com1tag:blogger.com,1999:blog-1169765624467945387.post-18909833494564386342014-02-16T21:46:00.001+00:002014-02-16T21:46:25.195+00:00You can't run that from batteries!Recently, I have managed to acquire a used, APC 3000 VA uninterruptible power supply – minus batteries. (APC branded battery packs cost almost as much as a new UPS. Generic sealed lead-acid batteries of the same capacity can be bought from the likes of <a href="http://www.tayna.co.uk/">http://www.tayna.co.uk/</a> for a fraction of that.) The UPS is basically a self-contained battery pack, charger and inverter. It converts DC from a bank of batteries, which are ordinarily kept charged from the mains, to AC when the mains fails. I plan to use this, in conjunction with a bank of large batteries, to implement a solar energy storage system.<br />
<br />
Now I have managed to pick up some batteries. Although they are not the right ones for this UPS, they are "just about" compatible – the right voltage, but the wrong capacity (there would normally be two series chains of four 12 V, 5.5 Ah batteries, in parallel for 48 V / 11 Ah; I have just one series chain of four 12 V, 7 Ah batteries, for 48 V / 7 Ah).<br />
<br />
These batteries are rather used, and have a remaining usable capacity somewhat lower than advertised – <i>but they cost nothing</i>, which is always a point in favour.<br />
<br />
And of course, having some batteries, we can test out the UPS!<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh1qLjYJqX_GoDd2CaIkGwv43Ga5jgBEZpj99uifa2qQtZjTBkJmuBgf2p5vyHbHynoDJcohZvyvytzda_BZmBRYVQO877M93VbByYG-q96a4IIuMuKdOaAeQrGjUVKYx5THym8vo7nzyuF/s1600/inverter1.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh1qLjYJqX_GoDd2CaIkGwv43Ga5jgBEZpj99uifa2qQtZjTBkJmuBgf2p5vyHbHynoDJcohZvyvytzda_BZmBRYVQO877M93VbByYG-q96a4IIuMuKdOaAeQrGjUVKYx5THym8vo7nzyuF/s1600/inverter1.jpg" height="320" width="236" /></a></div>
You can see clearly that these aren't the right batteries -- I have had to stand the battery tray on top of the UPS because these are too tall. The lamp was from an earlier test; look out for the black extension lead heading off the bottom left corner. The 4-way extension lead is fitted with a <a href="http://en.wikipedia.org/wiki/IEC_60320_C20#C20">"C20" plug</a> for the UPS output (which can be up to 3000 VA, which is more than the usual "C14" / kettle-type can handle.) The other end goes to .....<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgsOudT5M-Qy81zHpkKqviZj1evkgHq72TnwH_17maKgV8cmBHf0_LjZp9S3thwBTAX-evVG5hKhBi49h6QIk_tPP4FgfKpx_MZHlsk7cydqd_43lm_b1_2XQLWV7hojIWbmbwLHbasPSLK/s1600/uwave1.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgsOudT5M-Qy81zHpkKqviZj1evkgHq72TnwH_17maKgV8cmBHf0_LjZp9S3thwBTAX-evVG5hKhBi49h6QIk_tPP4FgfKpx_MZHlsk7cydqd_43lm_b1_2XQLWV7hojIWbmbwLHbasPSLK/s1600/uwave1.jpg" height="244" width="320" /></a></div>
This microwave oven! It's cooking just the burger from a microwave cheeseburger. I toasted the cob separately, and added my own special tomato and herb sauce.<br />
<br />
I was worried that the microwave would pull down the battery voltage far enough to trip the undervoltage cut-out in the UPS –this was what happened with a 2 kW kettle. Fortunately, the slow-start action of the magnetron filament heating up was enough to allow the UPS batteries to recover.<br />
<br />
This is a good sign. And the nice people at <a href="http://www.tayna.co.uk/">http://www.tayna.co.uk/</a> are very helpful. They certainly know their batteries. Juliehttp://www.blogger.com/profile/00911269487953748146noreply@blogger.com0tag:blogger.com,1999:blog-1169765624467945387.post-33094705269314166432014-01-01T07:51:00.000+00:002014-01-01T08:01:39.417+00:00Staffordshire OatcakesThese are a kind of pancake that don't actually taste of anything. The idea is that they can be served wrapped around literally any sweet or savoury filling, since there is no possibility of a flavour clash; and the texture of the oatcake brings out the flavour of the filling.<br />
<br />
They are ideal for travelling, because you can wrap them up in paper in such a way as to be able to take a few bites and re-wrap every so often. And despite the fact that oatcakes can be surprisingly filling, mini-oatcakes with ice cream also make a great dessert after a barbeque.<br />
<br />
My parents and three of my grandparents were born in Stoke-on-Trent, even although I wasn't born there. That does not stop me appreciating the Food of the Gods, at any rate, and I think I have the heritage.<br />
<ul>
<li>250 g. plain flour</li>
<li>250 g. oatmeal</li>
<li>500 ml. warm water</li>
<li>500 ml. milk</li>
<li>1 sachet (7 g.) bread machine yeast</li>
</ul>
Mix liquid, which should be at body temperature or maybe slightly higher; don't exceed 40 degrees. Add dry ingredients. Mix thoroughly for 1 minute, then cover loosely and leave to stand for 40 minutes to 1 hour until it has frothed up and then steadied out a bit. Mix again for another minute.<br />
<br />
Heat a large, heavy-based frying pan, melt a lump of butter over it and ladle in a dollop of the oatcake batter. Shake the pan about to cover the whole of the base and keep frying, watching the clock. As soon as the oatcake is beginning to come loose from the pan, note how much time has elapsed (about a minute with a 30 cm. pan; maybe 90 seconds if the oatcake is really thick) and time this long again. By this time the top side should be hardening all over and should be full of 3 - 4 mm. bubble holes. Turn over the oatcake. You can toss it if you are experienced with pancake-tossing; otherwise, slide the oatcake sideways onto a plate, then pick up the plate and invert it over the pan. Note, the bubble holes in the side cooked first will be a lot smaller, mostly under 1 mm. Cook for as long on this side as you did on the other side, then slide sideways onto a plate.<br />
<br />
As a guide, you should get 6 - 8, 30 cm. oatcakes out of this much mixture. It's best to add fillings, roll up and serve at once -- even microwave awhile if needed, to make sure the fillings are properly hot. But you can allow the oatcakes to cool (put a layer of kitchen foil, greaseproof paper or similar between each one and the next to avoid them sticking together) and serve later. They will keep for a few days in the fridge.<br />
<br />
<br />
<b>Fillings</b>: Oatcakes were basically a lunchtime meal for the Staffordshire miners; so fillings such as bacon, mushroom and cheese or scrambled egg, perhaps with chopped sausage, would have been popular. Or use something else that comes out of Staffordshire -- just down the A50 via Uttoxeter to Burton-on-Trent this time, find a nice real ale from a local brewery and cook up some cheap steak in an ale gravy with onions and mushrooms. Thicken the gravy enough, and you can almost eat a steak and ale oatcake bare handed. (But it probably would be even more delicious served on a plate with chunky hand-cut chips, petits pois and corn-on-the-cob.) Leftovers can probably be wrapped up in an oatcake, too.<br />
<br />
And while an oatcake doesn't make a very good
substitute for a pizza base, spread with the sauce and with cheese
and pizza toppings rolled up in the middle it makes a different kind of meal altogether.<br />
<br />
<b>Dessert oatcakes</b> to be served with a sweet filling probably are best made in a smaller frying pan. Fill with any combination of fruit, jam, jelly, custard, whipped cream, ice cream, grated chocolate and sticky sweet syrupy liquids and sprinkles you like.<br />
<br />
If travelling, you may even want to prepare an oatcake with mostly a savoury filling, but then a bit of sweet filling -- jam or fruit compôte and custard, say -- at one end. You can cut off a piece of oatcake to make a barrier between the sections. Roll up, wrap in paper, mark which end to open first and there's main course and pudding in one!Juliehttp://www.blogger.com/profile/00911269487953748146noreply@blogger.com0tag:blogger.com,1999:blog-1169765624467945387.post-39128674289944361182013-12-08T02:21:00.001+00:002013-12-08T03:05:36.080+00:00Hey! I'm out to my co-workers!Tonight, I officially came out as transgender to my co-workers, at the works christmas party. I went as Julie, not ${BOYNAME}, and was accepted thus by everyone.<br />
<br />
Think my boss must have suspcted for awhile; because if he's been looking at my out-of-hours activities like any decent hacker would then he must have spotted "Julie Montoya" signing some code that was embarrassingly similar in style to ${BOYNAME}'s code (he writes like a girl anyway, in a girlie language).<br />
<br />
I love you all <3 <3 <3<br />
<br />Juliehttp://www.blogger.com/profile/00911269487953748146noreply@blogger.com1tag:blogger.com,1999:blog-1169765624467945387.post-87254865270968767472013-08-25T01:25:00.000+01:002013-08-25T01:25:00.699+01:00R.I.P Shelley CatShelley Cat passed away this morning at 11:00.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgcdp7gvnzUXfYfIOvY6ln0tdrQzAH0KmH7ZfqeJ60YqpZyPdwsXDU0uAuqi0BQKz0CAFlU2yFj4KhHpujFkVcrXpOQCHVIzdvmyKjdNx2b_0IHngmV1OUzyHWqqsqqEvrQ2rd-Zw2NSs1J/s1600/IMAG0445.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="192" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgcdp7gvnzUXfYfIOvY6ln0tdrQzAH0KmH7ZfqeJ60YqpZyPdwsXDU0uAuqi0BQKz0CAFlU2yFj4KhHpujFkVcrXpOQCHVIzdvmyKjdNx2b_0IHngmV1OUzyHWqqsqqEvrQ2rd-Zw2NSs1J/s320/IMAG0445.jpg" width="320" /></a></div>
Almost exactly one year ago -- on the stormy Saturday night before the August bank holiday -- my next door neighbours, who knew I already had a cat, brought me a stray cat that they had found in the street, asking if I could look after it. I accepted, thinking that it would only be a few days until an owner was located.<br />
<br />
The poor little thing was in a terrible state; half drowned and half starved. I soon discovered that it was a she (at least, she did not object to the female pronoun) and she responded well to being towelled down, warmed in front of the woodburner and fed what seemed to be pack after pack of cat food. I took her to the vet's to see if she was microchipped, but she was not. I took a photograph of her and printed out leaflets, four to a page, asking "IS THIS YOUR CAT?" and giving my phone number; which I posted through letterboxes, and gave the local shops full-page versions to display in their windows.<br />
<br />
But nobody seemed to want the little cat back. I received just two phone calls; one from a person who had lost a cat but the description did not match; and one explaining how a cat looking like my picture had belonged to a woman whose boyfriend moved in with her, but the boyfriend had been horrible to the cat, kicked her, and one night "accidentally" left the back door open and she escaped<br />
<br />
Realising that she might be with me for some time, I decided she needed a name. So I called her Shelley because her mostly-black fur had brown, tortoiseshell-like patches.<br />
<br />
Shelley suffered with hyperthyroidism; which meant that she could eat and eat food but just never put on any weight. She was given medication for this, which allowed her to put on some weight and her general condition to improve. I also had her microchipped, to proclaim to the whole world that THIS CAT BELONGS TO: JULIE MONTOYA, c/o MONTOYA MANSIONS. Tel. XXXXXXXXXXX. <br />
<br />
Then, about 6 weeks ago, she suddenly seemed to have lost her appetite, and would not eat the piece of ham in which I had concealed her Vidalta (thyroid pill). She seemed to want it, just not to be able to take it, and I rushed her to the vet's. There was an abscess in her mouth and ulcers all over her tongue. She was given an injection of a long-term antibiotic and prescribed Metacam to relieve the pain and enable her to eat again.<br />
<br />
After about 2 weeks, Shelley seemed much better; but this turned out to be short-lived. She was soon back to the vet's, where she was prescribed Nisamox (amoxycillin -- artificial penicillin -- and clavulanic acid) and also Vetergesic (buprenorphine -- an opiate, prescribed to humans as Subutex), to be followed by more Metacam when the vetergesic ran out. <br />
<br />
One week ago, she was due to give a blood sample to measure her thyroid hormone level and make sure the Vidalta dosage was still doing its work; and they also ran some additional tests. Shelley tested positive for feline calicivirus. This is highly contagious. Younger, fitter cats may well be asymptomatic; but if the patient's immune system is in any way compromised, then the cat is rendered vulnerable to secondary infection. This is obviously what was happening to Shelley.<br />
<br />
Yesterday, Shelley took another turn for the worse. My partner and I made the decision that Shelley had suffered enough already. She was already due to go to the vet's today anyway. This time, it was to be a one way journey. I signed the consent form. We stood there, gently stroking Shelley, and she purred
as the fluid went in; then she became silent and fell asleep. Her
breathing slowed, she fell down softly onto the table, and that was the
end.<br />
<br />
<br />
Goodbye, Shelley. Rest in Peace. I will miss her funny little mannerisms. Her damaged back legs made her movements awkward, but she used to drag herself up onto the sofa or my bed using her front paws. She used to meow loudly when she wanted to be fed. And even although she had lived outdoors as a stray, she still preferred to go indoors to use a litter tray.Juliehttp://www.blogger.com/profile/00911269487953748146noreply@blogger.com0tag:blogger.com,1999:blog-1169765624467945387.post-20688871670360983562013-07-17T21:41:00.002+01:002013-07-17T21:51:45.676+01:00Who Does Software Piracy Really Hurt?It's often said that software piracy damages business. It does, but not for who you think it does.<br />
<br />
When someone uses a pirate copy of Microsoft Office to write letters, do their household finances and keep track of their CD collection, this does no harm to Microsoft; because they would never have paid £500 for a copy of Microsoft Office anyway, even if they could not have obtained a pirate copy free. Rather, they would have searched for a less expensive office suite offering the functionality they needed -- or even stuck to good old-fashioned notebook and pencil.<br />
<br />
Now supposing someone decides to release a basic office suite, with sufficient functionality for the needs of most users, and sell it for £50. A user with a brand new computer has a choice: Pay £500 for Microsoft Office, pay £50 for Cheap and Cheerful Office 2013 and save £450, take a pirate copy of Microsoft Office and save £500 or take a pirate copy of Cheap and Cheerful Office 2013 and save £50. Paying for CaCO13 <i>actually makes better economic sense</i> * <i>than not paying for it</i>, but the pirate copy of Microsoft Office is the clear winner.<br />
<br />
When, not if, the vendors of CaCO13 go out of business, it will be because of software piracy -- even although <i>no-one need ever make a single pirate copy of Cheap and Cheerful Office 2013</i>.<br />
<br />
And it isn't just Microsoft Office, of course. There's also Adobe Photoshop (for holiday snaps) and Dreamweaver (for creating web sites), and AutoCAD (for drawing diagrams, dressmaking patterns and so forth).<br />
<br />
Microsoft, Adobe and others tolerating rampant piracy is a deliberate tactic to eliminate competition, by saturating the market with freely available software. <i>They have nothing to lose from it anyway</i>, since the pirates would most probably have bought a competitor's product. What is more, this creates a huge pool of self-taught users of the major players' software. If an amateur photographic artist, who already uses an illegal copy of Adobe Photoshop for their art, gets a job editing photographs, then it makes sense for their new employers to purchase the tool with which they are already most familiar. Had they used some hypothetical inexpensive alternative software instead, they might have suggested it to their new employers, who might again have purchased the tool with which the employee was most familiar -- this time, from <b>the small, independent software vendor</b>, to Adobe's detriment.<br />
<br />
Another loser from pirated software is <b>the business that uses only legitimate, fully paid-up software</b>. When faced with an unusually large order, a business might have to take on additional staff, and so pay more for additional software licences for them. This will create an additional cost for the job, which will have to be reflected in the price offered and could only be offset against guaranteed future purchases. (<i>In this economic climate? YMBK.</i>) A rival business using pirated software would have no such increased overhead cost when taking on extra staff, and could undercut the competitor.<br />
<br />
Although the big software vendors focus their attention on businesses
and prosecute offenders heavily, and to much publicity, there are still far too many firms getting
away with software piracy.<br />
<br />
And lastly, but certainly not leastly, pirated software harms <b>the Open Source movement</b>.<br />
<br />
Freedoms Zero (<i>the freedom to enjoy the use the software</i>) and Two (t<i>he freedom to share the software</i>) can be taken by force if necessary (this, if nothing else, is what piracy <i>is</i>). Most people are not programmers, and cannot fully appreciate the value of Freedoms One (<i>the freedom to study the workings of the software</i>) and Three (<i>the freedom to adapt the software to one's needs</i>) -- freedoms in the practical exercise of which the Source Code, something jealously guarded by proprietary software vendors, is highly desirable. This, in turn, is perhaps something that programmers cannot fully appreciate, if their worldview is that of a programmer ever seeking to improve software incrementally towards perfection. Nonetheless, the fact that a particular freedom has perceived importance only to a minority should <i>never</i> be an excuse to permit it to become abridged -- to do so would simply be discrimination. (And those who perceive Freedoms One and Three as important, perceive them as fundamental.) To the majority, Freedoms 0 and 2 are sufficient; this may be unfair, but we have to work with it for now.<br />
<br />
Open Source software competes fairly with pirated software on price; and has traditionally been behind in features but has now overtaken proprietary software in some areas. This has come about because of both stagnation in the proprietary camp, and continued progress in the Open Source camp -- accelerating with the growth in user numbers, for even a complaint can lead to an improvement. Nonetheless, a perception remains that it must be somehow ... <i>unsophisticated</i>, if people feel the need to give it away. It is also disadvantaged by businesses continuing to use proprietary software (because most of the workforce are also using pirate copies of the same software).<br />
<br />
The reality is, every pirate copy of Microsoft Office is a lost "sale" of LibreOffice, OpenOfficeOrg, Calligra Suite, Trinity Office, or any number of other lesser-known Open Source projects -- a missed opportunity to educate someone in the use of an alternative product, who might go on to influence others to use it. In the case where a lesser-known project is chosen, it can actually influence the project positively by providing feedback, creating interest and tempting other users to try it and maybe keep it. And every pirate copy of a newer version of Windows than was originally installed on a machine (a tactic which is often unsuccessful, due to the tendency of proprietary software to increase its demands to match improvements in hardware as proprietary developers are given the latest, fastest workstations; therefore, proprietary software is sub-optimal on older, slower hardware with less RAM and disk space. Some Open Source developers are forced to work with less than the newest hardware, and make a deliberate effort to improve performance on slower hardware and limit memory requirements) is a lost "sale" of a complete Linux distribution.<br />
<br />
We should not take violations of proprietary end-user licence agreements any less seriously than we take violations of the GPL. Copyright law is ultimately what keeps the Source open; and this is what Microsoft, Adobe, AutoDesk et al are subverting when they subvert copyright law to their own ends by enforcing it selectively. If users do not wish to pay for software, that is their choice: but they should accept the gift of Open Source software, and not make unfair of proprietary software. For it is unfair: unfair to the legitimate users who pay, and unfair to the competitors whose work is spurned for something that its users should not even have.<br />
<br />
<br />
* The fallacy is: You actually save a full £500 by not paying for Cheap Office, if you aren't paying for MS Office either.Juliehttp://www.blogger.com/profile/00911269487953748146noreply@blogger.com2