Ryan McConville

About Blog Photos

Milo Contributes to Science

A little while ago Milo (Figure 1) signed up for a science experiment. He wore an accelerometer for around 2 weeks as part of the Feline Activity Study at the University of Bristol. This interesting study is being run by Dr Evelyn Maniaki who is studying the impact of feline degenerative joint disease on mobility and quality of life in cats.


Figure 1. Milo wearing his accelerometer.

Evelyn provided me with the data collected from Milos accelerometer. I plotted Milos activity levels (the metric the accelerometer provides) over each hour of the day. From anecdotal experience, I had a feeling that his behaviour is different when he is alone. One coarse way of measuring this was to divide the data into weekdays (when he spends more time alone) and weekends (when I'm more often home annoying him). This revealed a very interesting change in his patterns of behaviour.

You can see in Figure 2 that Milo is typically very active in the early hours of weekday mornings (4am until 8am), typically inactive from 9am until the evening, where he becomes consistently active until midnight. I can confidently say that 4am is a special hour for Milo where he occasionally seems to go into a frenzy of activity. Otherwise, given that he would typically be alone between 8am and 6pm it appears that his activity levels are somewhat correlated to when he's alone.


Figure 2. Milos activity levels (y-axis) versus hour of day (x-axis) on weekdays (Monday to Friday).

At weekends I'm more likely to be home during the day. Figure 2 plots Milos activity levels over Saturday and Sundays and reveals an interesting change in when he is active. For example, on weekdays he was very inactive between 9am and 1pm, but on the weekend that's pretty much the peak hours of his activeness.


Figure 3. Milos activity levels (y-axis) versus hour of day (x-axis) on Weekends (Saturday and Sunday).

I find it super fascinating that Milos life seems to be considerably affected by my patterns of behaviour.

This was posted on Fri 06 Mar 2020 by Ryan McConville

Erdos Number

This occasionally comes up in conversation and I can never remember so I'm just going to store it here for future reference.

The median Erdos number is 5; the mean is 4.69, and the standard deviation is 1.27.

My Erdos number is 4.

McConville, Ryan; Liu, Weiru; Miller, Paul Vertex. Clustering of Augmented Graph Streams, Proceedings of the 2015 SIAM International Conference on Data Mining (2015), pp. 109-117

Cheng, Jie; Greiner, Russell; Kelly, Jonathan; Bell, David; Liu, Weiru. Learning Bayesian networks from data: an information-theory based approach. Artificial Intelligence 137 (2002), no. 1-2, 43–90.

Greiner, Russell; Hayward, Ryan; Jankowska, Magdalena; Molloy, Michael. Finding optimal satisficing strategies for and-or trees. Artificial Intelligence 170 (2006), no. 1, 19–58.

Alon, N.; Erdos, P.; Gunderson, D. S.; Molloy, M. A Ramsey-type problem and the Turan numbers. J. Graph Theory 40 (2002).
This was posted on Wed 02 Aug 2017 by Ryan McConville

offlineimap with outlook365

Recently the University of Bristol made the switch from the Google to Microsoft platform for email, calendar etc.
As a user of mutt the impact was somewhat minimal for me but I did have to figure out the new settings to get offlineimap to sync my mail and mutt to send it.

Here is what worked for me.

[Account bristol]
localrepository = bristol-Local
remoterepository = bristol-Remote
status_backend = sqlite
maxsyncaccounts = 6

[Repository bristol-Local]
type = Maildir
localfolders = ~/Mail/bristol

[Repository bristol-Remote]
type = IMAP
remoteuser = userid@bristol.ac.uk
remotepass = password
remotehost = outlook.office365.com
remoteport = 993
realdelete = no
ssl = yes
sslcacertfile = /etc/ssl/certs/ca-certificates.crt
folderfilter = lambda folder: folder in ['INBOX', 'Sent', 'Drafts', 'Sent Items', 'Junk E-Mail']

I use mutt directly for SMTP and the settings that work for me are
set smtp_url = "smtp://userid@bristol.ac.uk@smtp.office365.com:587"


Hopefully this helps someone else who knows mutt is the one true way of working with email :)
This was posted on Sun 23 Jul 2017 by Ryan McConville

Rendering LaTeX in Inkscape

You can use the Inkscape extension Tex Text to insert and render LaTeX within your Inkscape graphics.

You can find the latest version here . I'll include all the commands I ran below to get this up and running with the current latest version of Tex Text and Inkscape 0.91 r13725

wget http://pav.iki.fi/software/textext/textext-0.4.4.tar.gz

tar -xvzf textext-0.4.4.tar.gz

cp textext.inx textext.py .config/inkscape/extensions/

Restart inkscape (if required).

Within Inkscape and you can find the new extension under Extensions > Tex Text.
Type in some LaTeX text and it will insert the rendered text into your document.
This was posted on Fri 08 Jan 2016 by Ryan McConville

Limiting Bandwidth with trickle

I have a lot of data and I would like to keep this data safe. For example, I have way too many pictures going back way too long, and I would like to keep these forever !

