Friday, June 14, 2013

Hanging with coders in Trinidad & Tobago

We met at the University of the West Indies, St. Augustine, Trinidad Campus

I never regret meeting up with the real people on the ground to get a pulse of what's up. Today* I had a meetup with a few persons from Trinidad's tech scene. Including +Kyle E. deFreitas, a teaching assistant in the Computer Science Department of the University of the West Indies St. Augustine, +Vani Kalloo a PhD student at UWI, Moodle guru +Anil Ramnanan who works at UWI's Open Campus and was a participant in Google Summer of Code, Kenfield Griffith and Crystal Peters of mSurvey. I decided to borrow +Shannon Clarke's "tell us your worst or most interesting developer experience" approach.

* note: it was Today on the day that I started this post, it is now many days later. I've decided not to alter it.
Vani is a PhD candidate in the Computer Science Department, she's working on game content for teaching maths. Her biggest fear is related to live demos going wrong, while she didn't get into specifics most of us knew exactly the type of thing she was talking about. If there's any consolation it might be that even Bill Gates' Traf-O-Meter was a failed demo before Microsoft found their feet. I also wondered if there might be some synergy between here work and what Edufocal is doing in Jamaica

Vani and Kyle

Kyle de Freitas shared with us about an initiative that he was involved with to develop "apps for the benefit of Trinidad and Tobago" (my words, I probably got some details wrong). For various reasons they deployed to Google app engine (GAE). The platform was new for all involved and this brought the usual learning curve related challenges, additionally they had to figure out (or are still figuring out) how ensure that the project will live after the initial work, one of his concerns was whether they would find expertise with the GAE related skillset to continue the development afterwards.

Kyle who is orginally from St. Vincent also runs a small company called Knowledge Hope (I really like the name) with 3 directors. Finally he mentioned a group called "Code Jammers" which in summary "encourages people to do great things" so far members of the group have placed in almost every [app/technology] competition they've partipated in.


Crystal (centre) and Kenfield (to the right) (yeah it's a bad pic)


Crystal Peters and Kenfield Griffith are part of the mSurvey team that develops tools for mobile data collection, their solution is used beyond the shores of Trinidad and Tobago as far as Kenya.

Kenfield's scary developer moment was related to a system that he developed in his earlier life as a which effectively overloaded Google's email servers at the time. The solution did a lot of parsing on the headers in SMTP messages.

Anil (in the foreground) (another bad pic)

Anil Ramnaran works with the Moodle Learning Management System platform and was tasked with creating a system that works in parallel with Moodle to integrate student registration and other academic administrative activities more tightly with Moodle (again, I may have some details incorrect). I certainly know who to reach out to once I need to do tinkering with the Moodle API.

David Bailey (right)

+David Bailey joined us later on in the meetup, he works with Infolink Services Ltd. which exists to allow the national inter-bank ABM systems to communicate properly with each other (fun job). He also does programming with mSurvey. He shared with us the challenges (not Infolink specific, in case his employer is reading this) of dealing with inheriting an existing system and grappling with whether to start from scratch or to extend said system. Often a system can be so straight jacketed that starting from scratch is faster than discovering and extending the existing system. Documentation may be a solution to the "starting from scratch" issue and Anil advocated for proper use of version control and David suggested further that developers should "put the documentation in the code".

Limited Customer Imaginations

David also raised the issue of customers' limited imaginations limiting projects which I totally get. If you as a developer have been around and are in tune with new developments you probably have a broader view of what is possible. Limiting your deliverables to what the customer imagines can be a bit of a straight jacket. When possible you really should find ways to convince customers not to hold on too tightly to ideas and to favour outcomes instead.

Wednesday, June 12, 2013

Modern Plone Practices Poster now translated!

Since my post this morning about Modern Plone Practices, I was contacted by +Leonardo J. Caballero G., he volunteered to translate the poster into Spanish.  So now we have a Spanish version.  If you want to translate it into another language let me know and I'll send you an invite to the LucidChart source file.

Print quality versions are available too.

Modern Plone Best Practices (or How to be ready for Plone 5)

This poster is meant to keep developers on the "golden path" it is based on tips from Eleddy's Everything you never wanted to know about Plone 5. I'm hoping it will steer developers (old and new) in the right direction. There are really 6 tips, but 5 for Plone 5 sounds so much better than 6 for Plone 5, so I sneakily combined 2 tips :).



Monday, June 10, 2013

A vertical image slider with jQuery and Plone's Products.Carousel

