Google Summer of Code 2013 (Final blog post)

All’s well that ends well.

 Here goes the final blog post of mine about the fascinating Google Summer of Code 2013 experience.

GSoC 2013 logo

It has been an enchanting experience, right from the first time of contact with my mentor till the last mail he sent me congratulating me on passing final evaluation. I still haven’t come in terms with the fact that it has finally concluded.

Initial phase of the GSoC period was spent in trying to understand the working of the current framework, setting up sugar-build, finding how the JavaScript and Python code communicate with each other, etc.

In the process I also made my first web activity

My first web actvivity

My first web activity

In fact, I probably learnt more programming while working on this project than what I did during 6th semester. My only regret is that there is no Google Winter of Code.

My work so far:

I’ve more or less elaborated in detail on my works so far in my previous blogs, so just to summarize everything, here it goes: Initially to get a hang of the CSS stuffs in Sugar-web I worked on the radio and checkbox buttons. Then I started developing the activity palette using the palette bits which Manuel had already built. Got the activity palette to sync with the datastore as well. Later on I started with developing the Markdown the markdown activity and also got the Object chooser api into sugar-web.

While working on this learnt a lots of new stuffs, RequireJs, LESS, Jasmine, Webkit2, just to name a few. It is also heartening to see the Sugar- web already being used by developers to make web activities and once we can get in all the Sugar bits into Sugar-web, I don’t think it’d be long before we have web activities becoming as popular as python activities, if not more.

The fun part and future plans:

Interacting and working with developers around the world, staying up late night coding, is what all programmers would love to do. Now coming to two very conspicuous developers in Sugar labs team, Daniel and Manuel. They were virtually the co-mentors for my project. I must thank them loads for putting up with my carelessness at certain times and my constant bugging them for help(I never spared Daniel even he was on a holiday, yet he patiently answered each of my queries and helped me out. :P). I only hope, one day I reach somewhere close to their level of expertise.

Hats off to Lionel!

This was the first Google Summer of Code experience for both of us, and I must confess, he has done an excellent job. Amidst all his energy sapping office work, he still found time to conduct weekly meeting, (which were done in a very organized and professional manner) responded within a short span of time whenever I pinged him and gave invaluable tips and helped me overcome many hurdles Despite being away for nearly 3 weeks on a holiday he manged to keep in touch with me and held weekly meeting, which says a lot about his dedication for his work. I’d be more than happy to be mentored by him in case I apply for GsoC next year(if he is okay with it ūüėõ ).

It is sad that all this magical experience lasted for only 3 months and I still haven’t had enough of it and that’s the primary reason why I took up a mini project in my college for the current semester, through which I can still keep contributing to Sugar Labs.

Final GSoC meeting with Lionel

Final GSoC meeting with Lionel

Lionel has some plans in store for me for the next couple of months, which I guess is something revolving around the Presence api in Sugar.

Challenges:

I’ve painted a rosy picture of GSoC so far, but don’t be deceived by it. Not everything went according to plan. I started with getting the latest sugar-build on my laptop. All my initial work experimentation with Sugar I did on a VM on Windows. I knew as the internship period ¬†progressed it would get more demanding so I had to immediately get a Linux distro. I tried Fedora, it didn’t like me, and it was the same the other way around as well. So we never got along together.

Then after a little experimentation with Ubuntu 12.04(which wasn’t supported), I finally settled for Ubuntu 13.04. Occasionally it kept crashing for some inexplicable reasons and I had a hard time rebuilding them every time. Must appreciate Daniel for improving and maintaining the sugar-build and always helping out folks like me who crashed their build very often.

Crashed my build several times!

Crashed my build several times!

Getting in the Object Chooser working in sugar-web and the setting up the preview field(which I unfortunately couldn’t complete before the deadline) were two very daunting tasks. Yes, I’ve worked with Python but had a hard time figuring out the working of the asynchronous functions in Webkit. Took me more than 3 weeks to land the Object Chooser bits in sugar-web. Regarding the preview field, I tried using the html2canvas library , but it gave me cross browser issues while running on some activities. Finally settled for the Webkit way.

