Cache Thumbnails and Images Using Picasso in Open Event Android

In the event based Android projects like Open Event Android, we have speakers and sponsors. And these projects needs to display image of the speakers and sponsors because it affects project a lot. So instead of every time fetching image from the server it is good to store small images(thumbnails) in the cache and load images even if device is offline. It also reduces data usage.

Picasso is mostly used image loading library for Android. It automatically handles ImageView recycling and download cancellation in an adapter, complex image transformations with minimal memory use, memory and disk caching.

But one problem is Picasso caches images for only one session by default. I mean if you close the app then all by default cached image will be removed.  If you are offline then Picasso will not load cached images because of it. It will make network calls every time you open the app.

In this post I explain how to manually cache images using Picasso so that images load even if the device is offline. It will make a network call only once for a particular image and will cache image in memory.

We will use okhttp3 library for OkHttpClient.

1. Add dependency

In order to use Picasso in your app add following dependencies in your app module’s build.gradle file.

dependencies {
        compile 'com.squareup.okhttp3:okhttp:3.8.1'
        compile 'com.squareup.picasso:picasso:2.5.2'
}

2. Make static Picasso object

Make static Picasso object in the Application class so that we can use it directly from the other activity.

public static Picasso picassoWithCache;

3. Initialize cache

Create a File object with path as app specific cache and use this object to create a Cache object.

File httpCacheDirectory = new File(getCacheDir(), "picasso-cache");
Cache cache = new Cache(httpCacheDirectory, 15 * 1024 * 1024);

Here it will create a Cache object with 15MB. getCacheDir() method returns the absolute path to the application specific cache directory on the filesystem.

OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder().cache(cache);

4. Initialize Picasso with cache

Now initialize picassoWithCache object using Picass.Builder(). Set downloader for picasso by adding  new OkHttp3Downloader object.

picassoWithCache = new Picasso.Builder(this).downloader(new OkHttp3Downloader(okHttpClientBuilder.build())).build();

5. Use picassoWithCache object

As it is a static object you can directly use it from any activity. All the images loaded using this picassoWithCache instance will be cached in memory.

Application.picassoWithCache().load(thumbnail/image url);

 

To know more how i solved this issue in Open Event Project visit this link. To learn more about Picasso features follow the links given below.

Continue ReadingCache Thumbnails and Images Using Picasso in Open Event Android

Displaying selective logs in Yaydoc with downloadable detailed logs

Yaydoc, our automatic documentation generation and deployment project, at the crux of it consists of bash scripts. These bash scripts perform various actions, including documentation generation, deployment to Github and deployment to Heroku.

Since the inception of the User Interface of the Web UI, we have been spitting out the output of the bash script directly to the console output block without any filter. We understand that the output contains a lot of jargon that provides no essential information to the user. Hence, to improve the user experience of our platform, we decided to separate the Detailed logs and show only basic logs outlining the flow of the processes.

To implement this, we append all the logs to a unique file, sending only basic logs to stdout and stderr. Since we attend to store logs and display them in the console block of Web UI simultaneously we use the tee command, piping it with echo commands.

function print_log {
  if [ -n “$LOGFILE” ]; then
    echo -e $1 | tee -a ${LOGFILE}
  else
    echo -e $1
  fi
}

${LOGFILE}  is a unique file that has the same name as the preview directory and the compressed repository. After storing the logs in the file, the contents of the file are outputted using the cat command and is then shown to the user in a modal which is after the Detailed Logs button is clicked.

$(“#btnLogs”).click(function () {
  socket.emit(‘retrieve-detailed-logs’, data);
  ....
});

socket.on(‘retrieve-detailed-logs’, function (data) {
  var process = spawn(‘cat’, [‘temp/’+data.email+’/’+data.uniqueId+’.txt’]);
  process.stdout.setEncoding(‘utf-8’);
  process.stdout.on(‘data’, function (data)) {
    socket.emit(‘file-content’, data);
  }
});

To keep the indentation of the logs, we display the content inside the HTML pre tags. Along with displaying the detailed logs, we also let our two additional functionalities. These are ‘Copy to Clipboard’ and ‘Download as text file’. The ‘copy to clipboard’ functionality is achieved using the clipboard.js jQuery library while the `Download` functionality is achieved using res.download(file) function of ExpressJS response.