My goal was to create a vertical sliding effect to allow a visitor to experience tall images in a small area.
The images were made too tall for the viewing area and then, using jQuery's animate, were made to slide upwards through the viewing area. I used Products.Carousel but I'm sure a similar effect could be achieved with collective.carousel.

Products.Carousel provides a simple interface for managing the banners making it easy to hand this system over to non-technical administrator. They will be able to benefit from the built-in workflow support (ability to expire, schedule, publish and unpublish banners).

(Products.Carousel has a simple event system with basic documentation (see: http://plone.org/products/carousel/#carousel-events), so it is possible to take advantage of event listeners to do fancier stuff)

The Structure

The viewing area is wrapped with the css selector span.carousel-image 
The carousel images can be selected based on a general selector such as .carousel img or based on the unique id associated with the slider

The Implementation

The key ideas are as follows:
  • We add custom css to match the viewing area class (called "carousel-image") to size we configure for the carousel.
  • We make the source images taller than the carousel viewing area.
  • We add custom css that enforces the height of the carousel images so they inherit the viewing area size.
  • We add custom javascript which will slide the image through the viewing area and is triggered upon changing of slides.

The CSS

To save on further explanation I've included annotations that explain the key CSS (There is other supporting CSS but it is more incidental to the functionality). In this example the carousel has the unique id "carousel-14937891799".

/*
 rule for image, overrides the default image size and enforces
the height of the carousel images to 400px tall
 */
#carousel-1493789179 img {
width: 961px;
height: 400px;
position:relative;
}
/* rule for the span on top of the image.
switches it to behave like a block then makes the viewing area only
200px tall while preventing overflow
 */
.carousel-image {
height: 200px;
overflow: hidden;
display: block;
}

The Javascript

I had to use a CSS Inspector (the one that comes with Chrome) to determine the ideal displacement of the image which worked out to be 197px. Here's the jQuery animate syntax.
jQuery('.carousel img').animate({top:"-=197px"},9000);

A simple and complete script might look like this (In my case I just added the line to a existing jquery custom script that runs on load).
):

jQuery(document).ready(function () {
        jQuery('.carousel img').animate({top:"-=197px"},9000);
)}; 
update: I decided to make use of Products.Carousel's event system, the result the following lines of code being added to my custom javascript:
jQuery(document).ready(function () {
     $("#carousel-1493789179 img").animate({top: "-=197px"})
   
    /* reset the slides to the top just before animation */ 
$('.carousel').bind('beforeAnimate',
        function () {
                    jQuery('.carousel img').css('top','0px');
    });
    /* initiate slide up animation after a new slide has been displayed (ie. on new animation) */
    $('.carousel').bind('afterAnimate',
        function () {
                    jQuery('.carousel img').animate({top:"-=197px"},6000);
    });
)};

Parting Thoughts

There are some weaknesses with this approach, for example it assumes that all banner images will always be 400px high. When there are multiple images in the Carousel the sliding up effect is lessened, this can be improved by tying the slide up effect to a Carousel event such as. It would also be good to add some easing for a smoother scroll effect.

Currently the script is fired even if there is no carousel present, I could make it detect the presence of a carousel first.

It might be useful to package this as an add-on for Products.Carousel so that it is 100% site administrator friendly in the future.

For the record, this was easier to do, back in the day with Flash, but then Android and iOS users would not be able to see it, plus my primary machine is now a Chromebook so there isn't much of an option for using the Flash IDE anyway. I would still be left to do the integration work so that mortals could manage the system when we're done.

Friday, June 7, 2013

Plone Upgrading Tip – Be careful with that Jquery UI add-on

Just  a quick note. On a Plone 4.3 upgrade I had pinned an old version of collective.js.jqueryui. This caused a few issues including a broken editing interface. The solution was to pin collective.js.jqueryui to the latest version (more importantly, the version that was compatible with Plone 4.3) which meant adding the following to the [versions] section of my buildout.

collective.js.jqueryui = 1.10.3

This little change fixed a whole lot of issues with my Plone 4.3 editing interface on a recently upgraded site.

Sunday, June 2, 2013

Fixing a broken view on a Dexterity based product after upgrading to Plone 4.3

TL;DR: I totally missed that the new Dexterity now ships with less dependencies. For me this meant that one of my products that depends on five.grok stopped working after the upgrade. The solution to the lack of the five.grok dependency in Dexterity was documented but not obviously enough for me so I'll repeat it here (skip to the last section of this post for details).

Troubleshooting

In order to identify what was broken I turned to the 'error_log' utility of the Zope Management Interface.



My little "trick" for enabling exceptions which are normally ignored by Plone is by adding a 'z' to the end of the exception name so that it gets logged and not skipped.