That means I need a good data backup strategy, and for this I have mostly settled on a combination of tools and scripts. Perhaps I'll write about my backup strategy in detail in the future. For this post it will suffice to say that the tool which handles the backup is duplicity (bonus, encrypted!) and one of the remote locations it backs up to is rsync.net , which I highly recommend.

So far, rsync.net can accept my data at the fastest rate I can push it. However this typically means that the rest of my Internet experience suffers when backups are running as my bandwidth is being saturated.
I had a little look around and came across a nice little tool called tricke which can limit the download/upload bandwidth of a process, all in userland!

It seems to be quite configurable but all I had to do was prepend 'trickle -u 800' to my backup scripts to limit duplicity to using at most 800Kb/s of my upload bandwidth. I quickly verified this with nethogs . Perfect!
This was posted on Fri 08 Jan 2016 by Ryan McConville

_QUB_WiFi Settings

So QUB have begun rolling out a new WiFi solution across the campus, deprecating qub_sec.
The settings for _QUB_WIFI have changed, so for convenience sake I'll list them here.

EAP Method (Authentication): PEAP
Phase 2 Authentication: MSCHAPv2
Identity: student number
Anonymous Identity: leave blank
Wireless Password: your password

Unlike before, after the first time you connect to _QUB_WiFi you need to sign in via some sort of web based portal. Going straight to Google or Facebook won't work due to HTTPS, so try example.com in order to be redirected to the _QUB_WiFi sign in page.

I've tested this on my Linux computer and Android phone.
This was posted on Thu 07 Jan 2016 by Ryan McConville

LinkiePie Personal Backups

While I do have off-site backups for linkiepie.com, why not take the safety of your data into your own hands?

Here I will quickly document a simple method of backing up all your link data stored in LinkiePie using the API. As mentioned in a previous post you can access your API key in the settings page ( https://linkiepie.com/settings/ ).

Using this API key you can issue a request to access a JSON blob of all your data. Let's use curl in a simple shell script to download it and save it to your home directory.
#!/usr/bin/env sh

curl -s "https://linkiepie.com/api/v1/links/?username=YOUR_USERNAME&api_key=YOUR_API_KEY&format=json&limit=0&offset=0" -o "$HOME/linkiepie_backup.json"
This will save a JSON file containing all of the links (and associated data) you have added to LinkiePie. This includes data such as the URL and extracted summary text of each link.

Depending on how much you use LinkiePie this may be quite a large file. I like to use an awesome tool called jq for exploring and extracting useful information from JSON files. Here's an example of using jq for extracting just the URLs from this file.

cat linkiepie_backup.json | jq '.objects[].url'

You can add the above sh script to cron for automatic periodic backups.

Easy :)
This was posted on Wed 06 Jan 2016 by Ryan McConville

Newsbeuter and LinkiePie

Newsbeuter is an open source RSS feed reader for terminals.
It's great for quickly consuming lots of information from websites. One nice feature is that it allows you to 'bookmark' specific links, and that's where LinkiePie comes in.
LinkiePie is a personal project of mine for storing and organising links, somewhat like Pocket and Instapaper, and I would like to send my links directly from newsbeuter to it.
It has a basic API for externally accessing some functionality and accounts are automatically generated API keys. The following is a quick guide for sending your bookmarked newsbeuter links straight to your LinkiePie account.

The first step, of course, is to get a LinkiePie account. When you have registered check out https://linkiepie.com/settings/ to get your API key. This is all you need to programmatically add and retrieve your links with LinkiePie.

Next we will setup a simple script that will interface with newsbeuter. Save the following code in a convenient directory or download it from here .
#!/bin/bash
URL="$1"
USERNAME=YOUR_USERNAME
API_KEY=YOUR_KEY
curl -k -H "Content-Type: application/json" -X POST --data "{\"url\": \"${URL}\"}" "https://linkiepie.com/api/v1/links/?username=${USERNAME}&api_key=${API_KEY}"

Make sure to change YOUR_USERNAME and YOUR_KEY to your own details.
Assuming you have the script in a file called linkiepie-bookmark.sh and have placed it in your home directory, the next step is to update your newsbeuter config file (.newsbeuter/config) with the following:
bookmark-cmd "~/linkiepie-bookmark.sh"
bookmark-autopilot yes

The final step is to set the executable bit on the script so newsbeuter can execute it.
chmod +x linkiepie-bookmark.sh

Restart newsbeuter and try it out by pressing Ctrl+B with an article highlighted or selected. You should then see that article in your LinkiePie account along with an archived version of the important text.

You can retrieve your data from LinkiePie via the API as well. The following request will return the the url, title and extracted text from the links you've added.
https://linkiepie.com/api/v1/links/?username=YOUR_USERNAME&api_key=YOUR_KEY&format=json&limit=10&offset=0

The number of results returned for each request is controlled by the limit parameter and adjusting the offset parameter, which specifies where in the list of results to start from, will allow you to move between these sets of results.
This was posted on Tue 16 Dec 2014 by Ryan McConville

