LUG Community Blogs

Aq: Saving the current state of your Ubuntu SDK app, with no effort

Planet WolvesLUG - Thu, 23/01/2014 - 19:14

Earlier today I gave an example of how to use U1DB to save the state of your Ubuntu app. Now, U1DB is useful for actually storing actual data, right enough. But if you want to save state — which tab was showing, what was being typed into a text field, what was chosen in a dropdown, where a list was scrolled to — then that’s built right in1 to the Ubuntu SDK.

It’s called StateSaver.

This isn’t used to store data, long term. It’s used to make your app automatically remember what position things were in. So quitting the app and restarting it, or switching to another and then switching back, means the app doesn’t reset to the front screen, doesn’t forget what you were halfway through typing in, doesn’t forget where you’d scrolled to.

To use it, just add StateSaver.properties to the Item you want to save things for. So, for example, if you want your ListView to remember the position it was scrolled to, do this:

ListView { id: mylistview model: someModel delegate: ListItem.Standard { text: "row " + model.index } StateSaver.properties: "contentY" }

Just that one thing. Now your ListView remembers where it was scrolled to after a restart. You can do the same with a set of Tabs (just add StateSaver.properties: "selectedTabIndex") or a TextField (StateSaver.properties: "text").

NB: this isn’t really for data saving. It might, or might not, be appropriate to use it for whether a switch is flipped or not. That’s a setting; when the switch is changed, you ought to be doing something with that information. Ideally you could drive everything, declaratively, off of whether the switch.checked is true, and if you can do that then StateSaver is the ideal place to have that info. But if you run a function when a switch is changed, then don’t use StateSaver to remember its state: use U1DB, and store the other stuff that changed alongside it. It’s about saving state, hence the name.

Saving the state of your app like this is an idea so good that other ideas gather at its feet to pray. I think that this should be turned on automatically for the “relevant” properties of each type of Ubuntu SDK widget, and if for some reason you don’t like it you can turn it off. Not for every single property, but for the ones where state makes sense: the scroll position for a ListView, the entered text for a TextField, the visible tab for Tabs. Small things like this are what make the difference between great apps and merely good ones. Any one individual app isn’t particularly harmed by not remembering this stuff; so many apps do not, on other platforms, that people are used to the idea of having their state thrown away. But if almost all the apps do do this, then the ones that don’t get called out on it and then it gets fixed, and that makes the whole platform better. It’s really important that we create a culture of desire for finished, polished apps for Ubuntu. If your app throws away where I was scrolled to, I want the developer to feel a bit embarrassed about that and immediately go to fix it. That’s what will make our platform feel consistent, feel tight, feel together, feel fun to use; the culture of pushing back on unfinished and unpolished and half-ready apps. Open source has historically not had that culture, but I’d really like to use a platform which does.

Importantly, though, for it to be reasonable for we users to require this of app developers, it has to not be really hard for app developers to do. This, taking complicated things and making them easy for app developers to implement, is what the platform is for. And StateSaver is a great example of it; the platform provides! I’m really impressed that this exists and is part of the SDK. (I’d be even more impressed if it did it automatically, as noted.) Good work, Ubuntu SDK team. This stuff needs more publicity!

Longer code example, which remembers which tab you were looking at, where the list is scrolled to, and what was typed in the text field:

import QtQuick 2.0 import Ubuntu.Components 0.1 import Ubuntu.Components.ListItems 0.1 as ListItem MainView { id: root width: units.gu(40) height: units.gu(70) Tabs { id: tabs StateSaver.properties: "selectedTabIndex" Tab { id: t1 title: "StateSaver, 1" page: Page { id: pg ListView { id: lv model: 40 clip: true anchors.fill: parent StateSaver.properties: "contentY" delegate: ListItem.Standard { text: "This is row " + model.index + ". Scroll to wherever." } } } } Tab { id: t2 title: "StateSaver, 2" Column { width: parent.width id: col2 spacing: units.gu(1) anchors.centerIn: parent Label { text: "Enter your favourite pie" horizontalAlignment: Text.AlignHCenter anchors.horizontalCenter: parent.horizontalCenter } TextField { id: tf width: parent.width - units.gu(2) StateSaver.properties: "text" anchors.horizontalCenter: parent.horizontalCenter } } } } }
  1. how did I not know this existed! Big thanks to Florian for cueing me in
Categories: LUG Community Blogs

Aq: Using U1DB in ListViews in Ubuntu SDK apps

Planet WolvesLUG - Thu, 23/01/2014 - 17:24

After explaining how to use U1DB to store simple bits of information in Ubuntu SDK apps, and saying that that caters for 80% of my need for data storage, I should explain the other thing I do, which is to store dynamic data; documents created from user data.

