Choose Your Own Adventure  Presentation

Hamad AlGhanim

Kuwait University Graduate

Research and development engineer at KGL

Computer Engineering Masters student




Web Development

Android & iOS Development


Live Tracking

Using WebSockets to track employees (Django Channels)

Things We Will Use:

  • Django
  • ASGI_Redis
    • Asynchronous Server Gateway Interface (replaces WSGI)
  • Daphne
    • HTTP, HTTP2, and WebSocket protocol server for ASGI
  • The new Django Channels

Websocket Server:

from channels import Group
from channels.sessions import channel_session
import json
from main.models import Employee

def connect(message):
    pk = message['path'].strip('/')
    Group('employee-'+ pk).add(message.reply_channel)
    message.channel_session['employee'] = pk

def ws_receive(message):
    pk = message.channel_session['employee']
    data = json.loads(message['text'])
    employee = Employee.objects.get(pk=pk)
    employee.location.latitude = data['location']["latitude"]
    employee.location.longitude = data['location']["longitude"]
    Group('employee-' + pk).send({'text': json.dumps(data)})

def disconnect(message):
    pk = message.channel_session['employee']
    type = message.channel_session['type']
    Group('employee-' + pk).discard(message.reply_channel)

Websocket Client:

function initMap() {
    var myLatLng = {lat: -25.363, lng: 131.044};
    var marker;
    var map = new google.maps.Map(document.getElementById('map'), {
        zoom: 16,
        center: myLatLng

    marker = new google.maps.Marker({
        position: myLatLng,
        map: map,
        title: 'Hello World!'
    ws = new WebSocket("ws://");

    ws.onmessage = function(event) {
	var ws_location = $.parseJSON(;
	var myLatLng = {lat: ws_location.latitude, lng: ws_location.longitude};

    ws.onclose = function() {
	console.log("Socket closed");

    ws.onopen = function() {



Web Scraping

Scraping My University's Portal System

What Do We Want to Achieve

  • Check University portal every n minutes
  • Update database with new seats
  • Notify people if the section they need has an empty seat (email and push)

Easy, right? Should take a day maximum? two?


Gonna tell you the sad truth about estimations

What Happened?

  • The website was an oracle ADF website.. which means?
  • Simple script won't cut it, used Selenium with Chrome
  • Switched to PhantomJS with Selenium
  • Docker + Celery + Django = ??

The Fix?

  • Heroku + DjangoQ + Django = Profit?
  • PhantomJS is too slow, no support for selenium..
  • [ 4 hours later looking at packets ]       Requests FTW!!


  • Down from 300 lines of code that fails most of the time to less than 100 reliable lines
  • Used to take nearly 3+ minutes for each subject, now can check nearly 8 subjects in 1 minute or less

Couldn't find the old screenshot :(

Future Plans?

  • Use Docker with a Linux box and not Heroku to get the best performance with no delay in scheduled tasks
  • Hopefully launch the app to the general public
  • Expand to other universities

A look at what the system scraped on its own


5 Must Have Android Libraries


Butter Knife

Before and After

class ExampleActivity extends Activity {
  @BindView( EditText username;
  @BindView( EditText password;
    public void onCreate(Bundle bundle) {
      // TODO Use fields... (Yes thats it)

    public void submit(View view) {
      // TODO submit data to server...
class ExampleActivity extends Activity {
  EditText username;
  EditText password;

  public void onCreate(Bundle bundle) {

      new View.OnClickListener() {
        public void onClick(View view) {
            // Do something here



Before and After

// Download image

// Yes this is it

// ------ also you can load gifs -------
// Customizable
     //can be a resource or a drawable
     //fallback image if error
     // reduce the image size to dimensions 
     // of imageView
     .resize(imgWidth, imgHeight) 
     //resizes the image in pixels
     .centerCrop() //or .centerInside()
     //or rotate(degrees, pivotX, pivotY)
     .noFade() //dont fade all fancy-like

// and more
private Bitmap DownloadImage(String url)
  Bitmap bitmap = null;
  InputStream in = null;
  String TAG = "DownloadImage";

      in = OpenHttpGETConnection(url);
      bitmap = BitmapFactory.decodeStream(in); 
  catch (Exception e)
      Log.d(TAG, e.getLocalizedMessage());

  return bitmap;

#3 + #4 + #5

Retrofit + Gson + Realm

Why All Three?

  • They all work together beautifully
    1. Retrofit (API calls)
    2. GSON (Serialize JSON objects)
    3. Realm (Replaces SQLite DB)
public interface GitHubService {
  Call<List<Repo>> listRepos(@Path("user") String user);

Retrofit retrofit = new Retrofit.Builder()

GitHubService service = retrofit.create(GitHubService.class);

Call<List<Repo>> repos = service.listRepos("octocat");

GSON + Realm

public class Repo extends RealmObject {

    @SerializedName("name") //name in JSON
    private String name;


RealmConfiguration realmConfig =
    new RealmConfiguration.Builder(context).build();

// Get a Realm instance for this thread
Realm realm = Realm.getDefaultInstance();


// Persist unmanaged objects
final Repo repo = realm.copyToRealm(oldRepo);

// Create managed objects directly
Repo newRepo = realm.createObject(Repo.class);


Realm Queries

RealmQuery<User> query = realm.where(Repo.class);

// Add query conditions:
query.equalTo("name", "octocat");
query.or().equalTo("name", "Dreamersoul");

// Execute the query:
RealmResults<User> result1 = query.findAll();
// thats it

Any Questions?

Choose Your Own Adventure

By Hamad Al-Ghanim

Choose Your Own Adventure

  • 244
Loading comments...

More from Hamad Al-Ghanim