Code Monkey home page Code Monkey logo

deep-learning-indaba / baobab Goto Github PK

View Code? Open in Web Editor NEW
54.0 54.0 34.0 11.4 MB

Baobab is an open source multi-tenant web application designed to facilitate the application and selection process for large scale meetings within the machine learning and artificial intelligence communities globally. Supported by the Deep Learning Indaba

Home Page: http://www.deeplearningindaba.com

License: Apache License 2.0

Dockerfile 0.03% Python 72.33% Mako 0.01% HTML 0.20% CSS 1.68% JavaScript 25.70% Shell 0.04% PLpgSQL 0.01%
docker flask postgres python reactjs

baobab's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

baobab's Issues

Implement "Save for later" in application form front-end

Depends on #66

Implement a "save for later" button on the application form. This entails the following:

  • Pre-populate the application form with the values from any existing response received from the back-end
  • Add a "save for later" button to the application form UI. This button should trigger a POST or a PUT to the back-end to save the response (post if its a new response, put if it's an update to an existing response). The is_submitted flag should be set to False when using this button.
  • Ignore validation (is_required and validation_regex) when saving for later, but apply validation when submitting

Add Ethnicity List

The ethnicity field on the Create Account form should be a selection box with the following options (as per the South African demographic groups, for reporting)
Black,
Coloured / Mixed Descent,
White,
Indian Descent,
Other

Data updates

Tracking issue for miscellaneous data updates required:

  • Update closing date for Indaba 2019 application form to 12 April 2019
  • Update placeholder on "May we add your CV..." question to "Select an option..." (it currently says Select and option...)
  • Update "Academic" to "Academic Faculty" in user category

Application form Integration

Update the application form front-end to send the correct JSON to the response API. Test that the functionality works end-to-end.

Create ApplicationForm controller

Depends on #18

Create a back-end controller that can be used to GET an application form.
GET should be able to retrieve an application form for a given eventId

POST is optional for now because we could insert the data for the Indaba2019 form directly into the database in the interim.

Example of JSON response:

{
"eventId": 1,
"is_open": true,
"deadline": "2019-04-30",
sections: [
{
"sectionId": 1,
"name": "Section 1",
"description": "Section 1 description",
"order": 1
"questions": [
{"description": "Question 1", "type": "short-text", "required": true, "order": 1},
{"description": "Question 2", "type": "single-choice", "required": false, "order": 2},
]
},
{
"sectionId": 2,
"name": "Section 2",
"description": "This is section 2",
"order": 1
"questions": [
{"description": "What is 2+2?", "type": "short-text", "required": true, "order": 1},
{"description": "Upload your CV", "type": "file", "required": false, "order": 2},
]
},
]

}

Definition of Done
This task is done when:

  • There is an implementation of an applicationForm API in api/app/applicationForm/api.py that accepts a GET request
  • The API correctly retrieves the applicationForm (and associated section and question) models from the database
  • The API serializes the applicationForm and associated models and responds with JSON conforming to the above example
  • There are unit tests for the API

Add VerifyEmail front-end

Add a front-end for the verify email functionality (at the moment the link in the email points to HOST/VerifyEmail?token=TOKEN - this involves calling the API (/api/v1/verify-email?token=TOKEN) and then redirecting the user to the home-page.

Create Response controller

Create a controller to handle saving and submitting of Responses as documented in the application process spec.

The controller should contain

  • A GET method that retrieves a response for a given event_id for the logged-in user. A serialized JSON response is returned of the form illustrated below.
  • A POST method that accepts a JSON serialized response and saves the response to the database. This will make use of the data model created in #21. If a response already exists (the response_id is populated in the JSON received), it should be updated, else a new response should be inserted and the new ID returned.
  • A DELETE method that accepts a response_id and sets the is_withdrawn flag and the withdrawn_timestamp on the Response object

Definition of Done
This task is done when

  • A new controller exists in api/app/response/api.py implementing methods described above which communicate using JSON of the form illustrated below
  • Unit tests exist for the response api
  • Checks exist in the API to ensure that a user can only retrieve/update/delete their own responses

An example of the JSON serialization of the Response/Answer model (NOTE: The response_id field should only be populated if the user is updating their response)
{
"response_id": 1,
"answers": [
{"question_id": 1, "value": "answer 1"},
{"question_id": 2, "value": "stuff"),
{"question_id": 3, "value": "hello world")
],
"is_submitted": false
}

Populate Application Form

Create a script/migration that populates data in the Event, ApplicationForm, Section and Question tables for the 2019 Indaba. The application form should be based on last year's form with the following changes:

  1. Exclude the personal information section, as most of these details are now captured in the user account creation form
  2. Add a section called "Previous attendance" with the following questions:
  • "Did you attend the 2017 or 2018 Indaba" - options: 2017, 2018, 2017 and 2018, Neither
  • "If you attended a previous Indaba, tell us how it has helped you grow or how you have used what you have learnt."
  1. Leave out the "Your skills and experience" section - we will not be asking these questions in the 2019 application form.

See this migration for an example of how to seed static data with bulk_insert

Add application status on home page

If a user has already submitted a response for the Indaba 2019 application form, add a status to the home page indicating this.
Also the apply page should provide an option of withdrawing their application.

Implement file upload in application form front end

Implement file-upload functionality in the application form front-end. Do this by sending a separate multipart/form-data POST request when saving the response to a dummy back-end REST endpoint (eg /file). The back-end should respond with a file-id, this file-id should then be included as the 'value' for the 'Answer' corresponding to the question asking for a file-upload.

(Chat to @avishkar58 if this doesn't make sense :) )

Front-end Background

Change the background on the front-end. The current image, while beautiful, is very large (file size) and it's difficult to read either white or black text on it. It also doesn't appear nicely on mobile. Maybe use something like a faded "watermark" of a baobab tree or something like that instead.

Definition of Done

  • New background chosen and applied
  • Background has a small file-size
  • Background renders correctly on mobile

Create ApplicationForm front-end

Create the necessary React components to implement an application form for an event.
This issue just involves creating the form with the relevant field types based on the JSON form specification returned by the API - submitting this form is another task.

Note that it should appear to the user of the app that each section is on a separate "page". The title of this page will be the section name, followed by the section description. The user should click on a "Next" button to progress to the next section.

You can work with a dummy API response for now so that this can be done independently of #19

Example JSON that we expect the API to send:

{
"eventId": 1,
"is_open": true,
"deadline": "2019-04-30",
sections: [
{
"sectionId": 1,
"name": "Section 1",
"description": "Section 1 description",
"order": 1,
"questions": [
{"id": 1, "description": "Question 1", "type": "short-text", "required": true, "order": 1},
{"id": 2, "description": "Question 2", "type": "single-choice", "required": false, "order": 2},
]
},
{
"sectionId": 2,
"name": "Section 2",
"description": "This is section 2",
"order": 2,
"questions": [
{"id": 3, "description": "What is 2+2?", "type": "short-text", "required": true, "order": 1},
{"id": 4, "description": "Upload your CV", "type": "file", "required": false, "order": 2},
]
},
]

}

Definition of Done:
This task is done when:

  • There are new components for ApplicationForm, Section and Question
  • There is a new ApplicationForm page that composes components based on the JSON spec
  • There is a mock applicationForm service with the relevant API call
  • There is at least one basic unit test of the page

Create ApplicationForm data model

This depends on #17

Create the data model for the ApplicationForm, Section and Question tables per the application process spec.

Create a migration to apply the changes to the database

Definition of Done
This task is done when

  • The relevant models exist in api/app/applicationForm/models.py
  • A new migration exists that creates the necessary tables in the database
  • The migration can be applied successfully
  • Unit tests are optional for this task

Add global config

Add global config to the React front-end (eg server URL). This must support being able to change config for dev/test/production.

Migrations failing from new postgres db.

Steps to reproduce:

Delete container for postgressql

docker container ps -a

(If container is running)

docker stop [containerID]
docker rm [containerID]

Recreate container

docker-compose build 

Run db update

docker-compose run web python ./api/run.py db upgrade --directory api/migrations

Error

Starting baobab_db_1 ... done
postgres://docker:[email protected]/docker
postgres://docker:[email protected]/docker
Traceback (most recent call last):
  File "./api/run.py", line 11, in <module>
    create_app().run()
  File "/usr/local/lib/python2.7/dist-packages/flask_script/__init__.py", line 417, in run
    result = self.handle(argv[0], argv[1:])
  File "/usr/local/lib/python2.7/dist-packages/flask_script/__init__.py", line 386, in handle
    res = handle(*args, **config)
  File "/usr/local/lib/python2.7/dist-packages/flask_script/commands.py", line 216, in __call__
    return self.run(*args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/flask_migrate/__init__.py", line 95, in wrapped
    f(*args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/flask_migrate/__init__.py", line 280, in upgrade
    command.upgrade(config, revision, sql=sql, tag=tag)
  File "/usr/local/lib/python2.7/dist-packages/alembic/command.py", line 276, in upgrade
    script.run_env()
  File "/usr/local/lib/python2.7/dist-packages/alembic/script/base.py", line 475, in run_env
    util.load_python_file(self.dir, "env.py")
  File "/usr/local/lib/python2.7/dist-packages/alembic/util/pyfiles.py", line 90, in load_python_file
    module = load_module_py(module_id, path)
  File "/usr/local/lib/python2.7/dist-packages/alembic/util/compat.py", line 216, in load_module_py
    mod = imp.load_source(module_id, path, fp)
  File "api/migrations/env.py", line 73, in <module>
    run_migrations_online()
  File "api/migrations/env.py", line 66, in run_migrations_online
    context.run_migrations()
  File "<string>", line 8, in run_migrations
  File "/usr/local/lib/python2.7/dist-packages/alembic/runtime/environment.py", line 839, in run_migrations
    self.get_context().run_migrations(**kw)
  File "/usr/local/lib/python2.7/dist-packages/alembic/runtime/migration.py", line 361, in run_migrations
    step.migration_fn(**kw)
  File "/code/api/migrations/versions/fbd283484655_.py", line 26, in upgrade
    update_question_data()
  File "/code/api/migrations/versions/fbd283484655_.py", line 37, in update_question_data
    update_question(session, 1, 'Enter 50 to 150 words', r'^\W*(\w+(\W+|$)){50,150}$')
  File "/code/api/migrations/versions/fbd283484655_.py", line 30, in update_question
    question = session.query(Question).filter(Question.id == question_id).first()
  File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/orm/query.py", line 3169, in first
    ret = list(self[0:1])
  File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/orm/query.py", line 2961, in __getitem__
    return list(res)
  File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/orm/query.py", line 3271, in __iter__
    return self._execute_and_instances(context)
  File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/orm/query.py", line 3296, in _execute_and_instances
    result = conn.execute(querycontext.statement, self._params)
  File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/engine/base.py", line 988, in execute
    return meth(self, multiparams, params)
  File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/sql/elements.py", line 287, in _execute_on_connection
    return connection._execute_clauseelement(self, multiparams, params)
  File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/engine/base.py", line 1107, in _execute_clauseelement
    distilled_params,
  File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/engine/base.py", line 1248, in _execute_context
    e, statement, parameters, cursor, context
  File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/engine/base.py", line 1466, in _handle_dbapi_exception
    util.raise_from_cause(sqlalchemy_exception, exc_info)
  File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/util/compat.py", line 374, in raise_from_cause
    reraise(type(exception), exception, tb=exc_tb, cause=cause)
  File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/engine/base.py", line 1244, in _execute_context
    cursor, statement, parameters, context
  File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/engine/default.py", line 546, in do_execute
    cursor.execute(statement, parameters)
sqlalchemy.exc.ProgrammingError: (psycopg2.ProgrammingError) column question.validation_text does not exist
LINE 1: ...on.validation_regex AS question_validation_regex, question.v...
                                                             ^
 [SQL: 'SELECT question.id AS question_id, question.application_form_id AS question_application_form_id, question.section_id AS question_section_id, question.type AS question_type, question.description AS question_description, question.headline AS question_headline, question.placeholder AS question_placeholder, question.validation_regex AS question_validation_regex, question.validation_text AS question_validation_text, question."order" AS question_order, question.options AS question_options, question.is_required AS question_is_required \nFROM question \nWHERE question.id = %(id_1)s \n LIMIT %(param_1)s'] [parameters: {'id_1': 1, 'param_1': 1}] (Background on this error at: http://sqlalche.me/e/f405)

Show logged-in information in navbar

Show logged-in information on the right-hand side of the Navbar - this should be a dropdown that includes a link to logout

Definition of Done:
This task is done when:

  • A new component has been created to implement the logged in front-end logic
  • The component has been integrated into the navbar found in webapp/src/App.js
  • The logout menu item invokes the appropriate service call to log the user out (remove the user token from local storage)
  • A manual integration test confirms this is working as expected

Policies

Come up with a privacy policy, policy for dealing with complaints about our emails and policy for dealing with bounced emails.

Implement Response confirmation email

Depends on #43

Send a confirmation email when the user submits their response.
This should be implemented in the POST method of the response API in app/api/responses/api.py and is triggered when the "is_submitted" flag is set to true in the request data. The email should be sent using api/app/utils/emailer.py. The email should be worded as follows (replace anything in angle brackets {} with the appropriate data)

Dear {User.title} {User.firstname} {User.lastname},

Thank you for applying to attend {Event.description}. Your application is being reviewed by our committee and we will get back to you as soon as possible. Included below is a copy of your responses.

{INSERT SUMMARY OF ANSWERS TO THE QUESTIONS IN THE RESPONSE}

Kind Regards,
The {Event.name} Organising Committee

Definition of Done
This task is done when

  • The POST method in api/app/response/api.py has been updated to create the email message
  • The emailer service is called to send the email
  • A unit test exists for this functionality which mocks out the email service.

Implement file-upload backend

Implement a REST end-point (File) that accepts a multipart/form-data POST request with contents of a file. This file should be saved to Google Cloud Storage (see this link) with an auto-generated (hash) ID as the file-name. The generated ID should be returned to the client.

Create Event Data model

Create the datamodel for Event and EventRole (using SQLAlchemy ORM), as per the applications process spec.

Pre-populate the event table with the following event:
name: Indaba 2019
description: The Deep Learning Indaba 2019, Kenyatta University, Nairobi, Kenya
startDate: 25 August 2019
endDate: 31 August 2019

Definition of Done
This task is done when

  • The relevant models exist in api/app/event/models.py
  • A new migration exists that creates the necessary tables in the database
  • Data is added as part of the migration
  • The migration can be applied successfully
  • Unit tests are optional for this task

CreateAccount descriptions can be improved

At the moment the field descriptions on the CreateAccount form are tooltips, this is not obvious to the user and also not visible on mobile. Rather make these one-liners below each field name (or introduce a clickable info icon to make it obvious that there's a tooltip and workable on mobile)

Add fields to Create Account form

Add the additional fields found in the User table of the Application Process Spec to the front-end CreateAccount page. This depends on #11 being completed before this will work end-to-end.

Definition of Done
This task is done when:

  • The CreateAccount component has been updated with the additional fields found in the application process spec
  • The fields are visible in the CreateAccount page
  • The service calls have been updated and correctly pass the full set of fields to the back-end API
  • A manual integration test has been performed as the functionality is working as expected.

Implement application withdrawal

On the Submitted component in ApplicationForm.js, implement a withdraw button, this should confirm that the user really wants to withdraw and then send a DELETE request to the back-end Respone controller (via applicationForm.service.js)

Implement PasswordReset functionality

Implement password reset functionality in the front-end - this should call the following back-end API endpoints:
/api/v1/password-reset/request
/api/v1/password-reset/confirm'

This depends on #13 which will send an email to the user asking them to confirm their password reset.

Definition of Done
This task is done when:

  • A new component has been created to request a password reset
  • A password reset page has been created using the above component
  • A new component has been created to confirm a password reset (set a new password)
  • A confirm password reset page has been created using the above component
  • Basic unit tests exist to test the rendering of the new pages
  • A manual integration tests confirms that the functionality works as expected

Create data model for Response and Answer

Create the data model for Response and Answer according to the application process spec.

This depends on #18

Definition of Done
This task is done when

  • New models exist in api/app/response/models.py
  • A new migration has been created to apply these changes to the database
  • The migration can be successfully applied

Logging - Phase 1

Ensure that all operations in back-end controllers (User, ApplicationForm, Response) are logged sensibly so that we can debug any issues that might occur when the app is in testing / production. This also involves determining where logs are stored and how they can be accessed when the application is running in GCP

Restart of Docker required to run docker-compose up

After successfully following steps 1-5 in the Getting Started (Detailed) instructions, on step 6 I got the following error after running docker-compose up

Starting baobab_redis_1  ... error
Starting baobab_db_1    ...
Starting baobab_webapp_1 ...

ERROR: for baobab_redis_1  Cannot start service redis: b'driver failed programming external 
connectivity on endpoint baoStarting baobab_db_1     ... error
rt/tcp:0.0.0.0:6379:tcp:172.17.0.2:6379: input/output error'

ERROR: for baobab_db_1  Cannot start service db: b'driver failed programming external connectivity 
on endpoint baobab_db_1 (f53ddbbdaf68bc30d741e576f3b33b9505119b74af8cc1447d2a37cd3d9eaecf): Error 
starting userland proxy: mkdir /port/tcp:0.Starting baobab_webapp_1 ... error

ERROR: for baobab_webapp_1  Cannot start service webapp: b'driver failed programming external 
connectivity on endpoint baobab_webapp_1 
(4e1626d5f44561103ef7c02013b1dc3885a48ae5a37741d4bc67572fbe8dc489): Error starting userland proxy: 
mkdir /port/tcp:0.0.0.0:8080:tcp:172.17.0.4:80: input/output error'

ERROR: for redis  Cannot start service redis: b'driver failed programming external connectivity on 
endpoint baobab_redis_1 (ecbfdfff3fa576ce4259ecfb2268b1ba91a89ca0d4db2a68f15a0237f4ecf1a4): Error 
starting userland proxy: mkdir /port/tcp:0.0.0.0:6379:tcp:172.17.0.2:6379: input/output error'

ERROR: for db  Cannot start service db: b'driver failed programming external connectivity on 
endpoint baobab_db_1 (f53ddbbdaf68bc30d741e576f3b33b9505119b74af8cc1447d2a37cd3d9eaecf): Error 
starting userland proxy: mkdir /port/tcp:0.0.0.0:5432:tcp:172.17.0.3:5432: input/output error'

ERROR: for webapp  Cannot start service webapp: b'driver failed programming external connectivity 
on endpoint baobab_webapp_1 (4e1626d5f44561103ef7c02013b1dc3885a48ae5a37741d4bc67572fbe8dc489): 
Error starting userland proxy: mkdir /port/tcp:0.0.0.0:8080:tcp:172.17.0.4:80: input/output error'
ERROR: Encountered errors while bringing up the project.

To fix this (from this link docker/for-win#2722), I had to shutdown Docker and restart it. The docker-compose up command would then run successfully. I'm posting this here since I think this is more of a work around than a permanent solution but may still be helpful if anyone else is running into the problem for now. I will continue to look into this for a more permanent solution.

My environment is Windows 10 Pro Build 17134 and I'm running Docker Engine 18.09.1

Add disability list to Create Account form

Make the disability question in the create account form a selection box with the following options:

No disabilities
Sight disability
Hearing disability
Communication disability
Physical disability (e.g. difficulty in walking)
Mental disability (e.g. difficulty in remembering or concentrating)
Difficulty in self-care
Other

Also add the following description:
"We use the Washington Group difficulty schemes. This information is collected to ensure that our facilities can accommodate the needs of all attendees."

New error for docker-compose build

This weekend I got some time off and I wanted to make some contributions. I have been trying to run docker-compose build for the whole of yesterday all in vain. I keep getting a react build error below. I have tried several things suggested on stack overflow and Github all in vain.

I am I doing something wrong? Have anyone encountered this error with the current app build?

$ react-scripts build
/bin/sh: 1: react-scripts: not found
error Command failed with exit code 127.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
ERROR: Service 'webapp' failed to build: The command '/bin/sh -c yarn build' returned a non-zero code: 1

PS: This happened when I made a git pull.

Add fields to User model

Add the fields found in the Application Process spec data model diagram to the backend AppUser model (api/app/users/models.py)

Create a migration to apply the changes to the database

Update the UserAPI in api/app/users/api.py to accept and populate the new fields

Definition of Done
This task is done when:

  • The new fields have been added to the model according to the spec
  • A migration has been created and can be successfully applied to the database
  • The API endpoints in api/app/user/api.py have been updated to account for these new fields
  • The tests in api/app/user/tests.py have been updated to incorporate the new fields

Implement User Account Deletion

Implement user account deletion by:

  • Updating the back-end User API to set the deleted flag on the User model.
  • Adding a delete link to the user profile page on the front-end (depends on ...)
  • Prevent users from logging in when the deleted flag is set

Definition of Done
This task is done when

  • The back-end User API has been updated
  • Unit tests exist for the delete functionality
  • A delete function is available on the front-end user profile page
  • The user is asked to confirm the deletion of their account
  • A manual integration test confirms this functionality works as intended.

Add word counter to TextArea form control

We have minimum and maximum word limits on our long-text questions, but no easy way for a user to see how many words they've entered. Add a word counter to the FormTextArea component.

Allow routing to specific pages

Allow routing to specific pages - e.g. [url]/login . This works locally but fails through docker (served via nginx) and through gcp.

Application form validation

Implement validation of the application form (using the is_required and validation_regex fields in Question). Note that validation should prevent users from submitting the form, but should not prevent users from "saving for later"

Form state gets copied between sections

Steps to reproduce:
Open the app and navigate to the application form (Apply link in menu)
Enter some text in the "Question 1" text box
Click Next to go to the next section
The text previously entered is now in the "What is 2+2?" text box. This is despite the textboxes having different ids.

User profile

Implement a user profile page that allows a user to update their user details. This should leverage the components built in #14 and make the relevant API call using the userService.

Definition of Done
This task is done when:

  • A user profile page has been created, leveraging the CreateAccount components
  • The userService has been updated to make the relevant API call (if not done already)
  • The user profile is accessible from the "logged in user" menu on the navbar (built in issue #10 )
  • A basic unit test has been added to check that the page renders
  • A manual integration test confirms that user accounts can be updated.

Update home page with blurb and upcoming events

Update the homepage with a "welcome to Baobab" blurb (anything sensible). Along with a table of "Upcoming events". The upcoming events table should list "Deep Learning Indaba 2019".

If the user has already applied for the event (use the applicationForm.service getResponse method to check for a response), the 2nd column in the table should say "Applied". If the user has not submitted a response, the 2nd column should contain an "Apply Now" button that navigates to the Apply (applicationForm) page.

For now, we can just hard-code the "Deep Learning Indaba 2019" event, but feel free to implement an EventList back-end controller and load the list of upcoming events if you want to!

Implement email verification

Add an email verification step after a user creates an account. This will be important to ensure that we can communicate with the candidate at a later stage.

Definition of Done
This task is done when:

  • A shared back-end email service exists which speaks to the Mandrill API (could be done as part of #13)
  • An email is sent after a user creates a new account with a link they can use to verify their email
  • The user is not able to login until they have verified their email
  • The necessary flags/data has been added to the data model (please document this)
  • There are unit tests for this functionality

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.