To understand more about how to retrieve data from U1DB through Indexes and Queries, you can read the core U1DB documentation. Its code examples are for the Python implementation, and QML works differently for creating documents (as we’ve seen, QML is declarative; there’s no code to write, you just describe a document and it all works), but indexing and querying documents have the same underlying philosophy regardless of implementation, and the core docs explain what an index is, what a query is, and how they work.

First, a simple code example.

import QtQuick 2.0 import Ubuntu.Components 0.1 import U1db 1.0 as U1db import Ubuntu.Components.ListItems 0.1 as ListItem MainView { width: units.gu(40) height: units.gu(71) /* ---------------------------------------------------- Set up the U1DB database Declare a named document ---------------------------------------------------- */ U1db.Database { id: db; path: "simpleu1dbdemo2.u1db" } U1db.Index { database: db id: by_type /* You have to specify in the index all fields you want to retrieve The query should return the whole document, not just indexed fields https://bugs.launchpad.net/u1db-qt/+bug/1271973 */ expression: ["things.type", "things.placename"] } U1db.Query { id: places index: by_type query: ["*", "*"] } Page { title: "U1DB ListModel" Column { id: col width: parent.width spacing: units.gu(1) Label { width: parent.width text: "Enter a place to add to list" horizontalAlignment: Text.AlignHCenter } Rectangle { id: ta width: parent.width - units.gu(2) color: "white" height: inp.height * 2 anchors.horizontalCenter: parent.horizontalCenter radius: 5 TextInput { id: inp width: parent.width - units.gu(2) anchors.centerIn: parent onAccepted: inp.adddoc() function adddoc() { /* Indexes do not work on top-level fields. So put everything in the document in a dict called "things" so that they're not top-level fields any more. https://bugs.launchpad.net/u1db-qt/+bug/1271972 */ db.putDoc({things: {type: "place", placename: inp.text}}) inp.text = "" } } } Button { text: "Add" width: ta.width anchors.horizontalCenter: parent.horizontalCenter onClicked: inp.adddoc() } } ListView { anchors.top: col.bottom anchors.bottom: parent.bottom width: parent.width model: places clip: true delegate: ListItem.Standard { text: model.contents.placename control: Button { text: "x" width: units.gu(4) onClicked: { /* To delete a document, you currently have to set its contents to empty string. There will be db.delete_doc eventually. https://bugs.launchpad.net/u1db-qt/+bug/1243395 */ db.putDoc("", model.docId); } } } } } }

You type in a place name and say “Add”; it gets added to the list. The list is stored in U1DB, so it persists; close the app and open it again and you still have your place names. Click a place to delete it.

This covers almost all the remaining stuff that I need to do with data storage. There are a few outstanding bugs still with using U1DB from QML, which I’ve annotated in the source above, and at the moment you have to work around those bugs by doing things that you ought not to have to; once they’re fixed, this becomes more intuitive to use.

Categories: LUG Community Blogs

Aq: Using U1DB in ListViews in Ubuntu SDK apps

Planet WolvesLUG - Thu, 23/01/2014 - 17:24

After explaining [how to use U1DB to store simple bits of information in Ubuntu SDK apps][], and saying that that caters for 80% of my need for data storage, I should explain the other thing I do, which is to store dynamic data; documents created from user data.

To understand more about how to retrieve data from U1DB through Indexes and Queries, you can read the core U1DB documentation. Its code examples are for the Python implementation, and QML works differently for creating documents (as we’ve seen, QML is declarative; there’s no code to write, you just describe a document and it all works), but indexing and querying documents have the same underlying philosophy regardless of implementation, and the core docs explain what an index is, what a query is, and how they work.

First, a simple code example.

import QtQuick 2.0 import Ubuntu.Components 0.1 import U1db 1.0 as U1db import Ubuntu.Components.ListItems 0.1 as ListItem MainView { width: units.gu(40) height: units.gu(71) /* ---------------------------------------------------- Set up the U1DB database Declare a named document ---------------------------------------------------- */ U1db.Database { id: db; path: "simpleu1dbdemo2.u1db" } U1db.Index { database: db id: by_type /* You have to specify in the index all fields you want to retrieve The query should return the whole document, not just indexed fields https://bugs.launchpad.net/u1db-qt/+bug/1271973 */ expression: ["things.type", "things.placename"] } U1db.Query { id: places index: by_type query: ["*", "*"] } Page { title: "U1DB ListModel" Column { id: col width: parent.width spacing: units.gu(1) Label { width: parent.width text: "Enter a place to add to list" horizontalAlignment: Text.AlignHCenter } Rectangle { id: ta width: parent.width - units.gu(2) color: "white" height: inp.height * 2 anchors.horizontalCenter: parent.horizontalCenter radius: 5 TextInput { id: inp width: parent.width - units.gu(2) anchors.centerIn: parent onAccepted: inp.adddoc() function adddoc() { /* Indexes do not work on top-level fields. So put everything in the document in a dict called "things" so that they're not top-level fields any more. https://bugs.launchpad.net/u1db-qt/+bug/1271972 */ db.putDoc({things: {type: "place", placename: inp.text}}) inp.text = "" } } } Button { text: "Add" width: ta.width anchors.horizontalCenter: parent.horizontalCenter onClicked: inp.adddoc() } } ListView { anchors.top: col.bottom anchors.bottom: parent.bottom width: parent.width model: places clip: true delegate: ListItem.Standard { text: model.contents.placename control: Button { text: "x" width: units.gu(4) onClicked: { /* To delete a document, you currently have to set its contents to empty string. There will be db.delete_doc eventually. https://bugs.launchpad.net/u1db-qt/+bug/1243395 */ db.putDoc("", model.docId); } } } } } }