socket.on(‘file-content’, function (data) {
  new Clipboard(‘#copy-button’);
  $(‘#detailed-logs’).html(data);
  $(‘#detailed-logs-modal’).modal(‘show’);
});

Resources:

  1. https://clipboardjs.com – A modern approach to copy text to clipboard
  2. https://socket.io/ – The fastest and most reliable real-time engine
Continue ReadingDisplaying selective logs in Yaydoc with downloadable detailed logs

Creating A Sample Event Web App Using the Open Event Framework

I have been creating sample events for the Open Event Framework by creating JSON files for them. In this blog, I will walk you through 4 easy steps to create a sample event for FOSSASIA Open Event. These are the steps that I followed while I contributed in making sample web apps:

Let’s start by taking the example of a sample event. I recently created a sample for FBF8’2017. F8 is conference held by Facebook annually.

I started by visiting the official F8 site. I personally used Google Chrome for it as I was almost positive that the official site will be having an API which will make it easier for me to extract JSON for the event. Also, Google Chrome developer tools make it easier to access the API. I have previously explained how to access JSON through APIs in one of my previous blog posts that can be found here.

So in the F8 site, I looked for the page that will lead me to the full schedule of the conference:

After clicking on the “SEE FULL SCHEDULE” button, this is where it leads us, with the developer tools ON.

That weird named file on that appears in under the XHR tab contains our JSONs!

[{1492502400: [{day: 1, sessionTitle: "Registration", sessionSlug: "day-1-registration",…},…],…}, {,…}]

0:{1492502400: [{day: 1, sessionTitle: "Registration", sessionSlug: "day-1-registration",…},…],…}

1:{,…}

This is how the file looks on clicking it at first. You must be seeing small clickable arrows on the sides which expand the JSON to reveal all the contents. But okay, we have crossed our first step: Obtaining JSON from the website’s API!

Step 2: Tailoring the JSON according to the Open Event format needs to be done now. To view the latest API format, visit here. Now this step is obviously most time-consuming and tedious. We need to modify the API we obtained from the F8 site to meet the Open Event requirements.

I mainly used Sublime text editor to do this. It has this great feature to find and replace text in text files.

Taking an example of a session object. This is what we will get from the API:-

allDay:false

createdAt:"2017–01–28T01:24:12.770Z"

day:1

displayTime:"3:00pm"

endTime:{__type: "Date", iso: "2017–04–18T15:50:00.000Z"}

iso:"2017–04–18T15:50:00.000Z"

__type:"Date"

hasDetails:true

objectId:"62yCeJMvAf"

ogImage:{__type: "File", name: "296643cca9aad196bbd3534324c52049_Making Great Camera Effects.png",…}

name:"296643cca9aad196bbd3534324c52049_Making Great Camera Effects.png"

url:"https://f82017-parse.s3.amazonaws.com/296643cca9aad196bbd3534324c52049_Making%20Great%20Camera%20Effects.png"

__type:"File"

onMySchedule:false

sessionDescription:"With AI that transforms images, Facebook's Camera Effects Platform lets you create animated masks, interactive overlays, frames, and other effects that people can apply to their photos and videos in the Facebook camera. Learn best technical and design practices for creating effects using this innovative technology, and see examples of successful effects."

sessionLocation:"G"

sessionSlug:"making-great-camera-effects"

sessionTitle:"Making Great Camera Effects"

sortTime:"1492527600"

speakers:[{speakerName: "Volodymyr Giginiak", createdAt: "2017–01–28T01:27:49.292Z",…},…]

0:{speakerName: "Volodymyr Giginiak", createdAt: "2017–01–28T01:27:49.292Z",…}

1:{speakerName: "Stef Smet", createdAt: "2017–01–28T01:30:16.022Z",…}

startTime:{__type: "Date", iso: "2017–04–18T15:00:00.000Z"}

iso:"2017–04–18T15:00:00.000Z"

__type:"Date"

tags:["Camera"]

0:"Camera"

updatedAt:"2017–04–18T19:19:16.501Z"

Now, this is where I used the find & replace feature in Sublime text to make it look like the open-event standard JSON. For instance, replacing “sessionLocation” with “microlocation”, “sessionDescription” with “long_abstract” and so on. Yes, there were a few manual changes as well that I had to make.

This is how the final JSON session object looked like after completing step 2:

{
     "short_abstract": "",
     "id": 26,
     "subtitle": "making-great-camera-effects",
     "title": "Making Great Camera Effects",
     "long_abstract": "With AI that transforms images, Facebook's Camera Effects Platform lets you create animated masks, interactive overlays, frames, and other effects that people can apply to their photos and videos in the Facebook camera. Learn best technical and design practices for creating effects using this innovative technology, and see examples of successful effects.",
     "end_time": "2017-04-18T15:50:00-07:00",
     "microlocation": {
        "id": 5,
        "name": "Hall G"
     },
     "start_time": "2017-04-18T15:00:00-07:00",
     "comments": "",
     "language": "",
     "slides": "",
     "audio": "",
     "video": "",
     "signup_url": "",
     "state": "accepted",
     "session_type": {
        "id": 6,
        "name": "50 minutes session",
        "length": "00.50"
     },
     "track": {
        "id": 2,
        "name": "Camera",
        "color": "#FF3046"
     },
     "speakers": [{
           "city": "",
           "heard_from": "",
           "icon": "",
           "long_biography": "",
           "small": "",
           "photo": "",
           "thumbnail": "",
           "short_biography": "",
           "speaking_experience": "",
           "sponsorship_required": "",
           "organisation": "Facebook",
           "id": 40,
           "name": "Volodymyr Giginiak"
        }
     ]
  }

Apart from this, there were places where I had to dig for information about speakers, their social website links, their images and so on because the open-event JSON format expects all this.

Step 3: JSON Validation

It is very likely that one of your JSON files will contain invalid JSON strings. So it is important to validate them. I used this online tool and I liked it very much. Once the JSON is validated, everything is set. All you need to now do is-move to step 4!

Step 4: Web app generation

Compress your JSON archive in .zip format and then go to the webapp generator. Enter your email ID and upload the zip file. Now, you can deploy, download and preview your personalised web-app, generated by FOSSASIA open-event web app generator.

The official web-app generator repo is here.

If you want to contribute to FOSSASIA by creating a sample, you can create an issue in the official open-event repo, along with a PR which contains the JSON sample files, the zipped file and a link to the web-app deployment on GitHub pages.

Continue ReadingCreating A Sample Event Web App Using the Open Event Framework

Create Scraper in Javascript for Loklak Scraper JS

Loklak Scraper JS is the latest repository in Loklak project. It is one of the interesting projects because of expected benefits of Javascript in web scraping. It has a Node Javascript engine and is used in Loklak Wok project as bundled package. It has potential to be used in different repositories and enhance them.

Scraping in Python is easy (at least for Pythonistas) as one needs to just import Request library and BeautifulSoup library (lxml as better option), write some lines of code using Request library to get webpage and some lines of bs4 to walk through html and scrape data. This sums up to about less than a hundred lines of coding, where as Javascript coding isn’t easily readable (at least to me) as compared to Python. But it has an advantage, it can easily deal with Javascript in the pages we are scraping. This is one of the motive, Loklak Scraper JS repository was created and we contributed and worked on it.

I recently coded a Javascript scraper in loklak_scraper_js repository. While coding, I found it’s libraries similar to the libraries, I use to code in Python. Therefore, this blog is for Pythonistas how they can start scraping in Javascript as they finish reading and also contribute to Loklak Scraper JS.

First, replace Python interpreter, Request and Beautifulsoup library with Node JS interpreter, Request and Cheerio JS library.

1) Node JS Interpreter: Node JS Interpreter is used to interpret Javascript files. This is different from Python as it deals with the project instead of a module in case of Python. The most compatible Node for most of the libraries is 6.0.0 , where as latest version available(as I checked) is 8.0.0

TIP: use `–save` with npm like here while installing a library.

2) Request Library :- This is used to load webpage to be processed. Similar to one in Python.

Request-promise library, a wrapper around Request with implementation of Bluebird library, improves readability and makes code cleaner (how?).

 

3) Cheerio Library:- A Pythonista (a rookie one) can call it twin of BeautifulSoup Library. But this is faster and is Javascript. It’s selector implementation is nearly identical to jQuery’s.