But on positive note I’ll be back working on them again in a couple of weeks time(as part of a mini-project in college), starting with where I left off last week.

On a concluding note, I sincerely thank Walter , Gonzalo , Martin and all the other Sugar Labs mentors for they have helped me and guided me in one way or the other. Also wish my fellow GSoCers all the best for their future endeavors. It’s been a pleasure working alongside you guys.

Adios Amigos!!

Google Summer of Code (Sugar Labs) Part 2

A little more than a month has elapsed since my last blog post on the work on my GSoC project.

This blog post will mostly revolve around a new web activity written using the HTML5 ‚Äď JavaScript framework and getting in the Object Chooser functionality in the current framework.

The current datastore api in sugar-web hasn’t really been tested extensively. Therefore the primary objective behind writing this activity is to test the datastore api by bringing in the object chooser into sugar-web.

Markdown Activity

Markdown is a text-to-HTML conversion tool was made by John Gruber for web writers. Markdown allows you to write using an easy-to-read, easy-to-write plain text format, then convert it to structurally valid XHTML (or HTML).

Here are some of the Markdown Syntax_examples.

Markdown activity is a web activity in sugar. It contains an editor that allows to write in markdown format and you can simultaneously see the formatted text on the right hand side.

Screenshot from 2013-08-25 14:56:42

It comes in with inbuilt editor buttons which can help you format/edit the markdown content.

So anyone can write HTML content and you need not know how to make use of various HTML tags.

You can download the activity here markdown activity.

I’ve also published it on github, you can play with it on your browser here.

Features of version Markdown version 1:
– Can convert markdown text to HTML format
– Text editors buttons(Bold, Header, Ordered/Unordered List , Undo/Redo, Link, Horizontal line, Italics)
– Datastore capability (activity is automatically saved and loaded when you open it at a later stage)

Framework used
The PageDown framework is made use of to parse the markable text and convert it to equivalent HTML text.

Overview of the framework:
Used in a regular browser environment, it provides a top-level object called Markdown with two properties:
Markdown.Converter¬†is a constructor that creates a converter object. Call this object’s¬†makeHtml¬†method to turn Markdown into HTML:
var converter = new Markdown.Converter();
document.write(converter.makeHtml("**I am bold!**"));

Markdown.Editor.js
var editor2 = new Markdown.Editor(converter2, "-second", options);

The created editor object has (up to) three methods:
Рeditor.getConverter() returns the converter object that was passed to the constructor.

– editor.run()¬†starts running the editor; you should call this¬†after¬†you’ve added your plugins to the editor (if any).

Рeditor.refreshPreview() forces the editor to re-render the preview according to the contents of the input, e.g. after you have programmatically changed the input box content. This method is only available after editor.run() has been called.

Challenges:

Well, I’d consider this task as the most challenging one allotted by Lionel so far. The initial work, mainly integrating the Pagedown framework into the activity went pretty fast. Pagedown framework came in with inbuilt format/edit buttons so I really didn’t have to reinvent the wheel there, I had to patch the framework in order to integrate sugar-like buttons though. The most daunting part was to bring in the Sugar Object Chooser feature into the activity.

Unfortunately, while I commenced work on this, my college reopened and I got tied up with campus recruitment and other college stuffs which impeded me from devoting all my attention towards the completion of the task.

Nevertheless, with help from Daniel, I managed to get the object chooser up and running in the sugar-web.
As I mentioned earlier, the main intention of this task was to test the datastore api in sugar-web. I can confidently say that it served it’s purpose as I managed to unearth bugs in the datastore api. Rest assured Daniel is at it and will be fixing them as soon as possible.

Working of Object Chooser:


def show_object_chooser(self, request):

chooser = ObjectChooser(self._activity)

chooser.connect(‘response’, self._chooser_response_cb, request)

chooser.show()

We call this function from JavaScript when we need to insert something from the journal in our activity.

ObjectChooser(self._activity) returns an object which we can use to bring up the object chooser(chooser.show()).

Before we bring up the object chooser we have to make sure we watch out for the response signals which occur when we interact with the object chooser. We do this using chooser.connect('response', self._chooser_response_cb, request) . This calls the _chooser_response_cb function on receiving a response signal.


def _chooser_response_cb(self, chooser, response_id, request):
if response_id == Gtk.ResponseType.ACCEPT:
object_id = chooser.get_selected_object_id()
self._client.send_result(request, [object_id])
else:
self._client.send_result(request, [None])
chooser.destroy()

Screenshot from 2013-09-06 22:15:50

This part takes care of the event handling in the object chooser. The response_id is Gtk.ResponseType.ACCEPT when the user selects an object from the listed objects in the list. We send the object_id of the selected object to the web activity using self._client.send_result(request, [object_id]) and [None] otherwise.

Finally we destroy the chooser object object created earlier and it closes the object chooser window.

I must thank Daniel for patiently answering each of my queries regarding the same and lent a big helping hand, and Lionel, who despite being away on vacation still found time to monitor and give me invaluable inputs on my work. Credits goes to Gonzalo Odiard too , for the markdown activity idea was initially proposed by him. This activity would be very useful as future help content for activities could be written in markdown. Looking forward to my next post where I’ll try to sum up all my work and write more about my GSoC experience by the end of this month , by when, hopefully I would have successfully completed my project.

Google Summer of Code 2013 (Sugar Labs)

Sugar

The award-winning Sugar Learning Platform promotes collaborative learning through Sugar Activities that encourage critical thinking, the heart of a quality education. Designed from the ground up especially for children, Sugar offers an alternative to traditional ‚Äúoffice-desktop‚ÄĚ software. Sugar Activities cover a broad range of applications: browsing, drawing, composing, writing, programming, etc. See this gallery of screenshots.

Introduction to the Sugar Interface describes multiple full-screen views: a Home view, from which Activities are launched; a Neighborhood view, where learners can connect to each other through a Jabber network; a Journal view, which can be used as a lab notebook; and the Activity view, where Sugar Activities are run.

Activities in Sugar

Learner applications in Sugar are called Activities. They are software packages that automatically save your work‚ÄĒproducing specific instances of the Activity that can be resumed at a later time. A specific Activity instance is a Journalevent (see this discussion of The Notion of “Keeping”). Many Activities support learner¬†collaboration, where multiple learners may be invited to join a collective Activity session.

Sugar Activities have no Save menu: everything is saved automatically. While the interface uses very little text, additional information is revealed when the user hovers over icons.

Writing activities in full HTML5-JavaScript.

The objective of this project is to allow developers to write activities for Sugar using only HTML5 and JavaScript (instead of the conventional Python code). HTML5 activities could be hosted on Sugar side-by-side with “standard” Python activities. Specifically HTML5 will be displayed on the Sugar Home view like any other activities. HTML5 activities could benefit from common Sugar features (Sugar UI, Datastore/journal, telepathy, …) like any other activities. Finally there should be no visual difference from the user perspective between a Python activity and a HTML5 activity. HTML5 activities could be named “Sugar Web Activity”.

This feature will be accommodated as a part of Sugar 0.100. Also, this project has been accepted as a Google Summer of Code 2013 project by Sugar Labs and I shall be working on this for the next few months.

HTML5 activities will be run via a WebKit instance. A JavaScript framework will expose Sugar Features to HTML5 activities. Specifically, this framework will allow to use HTML controls matching the Sugar widgets look&feel and will expose common and customized activity toolbars. The framework will also expose API for handling Telepathy (communication and collaboration between multiple Sugar machine) and Datastore (Sugar Journal reading and writing).