You type in a place name and say “Add”; it gets added to the list. The list is stored in U1DB, so it persists; close the app and open it again and you still have your place names. Click a place to delete it.

This covers almost all the remaining stuff that I need to do with data storage. There are a few outstanding bugs still with using U1DB from QML, which I’ve annotated in the source above, and at the moment you have to work around those bugs by doing things that you ought not to have to; once they’re fixed, this becomes more intuitive to use.

[how to use U1DB to store simple bits of information in Ubuntu SDK apps]: http://kryogenix.org/days/2014/01/23/a-simple-u1db-example-for-ubuntu-sdk-apps

Categories: LUG Community Blogs

Dick Turpin: Definition

Planet WolvesLUG - Thu, 23/01/2014 - 13:01
Email #1 "What is the screen definition of the three laptops you are selling?"

Me: "What do you mean by 'definition'? the screen sizes are two @ 14.1" inches and one @ 15.6" inches."

Email #2 "Not size, definition like 1260x800!"

Me: "Oh you mean 'Resolution' here are the links to the spec sheets."

Email #3 "Precisely"

Aye? I knew I should have become a Gibbon trainer.

Categories: LUG Community Blogs

Aq: A simple U1DB example for Ubuntu SDK apps

Planet WolvesLUG - Thu, 23/01/2014 - 12:42

On Reddit, Aaron Hastings said:

One of the features I’d really like to implement is for the app [a timetable viewer for trains] to save state upon exit. In other words, if a user selected the “Abbey Street” stop, then exited, the app should remember to load Abbey Street on next launch. I’ll have to look into how that’s implemented in Ubuntu.

I’d use U1DB to do that. A simple example:

import QtQuick 2.0 import Ubuntu.Components 0.1 import U1db 1.0 as U1db MainView { width: units.gu(40) height: units.gu(71) /* ---------------------------------------------------- Set up the U1DB database Declare a named document ---------------------------------------------------- */ U1db.Database { id: db; path: "simpleu1dbdemo.u1db" } U1db.Document { id: lastPlace database: db docId: "lastPlace" create: true defaults: { placename: "" } } Page { title: "Simple U1DB demo" Column { width: parent.width spacing: units.gu(1) Label { width: parent.width text: "Enter a place" horizontalAlignment: Text.AlignHCenter } Rectangle { width: parent.width - units.gu(2) color: "white" height: inp.height * 2 anchors.horizontalCenter: parent.horizontalCenter radius: 5 TextInput { id: inp width: parent.width - units.gu(2) anchors.centerIn: parent /* ---------------------------------------------------- Important part number one Retrieve the value from the declared U1DB document ---------------------------------------------------- */ text: lastPlace.contents.placename || "" /* ---------------------------------------------------- Important part number two Save a changed value back to the U1DB document ---------------------------------------------------- */ onTextChanged: lastPlace.contents = {placename: text} } } } } }

This mechanism fulfils about 80% of my data storage needs for Ubuntu SDK apps. You declare a database and a named document; you use the values in that document (documentQMLid.contents.fieldname) declaratively, and to save values, just set documentQMLid.contents.

Of course, you could do this with QML LocalStorage, but do you really want to be constructing SQL statements all day? I don’t. And if you use U1DB now, it keeps the door open for more complicated things later, such as syncing this data between devices, or storing more dynamic data and then querying it, which I should probably write another blog post about if there’s interest.

Categories: LUG Community Blogs

Aq: A simple U1DB example for Ubuntu SDK apps

Planet WolvesLUG - Thu, 23/01/2014 - 12:42

On Reddit, Aaron Hastings said:

One of the features I’d really like to implement is for the app [a timetable viewer for trains] to save state upon exit. In other words, if a user selected the “Abbey Street” stop, then exited, the app should remember to load Abbey Street on next launch. I’ll have to look into how that’s implemented in Ubuntu.

I’d use U1DB to do that. A simple example:

import QtQuick 2.0 import Ubuntu.Components 0.1 import U1db 1.0 as U1db MainView { width: units.gu(40) height: units.gu(71) /* ---------------------------------------------------- Set up the U1DB database Declare a named document ---------------------------------------------------- */ U1db.Database { id: db; path: "simpleu1dbdemo.u1db" } U1db.Document { id: lastPlace database: db docId: "lastPlace" create: true defaults: { placename: "" } } Page { title: "Simple U1DB demo" Column { width: parent.width spacing: units.gu(1) Label { width: parent.width text: "Enter a place" horizontalAlignment: Text.AlignHCenter } Rectangle { width: parent.width - units.gu(2) color: "white" height: inp.height * 2 anchors.horizontalCenter: parent.horizontalCenter radius: 5 TextInput { id: inp width: parent.width - units.gu(2) anchors.centerIn: parent /* ---------------------------------------------------- Important part number one Retrieve the value from the declared U1DB document ---------------------------------------------------- */ text: lastPlace.contents.placename || "" /* ---------------------------------------------------- Important part number two Save a changed value back to the U1DB document ---------------------------------------------------- */ onTextChanged: lastPlace.contents = {placename: text} } } } } }

This mechanism fulfils about 80% of my data storage needs for Ubuntu SDK apps. You declare a database and a named document; you use the values in that document (documentQMLid.contents.fieldname) declaratively, and to save values, just set documentQMLid.contents.

Of course, you could do this with QML LocalStorage, but do you really want to be constructing SQL statements all day? I don’t. And if you use U1DB now, it keeps the door open for more complicated things later, such as syncing this data between devices, or storing more dynamic data and then querying it, which I should probably write another blog post about if there’s interest.

Categories: LUG Community Blogs

Jono Bacon: On Accountability

Planet WolvesLUG - Thu, 23/01/2014 - 02:12

Every so often I see a scenario play out that I find rather disappointing.

It works like this: someone posts a topic to their blog that is critical or controversial. This person can either be a community member, commentator, employee or otherwise; it doesn’t matter who the person is. Then what happens is a series of comments are posted to that blog entry from readers that are critical of the post, thus challenging the author on their views. The author then either deletes the blog entry or disables the comments based on the feedback. In other words, a viewpoint is shared, an invitation for comment is provided, but that invitation is then revoked when the author of the blog post is dissatisfied with the response from their readers.

I have seen this happen countless times over the years and I don’t like this.

I believe we should all be accountable for our words. Our words have the ability to inspire, to entertain, to challenge, but to also hurt. Actions have consequences, and so do words.

As such, when I see someone openly share their thoughts on their blog and invite their readers to provide comments, I see that as a wonderful demonstration of accountability and engagement; debate is a beautiful thing when executed with politeness and respect. To then close that door, seemingly because people disagree with you, is in my mind the equivalent of walking out of a room in the middle of a debate. The excuse when folks are criticized of this behavior is typically “it is my blog and I can run it how I like“.

This is true: it is your blog, and you can run it how you like, but the true measure of a person is not just in what they say, but also in the conversation and discourse that follows.

Now, there are two very important caveats to my view here. Firstly, abusive, threatening, or otherwise offensive content is a perfect candidate for removal and the commentator for banning. We should never tolerate this. Secondly, I can understand the removal of a blog post if there is a legal requirement to do so. In the majority of cases where I have seen posts removed or comments disabled though, it has been for neither of these reasons.

Speaking personally, I have never, ever, switched off comments on my blog posts or deleted posts. Even when the Internet has seemingly come to get me, or when the press pick up on something and are critical, or when I have made a mistake and felt embarrassed at the outcome…I have never switched off comments and never deleted a blog post. This is because I feel I should be and I am accountable for my words.

For me, this is an ethical issue; in the same way I won’t go and re-write or edit a blog post if I get criticism for it (outside of minor grammatical/spelling fixes). My posts are a time-capsule of my thinking at that point in my life. For me to go and edit them would be me re-writing history. A blog is not a regularly updated record of your views (like a book), it is chronological diary of your views and progression as a person. Consequently, my blog is filled with moments from my past that don’t reflect my views, experience, or ideas of today. Some of those posts are even embarrassing. But you know what, those posts stay unchanged, and I am proud that I have never compromised on this accountability.

So with this in mind, I have a simple suggestion for those of you who run blogs: either switch your comments off entirely or always leave them on, but don’t turn them off when you don’t like the reaction from your readers. Polite and respectful debate helps us grow as human beings, helps us evolve our ideas and perspectives, and makes us better people. Let history be our record, not our edited version of history.

Categories: LUG Community Blogs

Mick Morgan: dis-unity

Planet ALUG - Wed, 22/01/2014 - 21:13