Let us code a basic Javascript scraper. I will take TimeAndDate scraper from loklak_scraper_js as example here. It inputs place and outputs its local time.

Step#1: fetching HTML from webpage with the help of Request library.

We input url to Request function to fetch the webpage and is saved to `html` variable. This scrapeTimeAndDate() function scrapes data from html

url = "http://www.timeanddate.com/worldclock/results.html?query=London";

request(url, function(error, response, body) {

 if(error) {

    console.log("Error: " + error);

    process.exit(-1);

 }

 html = body;

 scrapeTimeAndDate()

});

 

Step#2: To scrape important data from html using Cheerio JS

list of date and time of locations is embedded in table tag, So we will iterate through <td> and extract text.

  1. a) Load html to Cheerio as we do in beautifulsoup

In Python

soup = BeautifulSoup(html,'html5lib')

 

In Cheerio JS

$ = cheerio.load(html);

 

  1. b) This line finds first tr tag in table tag.

var htmlTime = $("table").find('tr');

 

  1. c) Iterate through td tags data by using each() function. This function acts as loop (in Python) iterating through list of elements in which data will be extracted.

htmlTime.each(function (index, element) {      

  // in python, we will use loop, `for element from elements:`

  tag = $(element).find("td");    // in python, `tag = soup.find_all('td')`

  if( tag.text() != "") {

    .

    .

    //EXTRACT DATA

    .

    .

  } else {

    //go to next td tag

    tag = tag.next();

  }

}

 

  1. d) To extract data

Cheerio JS loads html and uses DOM model traverse through. DOM model considers html is tree. So, go to the tag, and scrape data you want.

//extract location(text) enclosed in tag

location = tag.text();

//go to next tag

tag = tag.next();

