User Guide for the PSLab Remote-Access Framework

The remote-lab framework of the pocket science lab has been designed to enable user to access their devices remotely via the internet. The pslab-remote repository includes an API server built with Python-Flask and a webapp that uses EmberJS. This post is a guide for users who wish to test the framework. A series of blog posts have been previously written which have explored and elaborated various aspect of the remote-lab such as designing the API server, remote execution of function strings, automatic deployment on various domains etc. In this post, we shall explore how to execute function strings, execute example scripts, and write a script ourselves.

A live demo is hosted at pslab-remote.surge.sh . The API server is hosted at pslab-stage.herokuapp.com, and an API reference which is being developed can be accessed at pslab-stage.herokuapp.com/apidocs . A screencast of the remote lab is also available

Create an account

Signing up at this point is very straightforward, and does not include any third party verification tools since the framework is under active development, and cannot be claimed to be ready for release yet.

Click on the sign-up button, and provide a username, email, and password. The e-mail will be used as the login-id, and needs to be unique.

Login to the remote lab

Use the email-id used for signing up, enter the password, and the app will redirect you to your new home-page, where you will be greeted with a similar screen.

Your home-page

On the home-page, you will find that the first section includes a text box for entering a function string, and an execute button. Here, you can enter any valid PSLab function such as `get_resistance()` , and click on the execute button in order to run the function on the PSLab device connected to the API server, and view the results. A detailed blog post on this process can be found here.

Since this is a new account, no saved scripts are present in the Your Scripts section. We will come to that shortly, but for now, there are some pre-written example scripts that will let you test them as well as view their source code in order to copy into your own collection, and modify them.

Click on the play icon next to `multimeter.py` in order to run the script. The eye icon to the right of the row enables you to view the source code, but this can also be done while the app is running. The multimeter app looks something like this, and you can click on the various buttons to try them out.

You may also click on the Source Code tab in order to view the source

Create and execute a small python script

We can now try to create a simple script of our own. Click on the `New Python Script` button in the top-bar to navigate to a page that will allow you to create and save your own scripts. We shall write a small 3-line code to print some sinusoidal coordinates, save it, and test it. Copy the following code for a sine wave with 30 points, and publish your script.

import numpy as np
x=np.linspace(0,2*np.pi,30)
print (x, np.sin(x))

Create a button widget and associate a callback to the get_voltage function

A small degree of object oriented capabilities have also been added, and the pslab-remote allows you to create button widgets and associate their targets with other widgets and labels.
The multimeter demo script uses this feature, and a single line of code suffices to demonstrate this feature.

button('Voltage on CH1 >',"get_voltage('CH1')","display_number")

You can copy the above line into a new script in order to try it out.

Associate a button’s callback to the capture routines, and set the target as a plot

The callback target for a button can be set to point to a plot. This is useful if the callback involves arrays such as those returned by the capture routines.

Example code to show a sine wave in a plot, and make button which will replace it with captured data from the oscilloscope:

import numpy as np
x=np.linspace(0,2*np.pi,30)
plt = plot(x, np.sin(x))
button('capture 1',"capture1('CH1',100,10)","update-plot",target=plt)
Figure: Demo animation from the plot_test example. Capture1 is connected to the plot shown.
Resources

PSLab Remote Lab: Automatically deploying the EmberJS WebApp and Flask API Server to different domains

The remote-lab software of the pocket science lab enables users to access their devices remotely via the internet. Its design involves an API server designed with Python Flask, and a web-app designed with EmberJS that allows users to access the API and carry out various tasks such as writing and executing Python scripts. For testing purposes, the repository needed to be setup to deploy both the backend as well as the webapp automatically when a build passes, and this blog post deals with how this can be achieved.

Deploying the API server

The Heroku PaaS was chosen due to its ease of use with a wide range of server software, and support for postgresql databases. It can be configured to automatically deploy branches from github repositories, and conditions such as passing of a linked CI can also be included. The following screenshot shows the Heroku configuration page of an app called pslab-test1. Most of the configuration actions can be carried out offline via the Heroku-Cli

 

In the above page, the pslab-test1 has been set to deploy automatically from the master branch of github.com/jithinbp/pslab-remote . The wait for CI to pass before deploy has been disabled since a CI has not been setup on the repository.

Files required for Heroku to deploy automatically

Once the Heroku PaaS has copied the latest commit made to the linked repository, it searches the base directory for a configuration file called runtime.txt which contains details about the language of the app and the version of the compiler/interpretor to use, and a Procfile which contains the command to launch the app once it is ready. Since the PSLab’s API server is written in Python, we also have a requirements.txt which is a list of dependencies to be installed before launching the application.

Procfile

web: gunicorn app:app –log-file –

runtime.txt

python-3.6.1

requirements.txt

gunicorn==19.6.0
flask >= 0.10.1
psycopg2==2.6.2
flask-sqlalchemy
SQLAlchemy>=0.8.0
numpy>=1.13
flask-cors>=3.0.0

But wait, our app cannot run yet, because it requires a postgresql database, and we did not do anything to set up one. The following steps will set up a postgres database using the heroku-cli usable from your command prompt.

  • Point Heroku-cli to our app
    $ heroku git:remote -a pslab-test1
  • Create a postgres database under the hobby-dev plan available for free users.
    $ heroku addons:create heroku-postgresql:hobby-dev

    Creating heroku-postgresql:hobby-dev on ⬢ pslab-test1… free
    Database has been created and is available
    ! This database is empty. If upgrading, you can transfer
    ! data from another database with pg:copy
    Created postgresql-slippery-81404 as HEROKU_POSTGRESQL_CHARCOAL_URL
    Use heroku addons:docs heroku-postgresql to view documentation

  • The previous step created a database along with an environment variable HEROKU_POSTGRESQL_CHARCOAL_URL . As a shorthand, we can also refer to it simply as CHARCOAL .
  • In order to make it our primary database, it must be promoted

    $ heroku pg:promote HEROKU_POSTGRESQL_CHARCOAL_URL
    The database will now be available via the environment variable DATABASE_URL

  • Further documentation on creating and modifying postgres databases on Heroku can be found in the articles section .

At this point, if the app is in good shape, Heroku will automatically deploy its contents to pslab-test1.herokuapp.com. We can test it using a developer tool such as Postman, or make our own webapp to use it.

Deploying the EmberJS WebApp