The “cloud” is achingly trendy at the moment and new companies offering some-bollocks-as-a-service (SBaaS) keep popping up all over the ‘net. Personally I am extremely unlikely to use any of the services I have seen, I just don’t trust that particular business model.

I checked out the website for one of these companies today following an article I read on El Reg. The company’s website says, in answer to its own question, “what can you do with younity?” that you can:

Spontaneously access any file, from any device, without planning ahead.

Browse all your devices at once.

It further says:

share any file.
ANY FILE STORED ON ANY COMPUTER WITHOUT PLANNING AHEAD, VIA YOUNITY OR PRIVATELY TO FACEBOOK.

(I love that “privately to facebook” bit.)

However, further down it says “Step 1, download younity for Windows or Mac, Step 2, install on iOS”. So, the “any file stored on any computer” claim is just not true if, like me you have a mixture of Linux machines, Android tablet and CyanogenMod ‘phone. I’m pretty sure that claim must breach some advertising standard and I’d complain if I cared about using the product. Fortunately I don’t.

Another “cloud” company making some interesting claims is Backblaze, the company whose blog commentary on consumer grade disks I referenced below. They supposedly offer a service with “unlimited storage”, which “automatically finds files” on your computer and then stores them in the Backblaze cloud with “military-grade encryption”. The website says that “everything except OS files” is backed up, so the system must have the freedom (and permissions) to ferret about on your local disk and then pass the files it finds out to Backblaze’s pods. Forgive me if I don’t like that idea.

The section about encryption is intriguing because it claims:

When you use Backblaze, data encryption is built in. Files scheduled for backup are encrypted on your machine. These encrypted files are then transferred over a secure SSL (https) connection to a Backblaze datacenter where they are stored encrypted on disk. We use a combination of proven industry standard public/private and symmetric encryption methods to accomplish this task. To a Backblaze customer all of this is invisible and automatic. For example, when you create your Backblaze account, we automatically generate your private key that is used to uniquely protect your data throughout our system.

They go on to say:

Upon arriving at a Backblaze datacenter, your data is assigned to one or more Storage Pods where it is stored encrypted. Access to your data is secured by your Backblaze account login information (your email address and password). When you provide these credentials, your private key is used to decrypt your data. At this point you can view your file/folder list and request a restore as desired.

A blog posting by Backblaze’s Tim Nufire gives some detail about how the company encrypts your data. On the face of it, the use of a 2048 RSA public/private key pair in conjunction with ephemeral 128 bit AES symmetric keys (to actually encrypt the data) looks impressive – particularly when the company claims that the private key can be further protected by encryption with a user provided passphrase. But given that the company is US based, that claim bothers me. I am particularly sceptical about any claims that the company is unable to decrypt private data because /they/ generate the public/private key pair and they admit (in the blog post) that they store the private key on their servers. Sorry, but if my data is private enough for me to wish to protect it with strong encryption, then I want to use keys I have generated myself, on a system which I control.

Backblaze’s description of the file restoration process does not give me any warm feeling either. Here is what they say:

When you request a data restore, we do what is known as a cloud restore. This simplifies the data restoration process. For example, let’s assume your hard drive crashes and you get a new hard drive or even a new computer. To restore your data you first log in to Backblaze using a web browser by providing your Backblaze account information (email address and password). Once you have logged in to the Backblaze secure web interface you can request a restore of your data. You do not have to install Backblaze to get your data back. To make this work, we decrypt your data on our secure restore servers and we then zip it and send it over an encrypted SSL connection to your computer. Once it arrives on your computer, you can unzip it and you have your data back.

So if I want my data back, they get a clear text copy of it all before sending it to me. Worse, they even offer to send it to me through the post on a USB disk.

I don’t call that a private recovery system.

Categories: LUG Community Blogs

Aq: Notes on footnotes

Planet WolvesLUG - Wed, 22/01/2014 - 17:53

I use footnotes quite a bit in my posts. Normally for snarky asides, I grant you, but I picked that habit up from Terry Pratchett.

They’re easy to add to WordPress; I use Andrew Nacin’s Simple Footnotes WP plugin, and then all you have to do is drop [ref]footnote text here[/ref] into the text of your post 1 and it takes care of numbering the footnote, displaying it at the bottom of the page, allowing you to link back and forth.

However, as Jake Archibald pointed out on Twitter, footnotes at the bottom of the page feel rather like a print media sort of thing. That’s useful, if someone prints your page out, or if they run it through some sort of “easy reading” service such as Readability or iOS Reader, or if your page gets turned into an ebook — we don’t want to remove that capability. But, as noted, scrolling down to the bottom of the page to read a footnote and then scrolling back up again is stupid. The Simple Footnotes plugin gets half a point for this by making the footnote number (a superscript 1, or whatever) be a link which jumps to the footnote for you, and each footnote has its own “return” link which takes you back to where you were. That’s great on a touch device. If you’ve got a pointer, we have the ability to hover, and this is what tooltips are for, so if we add title="text of the footnote" to the footnote number link, you can see the text of the footnote without having to click and jump around the page at all by just mousing over the number.