//extract time(text) enclosed in tag

time = tag.text();

//save in dictionary like in python

loc_list["location"] = location;

loc_list["time"] = time;

 

Some other useful functions:-

1) $(selector, [context], [root])

returns object of selector(any tag) with class or id inside root

2) $(“table”).attr(name, value)

To get tag object having attribute having `value`

3) obj.html()

To get html enclosed in tags

For more just drop in here

Step#3: Execute scraper using command

node <scrapername>.js

 

Hoping that this blog is able to  how to scrape in Javascript by finding similarities with Python.

Resources:

Continue ReadingCreate Scraper in Javascript for Loklak Scraper JS

Best Practices when writing Tests for loklak Server

Why do we write unit-tests? We write them to ensure that developers’ implementation doesn’t change the behaviour of parts of the project. If there is a change in the behaviour, unit-tests throw errors. This keep developers in ease during integration of the software and ensure lower chances of unexpected bugs.

After setting up the tests in Loklak Server, we were able to check whether there is any error or not in the test. Test failures didn’t mention the error and the exact test case at which they failed. It was YoutubeScraperTest that brought some of the best practices in the project. We modified the tests according to it.

The following are some of the best practices in 5 points that we shall follow while writing unit tests:

  1. Assert the assertions

There are many assert methods which we can use like assertNull, assertEquals etc. But we should use one which describes the error well (being more descriptive) so that developer’s effort is reduced while debugging.

Using these assertions related preferences help in getting to the exact errors on test fails, thus helping in easier debugging of the code.

Some examples can be:-

  • Using assertThat() over assertTrue

assertThat() give more descriptive errors over assertTrue(). Like:-

When assertTrue() is used:

java.lang.AssertionError: Expected: is <true> but: was <false> at org.loklak.harvester.TwitterScraperTest.testSimpleSearch(TwitterScraperTest.java:142) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at org.hamcr.......... 

 

When assertThat() is used:

java.lang.AssertionError:
Expected: is <true>
     but: was <false>
at org.loklak.harvester.TwitterScraperTest.testSimpleSearch(TwitterScraperTest.java:142)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at org.hamcr...........

 

NOTE:- In many cases, assertThat() is preferred over other assert method (read this), but in some cases other methods are used to give better descriptive output (like in next examples)

  • Using assertEquals() over assertThat()

For assertThat()

java.lang.AssertionError:

Expected: is "ar photo #test #car https://pic.twitter.com/vd1itvy8Mx"

but: was "car photo #test #car https://pic.twitter.com/vd1itvy8Mx"

at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:20)