Shutdown Without Sudo From Your Terminal

Using dbus and ConsoleKit it's easy to power off your computer from the terminal. This is useful when you're not using a desktop like GNOME or Unity and you want to shutdown without superuser privileges.

dbus-send --system --print-reply --dest="org.freedesktop.ConsoleKit" /org/freedesktop/ConsoleKit/Manager org.freedesktop.ConsoleKit.Manager.Stop

Of course it's probably a good idea to create an alias for this rather long command.

alias turnoff='dbus-send --system --print-reply --dest="org.freedesktop.ConsoleKit" /org/freedesktop/ConsoleKit/Manager org.freedesktop.ConsoleKit.Manager.Stop'

For the sake of completeness you can also restart and suspend your computer using dbus and ConsoleKit.

To restart use:
dbus-send --system --print-reply --dest="org.freedesktop.ConsoleKit" /org/freedesktop/ConsoleKit/Manager org.freedesktop.ConsoleKit.Manager.Restart

To suspend use:
dbus-send --system --print-reply --dest="org.freedesktop.UPower" /org/freedesktop/UPower org.freedesktop.UPower.Suspend


This was posted on Sun 30 Nov 2014 (4 years, 7 months ago) by Ryan McConville

Getting X11 Keycodes

I wanted to use the key combination 'Fn+F2' to lock my computer with xscreensaver, but wasn't sure how to represent this key combination in the awesome wm rc.lua configuration file. Unfortunately you can't just insert combinations using 'Fn' like you would 'Ctrl', instead you must use the relevant 'Fn' combination keycode.

It turns out that you can use a tool called xev to print out events such as keypresses that occur in a X11 window. Running xev and pressing the desired key combination will output to a terminal information for this event, including the keycode. Doing this I discovered that 'Fn+F2' translated into keycode 160.

Adding the following to the key binding section of my rc.lua worked great.
awful.key({}, "#160", function () awful.util.spawn("xscreensaver-command -lock") end),
This was posted on Fri 31 Oct 2014 (4 years, 8 months ago) by Ryan McConville

Readable Websites From Your Terminal

A quick and easy way get a readable version of a webpage directly from your terminal is to use the dump argument of the lynx text based web browser.

This is great for times when you are working from your terminal and want to view a website, for example to view a link received via IM, but would prefer not to leave your terminal to do so.

While tools like curl and wget will return the HTML file, including the HTML tags, lynx will parse it and return a much more readable version.

The following will output a readable version of this webpage directly to your terminal via stdout.
lynx -dump https://ryanmcconville.com/blog/

lynx

Sometimes you may want to save a readable copy of a webpage to a text file to read later. This can be done by redirecting stdout to a file.
lynx -dump https://ryanmcconville.com/blog/ > blog.txt

Lynx can also be used interactively for browsing the web by dropping the dump argument. For a program that predates the world wide web, it works suprisingly well on many modern websites.
This was posted on Thu 30 Oct 2014 (4 years, 8 months ago) by Ryan McConville

How to Mount a Remote Filesystem using SSHFS

Sometimes I am running experiments on a remote computer but doing the analysis of the experiments on
a local computer. Rather than manually copying or periodically syncing the results data for analysis, it's easier to mount the remote directory locally so that the remote files can be treated as if they are on the local filesystem. SSHFS (SSH Filesystem)
is one such tool that allows you to do this. All you need is SSH access to the remote server and SSHFS installed on the client.

The following instructions were tested on Ubuntu 12.04.
apt-get install sshfs
Now that sshfs is installed we can use it to mount the remote filesystem locally. First we will make a directory where we would like the remote filesystem mounted.
mkdir ~/rfs
Now we use sshfs to mount the remove filesystem...
sshfs user@dest:/dir/anotherdir ~/rfs
..and lets check the contents of the remote directory we just mounted.
ls ~/rfs
If you want to unmount the remote filesystem you can do so with the following...
fusermount -u ~/rfs
This was posted on Wed 03 Sep 2014 (4 years, 10 months ago) by Ryan McConville

QUB Wifi (qub_sec) Phone Settings

EDIT: qub_sec has been deprecated and replaced by _QUB_WiFi. You can find the settings for _QUB_WiFi here .

The settings for the Queen's University Belfast wireless network can be hard to find (for me at least) and when actually found the settings are buried in some PDF file, so I'm posting them here for convenience.

EAP Method: TTLS
Phase 2 Authentication: PAP
Identity: student number
Anonymous Identity: leave blank
Wireless Password: your password

You can optionally choose to use the CA Certificate to verify the authenticity of the qub_sec connection. I'm hosting a copy here for my own conveience .

The names of the fields above are from my Android phone, and they are similar using NetworkManager on Linux. I haven't tried on iOS but it's probably similar too.
This was posted on Sun 24 Aug 2014 (4 years, 10 months ago) by Ryan McConville

Making Debian Look Like Xubuntu

If you prefer Debian over Ubuntu (and Ubuntu derivatives) but like the appearance of Xubuntu, then here’s some steps for making Xfce on Debian Wheezy look a lot more like Xubuntu. These steps are far from complete, but they make it look close enough to the default appearance of Xubuntu for me.