Since we are using the free plan on Heroku which only allows one dyno, our EmberJS webapp which shares the repository cannot be deployed on the same heroku server. Therefore, we must look for other domains where the frontend can be deployed.

Surge.sh allows easy deployment of Ember apps, and we shall set up our CI’s configuration file .travis.yml to do this for us when a pull request is made, and the build passes

This excerpt from .travis.yml only shows parts relevant to deployment on Surge.sh

after_success:
– pushd frontend
– bash surge_deploy.sh
– popd

Once the build has passed, the after_success hook executes a script called surge_deploy.sh which is located in the directory of the webapp.

Contents of surge_deploy.sh

#!/usr/bin/env bash
if [ “$TRAVIS_PULL_REQUEST” == “false” ]; then
echo “Not a PR. Skipping surge deployment”
exit 0
fi

ember build –environment=’production’

export REPO_SLUG_ARRAY=(${TRAVIS_REPO_SLUG//\// })
export REPO_OWNER=${REPO_SLUG_ARRAY[0]}
export REPO_NAME=${REPO_SLUG_ARRAY[1]}

npm i -g surge

# Details of a dummy account. So can be added to vcs.
export SURGE_LOGIN=j********[email protected]
export SURGE_TOKEN=4********************************f
export DEPLOY_DOMAIN=https://${REPO_NAME}.surge.sh
surge –project ./dist –domain $DEPLOY_DOMAIN;

The variables SURGE_LOGIN and SURGE_TOKEN must be specified, otherwise Surge will open a login prompt, and since there is no way to feed details into a prompt in a Travis build, it will timeout and fail. The surge token can be obtained with a simple `surge login` followed by `surge token` on your system’s terminal.

Final Application

A user’s homepage on the webapp deployed at pslab-remote.surge.sh . The EmberJS app has been configured to send all AJAX requests to the API server located at pslab-remote.herokuapp.com .

Resources

Designing A Remote Laboratory With PSLab: execution of function strings

In the previous blog post, we introduced the concept of a ‘remote laboratory’, which would enable users to access the various features of the PSLab via the internet. Many aspects of the project were worked upon, which also involved creation of a web-app using EmberJS that enables users to create accounts , sign in, and prepare Python programs to be sent to the server for execution. A backend APi server based on Python-flask was also developed to handle these tasks, and maintain a postgresql database using sqlalchemy .

The following screencast shows the basic look and feel of the proposed remote lab running in a web browser.

This blog post will deal with implementing a way for the remote user to submit a simple function string, such as get_voltage(‘CH1’), and retrieve the results from the server.

There are three parts to this:
  • Creating a dictionary of the functions available in the sciencelab instance. The user will only be allowed access to these functions remotely, and we may protect some functions as the initialization and destruction routines by blocking them from the remote user
  • Creating an API method to receive a form containing the function string, execute the corresponding function from the dictionary, and reply with JSON data
  • Testing the API using the postman chrome extension
Creating a dictionary of functions :

The function dictionary maps function names against references to the actual functions from an instance of PSL.sciencelab . A simple dictionary containing just the get_voltage function can be generated in the following way:

from PSL import sciencelab
I=sciencelab.connect()
functionList = {'get_voltage':I.get_voltage}

This dictionary is then used with the eval method in order to evaluate a function string:

result = eval('get_voltage('CH1')',functionList)
print (result)
0.0012

A more efficient way to create this list is to use the inspect module, and automatically extract all the available methods into a dictionary

functionList = {}
for a in dir(I):
	attr = getattr(I, a)
	if inspect.ismethod(attr) and a!='__init__':
		functionList[a] = attr

In the above, we have made a dictionary of all the methods except __init__

This approach can also be easily extrapolated to automatically generate a dictionary for inline documentation strings which can then be passed on to the web app.

Creating an API method to execute submitted function strings

We create an API method that accepts a form containing the function string and option that specifies if the returned value is to be formatted as a string or JSON data. A special case arises for numpy arrays which cannot be directly converted to JSON, and the toList function must first be used for them.

@app.route('/evalFunctionString',methods=['POST'])
def evalFunctionString():
    if session.get('user'):
        _stringify=False
        try:
            _user = session.get('user')[1]
            _fn = request.form['function']
            _stringify = request.form.get('stringify',False)
            res = eval(_fn,functionList)
        except Exception as e:
            res = str(e)
        #dump string if requested. Otherwise json array
        if _stringify:
            return json.dumps({'status':True,'result':str(res),'stringified':True})
        else:
            #Try to simply convert the results to json
            try:
                return json.dumps({'status':True,'result':res,'stringified':False})
            # If that didn't work, it's due to the result containing numpy arrays.
            except Exception as e:
                #try to convert the numpy arrays to json using the .toList() function
                try:
                    return json.dumps({'status':True,'result':np.array(res).tolist(),'stringified':False})
                #And if nothing works, return the string
                except Exception as e:
                    print( 'string return',str(e))
                    return json.dumps({'status':True,'result':str(res),'stringified':True})
    else:
        return json.dumps({'status':False,'result':'unauthorized access','message':'Unauthorized access'})
Testing the API using Postman

The postman chrome extension allows users to submit forms to API servers, and view the raw results. It supports various encodings, and is quite handy for testing purposes.Before executing these via the evalFunctionString method, user credentials must first be submitted to the validateLogin method for authentication purposes.

Here are screenshots of the test results from a ‘get_voltage(‘CH1’)’ and ‘capture1(‘CH1’,20,1)’ function executed remotely via postman.

 

Our next steps will be to implement the dialog box in the frontend that will allow users to quickly type in function strings, and fetch the resultant data

Resources:

 

Designing a Remote Laboratory with PSLab using Python Flask Framework

In the introductory post about remote laboratories, a general set of tools to create a framework and handle its various aspects was also introduced. In this blog post, we will explore the implementation of several aspects of the backend app designed with python-flask, and the frontend based on EmberJS. A clear separation of the frontend and backend facilitates minimal disruption of either sections due to the other.

Implementing API methods in Python-Flask

In the Flask web server, page requests are handled via ‘routes’ , which are essentially URLs linked to a python function. Routes are also capable of handling payloads such as POST data, and various return types are also supported.

We shall use an example to demonstrate how a Sign-Up request sent from the sign-up form in the remote lab frontend for PSLab is handled.

@app.route('/signUp',methods=['POST'])
def signUp():
	"""Sign Up for Virtual Lab

	POST: Submit sign-up parameters. The following must be present:
	 inputName : The name of your account. does not need to be unique
	 inputEmail : e-mail ID used for login . must be unique.
	 inputPassword: password .
	Returns HTTP 404 when data does not exist.
	"""
	# read the posted values from the UI
	_name = request.form['inputName']
	_email = request.form['inputEmail']
	_password = request.form['inputPassword']

	# validate the received values
	if _name and _email and _password:
		_hashed_password = generate_password_hash(_password)
		newUser = User(_email, _name,_hashed_password)
		try:
			db.session.add(newUser)
			db.session.commit()
			return json.dumps({'status':True,'message':'User %s created successfully. e-mail:%s !'%(_name,_email)})
		except Exception as exc:
			reason = str(exc)
			return json.dumps({'status':False,'message':str(reason)})

 

In this example, the first line indicates that all URL requests made to <domain:port>/signUp will be handled by the function signUp . During development, we host the server on localhost, and use the default PORT number 8000, so sign-up forms must be submitted to 127.0.0.1:8000/signUp .

For deployment on a globally accessible server, a machine with a static IP, and a DNS record must be used. An example for such a deployment would be the heroku subdomain where pslab-remote is automatically deployed ; https://pslab-stage.herokuapp.com/signUp

A closer look at the above example will tell you that POST data can be accessed via the request.form dictionary, and that the sign-up routine requires inputName,inputEmail, and inputPassword. A password hash is generated before writing the parameters to the database.

Testing API methods using the Postman chrome extension

The route described in the above example requires form data to be submitted along with the URL, and we will use a rather handy developer tool called Postman to help us do this. In the frontend apps , AJAX methods are usually employed to do such tasks as well as handle the response from the server.

 

The above screenshot shows Postman being used to submit form data to /signUp on our API server running at localhost:8000 . The fields inputName, inputDescription, and inputPassword are also posted along with it.

In the bottom section, one can see that the server returned a positive status variable, as well as a descriptive message.

Submitting the sign up form via an Ember controller.
  • Setting up a template
    We first need to set up a template that we shall call sign-up.hbs , and add the following form to it. This form contains the details essential for signing up , and its submit action is linked to an action called `signMeUp` . This action will be defined in the controller which we shall explore shortly

<form class="form-signin" {{action "signMeUp" on="submit"}} >
        <label for="inputName" class="sr-only">Your Name</label>
        {{input value=inputName type="text" name="inputName" id="inputName" class="form-control" placeholder="name" required=true autofocus=true}}
        <label for="inputEmail" class="sr-only">Email address</label>
        {{input value=inputEmail type="email" name="inputEmail" id="inputEmail" class="form-control" placeholder="Email address" required=true autofocus=true}}
        <label for="inputPassword" class="sr-only">Password</label>
        {{input value=inputPassword type="password" name="inputPassword" id="inputPassword" class="form-control" placeholder="Password" required=true autofocus=true}}
         
        <button class="btn btn-lg btn-primary btn-block" type="submit">Sign Up</button>
</form>

 

  • Defining the controller
    The controller contains the actions and variables that the template links to. In this case, we require an action called signMeUp. The success, failure, and error handlers are hidden for clarity.

import Ember from 'ember';
export default Ember.Controller.extend({
  actions:{
    signMeUp() {
        var request = Ember.$.post("/signUp",
 this.getProperties("inputName","inputEmail","inputPassword"),this,'json');
        request.then(this.success.bind(this), this.failure.bind(this),
this.error.bind(this));
    },
  },
});

The signMeUp action submits the contents of the form to the signUp route on the API server, and the results are handled by functions called success, failure, or error depending on the type of response from the backend server.

Resources:

 

Creating a notification dropdown in semantic UI for Open Event Frontend

Semantic UI comes packaged with highly responsive components to cater to all front end needs. The area of front-end development is so large, it is never possible to cover all the possible requirements of a developer with pre built components. Currently there is no means to display notifications on the navbar in Open Event Front-end project. In this article we are going to build a notification dropdown from scratch which will be used there to display notifications. So we begin by generating a new component via ember CLI

$ ember generate component notification-dropdown

This should generate the boiler-plate code for our component, with the template file located at: templates/components/notification-dropdown.hbs and the JS file located at components/notification-dropdown.js  It is assumed that you already have a basic ember app with at least a navbar set up. The notification drop down will be integrated with the navbar as a separate component. This allows us great flexibility in terms of location of the navbar, and also helps us  in not cluttering the code in one file.

We will use the popup component of semantic ui as the underlying structure of our dropdown. I have used some dummy data stored in a separate file, you can use any dummy data you wish, either  by directly hardcoding it or importing it from a js file stored somewhere else. It’s preferred if the mock data is called from a js file, because it helps in simulating the server response in a much more genuine way.

We will make use of the floating label of semantic UI to display the number of unread notifications. A mail outline icon should make for a good choice to use the primary icon to denote the notifications. Also, the floating label will require additional styling to make it overlap with the icon perfectly.

For the header in the dropdown we can give a ‘mark all as read’ button aligned to the right and the ‘notification’ header to the left. Also for best user experience even on small devices, we will make each notification item clickable as a whole instead of individual clickable elements in it. A selection link list of semantic UI should be perfect to display individual notifications as it gives a hovering effect and also, allows us to display a header. Moving onto individual notification items, it will have 3 sub parts

  • A header
  • Description
  • Human friendly notification time

For the header we will use the ‘header’ class predefined in semantic UI for list items.We will use ‘content’ class for description which is again a predefined semantic UI class, And finally the time can be displayed via moment-from-now helper of ember to display the time in a human friendly format.

<.i class="mail outline icon">
<./i>
<.div class="floating ui teal circular mini label">{{notifications.length}}<./div>
<.div class="ui wide notification popup bottom left transition ">
 <.div class="ui basic inverted horizontal segments">
   <.div class="ui basic left aligned segment weight-800">
     <.p>{{t 'Notifications'}}<./p>
   <./div>
   <.div class="ui basic right aligned segment weight-400">
     <.a href="#">{{t 'Mark all as Read'}}<./a>
   <./div>
 <./div>
 <.div class="ui fluid link celled selection list">
   {{#each notifications as |notification|}}
     <.div class="item">
       <.div class="header">
         {{notification.title}}
       <./div>
       <.div class="content weight-600">
         {{notification.description}}
       <./div>
       <.div class="left floated content">
         {{moment-from-now notification.createdAt}}
       <./div>
     <./div>
   {{/each}}
 <./div>
<./div>

 

Now the next challenge is to make the popup scrollable, they are not scrollable by default and may result in an error if their height exceeds that of the view port. So we apply some styling now. While applying such custom styles we have to be really careful so as to not to apply the styling in general to all of semantic UI’s components. It is very easy to overlook,  and may cause some unwanted changes. It is best to wrap it in a container class, in this case we have chosen to go ahead with notification as the class name. Also, since the notification dropdown should work consistently across all mobile devices, we need to set its maximum height not in terms of pixels but in terms of viewport height. The following styling code takes care of that as well as the icon which we are using to display the notification count.

.notification.item {
 margin: 0 !important;
 .label {
   top: 1em;
   padding: 0.2em;
   margin: 0 0 0 -3.2em !important;

 }
}

.ui.notification.popup {
 padding: 2px;
 .list {
   width: auto;
   max-height: 50vh;
   overflow: hidden;
   overflow-y: auto;
   padding: 0;
   margin: 0;
   .header {
     margin-bottom:5px;
   }
   .content {
     margin-bottom:2px;
   }
   }
 }

 

All of this takes care of the styling. Next, we need to take care of initialising the notification popup. For this we need to go to the navbar component as it is the one who calls the notification dropdown component. And add this to it:

didInsertElement() {
   this._super.call(this);
   this.$('.notification.item').popup({
     popup : '.popup',
     on    : 'click'
   });
 },

 willDestroyElement() {
   this._super.call(this);
   this.$('.notification.item').popup('destroy');
 }

 

The didInsertElement() makes sure that notification pop up is not rendered or initialised before the navbar is. On the other hand, willDestoroyElement() makes sure to clean up and destroy the pop up initialisation. Attached below are some screenshots of what the notification dropdown should look like.

On a wide screen
On mobile screens

Resources

Step by step guide for Beginners in Web Development for Open Event Frontend

Originally the frontend and backend of the Open Event Server project were handled by FLASK with jinja2 being used for rendering templates. As the size of the project grew, it became difficult to keep track of all the modifications made on the frontend side. It also increased the complexity of the code. As a result of this, a new project Open Event Frontend was developed by decoupling the backend and frontend of the Open Event Orga Server. Now the server is being converted fully into functional API and database and the open event frontend project is primarily the frontend for the Open event server API where organisers, speakers and attendees can sign-up and perform various functions.     

The Open Event Frontend project is built on JavaScript web application framework, “Ember.js”. To communicate with the server API Ember.js user Ember data which is a data persistence module via the exposed endpoints. Suppose if you’re coming from the Android background, soon after diving into the web development you can relate that the web ecosystem is much larger than the mobile one and for the first timers it can be difficult to adopt with it because of the reason that in web there are multiple ways to perform a task which can be restricted to very few in the case of Android. For web applications, one can find that much more components are involved in setting up the project while in android one can easily start contributing to project soon after compiling it in Android Studio. One thing which is relatable for both the android and web development is that in the case of android one has to deal with the varying screen sizes and compatibility issue while in the web one has to deal with adding support for different browsers and versions which can be really annoying.

Now let’s see how one can start contributing to the Open event frontend project while having no or a little knowledge of web development. In case if you’ve previous knowledge of JavaScript then you can skip the step 1 and move directly to another step which is learning the framework.

(Here all the steps have been explained in reference if you’re switching from Android  to Web development.)

Step 1. Learning the Language – JavaScript

Now that when you’ve already put your feet into the web development it’s high time to get acquainted with the JavaScript. Essentially in the case of Ember which is easy to comprehend, you can though start with learning the framework itself but the executables file are written in JavaScript so to write them you must have basic knowledge of the concepts in the language. Understanding of JavaScript will help in letting know where the language ends and where the framework starts. It will also help in better understanding of the framework. In my opinion, the basic knowledge of JavaScript like the scope of variables, functions, looping, conditional statements, modifying array and dictionaries, ‘this’ keyword etc. helps in writing and understanding the .js files easily. Also, sometimes in JavaScript, an error might not be thrown as an exception while compiling but it may evaluate the program to undefined, knowledge of the language will help in debugging the code.

Step 2. Learning the Framework – Ember

Ember is a JavaScript Framework which works on Model-View-Controller(MVC) approach. The Ember is a battery included framework which generates all the boilerplate code including components, routes. Templates etc.  required for building an application’s frontend. It is very easy to understand and comprehend. In Ember, we can easily define the data models and relationships and ember will automatically guess the correct API endpoints. Apart from this, the documentation of the ember on its website is very much sufficient to start with. One can easily start developing applications after going through the tutorial mentioned on the ember’s website.  

Step 3. Testing

In the case of Android application development to write test we use android libraries like Mockito and Robolectric. Also, testing is a bit more difficult in Android app development because we have to explicitly write the test but it is a lot easier in the case of web development. In the case of Ember, it provides an ease of testing which no other framework and libraries provide. While generating a component or template ember itself generates the test files for them and all we have to do is to change them according to our requirement. Ember generates unit, acceptance and integration tests by making testing easier. So we don’t have to write the test explicitly we only have to modify the test files generated by ember.    

Step 4. Styling

In Android we have colors.xml, styles.xml, drawables, gradients, shapes etc. for styling our application but in the case of Web, we have Cascading Style Sheets (CSS) for styling our application. Simply using pure CSS make design complicated and difficult to understand, so to make it easier we combine a bunch of design elements with a style file and use Syntactically Awesome Style Sheets (Saas) with mixins to do that which makes creating styles a lot easier and more straightforward. So for styling, our web application one should have the knowledge of HTML as well as CSS.

In conclusion, I can say that learning web development requires learning a few things in parallel which includes learning a language, learning a framework, how to perform testing and different styling skills to make an application beautiful. Due to dynamic nature of the JavaScript and the sheer number of packages and components involved, as opposed to the safe environment that Android Studio provides, it can be sometimes really frustrating.  However, once learned the basics, the knowledge and skills can be easily transferred and applied over and over again.    

Adding dynamic segments to a route in Open Event Frontend Project

When we talk about a web application the first thing comes up is how to decide what to display at a given time which in most of the application is decided with the help of the URL. The URL of the application can be set either by loading the application or by writing the URL manually or may be by clicking some link. In our Open Event Frontend project which is written in Ember.js, an incredibly powerful JavaScript framework for creating web applications, the URL is mapped to the router handlers with the helper of router to render the template for the page, to load the data model to display, to navigate within the application or to handle any actions within the page like button clicking etc.

Suppose the user opens the open event application for the very first time what s/he will see a page containing the list of all the events which are going to happen in the near future along with their details like event name, timings, place, tags etc. If the user clicks one of the events from the list, the current page will be redirected to the detailed specific page for that particular event. The behaviour of changing the content of the page which we observed during this process can be explained with the help of the dynamic segments concept. The dynamic segment is a section of the path for a route which changes based on the content of a page.
This post will focus on how we have added dynamic segments to the route in the open event frontend project.

Let’s demonstrate the process of adding the dynamic segments to the route by taking an example of sessions routes where we can see the list of all the accepted, pending, confirmed and rejected sessions along with their details.

To add a dynamic segment, we need to have a route with path which we add to the route definition in app/router.js file

this.route('sessions',  function() {
   this.route('list', { path: '/:sessions_state' });
});

Dynamic segments are made up of a : followed by an identifier. Ember follows the convention of :model-name_id for two reasons. The first reason is that routes know how to fetch the right model by default if we follow the convention. The second is that params is an object, and can only have one value associated with a key.

After defining the path in app/router.js file we need to add template file,  app/templates/events/sessions/list.hbs which contain the markup to display the data which is defined in the file, app/routes/events/sessions/list.js under the model hook of the route in order to display the correct content for the specified option.

Code containing the markup for the page in app/templates/events/sessions/list.hbs file

<div class="sixteen wide column">
  <table class="ui tablet stackable very basic table">
    <thead>
      <tr>
        <th>{{t 'State'}}</th>
        <th>{{t 'Title'}}</th>
        <th>{{t 'Speakers'}}</th>
        <th>{{t 'Track'}}</th>
        <th>{{t 'Short Abstract'}}</th>
        <th>{{t 'Submission Date'}}</th>
        <th>{{t 'Last Modified'}}</th>
        <th>{{t 'Email Sent'}}</th>
        <th></th>
        <th></th>
      </tr>
    </thead>
    <tbody>
      {{#each model as |session|}}
        <tr>
          <td>
            {{#if (eq session.state "confirmed")}}
              <div class="ui green label">{{t 'Confirmed'}}</div>
            {{else}}
              <div class="ui red label">{{t 'Not Confirmed'}}</div>
            {{/if}}
          </td>
          <td>
            {{session.title}}
          </td>
          <td>
            <div class="ui ordered list">
              {{#each session.speakers as |speaker|}}
                <div class="item">{{speaker.name}}</div>
              {{/each}}
            </div>
          </td>
          <td>
            {{session.track}}
          </td>
          <td>
            {{session.shortAbstract}}
          </td>
          <td>
            {{moment-format session.submittedAt 'dddd, DD MMMM YYYY'}}
          </td>
          <td>
            {{moment-format session.modifiedAt 'dddd, DD MMMM YYYY'}}
          </td>
          <td>
            {{session.emailSent}}
          </td>
          <td>
            <div class="ui vertical compact basic buttons">
              {{#ui-popup content=(t 'View') class='ui icon button' position='left center'}}
                <i class="unhide icon"></i>
              {{/ui-popup}}
              {{#ui-popup content=(t 'Edit') class='ui icon button' position='left center'}}
                <i class="edit icon"></i>
              {{/ui-popup}}
              {{#ui-popup content=(t 'Delete') class='ui icon button' position='left center'}}
                <i class="trash outline icon"></i>
              {{/ui-popup}}
              {{#ui-popup content=(t 'Browse edit history') class='ui icon button' position='left center'}}
                <i class="history icon"></i>
              {{/ui-popup}}
            </div>
          </td>
          <td>
            <div class="ui vertical compact basic buttons">
              {{#ui-dropdown class='ui icon bottom right pointing dropdown button'}}
                <i class="green checkmark icon"></i>
                <div class="menu">
                  <div class="item">{{t 'With email'}}</div>
                  <div class="item">{{t 'Without email'}}</div>
                </div>
              {{/ui-dropdown}}
              {{#ui-dropdown class='ui icon bottom right pointing dropdown button'}}
                <i class="red remove icon"></i>
                <div class="menu">
                  <div class="item">{{t 'With email'}}</div>
                  <div class="item">{{t 'Without email'}}</div>
                </div>
              {{/ui-dropdown}}
            </div>
          </td>
        </tr>
      {{/each}}
    </tbody>
  </table>
</div>

 

Code containing the model hook in app/routes/events/sessions/list.js to display the correct content. We access the dynamic portion of the URL using params.

import Ember from 'ember';

const { Route } = Ember;

export default Route.extend({
  titleToken() {
    switch (this.get('params.session_status')) {
      case 'pending':
        return this.l10n.t('Pending');
      case 'accepted':
        return this.l10n.t('Accepted');
      case 'confirmed':
        return this.l10n.t('Confirmed');
      case 'rejected':
        return this.l10n.t('Rejected');
    }
  },
  model(params) {
    this.set('params', params);
    return [{
      title         : 'Test Session 1',
      speakers      : [{ name: 'speaker 1', id: 1, organization: 'fossasia' }, { name: 'speaker 2', id: 1, organization: 'fossasia' }],
      track         : 'sample track',
      shortAbstract : 'Lorem Ipsum is simply dummy text of the printing and typesetting industry.',
      submittedAt   : new Date(),
      modifiedAt    : new Date(),
      emailSent     : 'No',
      state         : 'confirmed'
    },
    {
      title         : 'Test Session 2',
      speakers      : [{ name: 'speaker 3', id: 1, organization: 'fossasia' }, { name: 'speaker 4', id: 1, organization: 'fossasia' }],
      track         : 'sample track',
      shortAbstract : 'Lorem Ipsum is simply dummy text of the printing and typesetting industry.',
      submittedAt   : new Date(),
      modifiedAt    : new Date(),
      emailSent     : 'Yes',
      state         : 'confirmed'
    }];
  }
});

 

After the route is fully configured, we need to start linking it from the templates which mean we need to link it in our parent template, app/templates/events/view/sessions.hbs file using the {{link-to}} helper. The code for the linking looks like this:

    {{#tabbed-navigation isNonPointing=true}}
        {{#link-to 'events.view.sessions.index' class='item'}}
          {{t 'All'}}
        {{/link-to}}
        {{#link-to 'events.view.sessions.list' 'pending' class='item'}}
          {{t 'Pending'}}
        {{/link-to}}
        {{#link-to 'events.view.sessions.list' 'accepted' class='item'}}
          {{t 'Accepted'}}
        {{/link-to}}
        {{#link-to 'events.view.sessions.list' 'confirmed' class='item'}}
          {{t 'Confirmed'}}
        {{/link-to}}
        {{#link-to 'events.view.sessions.list' 'rejected' class='item'}}
          {{t 'Rejected'}}
        {{/link-to}}
      {{/tabbed-navigation}} 

 

The User Interface for the above code looks like this:

Fig. : The page containing all the accepted session

To conclude this, we can say the task of the route is to load the modal to display the data. For example, if we have the route this.route(‘sessions’);, the route might load all of the sessions for the app but we want only the particular type of session so the dynamic segments help to load the particular model and make it easier to load and display the data.

Reference: The link to the complete code is here. For getting more knowledge about dynamic segments please visit this.

Using Ember.js Components in Open Event Frontend

Ember.js is a comprehensive JavaScript framework for building highly ambitious web applications. The basic tenet of Ember.js is convention over configuration which means that it understands that a large part of the code, as well as development process, is common to most of the web applications. Talking about the components which are nothing but the elements whose role remain same with same properties and functions within the entire project. Components allow developers to bundle up HTML elements and styles into reusable custom elements which can be called anywhere within the project.

In Ember, the components consist of two parts: some JavaScript code and an HTMLBars template. The JavaScript component file defines the behaviour and properties of the component. The behaviours of the component are typically defined using actions. The HTMLBars file defines the markup for the component’s UI. By default, the component will be rendered into a ‘div’ tag element, but a different element can be defined if required. A great thing about templates in Ember is that other components can be called inside of a component’s template. To call a component in an Ember app, we must use {{curly-brace-syntax}}. By design, components are completely isolated which means that they are not directly affected by any surrounding CSS or JavaScript.

Let’s demonstrate a basic Ember component in reference to Open Event Frontend Project for displaying the text as a popup. The component will render a simple text view which will display the entire text. The component is designed with the purpose that many times due to unavailability of space we’re unable to show the complete text so such cases the component will compare the available space with the space required by the whole text view to display the text. If in case the available space is not sufficient then the text will be ellipsized and on hovering the text a popup will appear where the complete text can be seen.

Generating the component

The component can be generated using the following command:

$ ember g component smart-overflow

Note: The components name needs to include a hyphen. This is an Ember convention, but it is an important one as it’ll ensure there are no naming collisions with future HTML elements.This will create the required .js and .hbs files needed to define the component, as well as an Ember integration test.

The Component Template

In the app/templates/components/smart-overflow.hbs file we can create some basic markup to display the text when the component is called.

<span> {{yield}} </span>

The {{yield}} is handlebars expressions which will be helpful in rendering the data to display when the component is called.

The JavaScript Code

In the app/components/smart-overflow.js file, we will define the how the component will work when it is called.

import Ember from 'ember';

const { Component } = Ember;

export default Component.extend({
  classNames: ['smart-overflow'],
  didInsertElement() {
    this._super(...arguments);
    var $headerSpan = this.$('span');
    var $header = this.$();
    $header.attr('data-content', $headerSpan.text());
    $header.attr('data-variation', 'tiny');
    while ($headerSpan.outerHeight() > $header.height()) {
      $headerSpan.text((index, text) => {
        return text.replace(/\W*\s(\S)*$/, '...');
      });
      $header.popup({
        position: 'top center'
      });
      this.set('$header', $header);
    }
  },
  willDestroyElement() {
    this._super(...arguments);
    if (this.get('$header')) {
      this.get('$header').popup('destroy');
    }
  }
});

 

In the above piece of code, we have first taken the size of the available space in header variable and then taken the size of the content in header span variable. After that, we’re comparing both the sizes to check if the content is greater than the available space then we are ellipsizing the content and create a popup to display the complete text to produce good user experience.

Passing data to the component

To allow the component to display the data properly, we need to pass it in.

In the app/templates/components/event-card.hbs file we can call the component as many times as desired and pass in relevant data for each attribute.

<div class="ui card {{unless isWide 'event fluid' 'thirteen wide computer ten wide tablet sixteen wide mobile column'}}">
    {{#unless isWide}}
      <a class="image" href="{{href-to 'public' event.identifier}}">
        {{widgets/safe-image src=(if event.large event.large event.placeholderUrl)}}
      </a>
    {{/unless}}
    <a class="main content" href="{{href-to 'public' event.identifier}}">
      {{#smart-overflow class='header'}}
        {{event.name}}
      {{/smart-overflow}}
      <div class="meta">
        <span class="date">
          {{moment-format event.startTime 'ddd, MMM DD HH:mm A'}}
        </span>
      </div>
      {{#smart-overflow class='description'}}
        {{event.shortLocationName}}
      {{/smart-overflow}}
    </a>
    <div class="extra content small text">
      <span class="right floated">
        <i role="button" class="share alternate link icon" {{action shareEvent event}}></i>
      </span>
      <span>
        {{#if hasBlock}}
          {{yield}}
        {{else}}
          {{#each tags as |tag|}}
            <a>{{tag}}</a>
          {{/each}}
        {{/if}}
      </span>
    </div>
  </div>

 

Now if you view the app in the browser at localhost:4200, you will see something like this.

Fig. 1

In the end, we can say that with the components, the code remains much clear and readable. It makes more sense to the developers who happen upon them. The best part about them is their reusability across the application making the development process faster and much more efficient.

Reference: The Complete source for the smart overflow can be found here.

Forms and their validation using Semantic UI in Open Event Frontend

A web form acts as a communication bridge that allows a user to communicate with the organisation and vice versa. In the Open Event project, we need forms so users can contact the organisation, to register themselves, to log into the website, to order a ticket or to query for some information. Here are a few things which were kept in mind before we designed forms in the Open Event Frontend Project:

  • The forms were designed on the principle of keeping it simple which means that it should ask only for the relevant information which is required in actual.
  • They contained the relevant fields ordered in a logical way according to their importance.
  • They offered clear error messages instantly to give direct feedback and allow users to make instant corrections.
  • The clear examples were shown in the front of the field.
  • Proper spacing among the fields was maintained to display proper error messages to the respective form fields.
  • The mandatory fields are highlighted using ‘*’ to avoid confusion.
  • Proper colour combinations have been used to inform the user about the progress while filling the form. For eg. red for any ‘error or incomplete’ information while green signifies ‘correct’.
  • Saving the current data in case the user has to go back to make any corrections later.
  • Allowing to toggle through the form using the keyboard.

The above designing principles helped in avoiding the negative user experience while using the forms.

Let’s take a closer look at the form and the form validation in case of purchase a new ticket form on the Orders page in Open Event Front-end application.

Creating a form

Let’s start by writing some HTML for the form:

<form class="ui form" {{action 'submit' on='submit' }}>
  <div class="ui padded segment">
    <h4 class="ui horizontal divider header">
      <i class="ticket icon"></i>
      {{t 'Ticket Buyer'}}
    </h4>
    <div class="field">
      <label class="required" for="firstname">{{t 'First Name'}}</label>
      {{input type='text' name='first_name' value=buyer.firstName}}
    </div>
    <div class="field">
      <label class="required" for="lastname">{{t 'Last Name'}}</label>
      {{input type='text' name='last_name' value=buyer.lastName}}
    </div>
    <div class="field">
      <label class="required" for="email">{{t 'Email'}}</label>
      {{input type='text' name='email' value=buyer.email}}
    </div>
    <h4 class="ui horizontal divider header">
        <i class="ticket icon"></i>
        {{t 'Ticket Holder\'s Information'}}
    </h4>
    {{#each holders as |holder index|}}
      <div class="inline field">
        <i class="user icon"></i>
         <label>{{t 'Ticket Holder '}}{{inc index}}</label>
      </div>
      <div class="field">
        <label class="required" for="firstname">{{t 'First Name'}}</label>
        {{input type='text' name=(concat 'first_name_' index) value=holder.firstName}}
      </div>
      <div class="field">
        <label class="required" for="lastname">{{t 'Last Name'}}</label>
        {{input type='text' name=(concat 'last_name_' index) value=holder.lastName}}
      </div>
      <div class="field">
        <label class="required" for="email">{{t 'Email'}}</label>
        {{input type='text' name=(concat 'email_' index) value=holder.email}}
      </div>
      <div class="field">
        {{ui-checkbox label=(t 'Same as Ticket Buyer') checked=holder.sameAsBuyer onChange=(action 'fillHolderData' holder)}}
      </div>
    {{/each}}
    <p>
      {{t 'By clicking "Pay Now", I acknowledge that I have read and agree with the Open Event terms of services and privacy policy.'}}
    </p>
    <div class="center aligned">
      <button type="submit" class="ui teal submit button">{{t 'Pay Now'}}</button>
    </div>
  </div>
</form>

 

The complete code for the form can be seen here.

In the above code, we have used Semantic UI elements like button, input, label, icon, header and modules like dropdown, checkbox to create the basic structure of the form.

The form is created using the Semantic markup. Along with semantic UI collection “form”, the segment element has been used to create the grouping of similar content like we have a timer and its related description that after 10 minutes the reservation will no longer be held are put together in a segment where they are arranged using semantic UI view “statistic”. Due to the vastness of semantic UI, all the styling has been done using it like fields inlining, button styling, segment background coloring etc.

The form is created using the Semantic markup. Along with semantic UI collection “form”, the segment element has been used to create the grouping of similar content like we have a timer and its related description that after 10 minutes the reservation will no longer be held are put together in a segment where they are arranged using semantic UI view “statistic”. Semantic UI elements like button, input, label, icon, header and modules like dropdown, checkbox have been used. Due to the vastness of semantic UI, all the styling has been done using it like fields inlining, button styling, segment background colouring etc.

The page for the above HTML code looks like this:

Image for the order form

Fig. 1: Order Form to purchase a ticket

The complete form can be seen on this link.

Adding form validations

We can also add validation in HTML format but writing the validation in JavaScript file is considered good practice.

Let’s see how we can add validation to fields in Javascript.

  getValidationRules() {
    let firstNameValidation = {
      rules: [
        {
          type   : 'empty',
          prompt : this.i18n.t('Please enter your first name')
        }
      ]
    };
    let lastNameValidation = {
      rules: [
        {
          type   : 'empty',
          prompt : this.i18n.t('Please enter your last name')
        }
      ]
    };
    let emailValidation = {
      rules: [
        {
          type   : 'empty',
          prompt : this.i18n.t('Please enter your email')
        }
      ]
    };
    let validationRules = {
      inline : true,
      delay  : false,
      on     : 'blur',
      fields : {
        firstName: {
          identifier : 'first_name',
          rules      : [
            {
              type   : 'empty',
              prompt : this.i18n.t('Please enter your first name')
            }
          ]
        },
        lastName: {
          identifier : 'last_name',
          rules      : [
            {
              type   : 'empty',
              prompt : this.i18n.t('Please enter your last name')
            }
          ]
        },
        email: {
          identifier : 'email',
          rules      : [
            {
              type   : 'email',
              prompt : this.i18n.t('Please enter a valid email address')
            }
          ]
        },
        zipCode: {
          identifier : 'zip_code',
          rules   : [
            {
              type   : 'empty',
              prompt : this.i18n.t('Please enter your zip code')
            }
          ]
        } 
    };

Let’s break this up, first, we have an array of validation rules.

  zipCode: {
     identifier : 'zip_code',
        rules   : [
        {
          type   : 'empty',
          prompt : this.i18n.t('Please enter your zip code')
         }
      ]
   }

The first part zipcode is the identifier in Semantic.

The next bit of the identifier, this can match against either id, name or data-validate attributes on the element. We have here picked up the name which we’re using on our labels.

Next bit of the rules, which is an array of objects defining the type of validation, and the message to prompt the user with.

The second part is the settings:

inline : true,

delay : false,

on : 'blur',

This part says we want validation to occur on blur, delayed and to be inline. This gives us the following effect:

Fig. 2: Order Form after validation

To summarise the post, one can say we have seen here how the form to purchase the event ticket has been designed, coded and styled. The complete form can be seen on this link and the complete code can be seen here. The entire form has been designed in such a way to keep it simple, clear and trustworthy without losing the user interaction.

References:

Diving into the codebase of the Open Event Front-end Project

This post aims to help any new contributor to get acquainted with the code base of the Open Event Front-end project.

The open event front-end is primarily the front-end for the Open Event API server. The project provides the functionality of signing up, add, update and view events details and many other functions to the organisers, speakers and attendees of the event which can be concert, conference, summit or a meetup. The open event front-end project is built on a JavaScript web application framework Ember.js. Ember uses a library Ember data for managing the data in the application and for communicating with server API via endpoints. Ember is a battery included framework which means that it creates all the boilerplate code required to set up the project and create a working web application which can be modified according to our needs.

The open event front-end is primarily the front-end for the Open Event API server. The project provides the functionality of signing up, add, update and view events details and many other functions to the organisers, speakers and attendees of the event which can be concert, conference, summit or a meetup. The open event front-end project is built on a JavaScript web application framework Ember.js. Ember uses a library Ember data for managing the data in the application and for communicating with server API via endpoints. Ember is a battery included framework which means that it creates all the boilerplate code required to set up the project and create a working web application which can be modified according to our needs.

For example: When I created a new project using the command:

$ ember new open-event-frontend

It created a new project open-event-frontend with all the boilerplate code required to set up the project which can be seen below.

create .editorconfig
create .ember-cli
create .eslintrc.js
create .travis.yml
create .watchmanconfig
create README.md
create app/app.js
create app/components/.gitkeep
Installing app
create app/controllers/.gitkeep
create app/helpers/.gitkeep
create app/index.html
create app/models/.gitkeep
create app/resolver.js
create app/router.js
create app/routes/.gitkeep
create app/styles/app.css
create app/templates/application.hbs
create app/templates/components/.gitkeep
create config/environment.js
create config/targets.js
create ember-cli-build.js
create .gitignore
create package.json
create public/crossdomain.xml
create public/robots.txt
create testem.js
create tests/.eslintrc.js
create tests/helpers/destroy-app.js
create tests/helpers/module-for-acceptance.js
create tests/helpers/resolver.js
create tests/helpers/start-app.js
create tests/index.html
create tests/integration/.gitkeep
create tests/test-helper.js
create tests/unit/.gitkeep
create vendor/.gitkeep
NPM: Installed dependencies
Successfully initialized git.

Now if we go inside the project directory we can see the following files and folders have been generated by the Ember-CLI which is nothing but a toolkit to create, develop and build ember application. Ember has a runtime resolver which automatically resolves the code if it’s placed at the conventional location which ember knows.

➜ ~ cd open-event-frontend
➜ open-event-frontend git:(master) ls
app  config  ember-cli-build.js  node_modules  package.json  public  README.md  testem.js  tests  vendor

What do these files and folders contain and what is their role in reference to the project, “Open event front-end”?

Directory structure of open event frontend project

Fig 1: Directory structure of the Open Event Front-end project

Let’s take a look at the folders and files Ember CLI generates.

App: This is the heart of the project. It is responsible for deciding how our application will look and work. This is the place where folders and files for models, components, routes, templates and styles are stored. The majority of our application’s code is written in this folder. The adapter directory contains the application.js file which is responsible for authorising all outgoing API requests. Since our application is an event application so it has various screens which display the list of events, sessions, schedule, speakers, functionality to add, delete, modify the event details etc. Most of the screens have some features in common which can be reused everywhere inside the application which is kept in components directory. The controllers directory contains the files which will be responsible for the front-end behaviour which is not related to the models of our application. For example actions like sharing the event details. The data of the event is fetched by API but when the share functionality has to work is decided by the controller. Models directory helps in mapping the format of data i.e. in which format the data is fetched from the API. As we interact with the application, it moves through many different states/screens using different URLs. The routes directory decides which template will be rendered and which model will be loaded to display the data in the current template. The services directory contains the services which kept on running in the application like authentication service to check whether the current user has logged in or not, translation service to translate the details into some other language other than English which is supported by the app if required. The styles directory contains .scss files for styling of layouts. The template directory contains the layouts for the user interface of the application in form of Handlebar Templates which contains the HTML code which will be rendered on the screen when the template will be called via routes. The utils directory contains all the utility files like the format of date and time, demographic details, event type, type of topics etc.   

Directory structure of App folder

Fig 2: Directory structure of the app folder

Config: It contains files where we can we configure the settings of our application. The environment.js file contains the details like application name and API endpoints and other details required to configure the application. The deploy.js file contains the configurational details about the deployment.

Directory structure of config folder

Fig 3: Directory structure of config folder

Mirage: It contains the files which are required to mock the API server. Since we need to fetch the data from the server so whenever we make a request to get and post the data, mirage will respond to that data. It also contains the file which helps in seeding fake data for the application. Here mocking means creating objects that simulate the behaviour of real objects. The default.js application handles the seeding the fake data but currently, we don’t require that hence it’s empty. The config.js file has the method which sets the API host and namespace of the application.

Directory structure of mirage folder

Fig 4: Directory structure of mirage folder

Node_modules: As we know that Ember is built with Node and uses various node.js modules for functioning. So this directory contains all the files generated from the running the npm package manager which we run at starting while installing and setting up the project on the local device. The package.json file contains all the file maintains the list of npm dependencies for our app.

Public: This directory contains all the assets such as images and fonts related to the application. In the case of our application, to add images apart from the ones that are fetched from the API, they have to be placed here.

Directory structure of public folder

Fig 5: Directory structure of public folder

Translations: Since our application provides various languages support so this directory contains the files to translate the messages.

Directory structure of translations folder

Fig 6: Directory structure of translations folder

Tests: This is the best feature which Ember has provided. We don’t have to generate test they are automatically generated by the Ember-CLI which can be modified according to our requirements. Ember generates three types of test which are Acceptance, Integration and Unit tests. Other than that Ember offers testing for helpers, controllers, routes and models. Test runner of Ember-CLI testem is configured in testem.js. All three types of test have been used in our application.

Directory structure of test folder

Fig 7: Directory structure of test folder

ember-cli-build.js: This file contains the detail how Ember CLI should build our app. In the case of our project, it contains all the metadata such as app imports and other details to build the app.   

Vendor: This directory usually contains all the front-end dependencies (such as JavaScript or CSS) which are not managed by Bower go (which is a package manager for managing components that contain HTML, CSS, JavaScript, fonts). But in the case of our project, we have only kept .gitkeep inside this since we have not included any dependency which Bower doesn’t maintain.

To summarise, this post explains about the content and the role of different files and folders in the directory structure of the Open Event Front-end Project which may help a new contributor to get started by getting a basic understanding of the project.