at org.junit.Assert.assertThat(Ass........

 

For assertEquals()

org.junit.ComparisonFailure: expected:<[c]ar photo #test #car ...> but was:<[]ar photo #test #car ...>

at org.junit.Assert.assertEquals(Assert.java:115)

at org.junit.Assert.assertEquals(Assert.java:144)

at org.loklak.harvester.Twitter.........

 

We can clearly see that second example gives better error description than the first one.(An SO link)

  1. One Test per Behaviour

Each test shall be independent of other with none having mutual dependencies. It shall test only a specific behaviour of the module that is tested.

Have a look of this snippet. This test checks the method that creates the twitter url by comparing the output url method with the expected output url.

@Test

public void testPrepareSearchURL() {

    String url;

    String[] query = {

        "fossasia", "from:loklak_test",

        "spacex since:2017-04-03 until:2017-04-05"

    };

    String[] filter = {"video", "image", "video,image", "abc,video"};

    String[] out_url = {

        "https://twitter.com/search?f=tweets&vertical=default&q=fossasia&src=typd",

        "https://twitter.com/search?f=tweets&vertical=default&q=fossasia&src=typd",

    };

    // checking simple urls

    for (int i = 0; i < query.length; i++) {

        url = TwitterScraper.prepareSearchURL(query[i], "");


        //compare urls with urls created

        assertThat(out_url[i], is(url));

    }

}

 

This unit-test tests whether the method-under-test is able to create twitter link according to query or not.

  1. Selecting test cases for the test

We shall remember that testing is a very costly task in terms of processing. It takes time to execute. That is why, we need to keep the test cases precise and limited. In loklak server, most of the tests are based on connection to the respective websites and this step is very costly. That is why, in implementation, we must use least number of test cases so that all possible corner cases are covered.

  1. Test names

Descriptive test names that are short but give hint about their task which are very helpful. A comment describing what it does is a plus point. The following example is from YoutubeScraperTest. I added this point to my ‘best practices queue’ after reviewing the code (when this module was in review process).

/**

* When try parse video from input stream should check that video parsed.

* @throws IOException if some problem with open stream for reading data.

*/

@Test

public void whenTryParseVideoFromInputStreamShouldCheckThatJSONObjectGood() throws IOException {

    //Some tests related to method

}

 

AND the last one, accessing methods

This point shall be kept in mind. In loklak server, there are some tests that use Reflection API to access private and protected methods. This is the best example for reflection API.

In general, such changes to access specifiers are not allowed, that is why we shall resolve this issue with the help of:-

  •  Setters and Getters (if available, use it or else create them)
  •  Else use Reflection

If the getter methods are not available, using Reflection API will be the last resort to access the private and protected members of the class. Hereunder is a simple example of how a private method can be accessed using Reflection:

void getPrivateMethod() throws Exception {

    A ret = new A();

    Class<?> clazz = ret.getClass();

    Method method = clazz.getDeclaredMethod("changeValue", Integer.TYPE);

    method.setAccessible(true);

    System.out.println(method.invoke(ret, 2)); 
    //set null if method is static

}

 

I should end here. Try applying these practices, go through the links and get sync with these ‘Best Practices’ 🙂

Resources:

Continue ReadingBest Practices when writing Tests for loklak Server

Adding ActionMenuView to place Navigation Buttons in Phimpme Android

In the previous version of Phimpme a user had to use the traditional popup view to navigate the image to the Edit Activity or to the share activity or move and copy the image. We implemented an additional toolbar on the bottom of the screen to have quick access to the buttons for the said features.

First implementation with popup view

In the first version, we were using popup view to navigate the image while viewing it from the gallery. This is a traditional but rather confusing way for any new user to figure how to choose the edit option or share the image from the gallery.                       

                           
Adding ActionMenuView on the bottom of the screen

Let’s add action menu view to the xml file. To place the ActionMenuView at the bottom of the screen we set android:background to true. By default the color of the bottom action bar to be default color of the application. We want to make the color of the bottom bar to be transparent in order to see the image behind it. To set the color of the bottom bar translucent we append #59 with the color hex code. For example-  android:background=”#59000000”

<android.support.v7.widget.ActionMenuView
         android:id="@+id/toolbar_bottom"
         android:layout_width="match_parent"
         android:layout_height="?attr/actionBarSize"
         android:layout_alignParentBottom="true"
         android:background="#59000000"
         android:elevation="4dp"/>

Add items in the menu to be displayed on the bottom bar

Add menu.xml in res->menu. We need to add items in the menu.xml in order inflate in the bottom bar.

<menu xmlns:android="http://schemas.android.com/apk/res/android"
       xmlns:app="http://schemas.android.com/apk/res-auto">
     <item
         android:id="@+id/action_edit"
         android:orderInCategory="200"
         app:showAsAction="always"
         android:icon="@drawable/ic_mode_edit_white"
         android:title="Edit"/>
     <item
         android:id="@+id/action_copy"
         android:orderInCategory="150"
         app:showAsAction="always"
         android:icon="@drawable/ic_content_copy_white"
         android:title="Copy"/>
     <item
         android:id="@+id/action_move"
         android:orderInCategory="100"
         app:showAsAction="always"
         android:icon="@drawable/ic_folder_open_white"
         android:title="Move"/>
     <item
         android:id="@+id/action_details"
         android:orderInCategory="110"
         app:showAsAction="always"
         android:icon="@drawable/ic_info_white"
         android:title="Move"/>
 </menu> 

Inflating Bottom ActionMenuView

In your main activity get the id of the ActionMenuView and typecast it:

ActionMenuView bottomBar = (ActionMenuView) findViewById(R.id.toolbar_bottom);

Inflate the bottomBar with the menu.xml

Menu bottomMenu = bottomBar.getMenu();

getMenuInflater().inflate(R.menu.menu_bottom_view_pager, bottomMenu);

ActionMenuView shares the same onOptionItemSelected function with toolbar of the application. We will send the each item from the action menu bar onOptionItemSelected in a for loop. The loop will run till bottomMenu.size. This enables onClick of the navigation button.

for (int i = 0; i < bottomMenu.size(); i++){
             bottomMenu.getItem(i).setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener(){
                 @Override
                 public boolean onMenuItemClick(MenuItem item) {
                     return onOptionsItemSelected(item);
                 }
             });
         } 

Conclusion

While using two toolbars on the application we use ActionMenuView for the second toolbar which is at the bottom. ActionMenuView evenly spaces the button on the bottom toolbar.

Link:

https://github.com/fossasia/phimpme-android

Resources

Continue ReadingAdding ActionMenuView to place Navigation Buttons in Phimpme Android

Communication by pySerial python module in PSLab

In the PSLab Desktop App we use Python for communication between the PC and PSLab device. The PSLab device is connected to PC via USB cable. The power for the hardware device is provided by the host through USB which in this case is a PC. We need well structured methods to establish communication between PC and PSLab device and this is where pySerial module comes in. We will discuss how to communicate efficiently from PC to a device like PSLab itself using pySerial module.