I’m going to assume you already have Xfce installed. I typically do this during the Debian install procedure but if you didn't do that you can still replace the default GNOME desktop environment with Xfce. Here’s a nice overview of how to do both. The key to the appearance of Xubuntu is the Greybird Xfce theme that it uses by default. I prefer to get the latest version directly from the Github repository of The Shimmer Project rather than relying on potentially older packaged versions.

First let's get the theme itself.
wget https://github.com/shimmerproject/Greybird/archive/master.zip
unzip master.zip
su -c 'mv Greybird-master /usr/share/themes/'
rm master.zip


Now, let's get the Greybird icons.
wget https://github.com/shimmerproject/elementary-xfce/archive/master.zip
unzip master.zip
su -c 'mv elementary-xfce-master/* /usr/share/icons'
rm master.zip


The next step is to enable the theme. First go to Settings->Appearance and select 'Greybird-master' under the 'style' tab. Then under the ‘Icons’ tab select 'elementary Xfce dark'. Under the 'fonts' tab I typically enable anti-aliasing, set hinting to slight and set the sub-pixel order to RGB.

After doing this, you should be seeing a theme that looks similar to Xubuntu, but not quite. The next step is to go to Settings->Window Manager and under 'style' select 'Greybird-master'.

After doing this I find that my Debian installation looks close enough to Xubuntu for me, and certainly much better than the rather dated default Xfce theme.

screenshot
This was posted on Sat 19 Jul 2014 (4 years, 11 months ago) by Ryan McConville

Prevent SSH timeouts

The default setting on many SSH servers is to disconnect clients who have been inactive for a set period of time. If you ever left an SSH client running without interacting with it for a while, only to find a message such as Connection reset by peer , then this is likely the cause. I find the easiest way to prevent this is to configure your SSH client to send a null packet to the SSH server, almost like a heartbeat. Edit your ssh_config file setting ServerAliveInterval to:
ServerAliveInterval 60
and ServerAliveCountMax to
ServerAliveCountMax 3
ServerAliveInterval tells your SSH client to send a message every 60 seconds to the SSH server thereby preventing the server from disconnecting you for being idle. I chose the value of 60 but you can increase or decrease this as required. ServerAliveCountMax is the number of times to send the null packet and receive no response, before giving up.
This was posted on Wed 25 Jun 2014 (5 years ago) by Ryan McConville

Bing Image Retrieval V2

I was thinking about how the Bing Desktop application manages to retrieve the Bing image each day, so I used Wireshark to monitor the application as it runs. I noticed that it retrieves an XML document from http://www.bing.com/hpimagearchive.aspx?format=json&idx=0&n=1&mbl=1&mkt=en-ww, which provides the URL for the image. Using this I updated my script I originally posted here . It also looks like we can retrieve the higher resolution 1920x1200 image with this URL from outside the USA too.

#!/usr/bin/python
import urllib2
import os
import sys
import shutil
import argparse

from xml.dom import minidom


def main(save_location):
bing_url = 'http://www.bing.com'
xml_url = 'http://www.bing.com/hpimagearchive.aspx?format=json&idx=0&n=1&mbl=1&mkt=en-ww'

xml = urllib2.urlopen(xml_url)
xml_doc = minidom.parse(xml)
url_base = xml_doc.getElementsByTagName('urlBase')[0].firstChild.nodeValue
extension = xml_doc.getElementsByTagName('url')[0].firstChild.nodeValue.split('.')[-1]
image_url = bing_url + url_base + '_1920x1200.' + extension

try:
img = urllib2.urlopen(image_url)
except urllib2.HTTPError as e:
print(e)
sys.exit(-1)

image_name = image_url.split('/')[-1]

if not os.path.exists(save_location):
os.makedirs(save_location)

if save_location[-1] != '/' or save_location[-1] != '\\':
save_location += '/'

with open(save_location + image_name, 'wb') as f:
shutil.copyfileobj(img, f)


if __name__ == "__main__":
script_dir = os.path.dirname(os.path.realpath(__file__))
parser = argparse.ArgumentParser(description='Download todays Bing image.')
parser.add_argument('-d', '--dir', dest='save_location', action='store',
default=script_dir,
help='Directory to store the downloaded image (default: directory of this program)')

results = parser.parse_args()

main(results.save_location)


You can also find the repository at https://bitbucket.org/ryanmcconville/bing-daily-image-retriever
This was posted on Tue 24 Jun 2014 (5 years ago) by Ryan McConville

SQLite3 Show Table Information

When working with an SQLite3 database I occasionally forget a column name that I need to know. This tends to be followed by being unable to remember how to find out column names (and other information) for a table. Future me, here's how to do it.

If you know the table name, great. If not, you can ask SQLite3 to list all tables with the following command:
.tables

Once you know the table name, you can find the table information with the following:
PRAGMA table_info(table-name);

Each column in the table is printed out on a new row as follows:
cid|name|type|notnull|dflt_value|pk