The 'error_log' was able to report that the view (even though it was working up to Plone 4.2) was now raising a "Not Found" exception on my Plone 4.3 based site. The view in this case called '@@sermons' was somehow no longer properly registered.

Diagnosing the source

My view was registered using a package called 'five.grok' which uses convention over configuration to associate views with a package. Here's a snippet of code that registers a simple view (5 to 7 lines of code):
from five import grok
from Products.ATContentTypes.interface import IATFolder
grok.templatedir('.')
class Sermons(grok.View):
    """A BrowserView to display a Sermon listing on a Folder."""
    grok.context(IATFolder)  # type of object on which this View is available
    grok.require('zope2.View')  # what permission is needed for access

By convention because the class is called 'Sermons' it would be accessible via the name '@@sermons' or simply 'sermons' and would depend on a template called 'sermons.pt' in the same directory (not shown here). The bottom line is that this all used to work.

The solution

Reintroduce the dependency in my buildout configuration and rerun buildout. This meant explicitly declaring the grok dependency. I also declared an additional dependency on a package called 'relations' just in case I had other code that needed that, then I reran buildout. The actual line that changed in order to do this explicit declaration involved adding a line like the one below in the appropriate eggs section of my buildout configuration:

eggs =
    plone.app.dexterity [grok, relations]

Phew! my view worked after that.

Saturday, June 1, 2013

Notes from installing Debian on a CubieBoard

The CubieBoard is a cheap, ARM based computer that ships with Android 4 (ICS) installed, these are notes related to my first steps hacking around with the board and installing a Debian server image.

Image from the Cubieboard.org website

Materials

  • A 2GB micro SD card (I had problems with a 1GB card)
  • A development machine with OS X or Linux (there's a way to do this on Windows, but I didn't have any Windows machines at close hand)
  • Ethernet cable for connecting the CubieBoard to a network with DHCP support

Getting the Debian Image

My first task was to source the new image that would run the CubieBoard, I downloaded the image from http://romanrm.ru/en/a10/debian

The image needed to be "installed" on an microSD card. To achieve this on a Mac running OS X I had to run the following commands to become the root user then unmount the SD card and dump the debian server image to the SD card.
sudo su 
diskutil list #for me the sd card was located at /dev/disk1
diskutil unmountDisk /dev/disk1
bzip2 -dc a10-debian-server-2gb.2013-04-11.img.bz2 > /dev/disk1

The last step easily took 40 minutes.

Booting the CubieBoard

I then inserted the microSD in the microSD slot of the CubieBoard and powered it up.
It booted with little visible indication of success.

Logging into the Board

To be sure it was working I needed to find a way to log into the machine. I was able to find the ip address of my CubieBoard by accessing the administrative page of my router and viewing the list of DHCP clients. The output looked like this, the device identifies itself as being debian:



After this I logged in using the ip address that I discovered, the default username and password are "root" and "password".

ssh root@192.168.x.x     # x.x would be the rest of your ip address
And ran an update
apt-get update

 Playing with the LEDS

My first project entailed getting control over the CubieBoard's built in LEDs. I had to rebuild my script.bin which required installing supporting tools (fex2bin and bin2fex). bin2fex converts the script.bin to a text editable script.fex file and fex2bin regenerates the binary file that the CubieBoard looks for at boot time. I had to retrieve the latest version of the tools from github using the commands below:
apt-get install git-core pkg-config libusb-1.0-0-dev build-essential
git clone https://github.com/linux-sunxi/sunxi-tools.git
cd sunxi-tools
make
Then I created a fex file from my script.bin
./bin2fex /boot/script.bin > /boot/script.fex
Edited the /boot/script.fex file to include the following:

[leds_para]
leds_used = 1
leds_num = 2
leds_pin_1 = port:PH20<1><default><default><0>
leds_name_1 = "green:ph20:led1"
leds_pin_2 = port:PH21<1><default><default><0>
leds_name_2 = "blue:ph21:led2"

Then recreated and installed the new script.bin and rebooted
./fex2bin /boot/script.fex > /boot/script.bin
reboot

After reboot it still would not work, it turned out that I still needed to install a special module so that the OS would "see" the LEDs, the following command worked for me:
modprobe leds_sunxi 

To ensure that the module was loaded on future boots I added the module to /etc/modules file:
echo "leds_sunxi" >> /etc/modules
I hope to do a lot more with this system as I become more familiar with it, I got a lot of help by Googling for the information, for more about working with the LEDS see http://linux-sunxi.org/Cubieboard/Programming/StatusLEDs