Host ID: 282
In part 1 I described cross-compiling, what it means and why you might want to, or even need to use it.
I also described how to create a cross-compiler tool-chain using crosstool-ng.
In this show I will demonstrate using one of the cross-compilers which I created as described in the last show to compile a Raspberry Pi Linux kernel.
As usual with my shows the show-notes can't be squashed into 4k, so there is an HTML version at:
Back in the summer of 2014 I started going to the Surrey Linux User Group.
I was asked to give a short presentation about Linux accessibility and how, although I am totally blind, I still write code and muck about with Linux.
I was then asked to give the same presentation at the Portsmouth LUG.
This time I made it more comprehensive and took more kit.
So I take this opportunity to give my version of the "What's in my bag" shows that some folks have been doing. As I am unemployed, like a lot of blind folks, I have been unable to justify this before now because I don't lug an interesting collection of stuff to and from work.
Here's a simple bullet list about the crate and it's contents:
- The crate is a 35 litre capacity 'Really Useful Box'
- First in were 2 Dell Latitude D630 (64-bit) laptops
- Next in was a Dell Inspiron (32-bit) laptop, clunky and slow
- The three laptops were sandwhiched between 3-ply layers of bubble-wrap
- Next in was a Seika 40-cell refreshable Braille display
- Next was a clear polycarbonate, zip-up pencil case stuffed with audio leads
- Then a 'Mesh' Bluetooth and line-in external speaker
- And a Braun external speaker/FM radio/micro-SD boom-box
- A four-way mains power splitter
- The three AC adaptors for the laptops
- On the top of the box, because it was too wide to go in, was a USB keyboard
- Mobile phone charging battery 'brick', for the Raspberry Pi
- A Raspberry Pi, a Banana Pi and some Arduino bits and pieces
Here's what I demonstrated with two of the laptops:
- Trisquel Linux and accessibility in the Gnome desktop with Orca
- Accessibility in the console with Debian and the Braille display on the Inspiron
The second Latitude was with me so I could get some sighted help with BIOS settings.
My thanks have to go to Tony Wood for the lift to and from both of these accessibility presentations. I could not have done either, especially the Portsmouth one without his help.
Thanks also to Lisi, the coordinator of the Portsmouth LUG and to the folks of that LUG for their enthusiasm.
Here's the link to the HPR show about my Raspberry Pi tts code fix:
Cross-compilers, Part 1
In this show I'll introduce the concept of cross-compiling software, explain what it is and why you might want/need to do it.
I'll also talk about a great piece of kit for creating cross-compiler tool-chains on Linux; crosstool-ng.
As with most of my shows, the show notes are far too long to fit into the restricted size, so there's an HTML version as well, at:
Here are some bullet-points:
- cross-compilers, why and what?
- Cross-compiler tool-chain generation gotchas
- Raspberry Pi cross-compiling tool-chain generation with crosstool-ng
- Compiling a kernel on a Pi takes 15 hours
- On my not-so-screaming quad-core Debian machine it takes 15 minutes
- Debian Linux: https://www.debian.org/
- Raspberry Pi: http://www.raspberrypi.org
- Crosstool-ng: http://crosstool-ng.org/
- Arch Linux ARM: http://archlinuxarm.org/developers/distcc-cross-compiling
- Klaatu: http://hackerpublicradio.org/correspondents.php?hostid=78
- Klaatu's Kernel Compile Show: http://hackerpublicradio.org/eps.php?id=0087
There are a few files for this show, the ct-ng .config files downloaded from Arch Linux ARM and a README.md about them. The original markdown source of the full show notes is in the tarball as well http://hackerpublicradio.org/eps/hpr1706/282-Mike_Ray-hpr1706-Cross-compilers_Part_1.tar.gz.
Since April last year the text-to-speech using eSpeak in the Raspberry Pi console has stuttered very badly and regularly crashes the kernel.
Here's how I fixed it.
Cloning my github repo:
Installation:cd ttsprojects/raspberry-pi/libilctts/build sudo ./build.sh cd ../../piespeakup sudo ./build.sh
Bingo! Speech should work.
This has only just been released and there is still work to do on the documentation.
Note: I am not connected to the Raspberry Pi Foundation in any way and anything I say or do is not endorsed by them.
My email address is connected with a Freelists email list I set up and an accompanying web site:
The 'VI' is for 'Visually Impaired' and I DID check with the Foundation about the similarity of the web address before I created it.
To join our email list send an email to:
With 'subscribe' in the subject.
The Banana Pi - First Impressions
They say duplication is the sincerest form of flattery, substitute the word of your choice for 'duplication'.
The Banana Pi is made in China and bears an uncanny resemblance to the Raspberry Pi.
Not just the name, the board is fractionally larger, some of the features on the board are similarly placed:
- 26-pin GPIO
- 3.5mm analogue audio jack
- RCA composite video jack
- SD card slot
There are things the RPI does not have:
- Power button
- uBoot button
- USB-otg port (otg = on-the-go, a bi-directional USB port)
- SATA connector
The processor is a dual-core running slightly faster than the Raspberry Pi, although to be fair, of course, the RPI can be over-clocked.
The Banana Pi has twice the RAM and a dual-core processor.
The SoC is the ARM Allwinner A20.
Getting my Hands on a Banana Pi
My first Banana dropped through the letterbox a couple of days ago.
Thanks to some kind soul on the Raspberry Pi Facebook group who described the connectors on the edges of the board I narrowly avoided plugging the power supply into the USB-otg port. The power micro-USB is on the underside of the board between the SATA power and data connectors which are on the upper side of the board.
Can't really say much about it because I can't actually see the build quality, but it feels nice. The PCB is fractionally thinner than the RPI.
I had an initial struggle to find a download link for any images.
The downloads page of lemaker.org has a two row table on it which appears to be upside-down and it has links to Google-drive, two different public DropBox links, a MS One-Drive link, and something I didn't initially find, an FTP link.
Both of the DB links are duff because they have suspended the account because of excessive traffic.
This is the FTP download link:
When I found the FTP page I grabbed images for:
- Arch Linux
I downloaded and extracted all of these images to my Debian desktop machine and tried to write and boot them in succession.
The first I tried was Arch, on the assumption that would not have a desktop installed.
After writing the card I looked at it on my Debian machine with parted and it appeared to have two partitions. As with the Raspberry Pi there is a small FAT16 partition and a bigger ext4 partition.
The FAT partition contained the same files as the Raspberry Pi:
And some others I can't remember.
In addition it contained:
It appears uEnv.txt is equivalent to the Raspberry Pi cmdline.txt file, and uImage is, of course, the kernel.
So oddly it has the files for the RPI and it's own in the FAT partition.
Then I tried Bananian, and this appears to be Debian Wheazy for ARM.
Similar story with the FAT partition.
It is a very minimal installation which has little more than the Linux Standard Base (LSB) packages. I like this because I like to have control.
Sound and Stuff
I found a review from April this year that said the sound driver snd-bcm2835 was not available. At the name snd-bcm2835 my heart sank because I expected the BPI to have the same stuttering text-to-speech problems as the RPI.
Not expecting much I did, as root:
apt-get install alsa-base alsa-utils
Looking through /lib/modules/... blah blah I found a driver called:
And I got pink noise!
Next I did:
apt-get install espeakup update-rc.d espeakup defaults modprobe speakup_soft
And speakup burst into life with no stuttering!
The online community and code-base for the Banana Pi is not yet very mature, and because the origin of the beast is China, a lot of what's out there is in Chinese.
But it is growing. And after all, it took the RPI a while to take off and go ballistic.
At the moment I would say the Banana Pi is not for the faint-hearted or the total newbie, although, a lot of newbie questions are generic and don't have machine-specific answers.
Australian community page with forums:
The worst thing about the Banana Pi is, when writing emails about it, and these show-notes, typing the word 'banana' and knowing when to stop!
How to implement a many-to-many join in a relational database
The purpose of this HPR show is to demonstrate the best, and really the only way to define a many-to-many relationship between two entities in a database.
What triggered it?
There has been some discussion between Ken and Dave on the community news podcasts, presumably relating to some work which is being done on the HPR web site. I sent Ken an email explaining how to implement a many-to-many relationship and got a predictable response; do a show :)
So here it is.
What do I mean by database entity?
In analysing the structure of the data which is to be stored by a database, one of the most important things to do is to identify what entities are to be stored and manipulated.
What constitutes an entity is often quite simple; some examples might be 'customer', 'billing address', 'shipping address', 'invoice', 'invoice item' etc.
In fact it's also true to say that more often than not entities and tables have a one-to-one relationship. If the analysis of your data reveals that there is a 'customer' entity, then there will probably be a 'customer' table.
One area where this might not be quite true is where the mechanism used to implement the whole software system demands a greater level of granularity. There are some e-commerce systems which are written with object-oriented technology and which demand that the data model matches the objects in the system. Typically this results in a data model that might look like it is over-normalised.
But for the sake of this example, we will assume that one entity occupies one table.
In fact if you find your analysis has any two tables that appear to have a one-to-one relationship, there is probably something wrong with your analysis because these two tables could be merged into one.
In a database system comprised of a number of tables, one table per entity, there will be complex relationships between the entities. This is the reason we talk about 'relational' databases. Or perhaps it is because all the columns in a table are supposed to be related to the unique identifier in that table, not sure, and neither was Mr. Codd.
Types of relationship
One-to-many or many-to-one, depending on which end of the telescope you are looking through. For example a customer might make one, or many purchases from your company e-commerce system. In which case there will be a one-to-many relationship between the 'customer' table and the 'invoice' table in the sales ledger.
Note that if the customer has only ever made one purchase there will only be one row in the invoice table, but it COULD contain more. The more end is really one-or-more.
Because one visit to the web site might result in the customer dropping more than one item into his shopping cart, there will also be an 'invoice lines' or 'invoice items' table.
How these relationships are represented on diagrams
Classically an entity relationship diagram consists of a series of rectangles, one for each table with the name of the entity written in the box. The entity rectangles are joined together by lines. These lines have what are usually called 'crows feet' at the 'many' end. A crows foot looks just like what it says, where the line joins the many end of the join, the line splits into three prongs before it hits the side of the many entity rectangle. Depending on what mechanism has been used to create this diagram, the crows foot can also look more like a fork than a crows foot, but there are still three prongs.
In this text I will use a line consisting of dashes to join entities, and a backwards left or right arrow to represent the many end of a relationship.
So, using the example above, the one-to-many relationship between customer and invoice looks like this:
Here the less-than sign is used at the many end and should be thought of as a crows foot with the middle toe missing.
How to join two tables in a many-to-many relationship
You will not come across this relationship very often. It is far less common than a simple one-to-many or many-to-one.
One example where this might be useful, and the example I use in this text, is a music database where two of the entities are:
Clearly there will be multiple artists, and multiple genres. And it is not inconceivable that an artist might appear in more than one genre. And a given genre will clearly contain more than one artist.
So this gives rise to a many-to-many relationship, which in pure analysis terms could be diagrammed like this:
But this is NOT the way to define it in actual physical database tables.
Observing the rules of normalisation, an artist should be identified by one property, the artist name, and a genre should be identified by one single property, the genre name.
More often, and in our example below, each entity is given a unique identifier which is in addition to it's actual name.
This is how changing a simple name in one table can result in the change being seen globally over the entire database system. For example in a customer table, the row:
id name -- ---- 1 Mickey Mouse
Will cause 'Mickey Mouse' to be shown as the customer name wherever the identifier '1' is used to retrieve records or to join tables in a complex SQL query.
Change 'Mickey Mouse' to 'Donald Duck' in this table, and 'Donald Duck' will appear everywhere 'Mickey Mouse' was seen before.
When two tables are to be joined to make a query, columns, or multiple columns are given indexes. A column which contains the key from another table is called a 'foreign key'.
Going back to our customer and invoice example from above, the invoice table will contain the customer identifier from the customer table. And because a single customer can make more than one visit to our web site to buy stuff, the column containing the customer identifier in the invoice table is not given a unique index.
If the customer with the identifier '12345' has made five different shopping excursions to our site, there will be five rows in the 'invoice' table containing the customer identifier '12345'.
Armed with this information, how will we represent this:
Clearly the artist table should contain a foreign key from the genre table, and the genre table should contain a foreign key from the artist table.
The rules of normalisation say that all the attributes in a table (columns) should relate to the primary key of the table. Clearly putting a genre foreign key into the artist table, or an artist foreign key into the genre table busts this rule wide open. Don't do it
To solve this problem we introduce another table between the artist table and the genre table, which I always suffix with '_xref', short for cross-reference.
Now our entity relationship diagram will look like this:
What does the artistgenrexref table contain? Simple, it contains the bare minimum to define a unique row which joins an artist and a genre.
If the artist identifier is called artistid and the genre identifier is called genreid, then the xref table contains two columns:
What kind of index do we need on this table to make a unique relationship between an artist and a genre? We need a unique compound index which uses both columns.
This will ensure that one and only one row can appear in the table joining one artist to one genre. But because an artist can belong to more than one genre, both columns in the index mean this is possible.
A worked example
In the example code and data below, I have used SQLite3.
SQLite is the world's most used Relational Database System (RDBMS).
How can this claim be made?
Well if you have a smart-phone in your pocket, it probably uses SQLite. If you have a satellite TV receiver, a Tivo or some other kind of home media device, it probably contains SQLite.
And if you are really strange and have a fridge which will tell you what's inside, it probably uses SQLite. And there will be one row which says 'half an onion wrapped in foil which has been in here for six months'.
Several times I have been brought Blackberry hand-sets and asked to retrieve important documents or texts from it when the user interface mechanism has failed. Something that often happens with that flavour of soft fruit.
SQLite is easy to install on your Linux machine. In fact it is used by so many other packages that it may well be on there already. But you may have to install the interactive SQLite3 program.
On Arch Linux:
$ sudo pacman -S sqlite3
On Debian or Ubuntu:
$ sudo apt-get install sqlite3
Below I have inserted the contents of all the files which I created to demo this many-to-many relationship strategy.
Each file is topped and tailed by the string '--snip--'. In the SQLite3 interactive program, a double dash ('--') starts a line comment. Each file also contains the name of the file and a description of what it does.
An exception is the .csv files I have used to load data into my little test database. These have the '--snip--' tops and tails in this text but they do not exist in the actual data, for obvious reasons. If you are snipping out the csv data to try this at home, don't include anything but the data lines in the csv data.
To start an interactive SQLite 3 prompt and create your test database, do this at a Linux or Windows command prompt. Here the prompt is represented by a dollar sign:
$ sqlite3 music.db
You will get this prompt:
Because the first thing I alwys want to know about apiece of software I haven't used before is how to get out, to get out of the interactive SQLite3 session, type this, of course 'sqlite>' is the prompt:
To run a file of commands you have defined in an external file, do this:
Where 'filename' is a file containing dot prefixed commands and/or SQL.
The files from my working example:
The following file contains commands to create tables and indexes in the database named on the command-line when you called sqlite3.
--snip-- -- -- file name: ddl.sql -- -- ddl = 'data definition language' -- -- This SQL creates three tables, the artists table tbl_artist, -- the genre table tbl_genre, and the cross-reference -- ttable tbl_artist_genre_xref -- -- The xref table is what provides the many-to-many relationship -- between artist and genre by virtue of it's -- compund index; idx_artist_genre_xref, -- which has two columns included in it -- -- I use the tbl_ prefix for tables and the idx_ prefix for indexes. -- These might seem redundant but they are useful for preventing -- collisions between database component names and reserved words. -- -- Create the artist table create table tbl_artist ( artist_id integer not null primary key, artist_name text not null ); -- Create the genre table create table tbl_genre ( genre_id integer not null primary key, genre_name text not null ); -- Create the artist_genre_xref table -- -- I use number for both columns instead of integer because SQLite -- does something funky with auto-incrementing integer -- columns which have a 'not null' constraint, I think create table tbl_artist_genre_xref ( artist_id number not null, genre_id number not null ); create unique index idx_artist_genre_xref on tbl_artist_genre_xref ( artist_id, genre_id ); --snip--
There follow three files which contain comma-separated values (.csv) records for loading into each table.
The first is artist data:
--snip-- 1,"Horslips" 2,"Runrig" 3,"The Pogues" 4,"Led Zeppelin" 5,"Disturbed" 6,"Martin Carthy" 7,"Steeleye Span" 8,"Schubert" 9,"Mozart" --snip--
The first three artists fall into both the folk and rock genres. Led Zeppelin and Disturbed will be in rock only.
Martin Carthy and Steeleye Span are folk only.
Schubert and Mozart need no further explanation.
The next is data to load into the genre table:
--snip-- 1,"Folk" 2,"Rock" 3,"Classical" 4,"Scottish" 5,"Irish" --snip--
The last data file is the data which will be loaded into the artistgenrexref table. It contains only numerical data:
--snip-- 1,1 2,1 3,1 1,2 2,2 3,2 4,2 5,2 6,1 7,1 8,3 9,3 1,5 3,5 2,4 --snip--
What is this data doing? Well there are some artists there which will appear in both the 'folk and the 'rock' genres. Horslips are a seventies Irish folk-rock band. I still play their 'The Book of Invasions' album at least once a week. This is either because it is a seminal album or because I am a dinosaur who refuses to be dragged kicking and screaming into the 21st century. Runrig are a band from the Western Isles of Scotland who cross over the folk/rock boundary also. Check links at the end of this text.
The next file loads the data from these .csv files into the three database tables.
--snip-- -- -- file name: load.sql -- -- Load some data into the tables from three CSV files -- .separator "," .import artist.csv tbl_artist .import genre.csv tbl_genre .import xref.csv tbl_artist_genre_xref --snip--
There now follow some SQL queries which retrieve data-sets which should be obvious from the file names:
--snip-- -- -- file name: select-folk-only.sql -- -- This is where the SQL gets a bit hairy, using a sub-query to exclude -- everything except the category we want from the record-set. -- -- This is the kind of situation where a view -- might be useful to hide some of the SQL complexity from -- the user. -- select a.artist_id, a.artist_name, x.genre_id from tbl_artist as a, tbl_artist_genre_xref as x where a.artist_id = x.artist_id and x.genre_id = 1 and a.artist_id not in ( select a.artist_id from tbl_artist as a, tbl_artist_genre_xref as x where a.artist_id = x.artist_id and x.genre_id != 1 ); --snip-- --snip-- -- -- file name: select-folk.sql -- -- Straight-forward query to select artists that appear in the folk -- category. -- -- This will return artists that appear in the folk category, which -- includes artists that appear either exclusively in folk or in BOTH -- folk and any other category also. -- -- A little hard to get your head around. Remember the artists returned -- by this set are in both folk and any other category. -- select a.artist_id, a.artist_name, x.genre_id from tbl_artist as a, tbl_artist_genre_xref as x where a.artist_id = x.artist_id and x.genre_id = 1; --snip-- --snip-- -- -- file name: select-rock-only.sql -- -- This is where the SQL gets a bit hairy. It uses a sub-query to -- exclude everything except the category we want from the record-set. -- -- This is the type of query where a view might be useful to hide some -- of the SQL complexity from the user -- select a.artist_id, a.artist_name, x.genre_id from tbl_artist as a, tbl_artist_genre_xref as x where a.artist_id = x.artist_id and x.genre_id =2 and a.artist_id not in ( select a.artist_id from tbl_artist as a, tbl_artist_genre_xref as x where a.artist_id = x.artist_id and x.genre_id != 2 ); --snip-- --snip-- -- -- file name: select-rock.sql -- -- select all artists which appear in the rock category -- select a.artist_id, a.artist_name from tbl_artist as a, tbl_artist_genre_xref as x where a.artist_id = x.artist_id and x.genre_id = 2; --snip-- --snip-- -- -- file name: select-scottish.sql -- -- Straight-forward query to select artists that appear in the scottish -- category. -- -- This will return artists that appear in the scottish category, which -- includes artists that appear either exclusively in scottish or in -- BOTH scottish and any other category also. -- select a.artist_id, a.artist_name, x.genre_id from tbl_artist as a, tbl_artist_genre_xref as x where a.artist_id = x.artist_id and x.genre_id = 4; --snip-- --snip-- -- -- file name: select-irish.sql -- -- Straight-forward query to select artists that appear in the irish -- category. -- -- This will return artists that appear in the irish category, which -- includes artists that appear either exclusively in irish or in BOTH -- irish and any other category also. -- select a.artist_id, a.artist_name, x.genre_id from tbl_artist as a, tbl_artist_genre_xref as x where a.artist_id = x.artist_id and x.genre_id = 5; --snip--
The next files, all prefixed 'dump' will dump the record-sets returned by the above SQL queries into corresponding .csv files:
--snip-- -- -- file name: dump-folk-only.sql -- -- Dump all artists that appear ONLY in the folk category -- into folk-only.csv -- .mode csv .output folk-only.csv .read select-folk-only.sql --snip-- --snip-- -- -- file name: dump-folk.sql -- -- Dump all artists that appear in the folk category -- into folk.csv -- .mode csv .output folk.csv .read select-folk.sql --snip-- --snip-- -- -- file name: dump-rock-only.sql -- -- Dump all artists that appear ONLY in the rock category -- into rock-only.csv -- .mode csv .output rock-only.csv .read select-rock-only.sql --snip-- --snip-- -- -- file name: dump-rock.sql -- -- Dump all artists that appear in the rock category -- into rock.csv -- .mode csv .output rock.csv .read select-rock.sql --snip-- --snip-- -- -- file name: dump-scottish.sql -- -- Dump all artists that appear in the scottish category -- into scottish.csv -- .mode csv .output scottish.csv .read select-scottish.sql --snip-- --snip-- -- Dump all artists that appear in the irish category -- into irish.csv -- .mode csv .output irish.csv .read select-irish.sql --snip--
In a real-world example, the hard-coded numeric genre identifiers in the above queries would be replaced by placeholders like '?' which would be replaced by actual values at run-time.
In conclusion, in my experience programming all manner of systems using Oracle, MySQL and SQLite databases, this method is the only one which doesn't take diabolical liberties with the rules of database normalisation.
It may result in SQL queries which will make you scratch your head, but that is far more acceptable than doing stuff like trying to shoe-horn a many-to-many relationship into your database structure by other means.
One of the most crucial aspects of using a high-end RDBMS like Oracle, MySQL or SQLServer, is the need to get as much data selection done by the server as possible.
This is because the server is a big fat box in a cupboard connected to your machine by a network infrastructure. It might be next door or on the other side of the world.
It makes far more sense for the server to return to you those records, and ONLY those records you want, over the network.
Any other strategy for implementing a many-to-many relationship is likely to result in you pulling stuff back to your machine which you are ultimately going to drop in some kind of loop. Slow and wasteful of bandwidth.
In the example I have used, the cross-reference table was populated manually. In most real-world implementations the cross-reference table will be populated in response to records being added to the two outer tables, or in response to user-intervention using a client application. Often triggers are used to create the cross-reference rows.
If you were authoring a music database application in which such a relationship exists between artist and genre, the user interface would probably provide a means for the user to decide which genres to plop artists into.
I have used SQLite to demo this strategy. While SQLite is a great tool, it is a 'lite' tool that is designed for single-user applications, in particular embedded systems.
If you are thinking of starting an airline and want to implement a world-wide seat booking application which will serve many concurrent users, needing complex transactional operations, don't use SQLite or your customer complaints are likely to exceed bookings.
My example data definitions also contain no constraints for preventing orphaned rows. These are rows in a table containing a foreign key where no record exists in the table identified by the foreign key. Because in my example I load the 'parent' tables before I load the table which contains foreign keys to both of those tables, there is no risk of creating orphaned rows.
Most RDBMS systems include a mechanism for what is called 'cascaded deletes', that is, when deleting a row from a parent table, any row in a table containing a foreign key for that row, a 'child' row, will also be deleted, preventing 'orphaned' records.
Applying this to the above example, deleting 'Runrig' from the artists table would also delete all rows from the artistgenrexref table with the identifier for 'Runrig'.
- Database normalisation according to Mr Codd: http://en.wikipedia.org/wiki/Database_normalization
- SQLite: http://www.sqlite.org/
- Horslips are/were an Irish folk-rock band
The first two tracks from 'The Book of Invasions; a Celtic Symphony' live:
- Runrig are a Scottish folk-rock band who have been around for years.
Loch Lomond live:
If any queries result from this show about any of the terms I might have very casually scattered about relating to database theory, assuming I know the answers, I can do more shows about those.
Maybe one about SQLite in particular.
Accessibility tools for the visually impaired
A short explanation of how I personally got involved with accessible computing, a definition of the term 'accessible' as it is applied to anything in relation to persons with physical or cognitive impairment, and very short list of the most commonly used adaptive tools to improve accessibility to Windows and Linux.
- The NVDA screen-reader: http://nvaccess.org
- The Orca screen-reader: https://help.gnome.org/users/orca/stable/
- The brltty refreshable Braille display driver: http://mielke.cc/brltty/
brltty has to be the most impressive example of well-documented Open Source.
- Debian Accessibility: https://www.debian.org/devel/debian-accessibility/
Debian has a fully accessible installer. I have installed Debian 7.4 from the net install CD ISO image. The installer is text-based and presents no problem for even the totally blind.
See the Debian Accessibility page linked to above.
- Ubuntu Accessibility: https://help.ubuntu.com/community/Accessibility The Ubuntu 'Ubiquity' graphical installer is totally accessible. Installing from a live CD or DVD image is simple. See the page linked above.
- Vinux (an Ubuntu variant which is accessible out-of-the-box): http://vinuxproject.org/ This is an Ubuntu variant which comes up talking from the first. Not only is the installer accessible, but considerable attention has been paid to including only applications which are accessible on the CD and DVD images. Applications which are either inaccessible or which simply have little or no relevance to the visually impaired are excluded.
- Talking Arch: http://talkingarch.tk/ Chris Brannan created an accessible ISO image of Arch Linux.
This uses the speakup console-mode screen-reader to provide a way of installing Arch Linux for the visually impaired. Console-mode only, but providing a great starting-point. I have tried various desktops on top of this installation, including mate, LXDE and others.
Talking Arch is now maintained by a couple of names which will be familiar to the Linux VI community; Kyle and Kelly. Erm...embarassingly I can't find their last names right now.
Mike Ray. June 2014