A real world example:
3|date_retrieved|TIMESTAP|0||0

More information on this can be found here: http://www.sqlite.org/pragma.html#pragma_table_info
This was posted on Tue 24 Jun 2014 (5 years ago) by Ryan McConville

Limiting Disk IO on Linux with ionice

As part of my research I tend to be working with relatively large files. One 150GB file I work with particularly often involves moving an updated version of it from one directory to another. On my Ubuntu desktop this causes everything to become unresponsive for the duration of the transfer.

One solution to this is ionice which lets you set the IO priority of processes. It's kind of like regular nice but for IO specifically. I found that the follow command, which sets the scheduling class to be 'Idle', let my desktop remain completely responsive while the transfer was taking place.

ionice -c 3 cp $src_file $dst_directory
This was posted on Tue 24 Jun 2014 (5 years ago) by Ryan McConville

Android Wikipedia Widget Stats Update

On the 24th of April 2012, I published an Android application, that I developed over the course of a week, onto the Android store. I initially developed it for my own use as I thought it would be cool to see the daily featured Wikipedia article on my phone homescreen each day. For almost a year I got very few downloads, and I kind of expected that. However I kept publishing updates as I discovered bugs and thought of improvements, such as adding in the 'today in history' section as an option.

A couple of these updates must have been useful, as a few of them resulted in a spike in the number of downloads. These can be seen in the image below.

install graph


At this moment in time I have over 15,000 installs, with around 30% of users still having it installed. I'm quite surprised I have got so many downloads, and I feel somewhat guilty for not continuing to make improvements due to being occupied with other things.

Oh, and the link to the application on the Play store is: https://play.google.com/store/apps/details?id=com.rmc.dfaw

This was posted on Tue 24 Jun 2014 (5 years ago) by Ryan McConville

Windows Battery Recorder

Continuing in my effort to create blog posts of old bits of code I can find lying around on my computer and internal git server, I decided to post this small C++ project. It logs the percentage of battery left at specific intervals into a SQLite3 database. Again, this is one of my first C++ projects so I'm not exactly confident it's done to a high standard. :)

Nonetheless, the code is included below and a the git repository on bitbucket can be found here: https://bitbucket.org/ryanmcconville/windows-battery-stats/

#include "stdafx.h"
#include "iostream"
#include "sstream"
#include "time.h"
#include "vector"
#include "iostream"
#include "Windows.h"
#include "fstream"
#include "Shlobj.h"
#include "stdio.h"
#include "WbemCli.h"
#include "sqlite3.h"

using namespace std;

//get the users home directory
wstring GetHomeDirectory(){
PWSTR path;
SHGetKnownFolderPath(FOLDERID_Profile, 0, NULL, &path);
return path;
}

void WriteDefaultConfiguration(char *defaulttime){
ofstream config_file;
config_file.open("config.ini", ios::out);
config_file.write(defaulttime, strlen(defaulttime));
config_file.close();
}

int ConvertToMilliseconds(int interval){
return ((interval * 60) * 1000);
}

int ReadConfigurationFile(){
char defaulttime[7] = "10";
char line[7];
ifstream config_file;
config_file.open("config.ini",ios::in);
if(!config_file.is_open()){
WriteDefaultConfiguration(defaulttime);
config_file.open("config.ini",ios::in);
if(!config_file.is_open()){
return ConvertToMilliseconds(atoi(defaulttime));
}
}
config_file.get(line, 10);
int interval;
interval = atoi(line);
int interval_milli = ConvertToMilliseconds(interval);
return interval_milli;
}

sqlite3* CreateDatabase(){
sqlite3 *db;
char *err = 0;

int rc = sqlite3_open("battery_stats.sqlite", &db);

if(rc){
fprintf(stderr, "cant open database %s\n", sqlite3_errmsg(db));
}

char *sql = "CREATE TABLE IF NOT EXISTS stat(" \
"date DATETIME NOT NULL," \
"battery_percentage INT NOT NULL," \
"ac_connected INT NOT NULL);";

sqlite3_stmt *statement;
if(sqlite3_prepare_v2(db, sql, -1, &statement, 0) == SQLITE_OK){
sqlite3_step(statement);
}
sqlite3_close(db);

return db;
}