How to read and write data back to PSLab device?

pySerial is a python module which is used to communicate serially with microcontroller devices like Arduino, RaspBerry Pi, PSLab (Pocket Science Lab), etc. Serial data transfer is easier using this module, you just need to open a port and obtain serial object, which provides useful and powerful functionality. Users can send string (which is an array of bytes) or any other data type all data types can be expressed as byte string using struct module in python, read a specific number of bytes or read till some specific character like ‘\n’ is encountered. We are using this module to create custom read and write functions.

How to Install pySerial and obtain serial object for communication?

You can install pySerial using pip by following command

pip install pyserial

Once it’s installed we can now import it in our python script for use.

Obtain Serial Object

In Linux

>>> import serial
>>> ser = serial.Serial(‘/dev/ttyUSB0’)

In Windows

>>> ser = serial.Serial()
>>> ser.baudrate = 19200
>>> ser.port = ‘COM1’

Or

>>> ser = serial.Serial(‘COM1’, 19200)

You can specify other properties like timeout, stopbits, etc to Serial constructor.

Complete list of parameters is available here. Now this “ser” is an object of Serial class that provides all the functionalities through its interface. In PSLab we obtain a serial object and implement custom methods to handle communication which isn’t directly provided by pySerial, for example if we need to implement a function to get the version of the PSLab device connected. Inside the version read function we need to send some bytes to the device in order to obtain the version string from device as a byte response.

What goes under the hood?

We send some sequence of bytes to PSLab device, every sequence of bytes corresponds to a unique function which is already written in device’s firmware. Device recognises the function and responses accordingly.

Let’s look at code to understand it better.

ser.write(struct.Struct(‘B’).pack(11))  #  Sends 11 as byte string
ser.write(struct.Struct(‘B’).pack(5))   #  Sends 5 as bytes string
x = ser.readline()                      #  Reads bytes until ‘\n’ is encountered   

To understand packing and unpacking using struct module, you can have a read at my other blog post Packing And Unpacking Data in JAVA in which I discussed packing and unpacking of data as byte strings and touched a bit on How it’s done in Python.  

You can specify how many bytes you want to read like shown in code below, which is showing and example for 100 bytes :

x = ser.read(100)

After your communication is complete you can simply close the port by:

ser.close()

Based on these basic interface methods more complex functions can be written to handle your specific needs. More details one how to implement custom methods is available at python-communication-library of PSLab which uses pySerial for communication between Client and PSLab device.

An example of custom read function is suppose I want to write a function to read an int from the device. int is of 2 bytes as firmware is written in C, so we read 2 bytes from device and unpack them in client side i.e on PC. For more such custom functions refer packet_handler.py of PSLab python communication library.

def getInt(self):
      “””
      reads two bytes from the serial port and
      returns an integer after combining them
      “””
      ss = ser.read(2)  # reading 2 bytes from serial object
      try:
          if len(ss) == 2:
              return CP.ShortInt.unpack(ss)[0]  # unpacking bytes to make int
      except Exception as ex:
          self.raiseException(ex, “Communication Error , Function : get_Int”)

Resources

Continue ReadingCommunication by pySerial python module in PSLab

Versioning of SUSI Skills

This is a concept for the management of the skill repository aka The “SUSI Skill CMS.

With SUSI we are building a personal assistant where the users are able to write and edit skills in the easiest way that we can think of. To do that we have to develop a very simple skill language and a very simple skill editor

The skill editor should be done as a ‘wiki’-like content management system (cms). To create the wiki, we follow an API-centric approach. The SUSI server acts as an API server with a web front-end which acts as a client of the API and provides the user interface.

The skill editor will be ‘expert-centric’, an expert is a set of skills. That means if we edit one text file, that text file represents one expert, it may contain several skills which all belong together.

An ‘expert’ is stored within the following ontology:

model  >  group  >  language  >  expert  >  skill

To Implement the CMS wiki system we need versioning with a working AAA System. To implement versioning we used JGit. JGit is an EDL licensed, lightweight, pure Java library implementing the Git version control system.

So I included a Gradle dependency to add JGit to the SUSI Server project.

compile 'org.eclipse.jgit:org.eclipse.jgit:4.6.1.201703071140-r'

Now the task was to execute git commands when the authorised user makes changes in any of the expert. The possible changes in an expert can be

1. Creating an Expert
2. Modifying an existing Expert
3. Deleting an Expert

1. git add <filename>

2. git commit -m “commit message”

Real Example in SUSI Server

This is the code that every servlet shares. It defines the base user role set a URL endpoint to trigger the endpoint

