Exporting from raw to jpeg with darktable: a few things I’ve observed

I’ve been playing around with exporting to jpeg lately, because after our recent Easter holiday I had a few hundred pics to process – some of which might get shared with family. In parallel with this I’ve been building Darktable from git master and was racking my brains trying to work out why the export process (from what is effectively a nightly build) was giving me useless output files. By “useless” I mean “had no content except for EXIF info”. Very, very annoying.

After firing up badopen.d and while testing the various intent and profile settings for exporting to file-based storage, I realised that stacks such as this:

0 100408                    openat:return open for '/opt/darktable/share/darktable/color/out/image' failed
             libc.so.1`syscall+0x5
             libc.so.1`__open+0x29
             libc.so.1`open+0xd4
             libc.so.1`_endopen+0xa1
             libc.so.1`fopen+0x29
             liblcms2.so.2.0.3`cmsOpenIOhandlerFromFile+0x73
             liblcms2.so.2.0.3`cmsOpenProfileFromFileTHR+0x4c
             liblcms2.so.2.0.3`cmsOpenProfileFromFile+0x2c
             libdarktable.so`dt_colorspaces_create_output_profile+0x3e4
             libjpeg.so`write_image+0x173
             libdarktable.so`dt_imageio_export_with_flags+0x55e
             libdarktable.so`dt_imageio_export+0xfb
             libdisk.so`store+0x38f
             libdarktable.so`dt_control_export_job_run._omp_fn.0+0x40b
             libdarktable.so`dt_control_export_job_run+0x345
             libdarktable.so`dt_control_run_job+0x21c
             libdarktable.so`dt_control_work+0x41
             libc.so.1`_thrp_setup+0x9d
             libc.so.1`_lwp_start

were probably indicative of something strange in LCMS-land. Sure enough, the ‘always use littlecms2 when exporting’ box was ticked in the core options dialog. Turning that off made a world of difference – no more empty images! I assume that if I can locate an LCMS2 output profile then I’d have more success using it

:)

For giggles (and because I’m still annoyed by this ticket, I decided to go through all the export options and compare the output:










Quick-n-dirty Darktable library backup script

One feature that Lightroom has which I think Darktable needs is the ability to perform a backup of your current catalog from within the application. Lightroom checks every week to see if you’ve made a backup recently, and then prompts you to make one. You can ignore it, of course, but you never know when you’re going to want that backup.

While I figure out a way to make this happen from within Darktable, I’ve got this little quick-n-dirty shell script which I run out of cron at midnight every night:

#!/bin/bash
DTLIB=$HOME/.config/darktable/library.db
DTNEWLIB=${DTLIB}-`/usr/bin/date +%Y%m%d_%H%M`
ECHO=/bin/echo
SQLITE3=/usr/bin/sqlite3

RESULT=`$ECHO .dump | $SQLITE3 $DTLIB | $SQLITE3 $DTNEWLIB`

if [ $? -eq 0 ]; then
    $ECHO "Dumped $DTLIB to $DTNEWLIB"
else
    $ECHO "FAILED to dump $DTLIB to $DTNEWLIB"
    exit RESULT
fi



The 2012 coffee hedge harvest has begun

Regular-ish readers of this blog will remember that one of my grand not-at-all-nefarious plans for our front hedge is to replace the mock orange with coffee. It’s going reasonably well so far – two large plants, one medium and one small:

The Hedge

There’s still a mock orange in there (on the right), and the rest of the hedge is just out of shot on the right. I’ll get to it in the next few years.

Just after lunch, C and I went to harvest the first lot of cherries and got about 20-21g:

http://a.yfrog.com/img863/7496/s60ui.jpg

While we were picking them I noticed that there were several others that appeared to have withered on the branch, and I’m rather annoyed about it. I need to figure out what is going on with them, whether it’s a disease or infestation… I certainly don’t want it spreading!

/images/2012/03/20120330_125731_IMG_9392-300x200.jpg/images/2012/03/20120330_125634_IMG_9391-300x200.jpg/images/2012/03/20120330_125509_IMG_9385-300x200.jpg






Something to be wary of with firefox v11

I pulled in firefox v11 (tarball) so I could test the Strava website’s preference settings as suggested by their support team.

My usual method operation is to have a vpn and non-vpn profile, so that I can have different proxy settings, different bookmarks/cookies/history etc and keep work/non-work separate.

My script to run with this was

#!/bin/sh
MOZ_NO_REMOTE=1
LD_PRELOAD=libumem.so
/usr/bin/firefox -P nonvpn $*

However, with firefox v11, having the **LD_PRELOAD=libumem.so** causes a crash with a stack like the following – for every profile except the default:

-----------------  lwp# 1 / thread# 1  --------------------
 fb157ff7 waitid   (0, 36fb, 8037c20, 3)
 fb108528 waitpid  (36fb, 8037ccc, 0, fa03151c) + 68
 fa031563 __1cVrun_bug_buddy_solaris6F_v_ (8037d38, fdd995d4, 8037d38, fbd6cb04, b, fb1f1000) + 5f
 fa0315d0 __1cUbugbuddy_segv_handle6Fi_v_ (b, fb1f1000, 8037d38, fbd6ca52) + 64
 fbd6cb04 __1cNnsProfileLockSFatalSignalHandler6FipnHsiginfo_pv_v_ (b, 8038028, 8037e28, fb12d697, b, fb1f1000) + c0
 fb153a75 __sighndlr (b, 8038028, 8037e28, fbd6ca44) + 15
 fb14705b call_user_handler (b) + 2af
 fb1472b7 sigacthandler (b, 8038028, 8037e28) + ee
 --- called from signal handler with signal 11 (SIGSEGV) ---
 fdab68c9 malloc_usable_size (8d86bd8, 806d088, 3a10bfd8, fe901314) + 31
 fe90132b moz_malloc_usable_size (8d86bd8, fefd0ab7, a0, fce91758, fe1a0938) + 23
 fce9176a __1cHmozillaHstorage9uX__unnamed_KE3w7ZnwXPWNZNsqliteMemSize6Fpv_i_ (8d86bd8, 18) + 1e
 fab46253 mallocWithAlarm (18) + af
 fab462e7 sqlite3Malloc (18, fabf2a10, fab3d81f, fab4692e) + 57
 fab46941 sqlite3MallocZero (18, fabf1b70, 8038210, fab45c0e) + 21
 fab45c4e pthreadMutexAlloc (1, fabf2c10, 0, fab45ac4) + 4e
 fab45ae7 sqlite3MutexAlloc (1, fabf1b70, 8038280, fabbd4d2) + 2f
 fabbd4f9 sqlite3_initialize (8cb1388, fdd995d4, 80382b0, fce90b66, 8be7414, fdd995d4) + 95
 fce917f2 __1cHmozillaHstorageHServiceKinitialize6M_I_ (8be7408, fe2c0018, 8038430, fce90c54) + 36
 fce90dc6 __1cHmozillaHstorageHServiceMgetSingleton6F_p2_ (814b548, fdd995d4, 8038460, fd2c0a28, 0, fddd15a8) + 1ae
 fce8e1f9 __1cHmozillaHstorageSServiceConstructor6FpnLnsISupports_rknEnsID_ppv_I_ (0, fddd15a8, 8038524, fdc0d53d, 814b548, fdd995d4) + 29
 fd2c0a28 __1cHmozillaOGenericFactoryOCreateInstance6MpnLnsISupports_rknEnsID_ppv_I_ (8d4d218, 0, fddd15a8, 8038524) + 18
 fd309d19 __1cWnsComponentManagerImplbACreateInstanceByContractID6MpkcpnLnsISupports_rknEnsID_ppv_I_ (814b548, fdc0d51e, 0, fddd15a8, 8038524) + 8d
 fd30a8cd __1cWnsComponentManagerImplWGetServiceByContractID6MpkcrknEnsID_ppv_I_ (814b548, fdc0d51e, fddd15a8, 8038594) + 3b5
 fd2b5930 __1cYnsGetServiceByContractID2f6kMrknEnsID_ppv_I_ (80385ac, fddd15a8, 8038594, fd2b4521) + 30
 fd2b453b __1cNnsCOMPtr_baseZassign_from_gs_contractid6MknYnsGetServiceByContractID_rknEnsID__v_ (80385dc, fdc0d51e, fddd15a8, 80385c8) + 27
 fcf342b0 __1cTnsPermissionManagerGInitDB6Mb_I_ (8cb1468, 0, 80389f0, fcf33482) + 1a8
 fcf340fd __1cTnsPermissionManagerEInit6M_I_ (8cb1468, feb599f0, 8038a20, fcf332f2) + d91
 fcf33346 __1cTnsPermissionManagerRGetXPCOMSingleton6F_pnUnsIPermissionManager__ (8038af4, fdd995d4, 8038a50, fd2c0a28, 0, 8517258) + 62
 fcf326f1 __1cbFnsIPermissionManagerConstructor6FpnLnsISupports_rknEnsID_ppv_I_ (0, 8517258, 8038af4, 814b548, 8038af4, fdd995d4) + 29
 fd2c0a28 __1cHmozillaOGenericFactoryOCreateInstance6MpnLnsISupports_rknEnsID_ppv_I_ (8d4d1f0, 0, 8517258, 8038af4) + 18
 fd309c3e __1cWnsComponentManagerImplOCreateInstance6MrknEnsID_pnLnsISupports_rk1ppv_I_ (814b548, 87cbb5c, 0, 8517258, 8038af4) + 6a
 fd30a151 __1cWnsComponentManagerImplKGetService6MrknEnsID_rk1ppv_I_ (814b548, 87cbb5c, 8517258, 8038b40) + 33d
 fcbca291 __1cHnsJSCIDKGetService6MrknCJSFValue_pnJJSContext_Cp2_I_ (87cbb48, 8038de4, 8a5d288, 1, 8038e14, 8038dc0) + 1f9
 fd32be07 NS_InvokeByIndex_P (87cbb48, b, 4, 8038de4) + 51
 fcbee65f __1cQCallMethodHelperECall6M_i_ (8038dc0) + ed7
 fcbeb570 __1cQXPCWrappedNativeKCallMethod6FrnOXPCCallContext_n0AICallMode__i_ (8038ee0) + 23c
 fcbf7045 __1cRXPC_WN_CallMethod6FpnJJSContext_IpnCJSFValue__i_ (8a5d288, 1, f7a00630, fd598c39) + 1cd
 fd599151 __1cCjsMInvokeKernel6FpnJJSContext_n0AICallArgs_n0AOMaybeConstruct__b_ (8a5d288, f7a00640, 1, 0) + 529
 fd5a8d54 __1cCjsJInterpret6FpnJJSContext_pn0AKStackFrame_n0AKInterpMode__b_ (8a5d288, f7a005f8, 0, fd598a85) + 984c
 fd598bfd __1cCjsJRunScript6FpnJJSContext_pnIJSScript_pn0AKStackFrame__b_ (8a5d288, f7819b00, f7a005f8, fd598c39) + 185
 fd599091 __1cCjsMInvokeKernel6FpnJJSContext_n0AICallArgs_n0AOMaybeConstruct__b_ (8a5d288, f7a005f8, 0, 0) + 469
 fd565891 __1cLjs_fun_call6FpnJJSContext_IpnCJSFValue__i_ (8a5d288, 1, f7a005d0, fd565906) + 131
 fd565b17 __1cMjs_fun_apply6FpnJJSContext_IpnCJSFValue__i_ (8a5d288, 1, f7a005d0, fd598c39) + 21f
 fd599151 __1cCjsMInvokeKernel6FpnJJSContext_n0AICallArgs_n0AOMaybeConstruct__b_ (8a5d288, f7a005e0, 1, 0) + 529
 fd5a8d54 __1cCjsJInterpret6FpnJJSContext_pn0AKStackFrame_n0AKInterpMode__b_ (8a5d288, f7a00588, 0, fd598a85) + 984c
 fd598bfd __1cCjsJRunScript6FpnJJSContext_pnIJSScript_pn0AKStackFrame__b_ (8a5d288, f7819a00, f7a00588, 803c900) + 185
 fd59a617 __1cCjsUInvokeGetterOrSetter6FpnJJSContext_pnIJSObject_rknCJSFValue_Ip69A_b_ (8a5d288, f78250a0, 803ca00, 0, 0, 803d828) + 5c3
 fd5d84e3 __1cbAjs_GetPropertyHelperInline6FpnJJSContext_pnIJSObject_3iIpnCJSFValue__i_ (8a5d288, f78250a0, f78250a0, f781dd40, 1, 803d828) + 6bf
 fd5d3a28 __1cUjs_GetPropertyHelper6FpnJJSContext_pnIJSObject_iIpnCJSFValue__i_ (8a5d288, f78250a0, f781dd40, 1, 803d828, 8a4bcac) + 1c
 fd5ad075 __1cCjsJInterpret6FpnJJSContext_pn0AKStackFrame_n0AKInterpMode__b_ (8a5d288, f7a00538, 0, fd598a85) + db6d
 fd598bfd __1cCjsJRunScript6FpnJJSContext_pnIJSScript_pn0AKStackFrame__b_ (8a5d288, f788bb00, f7a00538, fd598c39) + 185
 fd599091 __1cCjsMInvokeKernel6FpnJJSContext_n0AICallArgs_n0AOMaybeConstruct__b_ (8a5d288, f7a00508, 3, 0) + 469
 fd516396 __1cUarray_readonlyCommon4nUArrayForEachBehavior__6FpnJJSContext_rnCjsICallArgs__b_ (8a5d288, 803e748, 803e768, fd5d3a48) + 43a
 fd512518 __1cNarray_forEach6FpnJJSContext_IpnCJSFValue__i_ (8a5d288, 1, f7a004e0, fd598c39) + 30
 fd599151 __1cCjsMInvokeKernel6FpnJJSContext_n0AICallArgs_n0AOMaybeConstruct__b_ (8a5d288, f7a004f0, 1, 0) + 529
 fd5a8d54 __1cCjsJInterpret6FpnJJSContext_pn0AKStackFrame_n0AKInterpMode__b_ (8a5d288, f7a004a0, 0, fd598a85) + 984c
 fd598bfd __1cCjsJRunScript6FpnJJSContext_pnIJSScript_pn0AKStackFrame__b_ (8a5d288, f788ba80, f7a004a0, fd598c39) + 185
 fd599091 __1cCjsMInvokeKernel6FpnJJSContext_n0AICallArgs_n0AOMaybeConstruct__b_ (8a5d288, f7a00470, 3, 0) + 469
 fd516396 __1cUarray_readonlyCommon4nUArrayForEachBehavior__6FpnJJSContext_rnCjsICallArgs__b_ (8a5d288, 80404c8, 80404e8, fd5d3a48) + 43a
 fd512518 __1cNarray_forEach6FpnJJSContext_IpnCJSFValue__i_ (8a5d288, 1, f7a00448, fd598c39) + 30
 fd599151 __1cCjsMInvokeKernel6FpnJJSContext_n0AICallArgs_n0AOMaybeConstruct__b_ (8a5d288, f7a00458, 1, 0) + 529
 fd5a8d54 __1cCjsJInterpret6FpnJJSContext_pn0AKStackFrame_n0AKInterpMode__b_ (8a5d288, f7a002b0, 0, fd598a85) + 984c
 fd598bfd __1cCjsJRunScript6FpnJJSContext_pnIJSScript_pn0AKStackFrame__b_ (8a5d288, f7886b80, f7a002b0, fd598c39) + 185
 fd599091 __1cCjsMInvokeKernel6FpnJJSContext_n0AICallArgs_n0AOMaybeConstruct__b_ (8a5d288, f7a00298, 3, 0) + 469
 fd565aa6 __1cMjs_fun_apply6FpnJJSContext_IpnCJSFValue__i_ (8a5d288, 2, f7a00268, fd598c39) + 1ae
 fd599151 __1cCjsMInvokeKernel6FpnJJSContext_n0AICallArgs_n0AOMaybeConstruct__b_ (8a5d288, f7a00278, 2, 0) + 529
 fd5a8d54 __1cCjsJInterpret6FpnJJSContext_pn0AKStackFrame_n0AKInterpMode__b_ (8a5d288, f7a00188, 0, fd598a85) + 984c
 fd598bfd __1cCjsJRunScript6FpnJJSContext_pnIJSScript_pn0AKStackFrame__b_ (8a5d288, f7849d80, f7a00188, fd598c39) + 185
 fd599091 __1cCjsMInvokeKernel6FpnJJSContext_n0AICallArgs_n0AOMaybeConstruct__b_ (8a5d288, f7a00158, 3, 0) + 469
 fd516396 __1cUarray_readonlyCommon4nUArrayForEachBehavior__6FpnJJSContext_rnCjsICallArgs__b_ (8a5d288, 8043f28, 8043f48, fd5d3a48) + 43a
 fd512518 __1cNarray_forEach6FpnJJSContext_IpnCJSFValue__i_ (8a5d288, 1, f7a00130, fd598c39) + 30
 fd599151 __1cCjsMInvokeKernel6FpnJJSContext_n0AICallArgs_n0AOMaybeConstruct__b_ (8a5d288, f7a00140, 1, 0) + 529
 fd5a8d54 __1cCjsJInterpret6FpnJJSContext_pn0AKStackFrame_n0AKInterpMode__b_ (8a5d288, f7a00038, 0, fd598a85) + 984c
 fd598bfd __1cCjsJRunScript6FpnJJSContext_pnIJSScript_pn0AKStackFrame__b_ (8a5d288, f7863d80, f7a00038, 8045b50) + 185
 fd59973e __1cCjsGInvoke6FpnJJSContext_rknCJSFValue_6Ip47_b_ (8a5d288, 8045c18, 8045c48, 3, 8045fcc, 8045e48) + 5a6
 fd500b01 JS_CallFunctionValue (8a5d288, f7825cd0, f7871ea0, ffffff87, 3, 8045fcc) + 81
 fcbe4149 __1cTnsXPCWrappedJSClassKCallMethod6MpnOnsXPCWrappedJS_HpknTXPTMethodDescriptor_pnRnsXPTCMiniVariant__I_ (8b75f88, 8c50df8, 3, 84db090, 8046420, 8c48d98) + 2119
 fcbdb8fb __1cOnsXPCWrappedJSKCallMethod6MHpknTXPTMethodDescriptor_pnRnsXPTCMiniVariant__I_ (8c50df8, 3, 84db090, 8046420) + 15f
 fd32bd54 __1cSPrepareAndDispatch6FpnOnsXPTCStubBase_IpI_I_ (8bc8018, 3, 80464e4) + 1b0
 fd32be35 __1cOnsXPTCStubBaseFStub36M_I_ (8bc8018, 0, fdaba278, 0) + 22
 fbd66f59 __1cQnsXREDirProviderJDoStartup6M_I_ (8046670, fdab8e7b, fddc1cd8, 0) + a1
 fbd60b9f XRE_main (3, 8047720, 80683c8, 2) + 204b
 08052f9a main     (3, 8047720, 8047730, feffb8fc) + 56a
 0805296d _start   (3, 804788c, 0, 0, 0, 80478b8) + 7d

It was the first part which drew my attention: .. code-block:

--- called from signal handler with signal 11 (SIGSEGV) ---
fdab68c9 malloc_usable_size (8d86bd8, 806d088, 3a10bfd8, fe901314) + 31
fe90132b moz_malloc_usable_size (8d86bd8, fefd0ab7, a0, fce91758, fe1a0938) + 23
fce9176a __1cHmozillaHstorage9uX__unnamed_KE3w7ZnwXPWNZNsqliteMemSize6Fpv_i_ (8d86bd8, 18) + 1e

There were a few google hits for jemalloc in conjunction with

$ /opt/SUNWspro/sunstudio12.1/bin/dem __1cHmozillaHstorage9uX__unnamed_KE3w7ZnwXPWNZNsqliteMemSize6Fpv_i_
__1cHmozillaHstorage9uX__unnamed_KE3w7ZnwXPWNZNsqliteMemSize6Fpv_i_ == int mozilla::storage::__unnamed_KE3w7ZnwXPWNZ::sqliteMemSize(void*)

The one which stood out was https://bugzilla.mozilla.org/show_bug.cgi?id=720682, so I did the obvious thing and removed the libumem allocator from the stack.

Hey presto, all now works with non-default profiles!







How to build a Package archive for Darktable

It occurred to me that while I’ve got a package manifest for Solaris 11 builds of Darktable included in the git repo, I haven’t provided any details on how to actually turn what you install into $PREFIX into an installable package.

At the widest, least-focused view, you create a repo, spin up a pkg.depotd over that repo and then pkgsend to it. Simple!

So having built the bits, you’re given this message:

Darktable finished building, to actually install darktable you need to type:
# cd build; sudo make install

Following those instructions (noting that on Solaris you need to use gmake), you’ll find yourself with built objects under /opt/darktable. Now you need to create the repo:

# /usr/bin/pkgrepo create /scratch/src/REPO
# /usr/bin/pkgrepo add-publisher -s /scratch/src/REPO JMCP

This creates a repo rooted at /scratch/src/REPO, and gives it a publisher attribute of JMCP. You can some information about this repo by using the info subcommand to pkgrepo:

root@build:~# /usr/bin/pkgrepo info -s /scratch/src/REPO
PUBLISHER PACKAGES STATUS           UPDATED
JMCP      9        online           2012-03-14T22:39:46.655791Z
root@build:~# /usr/bin/pkgrepo info -s http://localhost:24601
PUBLISHER PACKAGES STATUS           UPDATED
JMCP      9        online           2012-03-14T22:39:46.655791Z
#
root@build:~# /usr/bin/pkgrecv -s http://localhost:24601 --newest
pkg://JMCP/darktable/darktable@1.0,1.0.0:20120314T223944Z
pkg://JMCP/darktable/darktable-git@0.9.3,1.0.0:20120305T134755Z
pkg://JMCP/darktable/library/OpenEXR@1.7.0,1.0.0:20120130T161629Z
pkg://JMCP/darktable/library/exiv2@0.22,1.0.0:20120130T161616Z
pkg://JMCP/darktable/library/flickcurl@1.22,1.0.0:20120130T161619Z
pkg://JMCP/darktable/library/ilmbase@1.0.2,1.0.0:20120130T162615Z
pkg://JMCP/darktable/library/lcms2@2.3,1.0.0:20120130T161623Z
pkg://JMCP/darktable/library/lensfun@0.2.5,1.0.0:20120130T161625Z
pkg://JMCP/darktable/library/tiff4@4.0.0,1.0.0:20120130T161632Z

(See what I did there? :>)

Now you can spin up the pkg.depotd:

# /usr/lib/pkg.depotd -p 24601 -d /scratch/src/REPO  > /tmp/pkg.depotd.$$ 2>&1 &

I told the daemon to use port 24601, with a repo that’s rooted at /scratch/src/REPO, to send the output to a file named /tmp/pkg.depotd.$$ (where $$ is the PID of this shell), and to background itself.

After this, you need to publish the package to the repo. You’ll notice that I have several packages in my repo; these are the dependencies that I’ve built for Darktable – you can get them here.

$ sudo pkgsend publish  -s http://localhost:24601 --fmri-in-manifest -d / /scratch/src/photostuff/darktable/fromgit/1.0/packaging/Solaris_11/darktable-manifest.pkg5
Password:
PUBLISHED
pkg://JMCP/darktable/darktable@1.0,1.0.0:20120314T223944Z

This pkgsend command publishes the package with a manifest found in /scratch/src/photostuff/darktable/fromgit/1.0/packaging/Solaris_11/darktable-manifest.pkg5 (which includes the pkg fmri) to the depot operating at http://localhost:24601, and looks for the files specified in the manifest starting at the root of my filesystem. When successful, the result is as you see above: the fully-specified pkg fmri.

On my client system I can then (after enabling the JMCP publisher), utter

# pkg install pkg://JMCP/darktable/darktable

and I’ll get the latest version of the package installed.

The tedious part is turning the output from sudo gmake install > install.log 2>&1 into a manifest. However, once you’ve got a basic version figured out, you can make use of /usr/bin/pkgfmt and /usr/bin/pkglint to help you iron out the bugs.

Version 1.0 of Darktable is just around the corner, so I expect to be making a new version of the package available at the usual location within a day of the announcement.




Hey Medicare, what’s going on?

We’re very grateful that we have the Medicare Safety Net available to us; I’ve mentioned the Safety Net previously, and complained about the bureacracy involved. Here’s another annoyance with the bureacracy:

J and I have a shared card which also lists C and A. Pretty normal. J is person #1 on the card, I’m person #2.

Guess what should arrive in today’s post: not one, but two letters addressed TO ME: * Medicare Safety Net – your family could be entitled to higher Medicare benefits*.

Somehow they’ve got me as the Family Contact person, rather than J; rather strange, not least because it’s J who tends to do our interaction with Medicare.

Two A5-sized forms were included (one in each letter), which I have to write on and take to our local Medicare office. I checked, and I cannot provide this information via their website. I can do a bunch of other data provision tasks via their website, why not this?

GRRRRRRRR.