int _tmain(int argc, _TCHAR* argv[]){

//hide console window
HWND hWnd = GetConsoleWindow();
ShowWindow(hWnd, SW_HIDE);
int interval_time = ReadConfigurationFile();
sqlite3 *db = CreateDatabase();

while(true){
SYSTEM_POWER_STATUS status;
::GetSystemPowerStatus(&status);//get battery life
int per = status.BatteryLifePercent;
//get time
time_t rawtime;
struct tm* printtime;
time(&rawtime);
printtime = localtime(&rawtime);
string timenow = asctime(printtime);
//create structure to hold percentage as a string
char strPer[4];
//copy int percentage to string
itoa(per, strPer, 10);
//open textfile to write to
ofstream batteryStats;
batteryStats.open(GetHomeDirectory() +L"/battery_stats.txt", ios::app);
int AC = (int) status.ACLineStatus;
string acconnected;
if(AC){
acconnected = "AC connected";
}else{
acconnected = "AC disconnected";
}

if(!batteryStats.is_open()){
cout<< "Error";
}else{
batteryStats << "\n" << timenow < }

sqlite3_stmt *statement;
char *sql = "INSERT INTO stat (date, battery_percentage, ac_connected) VALUES(?, ?, ?);";
if(sqlite3_prepare_v2(db, sql, strlen(sql), &statement, 0) == SQLITE_OK){
sqlite3_bind_text(statement, 1, asctime(printtime),strlen(asctime(printtime)), 0);
sqlite3_bind_int(statement, 2, per);
sqlite3_bind_int(statement, 3, AC);

sqlite3_step(statement);
sqlite3_finalize(statement);
} else {
fprintf(stderr, "cant update database %s\n", sqlite3_errmsg(db));
}

batteryStats.close();
//sleep for specified time
Sleep(interval_time);
}
}

This was posted on Tue 24 Jun 2014 (5 years ago) by Ryan McConville

Bing Image Retrieval

A few years ago, when learning Python, I wrote a little script that will retrieve and save to disk the current bing.com background image. The directory where the image is saved is the first argument. You can run it via cron if you use a Linux based OS or via Windows Task Scheduler if you use, well, Windows.

I did notice that if you access bing.com from a USA IP address then you have the ability to retrieve a higher resolution 1920x1200 image, whereas from the UK (and likely elsewhere) you can only access the 1366x768 image.

import re
import urllib2
import os
import shutil
import sys

bing_url = 'http://www.bing.com'
save_location = sys.argv[1]

p = re.compile('/az/.+?(jpg)')
resp = urllib2.urlopen(bing_url).read()

image_url = p.search(resp).group()
if '_EN-US' in image_url:
res = image_url.split('_')
extension = image_url.split('.')[-1]
image_url = '_'.join(res[:-1]) + '_1920x1200.' + extension

try:
img = urllib2.urlopen(bing_url + image_url)
except urllib2.HTTPError as e:
print e
sys.exit(-1)

image_name = image_url.split('/')[-1]

if not os.path.exists(save_location):
os.makedirs(save_location)
with open(save_location + image_name, 'wb') as f:
shutil.copyfileobj(img, f)


Edit: I have since updated this script with some nice new changes. You can find that post here: https://ryanmcconville.com/blog/post/bing-image-retrieval-v2/
This was posted on Mon 23 Jun 2014 (5 years ago) by Ryan McConville

QUB Email Settings

Last week my Queen's University Belfast (QUB) IMAP settings stopped working. After tracking down that this was the reason I wasn't receiving new emails, I discovered the following IMAP and SMTP settings which now work. I have tested these settings with Outlook, Thunderbird and my Android phone. I assume they will also work with iOS and OSX clients too.

Note that there seems to be two different types of email accounts currently in use within QUB, but the following should work for 'Office 365' accounts, i.e. the new ones.

IMAP
Server name: outlook.office365.com
Port: 993
Encryption method: SSL

SMTP
Server name: smtp.office365.com
Port: 587
Encryption method: STARTTLS

User name: studentnumber@ads.qub.ac.uk.


Staff Accounts
Here are the settings that work for me to get staff email to work over IMAP/SMTP.
IMAP
Server name: owa.qub.ac.uk
Port: 993
Encryption method: SSL/TLS

SMTP
Server name: smtp.qub.ac.uk
Port: 587
Encryption method: STARTTLS

User name: staff number
This was posted on Mon 23 Jun 2014 (5 years ago) by Ryan McConville

PGP Public Key

Here is a copy of my PGP public key. If you don't know what that is and would like to learn more then I suggest reading this . This website is currently served over HTTPS so it should be reasonably secure method of sharing the key. You can also find it in all the usual places, such as the MIT key server here .
Key fingerprint = F2B4 BD37 3C2B 141E FD97 6B58 DFDE 9735 A4F0 944D