public class ModifyExpertService extends AbstractAPIHandler implements APIHandler {
    @Override
    public String getAPIPath() {
        return "/cms/modifyExpert.json";
    }

This is the part where we do all the processing of the URL parameters and store their versions. This method takes the “Query call” and then extracts the “get” parameters from it.
For the functioning of this service, we need 5 things, “model”, “group”, “language”, “expert” and the “commit message”.

@Override
public ServiceResponse serviceImpl(Query call, HttpServletResponse response, Authorization rights, final JsonObjectWithDefault permissions) {

    String model_name = call.get("model", "general");
    File model = new File(DAO.model_watch_dir, model_name);
    String group_name = call.get("group", "knowledge");
    File group = new File(model, group_name);
    String language_name = call.get("language", "en");
    File language = new File(group, language_name);
    String expert_name = call.get("expert", null);
    File expert = new File(language, expert_name + ".txt");

Then we need to open your SUSI Skill DATA repository and commit the new file in it. Here we call the functions of JGit, which do the work of git add and git commit.

FileRepositoryBuilder builder = new FileRepositoryBuilder();
Repository repository = null;
try {

    repository = builder.setGitDir((DAO.susi_skill_repo))
            .readEnvironment() // scan environment GIT_* variables
            .findGitDir() // scan up the file system tree
            .build();

    try (Git git = new Git(repository)) {

The code above opens our local git repository and creates an object “git”. Then we perform further operations on “git” object. Now we add our changes to “git”. This is similar to when we run “git add . ”

    git.add()
                .addFilepattern(expert_name)
                .call();

Finally, we commit the changes. This is similar to “git commit -m “message”.

    git.commit()
                .setMessage(commit_message)
                .call();

At last, we return the success object and set the “accepted” value as “true”.

    json.put("accepted", true);
        return new ServiceResponse(json);
    } catch (GitAPIException e) {
        e.printStackTrace();
    }

Resources

JGit documentation : https://eclipse.org/jgit/documentation/

SUSI Server : https://github.com/fossasia/susi_server

 

Continue ReadingVersioning of SUSI Skills

How Device Service Makes it Easy to Implement Responsive UI in Open Event Frontend

This blog article will illustrate how the device service which has been used frequently in Open Event Frontend, works to make the UI responsive and render it selectively based on device side. To quote the official documentation,

An Ember.Service is a long-lived Ember object that can be made available in different parts of your application.

The device service is precisely that. It is available universally across the app  and its chief purpose is to provide an object through out the app, which allows us to actively determine the device size at the instant of rendering.  This allows us to have a very easy implementation of a highly responsive UI and also makes it redundant to use  css media queries to achieve similar results. The services allow us to maintain a persistent connection and has to be injected. Like all other ember entities, the boiler plate code of a service may be generated via simply using Ember CLI.

$ ember generate service device

To begin with we define the various breakpoints (in terms of width of the screen) that we want in our app. We will be keeping this outside the service object to keep it lean and faster to loop over. We need to ensure that these break points are exactly the same ones used for semantic UI. This is because we want to be aware of what device the current width represents according to semantic UI because various components of semantic UI behave according to these device sizes. For instance various fields of a form may be stackable only for mobiles, and not for tablets.

const breakpoints = {
mobile: {
  max : 767,
  min : 0
},
tablet: {
  max : 991,
  min : 768
},
computer: {
  max : 1199,
  min : 992
},
largeMonitor: {
  max : 1919,
  min : 1200
},
widescreen: {
  min: 1920
}

Our goal is to iterate over these breakpoints and compare the window width with them, and then assign the device type to the required variable. So we begin with the iterating loop, Also we will always need to keep track of the current screen width, hence we define currentWidth property, whereas the deviceType property will keep track of the current device using currentWidth and the breakpoints. These all will be defined inside the service object. The logic for deviceType property is basically to iterate over all the breakpoints and then it checks if the current width of the document lies within the range of a particular breakpoint.

export default Service.extend({

currentWidth: document.body.clientWidth,

deviceType: computed('currentWidth', function() {
  let deviceType = 'computer';
  const currentWidth = this.get('currentWidth');
  forOwn(breakpoints, (value, key) => {
    if (currentWidth >= value.min && (!value.hasOwnProperty('max') || currentWidth <= value.max)) {
      deviceType = key;
    }
  });
  return deviceType;
}),
})

 

Now it is possible for us to use the deviceType property to calculate other useful properties for device type. For instance, we can add the following to the service object.The very point of using this service is the fact that, though semantic UI supports these breakpoints for devices of various sizes but it doesn’t allow us to use them as boolean properties on the basis of which we can decide, which content to render and which not. Also, since the breakpoints are exclusive, there is no possible overlapping of the properties by them being true simultaneously.Using equal operator is a safe way to compare a computed property.

isMobile       : equal('deviceType', 'mobile'),
isComputer     : equal('deviceType', 'computer'),
isTablet       : equal('deviceType', 'tablet'),
isLargeMonitor : equal('deviceType', 'largeMonitor'),
isWideScreen   : equal('deviceType', 'widescreen'),

One very important thing we should realise is, that even the the deviceType is observing currentWidth, however document.body.clientWidth is not binded, and thus currentWidth needs to be calculated, every time the window is resized, so we add an init() for the service. It will make sure that whenever the window is resized, the currentWidth object will be initialised.

init() {
this._super(...arguments);
$(window).resize(() => {
  debounce(this, () => {
    this.set('currentWidth', document.body.clientWidth);
  }, 200);
});}

This completes the service, now we can see from the following example how will this service be used. In this example we try to make the menu responsive, by using an icon only menu for mobile devices where as a full menu for larger ones. The properties of the service may simply be used via device.<property>.

{{#if device.isMobile}}
 <.div class= ui grouped  icon buttons>
   <.div class=”ui button><.i class=”checkmark icon><./div>
   <.div class=”ui button><.i class=”cancel icon><./div>
 <./div>
{{else}}
 <.div class= ui grouped buttons>
   <.div class=”ui button>Apply<./div>
   <.div class=”ui button>Cancel<./div>
 <./div>
{{/if}}

Resources

**image is licensed under free to use CC0 Public Domain

Continue ReadingHow Device Service Makes it Easy to Implement Responsive UI in Open Event Frontend

Servlets and Containers in SUSI Server

The core of SUSI Clients is the SUSI server that holds the “intelligence” and “personality” of SUSI AI. SUSI Server is in JAVA and it uses the concepts of Servlets heavily. While implementing server for SUSI, we have used JAVA as the backend language and hence are using servlets and Servlet containers heavily.

The problem that servlets are solving is regarding how to generate dynamic content on every request if the request comes with different parameters.  This is not possible by simply using HTML.

Servlets are widely used for dynamic content and have inbuilt support for HTTP (Hypertext Transfer Protocol).

In this blog post, along with basics of servlets and servlet containers, I am explaininghow to make classes for custom servlets. I am using an example of AbstractAPIHandler class that we have used in SUSI server for clear picture.

Web Server

Before we can understand a  servlet container, we need to understand what is a web server.

A web server uses HTTP protocol to transfer data. When a user types in a URL in a browser or any client, he first sees loading and then see the content of the page. So actually there is a server that is sending the content of the page to the user. The transfer of data is in HTTP protocol.

Servlet Container

From the example above, a user can request static pages from the server. Hence the pages will be very basic and we cannot do much with user inputs and dynamic data such as making a real time chat bot. So the idea of having Servlet container is using Java to dynamically generate the content of a web page from the server side.  

The flow of Control

The servlet container manages servlets through servlet life cycles. The container calls a servlet as soon as it receives an HTTP request. Then the servlet does the processing of the data which it has received from the request. the container sends the HTTP response back to the client and then the clients render it to show the final output.

The flowchart below explains how a request is processed from a browser to a servlet container and then to a servlet. It shows the usage of a generic Servlet.

Similarly in SUSI-Server we have a “AbstractAPIHandler” which is a generic servlet that every other servlet inherits.

Structure of a Servlet

public class ServletName extends HttpServlet {

public void init() throws ServletException {
// Servlet Initialization
}

protected void service(HttpServletRequest req,
HttpServletResponse resp)
throws ServletException, IOException {
// Code for the Service Method
}
/**
* Process a GET request
*/
protected void doGet(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
// Code for the doGet() method
}
/**
* Process a POST request
*/
protected void doPost(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
// Code for the doPost() method

}
/**
* Process a PUT request
*/
protected void doPut(HttpServletRequest req,
HttpServletResponse resp)
throws ServletException, IOException {
//Code for the doPut() method

}
}

Abstract API Handler

public abstract class AbstractAPIHandler extends HttpServlet implements APIHandler {
}

The function below sets the Minimum Base Role of the SUSI user. We can set which servlet is accessible by which user.

@Override
public abstract BaseUserRole getMinimalBaseUserRole();

The function below gets the Default Permissions of a user Role in SUSI Server. The permissions for each SUSI user can be different.

@Override
public abstract JSONObject getDefaultPermissions(BaseUserRole baseUserRole);

The function below finally sets whatever output we want to show as a response when we query the SUSI Server.

   public abstract ServiceResponse serviceImpl(Query post,  HttpServletResponse response, Authorization rights, final JsonObjectWithDefault permissions) throws APIException;

Each Servlet in SUSI Server extends this class (AbstractAPIHandler.java). This also increases code reusability.

A Servlet is not a just a simple java class. You cannot run a servlet using javac or by running main() function. In order to run a servlet, you have to deploy this Servlet on a web server.

References

SUSI Server : https://github.com/fossasia/susi_server/

Docs: http://docs.oracle.com/javaee/6/tutorial/doc/bnafd.html

Continue ReadingServlets and Containers in SUSI Server