Footnotes with a properly-sized hit target

That superscript 1 is a pretty tiny target though, either to click or to hover over. It would be nice if the mouse target were bigger, but we don’t want a bunch of white space around the number. So, a little CSS:

a.simple-footnote { text-decoration: none; position: relative; color: rgba(255,0,0,0.7); /* cater for WP putting too much left spacing in before footnote numbers */ margin-left: -.2em; } a.simple-footnote::after { content: " "; position: absolute; display: inline-block; padding: 1em; margin-left: -1.3em; margin-top: -.3em; border: 1px solid transparent; border-radius: 2px; } a.simple-footnote:hover::after { background: rgba(0,0,0,0.2); border: 1px solid rgba(0,0,0,0.4); }

which I added to Admin > Appearance > Edit CSS in WordPress. Now you get a nice large hit target for your mouse, which lights up when you’re over it, and a tooltip, but your page still contains its footnotes properly when run through Readability or printed (which it might not if you were to use some sort of JavaScript popover library rather than the stuff that’s just built in to the browser and understood by accessibility tools).

Notes:

  1. like this!
Categories: LUG Community Blogs

Aq: Notes on footnotes

Planet WolvesLUG - Wed, 22/01/2014 - 17:53

I use footnotes quite a bit in my posts. Normally for snarky asides, I grant you, but I picked that habit up from Terry Pratchett.

They’re easy to add to Wordpress; I use Andrew Nacin’s Simple Footnotes WP plugin, and then all you have to do is drop [ref]footnote text here[/ref] into the text of your post1 and it takes care of numbering the footnote, displaying it at the bottom of the page, allowing you to link back and forth.

However, as Jake Archibald pointed out on Twitter, footnotes at the bottom of the page feel rather like a print media sort of thing. That’s useful, if someone prints your page out, or if they run it through some sort of “easy reading” service such as Readability or iOS Reader, or if your page gets turned into an ebook — we don’t want to remove that capability. But, as noted, scrolling down to the bottom of the page to read a footnote and then scrolling back up again is stupid. The Simple Footnotes plugin gets half a point for this by making the footnote number (a superscript 1, or whatever) be a link which jumps to the footnote for you, and each footnote has its own “return” link which takes you back to where you were. That’s great on a touch device. If you’ve got a pointer, we have the ability to hover, and this is what tooltips are for, so if we add title="text of the footnote" to the footnote number link, you can see the text of the footnote without having to click and jump around the page at all by just mousing over the number.

[caption id=”attachment_2310” align=”aligncenter” width=”250”][]Footnotes with a properly-sized hit target Footnotes with a properly-sized hit target[/caption]

That superscript 1 is a pretty tiny target though, either to click or to hover over. It would be nice if the mouse target were bigger, but we don’t want a bunch of white space around the number. So, a little CSS:

a.simple-footnote { text-decoration: none; position: relative; color: rgba(255,0,0,0.7); /* cater for WP putting too much left spacing in before footnote numbers */ margin-left: -.2em; } a.simple-footnote::after { content: " "; position: absolute; display: inline-block; padding: 1em; margin-left: -1.3em; margin-top: -.3em; border: 1px solid transparent; border-radius: 2px; } a.simple-footnote:hover::after { background: rgba(0,0,0,0.2); border: 1px solid rgba(0,0,0,0.4); }

which I added to Admin > Appearance > Edit CSS in Wordpress. Now you get a nice large hit target for your mouse, which lights up when you’re over it, and a tooltip, but your page still contains its footnotes properly when run through Readability or printed (which it might not if you were to use some sort of JavaScript popover library rather than the stuff that’s just built in to the browser and understood by accessibility tools).

  1. like this!
Categories: LUG Community Blogs

Dick Turpin: Let me guess.

Planet WolvesLUG - Wed, 22/01/2014 - 12:16
Why do people ring without the most basic of information?

Customer: "Hi have you got an internal fan for a Dell Server?"
Me: "Tower or Rackmount?"
Customer: "Rackmount."
Me: "Which model?"
Customer: "Oh, I'll have to come back to you."
Categories: LUG Community Blogs

Anton Piatek: So Make It has a new location

Planet HantsLUG - Wed, 22/01/2014 - 09:57