-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1

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
tjoWvk4iLvNKMognEm0b1bKDzppAIRjw5ABm3D9tGdnvYQJQQVzRTdLMOlAwoaqa
Yokmuoi90z9zdBj6nd8WAs3uzweS5QoktPdpm7KUXvryFFSH9ehoe2t/r0tkPKSm
LWvLoLUKna1EU+o2dyJqHT7tQehjEtZdRtRqLLQtvifA9VSS6MED3kX4DCjrj98F
9WBX9hUwo1+TRwI+3AitpmKt/s5AYEZ50ticZRHE7M+ikoxEvfPo0ZSG5dzKmcht
zcOzcM35196wXG4AZbJ8RhktkcAgC2EG7azDtIkATvjhJR2uKu9oYzOeKtzfoJy7
jDQ6hpCI281TEbEHdvXtVC+lohlEF9wLkikspx/bo0h5eLL7FQNCkGrDC2HoXPSM
cenveU1Yh6Vi6sCsPVmkBMfPiLaW+7lGkidosjWAwk1IEdI/KNB4IuL4d/ggggbq
L+gClQbG7WP4IZcE4mgZW2cnSgTcHB6DjYVlQ8hr7w2a2YueJSUye5ilsJ0pQqCp
lhHkjPe8N0gHvsqZktJ5dt6dkDqUkCC7wF3PEUssvLIHGdbVX7RNYjSKuZRakF3G
1DQky6Huba3+pI8IlHmLg8lPhNAMkqNiU6lRi5FTmZQq5LQpUnlhbiBNY0NvbnZp
bGxlIDxybWNjb252aWxsZTA3QHF1Yi5hYy51az6JAjgEEwECACIFAlRjOHECGwMG
CwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEN/elzWk8JRNkVEP/2cgjK2ZQtUi
D2poDL9oIfIuPbNhDwnj9ws1qKEZUHwL+hmZxbM0Z3k87PS7HS0Y+nIEkny0vqUE
K0PHCnCYYjHGXUadnTFjxV1LPivxmLhE/b2j3i5hnlPIvUa8OYynuw19N58ssXvy
LQegi63IquURjYQ+mQURpGrT1z+NZoqs9OrWHuZL1x0YGSlqi4HBSsvsCBafaCrg
Q3Kx2JI0QrJuhcNjcblgOOmk/AlTZ3gdOh5daQoxa5eFGXq/5H8Km0p91oIHwSzd
P6NzSAlEf4ngG26LDsUX+EKCx08534Vs259dZEW2g5fCd4LKezMUhQED54sKmZZt
Rozqy4ZM2IpH/1CuZnSw2BZ3hbeK5OTOP6K4CFdCHPsWcRRgBZYCiVLkuev0c3oF
pY8Dc9+UunWLii7EMLKcfWlKmnu/0qgaOtlLIdX0xx1CttudDWPnqZlnU/qAf7sJ
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
Y273
=x0tf
-----END PGP PUBLIC KEY BLOCK-----
This was posted on Thu 20 Mar 2014 (5 years, 3 months ago) by Ryan McConville

Acer C720 Chromebook

Recently I got an Acer C720 Chromebook and wanted to write a little bit about what I think of it. Basically, it's a small 11.6 inch screen laptop but instead of running a more typical operating system such as Windows 7 or Debian/Ubuntu (more on that later), it runs an operating system from Google called ChromeOS. To the user, it's pretty much just the Chrome web browser with some basic but nice operating system type features around it, such as a lock screen and notification area. While the world seems to be heading towards a cloud-based-always-online type environment, I'm not so keen on that idea on my own personal computers. So why did I get it? I got it because of its low price point (~£200), good battery life, good build quality, and its ability to run a more conventional operating system such as Debian or Ubuntu.

First, the build quality feels very good for the price point. I have used laptops that cost twice the price but don't feel as well built. It has a very plain appearance, definitely not as quirky and fun as it's competitor the HP Chromebook 14, but that's a positive for me. It's weighs just over 1.1 kg, which is a nice change compared to my older laptop that weighs about 2.7 kg. So while I may notice and appreciate the lightness more than some, I find it very portable. The 11.6 inch screen has a resolution of 1366x768 so while the pixel density for the screen size is pretty good, the quality of the display itself leaves a lot to be desired due to the dull washed out colours and poor viewing angles. The battery life on the C720 is fantastic however and I'm getting around 8 hours of use on a full charge, not much less than Acers claimed 8.5 hours.

To be honest, I haven't spent very much time in ChromeOS since my current way of working just doesn't fit into the web based workflow that ChromeOS kind of forces you to have. However, what I did see in the short time I used it was promising. The experience was smooth and everything worked nicely. I would have no hesitations recommending it to someone who doesn't need access to a more traditional operating system. However not using ChromeOS much doesn't mean I haven't been using the C720 chromebook much! In fact, it's quite the opposite. One of the first things I done when I unboxed it, after a quick tour of ChromeOS, was setup Ubuntu using crouton.

Crouton is a set of scripts that makes setting up a chroot extremely easy. If you aren't familiar with what a chroot is, don't worry. Crouton has abstracted away all of the messy details and all you really need to know is that it's a way of getting another Linux distribution running on your chromebook. It requires enabling 'developer mode' and you can do this by holding down esc and refresh and then pressing the power button. This puts it into 'recovery mode' and if you press CTRL+D at the recovery screen, you will reboot into ChromeOS with developer mode enabled. This process wipes all user data stored on the device including ChromeOS user accounts. Once you are running ChromeOS with developer mode enabled you can follow the instructions found in the README in croutons github repository to get your new operating system up and running.

However a brief overview of the steps required is as follows:
Download the crouton script from the following URL: https://goo.gl/fd3zc This will save to your 'Downloads' directory.

Open a crosh shell using CTRL+ALT+T in ChromeOS and then type shell . Note this only works in developer mode.

Now type sudo -e ~/Downloads/crouton -r precise -t unity -e .

This will install the 'precise' release of Ubuntu with the Unity desktop. The final -e switch encrypts the chroot.