Before you commence, ensure that you have a work development environment http://developer.sugarlabs.org/dev-environment.md.html.

Creating Web Activity

To create your own web activity, enter the sugar-build shell

./osbuild

Create an activity based on the default template

volo create my-activity ./sugar-web-template
cd my-activity

Choose a name for your activity. Write it in the activity name and bundle-id in activity/activity.info, and also in the title tag of index.html.

Install the activity for development

python setup.py dev

Now you should have a basic activity running!

You can refer http://developer.sugarlabs.org/activity.md.html for more details,

The working of the activity:

index.html

Here lies the skeleton of the activity that you’re going create. It comes with a basic template (sugar-web-template) but as you go

on developing your activity, you will be making changes to it.

For the current template we make use of the require js framework.

Notice that in the script tag we do not include all the js files in it, but rather a more subtle,

¬†¬†<script data-main=“js/loader”src=“lib/require.js”></script>

 This can be done because the require js framework holds together all the dependencies and links them together.

  DOM ready feature of requirejs,

 In activity.js we make use of this feature:

require([‘domReady!’], function (doc) {

//code

}
 It is made use of to ensure that the various elements of the DOM must be ready before we attempt to communicate with them using
the JavaScript. In modern browsers it is done by waiting for the DOMContentLoaded event.
But not all browsers support DOMContentLoaded event hence we make use of domReady module which implements a cross-browser to determine
when DOM is ready.

If you need more details about the working of require js, please refer the documentation here http://requirejs.org/.

How the Sugar UI is replicated:

sugar-web/graphics/

The contents inside this provide the JavaScript and CSS files which are responsible for replicating the sugar UI.

We make use of LESS framework to write and compile the CSS to ensure that the sugar UI is dynamic and flexible to ensure that the

Sugar UI will work even when it is run under different screen resolutions, namely android phones, tablets, etc.

Example:

Let us for instance take a function palette.js which is used to replicate the palettes in Sugar.

function createPaletteElement() {
            if (paletteElem !== undefined) {
                return;
            }
¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†paletteElem = document.createElement(‘div’);
¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†paletteElem.className = “palette”;
¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†paletteElem.style.visibility = “hidden”;
            document.body.appendChild(paletteElem);
¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†if (that.invoker.classList.contains(“toolbutton”)) {
¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†invokerElem = document.createElement(‘div’);
¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†invokerElem.className = “palette-invoker”;
                var style = that.invoker.currentStyle ||
¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†window.getComputedStyle(that.invoker, ”);
                invokerElem.style.backgroundImage = style.backgroundImage;
¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†invokerElem.addEventListener(‘click’, function (e) {
                    that.toggle();
                });
                paletteElem.appendChild(invokerElem);
           }
¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†wrapperElem = document.createElement(‘div’);
¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†wrapperElem.className = “wrapper”;
            paletteElem.appendChild(wrapperElem);
            if (that.primaryText !== undefined) {
¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†headerElem = document.createElement(‘div’);
¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†headerElem.className = “header”;
                headerElem.innerText = that.primaryText;
                wrapperElem.appendChild(headerElem);
            }
¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†headerSeparatorElem = document.createElement(‘hr’);
¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†headerSeparatorElem.className = “header-separator”;
¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†headerSeparatorElem.style.display = “none”;
            wrapperElem.appendChild(headerSeparatorElem);
¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†containerElem = document.createElement(‘div’);
¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†containerElem.className = “container”;
            wrapperElem.appendChild(containerElem);
            updatePosition();
        }

Whenever we need to create a palette this function is called , div element is created and appended to the required tags. These div tags are given the class names as ‚Äúpalette‚ÄĚ and the respective styling for them is done in the sugar.css/sugar.less files. To append content to the palettes, we simple create instantiate palette.Palette and call setContent using the same object and pass the tags as parameters.

Communication between sugar and the JavaScript framework:

When Web Activity needs to call Sugar system API, JavaScript has to call Python code. The communication between the webkit and the python code happens through websockets, through which the data is encoded in JSON/binary format. ¬† bus.sendMessage(‚Äúfunction.name‚ÄĚ,parameters, callback); ¬† The corresponding calls from the framework are matched here in this python program: /sugar/src/jarabe/apisocket.py In the respective methods which map the ‚Äúsugar calls‚ÄĚ from the JavaScript framework, we’d have to write the python code in this file.

Mapping sugar api with the framework:

Taking the example of the datastore api:

sugar-web/datastore.js:

Lets consider the function ‚Äúdatastore.create‚ÄĚ in datastore.js:

    datastore.create = function (metadata, callback) {
        function onResponseReceived(responseError, result) {
            if (responseError === null) {
                callback(null, result[0]);
            } else {
                callback(responseError, null);
            }
        }
        var params = [metadata];
¬†¬†¬†¬†¬†¬†¬†¬†bus.sendMessage(“datastore.create”, params, onResponseReceived);
    };

This function is made use of in order to create a new datastore object.

We pass the metadata as parameters to the function call.

Metadata contains all the activity details such as activity id, name, creation date,etc.

The parameters of bus.sendMessage() is passed to :

 sugar-web/bus.js:

    bus.sendMessage = function (method, params, callback) {
        var message = {
¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†“method”: method,
¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†“id”: lastId,
¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†“params”: params
        };
        if (callback) {
            callbacks[lastId] = callback;
        }
        client.send(JSON.stringify(message));
        lastId++;
    };

These parts in bus .js are primarily responsible for the communication from and to the activity .

The data is encoded into JSON format and then is sent through the websockets to interact with the python functions in Sugar.

In /sugar/src/jarabe/apisocket.py:

we have the matching function under the DatastoreAPI classs

def create(self, request):

        def reply_handler(object_id):
            self._client.send_result(request, [object_id])
        def error_handler(error):
            self._client.send_error(request, error)
¬†¬†¬†¬†¬†¬†¬†¬†self._data_store.create(request[“params”][0], “”, True,
                                reply_handler=reply_handler,
                                error_handler=error_handler)

Here we make the sugar call in python and create the datastore object and send it back to the JavaScript framework using self._client.send_result().

Writing test specifications:

sugar-web/test/

The unit test specifications reside here and we make use of the Jasmine framework [1].

These are written to ensure that sugar doesn’t break.

Let’s take a peek at sugar-web/test/envSpec.js¬†

define([“sugar-web/env”], function (env) {
¬†¬†¬†¬†describe(“environment”, function () {
¬†¬†¬†¬†¬†¬†¬†¬†it(“should not return undefined”, function () {
            env.getEnvironment(function (error, environment) {
                expect(environment.bundleId).not.toBeUndefined();
                expect(environment.activityId).not.toBeUndefined();
                expect(environment.activityName).not.toBeUndefined();
            });
        });
    });
});

Here we assert the fact that the variables (bundleId, activityId and activityName) are there in environment. The expectation is defined within ‘expect()’ and each expectation has a matcher. We make use of not.toBeDefined() matcher to make sure that the expected variables are present.

My works:

Under the watchful guidance of Lionel Lask√©¬†(my mentor for the GSoC project), so far I’ve been assisting Daniel Narvaez and Manuel (the sugar lab developers who are currently working on the framework ) and contributed a few patches.

Namely, added sugar like radio-buttons and check boxes. Created an activity palette, which syncs with the datastore.

I also wrote a small test for env.js using the Jasmine framework.

I’m also simultaneously creating a small game while working on the framework, which I’ll probably complete by the end of the GSoC period [2].

You can track the work here on our wiki page in sugar labs [3].
Hopefully, I’ll be back with an update on this work by the end of this month