(originally posted at http://blog.somakeit.org.uk/2014/01/20/a-place-of-our-own/)

It’s our very sincere pleasure to announce that we will be holding the Grand Opening of our first dedicated space:

On
1st February 2014 at 2pm
(please arrive from 1pm)

At
Southampton Makerspace,
Unit K6, Liners’ Industrial Estate,
Freemantle,
Southampton SO15 3FQ

It’s been a very long road but we’re very excited to finally have a place of our own, allowing us a lot more flexibility and freedom (not to mention warmth!). If you’re not familiar with Southampton Makerspace (or even if you are) you may be interested to read on.

What is Southampton Makerspace?

Wikipedia states:

hackerspace (also referred to as a hacklabmakerspace, or hackspace) is a community-operated workspace where people with common interests, often in computers, technology, science, digital art or electronic art, can meet, socialize and/or collaborate.

But we like to think of Southampton Makerspace as a friendly and inclusive community of people who like making things (be they physical, digital or otherwise) and sharing knowledge, experience and tools. Currently the interests of the current membership seem to focus on subjects of technology (3D printing, microcontrollers (Arduino, etc), robotics, home automation, computers (Raspberry Pi, etc) and programming), wood- and metal-work and more arty disciplines such as costume design. We have a significant number of tools available to facilitate these activities and our members are often willing to lend their own personal tools too.

We are keen to attract new members to expand our horizons and build upon other forms of making such as costume design and props, pottery, photography, fine art, glass blowing, baking, games design and anything else that tickles your creative fancy!

Looking back (or: a brief history of Southampton Makerspace)

Activity interest according to the 2012 SoutHACKton survey

It all started as a call to Southampton hackers in 2009, followed by a tentative first meeting at the Crown Inn to gauge interest. Then there were some further meetups including a visit and workshop from Mitch Altman and Jimmie P Rodgers of Noisebridge, San Francisco. We started joint meetings with a Dorkbot group at the Arthouse, where we effectively merged and continued to meet monthly for the next few years (except one meeting at ASpace). Finally by September 2012 our community had grown sufficiently that getting a space of our own seemed feasible, so we ran a survey, the results of which were very promising. In the mean time we started meeting at DHaus/Etch; a venue that enabled us to hack easily without having to worry about the safety of other patrons.

At the beginning of 2013 we attempted to set up a makerspace as a charity, but this was quickly quashed by the Charity Commission who insisted that we were an educational outfit and thus must register with Ofsted to qualify. Not being fans of bereaucracy but not giving in easily we decided to go ahead the next best way – as a non-profit company limited by guarantee (CLG) – So Make It Ltd. Whilst we were sorting out the paperwork to register with Companies House one of our members had located someone who could help us out with somewhere to meet and keep our stuff – Tim from rideride Cycle Workshop was very supportive of our venture. He very generous allowed us to use a 500sqft area in the corner of their warehouse at just the cost of the electricity we used until we were big enough to afford a space of our own. We continued to grow and met much more frequently at the rideride warehouse; until finally at the end of 2013 we realised we were big enough to set out on our own and we crowdfunded some capital and started looking for places to go.

Having ruled out a large number of places; at the very end of 2013 we finally found a suitable and affordable place – Unit K6. We signed the contract early in January and spent the rest of the month moving in and improving the space. There’s still plenty to do but we’re very proud of what we’ve achieved – and it’s much easier to heat than our previous space!

Looking Forward

The Makerspace has run a number of events covering quadcopter dronesbuild your own mini-Arduino and use it to power your Christmas Lightslearn to program Node.JS and a behind the scenes of rendering in 3DS Max; not to mention our regular 3D printing meetups and of course our thrice-weekly regular openings. But now we have a place of our own with a dedicated workshop room we hope to run many more events in 2014!

Having a space of our own also gives us a lot more freedom – we intend to expand our number of keyholders significantly. Any member can become a keyholder by passing a short list of sensible pre-requisites. We’ll be “hacking” our front door such that any keyholder can get in to the space by scanning an wireless card or similar (like opening the gates at the London Underground using your Oyster card) which gets past the issues of potentially having to revoke all copies of traditional keys. By having more keyholders we should have the space open considerably more than we’ve been able to commit to in the past, and this also relieves the pressure on the trustees freeing them up to work on growing the space in other ways.

Categories: LUG Community Blogs

Mick Morgan: backblaze back seagate

Planet ALUG - Tue, 21/01/2014 - 20:30

In October last year I noted that the Western Digital “Green” drives in my desktop and a new RAID server build looked to be in imminent danger of early failure. That conclusion was based on a worryingly high load-cycle count which a series of posts around the net all attributed to the aggressive head parking features of these drives in order to save energy when not in use. I decided at the time to replace the desktop disk and recycle it to the RAID server. I have since decided to replace the entire RAID array as soon as I can. But which disks to use?

Well, Backblaze, a company which offers “unlimited” on-line backup storage for Mac and Windows users, has just published a rather useful set of statistics on the disks that they use in their storage arrays. The most interesting point is that they use the same domestic grade disks as would be used by you or I rather than the commercial grade ones used in high end RAID systems.

According to the backblaze blog post, at the end of 2013 they had 27,134 consumer-grade drives spinning in their “Storage Pods”. Those disks were mostly Seagate and Hitachi drives, with a (much) lower number of Western Digital also in use. Backblaze said:

Why do we have the drives we have? Basically, we buy the least expensive drives that will work. When a new drive comes on the market that looks like it would work, and the price is good, we test a pod full and see how they perform. The new drives go through initial setup tests, a stress test, and then a couple weeks in production. (A couple of weeks is enough to fill the pod with data.) If things still look good, that drive goes on the buy list. When the price is right, we buy it.

They also noted:

The drives that just don’t work in our environment are Western Digital Green 3TB drives and Seagate LP (low power) 2TB drives. Both of these drives start accumulating errors as soon as they are put into production. We think this is related to vibration. The drives do somewhat better in the new low-vibration Backblaze Storage Pod, but still not well enough.

These drives are designed to be energy-efficient, and spin down aggressively when not in use. In the Backblaze environment, they spin down frequently, and then spin right back up. We think that this causes a lot of wear on the drive.

Apart from the vibration point, I’d say that conclusion was spot-on given the reporting I have seen elsewhere. And the sheer number of drives they have in use gives a good solid statistical base upon which to draw when making future purchasing decisions. Backblaze note that the most reliable drives appear to those made by Hitachi (they get “four nines” of untroubled operation time, while the other brands just get “two nines”) but they also note that the Hitachi drive business was bought by Western Digital around 18 months ago – and WD disks do not seem to perform anywhere near as well as the others in use.

The post concludes:

We are focusing on 4TB drives for new pods. For these, our current favorite is the Seagate Desktop HDD.15 (ST4000DM000). We’ll have to keep an eye on them, though. Historically, Seagate drives have performed well at first, and then had higher failure rates later.

Our other favorite is the Western Digital 3TB Red (WD30EFRX).

We still have to buy smaller drives as replacements for older pods where drives fail. The drives we absolutely won’t buy are Western Digital 3TB Green drives and Seagate 2TB LP drives.

So I guess I’ll be buying more Seagates in future – and I was right to dump the WD caviar green when I did.

(As an aside, I’m not convinced the Backblaze backup model is a good idea, but that is not the point here).

Categories: LUG Community Blogs

Tony Whitmore: Big Finish Day 4

Planet HantsLUG - Mon, 20/01/2014 - 23:27

I had a great time at the weekend, taking photographs at Big Finish Day 4. The event is for fans of the audio production company, who make audio plays of Doctor Who, The Avengers, Dark Shadows, Blake’s 7 and much more. I’ve listened to Big Finish audio plays for years, mostly their Doctor Who range (of course!). The production standards are superb and one of their recent releases is up for a BBC audio drama award. I’ve been lucky enough to do some work for them over the last few months, and was asked to go along to capture some of the event.

In the morning I was wandering around taking candid shots of people enjoying the convention and the panels. It was rather like taking wedding photographs although slightly more relaxed. There are so many different moments to capture in a short time during a wedding ceremony, but a convention panel is a little more static and a good deal longer. Fortunately the urbane Nick Briggs kept the crowd laughing through the morning, and there was a really great atmosphere through the whole event.

https://twitter.com/DudleyIan/status/424504877109510144

In the afternoon I set up a portable studio to take some photos of various Big Finish actors. I was rather pleased with this set up, especially as it all managed it fit in my car! Apart from the background roll.

I really enjoyed working at Big Finish Day, catching up with some of the very nice people I’ve met at recording sessions, and hope to be asked back again!

Pin It
Categories: LUG Community Blogs

Meeting at "The Moon Under Water"

Wolverhampton LUG News - Mon, 20/01/2014 - 15:12


53-55 Lichfield St
Wolverhampton
West Midlands
WV1 1EQ

Eat, Drink and talk Linux

Event Date and Time:  Wed, 22/01/2014 - 19:30 - 23:00
Categories: LUG Community Blogs

Mick Morgan: thrust update

Planet ALUG - Mon, 20/01/2014 - 14:18

I have just run a search for further evidence of the possible compromise at thrustvps and found threads on webhostingtalk, vpsboard, freevps.us and habboxforum amongst others. All of those comments are from people (many, like me, ex-customers) who have received emails like the one I referred to below.

So, I guess thrust /do/ have a real problem.

Categories: LUG Community Blogs

Dick Turpin: Back(up) to basics

Planet WolvesLUG - Mon, 20/01/2014 - 11:15
Customer: "I haven't had an email to say that its failed but I don't think the server backed up. The tape was out the drive and I don't know if that was because nobody pushed it in or if it was ejected?"
Engineer: "Have you tried pushing the tape in to see what's on it?"
Customer: "Oh"

Welcome to Monday morning.
Categories: LUG Community Blogs
Syndicate content