Simply running sudo -e ~/Downloads/crouton will provide you with more information, including how to find out about other releases that you can install.
The rest is pretty much automated and after it's complete you will have your chroot setup.

I typically enter my chroot with the command sudo -b startunity . The -b switch backgrounds the process so you can close the ChromeOS tab.

You can switch between the chroot and ChromeOS with CTRL+SHIFT+LEFTARROW and CTRL+SHIFT+RIGHTARROW .

Since the C720 has a x86 CPU, it doesn't suffer from having a restricted set of applications like ARM based chromebooks when running an OS like Debian. The C720 contains a dual core 1.4GHz Celeron CPU (2955U) with the current generation Intel Haswell microarchitecture making it an efficient and capable little device. So while I won't be keen to run any very intensive tasks on it, due to the limited 2GB of RAM and 16GB of SSD storage, it can run pretty much all of the applications you would expect.

While using crouton does have a negative effect on the default security of the device, you can take steps to recover some security. These are just some general tips and in no way comprehensive. First, make sure you set a root password on ChromeOS since it's not set by default when developer mode is enabled. You can do this with the following command:
sudo chromeos-setdevpasswd
Crouton supports encryption of your chroot and this is done by using the -e switch with the crouton script.
When using Unity on 12.04 I found that it was not possible to lock your computer on a default install, but that can be solved by installing the relevant package (gnome-screensaver) manually.

In summary, I am very happy with the C720 as it's a lightweight, long lasting and reasonably well performing Linux laptop.
This was posted on Tue 11 Feb 2014 (5 years, 4 months ago) by Ryan McConville

LinkiePie

So as a follow up to my previous post, I decided that it would be a good idea to write a little bit about a project that I spent some of my free time working on. Now that I have started my PhD I have less time for working on side projects, so this is probably a good landmark. It's called LinkiePie (https://linkiepie.com) and I started it whenever I was compiling links for the 'stuff I have found interesting recently' posts on my blog. The idea of LinkiePie is that it's a place to store, organise and categorise interesting stuff you find on the web.

Basically, a LinkiePie is a list where you store the links to the interesting stuff you come across on the web, and you can create as many of them as you want. So, for example, you can have a LinkiePie for links related to a specific web development technology you like, or one for links related to some topic you are researching, or maybe a LinkiePie for links you think some of your friends would like.

You can also make your LinkiePies public so that you can share them with others. Making it public will give you a URL that you can send to someone else and they will be able to see whatever you put into that LinkiePie.

One other feature I thought would be pretty cool is grabbing the relevant content of the page that you are storing. So if it disappears or changes in the future, you still have a copy of what you found interesting at the time.

This is very much a work in progress, but as I said, I thought I would write about what I have done so far.

Here are two LinkiePies for the first two 'stuff I have found interesting recently' posts on my blog.
https://linkiepie.com/pie/ryan/interesting-things-0/
https://linkiepie.com/pie/ryan/interesting-things-1/
This was posted on Tue 12 Nov 2013 (5 years, 7 months ago) by Ryan McConville

Stuff I have found interesting recently - Part 1

https://www.facebook.com/notes/facebook-engineering/scaling-apache-giraph-to-a-trillion-edges/10151617006153920

http://haxit.blogspot.co.uk/2013/08/hacking-transcend-wifi-sd-cards.html

http://steve-yegge.blogspot.co.uk/2006/03/execution-in-kingdom-of-nouns.html

https://blog.mozilla.org/javascript/2013/08/01/staring-at-the-sun-dalvik-vs-spidermonkey/

http://blogs.hbr.org/cs/2013/04/the_science_of_what_we_do_and_dont_know_about_data_visualization.html

http://highscalability.com/blog/2013/5/13/the-secret-to-10-million-concurrent-connections-the-kernel-i.html

http://contextis.co.uk/research/white-papers/pixel-perfect-timing-attacks-html5/

This was posted on Thu 15 Aug 2013 (5 years, 10 months ago) by Ryan McConville

Stuff I have found interesting recently - Part 0

http://www.denbeste.nu/essays/futurecs.shtml

http://www.devttys0.com/2013/06/differentiate-encryption-from-compression-using-math/

http://www.economist.com/news/briefing/21582042-it-getting-easier-foresee-wrongdoing-and-spot-likely-wrongdoers-dont-even-think-about-it

http://matt.might.net/articles/books-papers-materials-for-graduate-students/

http://blog.hyfather.com/blog/2013/04/18/ssh-uses-four-tcp-segments-for-each-character/

http://talks.golang.org/2013/oscon-dl.slide

http://matt.might.net/articles/what-cs-majors-should-know/
This was posted on Tue 06 Aug 2013 (5 years, 11 months ago) by Ryan McConville

Hello, World!

Hello, this is my first blog post!

I'm not sure how often I'll update this blog as I am just building this for fun and also as an opportunity to build more software with Python. Although I figured I should at least make a hello world post! :)
This was posted on Sat 23 Mar 2013 (6 years, 3 months ago) by Ryan McConville