Giter VIP home page Giter VIP logo

webpa's Introduction

WebPA - An Online Peer Assessment Tool for Higher Education

WebPA is an online peer assessment system, or more specifically, a peer-moderated marking system. It is designed for teams of students doing groupwork, the outcome of which earns an overall group mark. Each student in a group grades their team-mates and their own performance. This grading is then used with the overall group mark to provide each student with an individual grade. The individual grade reflects the students contribution to the group.

Requirements

PHP

The following versions of PHP are supported for the latest version of WebPA:

  • PHP 7.4
  • PHP 8.0

Your PHP instance must also have the following extensions enabled:

  • MySQLi
  • Sessions
  • XML

NPM

Node package manager is required to install feather-icons, an icon package used by WebPA. Once you have downloaded WebPA navigate to its root on the command line and run:

  • npm install
  • npm run build

The first command will retrieve the feather-icons package and the second will move the relevant files to WebPA's js directory for use in the application.

Installation

Download

The easiest way to download WebPA is with the composer package manager using the following command:

composer create-project --prefer-dist --no-dev webpa/webpa webpa

Alternatively you can download the latest release from this repository's release page.

Configuration

WebPA has a number of configuration options allowing you to set your database credentials, SMTP mail host details and various other options.

The application comes bundled with a .env.example file which lists all of the configuation key-value pairs you can set.

For speedy development, you can copy this .env.example file to a file called .env and change the values to suit your environment. The path of this file can be set in the includes/inc_global.php file.

For production environments, please avoid using the .env file as storing sensitive credentials in a file could be a security risk. Instead you should set these key-pairs as environment variables. In Apache, you can set these in your .htaccess file as follows:

SetEnv DB_HOST localhost

At a minimum, you should set the following environmental variables to let WebPA function:

  • APP_WWW - URL to your instance of WebPA (set without a closing '/')
  • DOC_ROOT - Directory path to the WebPA files (set with a closing '/')
  • DB_HOST - Database host
  • DB_USER - Database username
  • DB_PASS - Database password
  • DB_NAME - Database name
  • DB_PREFIX - Database table prefix. Usually set to 'pa2_'

For more information on the dotenv file please visit the dotenv package's repository. For more information on setting environmental variables in Apache, please visit Apache's website.

Initialise the Database

Run the following scripts to initialise the database (edit the files to change the names and password as required):

  • install/webpa2_database.sql: create the database schema and user account;
  • install/webpa2_tables.sql: create the database tables;
  • install/webpa2_administrator.sql: create an administrator account and sample module.

Upgrading an Existing Installation

If you already have WebPA installed and are upgrading from version 3.1.0 or below, please run:

  • install/webpa_security_update.sql

Login to WebPA

  • navigate to root of WebPA application
  • enter a username of admin and a password of admin
  • change the password to something more secure after logging in

Delete the install folder when you're finished.

LTI Extension

The standard installation of WebPA does not include LTI (Learning Tools Interoperability) support which allows it to integrate seamlessly with most popular Virtual Learning Environments. This can be added via an extension created by Stephen P Vickers. Please visit Stephen's site for instructions on how to obtain and install this extension.

Documentation

Documentation for WebPA can be found on the WebPA project site.

Changelog

Please see our changelog for a list of updates for this system.

This project uses semantic versioning from version 3.0.0 onwards.

Contributing

We always welcome contributors to WebPA. If you can help with development, testing, or documentation, please submit a pull request to this repository.

Support

Bugs and feature requests are tracked on this project's GitHub issue tracker.

License

This software is distributed under the GNU General Public License version 3.

You may copy, distribute and modify the software as long as you track changes/dates in source files. Any modifications to or software including (via compiler) GPL-licensed code must also be made available under the GPL along with build & install instructions.

Credits

WebPA was originally developed by the Centre for Engineering and Design Education at Loughborough University with financial support from JISC's e-Learning Capital Programme.

It continues to be maintained by a number of open source contributors. We thank them for their time and effort supporting this system.

webpa's People

Contributors

johnsmith-lt avatar jonathan-knight avatar leoramsy avatar mcrauwel avatar patfleury avatar paulheaney avatar rcraggs avatar sephster avatar tsalyers avatar

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

Watchers

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

webpa's Issues

Change default authentication to DB ?

Out of the box authentication is set to SAML. Without changing any settings I was able to 'login' as both Admin and as a default student account I added but upon further testing I realised that the password was not being checked...

Not sure if this is a problem with the SAML authenticator (surely it would be best to not authenticate if it's unable to contact the authentication service since I didn't add one??)

But anyway, the problem is that this could be a gotcha for new installs who think authentication is taking place when in fact, if you know the username then you can get in by adding a non-empty password...

This has been checked on XAMPP on Mac only so not sure if the same happens on a proper server install.

Structure of release 3.1

Release 3.1 has a different structure from previous releases; all the source files are included in a directory named src. This means that when installing using composer the code is accessed at .../webpa/src rather than just .../webpa which is not very convenient.

LDAP authenication fails to update database with new user

In version 3.1.1, there is an issue with LDAP authentication.

When we retrieve:

   $_fields = [
            'forename' => $info[0]['givenname'][0],
            'lastname' => $info[0]['sn'][0],
            'email' => $info[0]['mail'][0],
            'user_type' => get_LDAP_user_type($info[0][LDAP__USER_TYPE_ATTRIBUTE]),
        ];
        $els = [];
        foreach ($_fields as $key => $val) {
            $els[] = "$key = '$val'";
        }

from AD and then try to insert it into the database:

$sql = 'INSERT INTO ' . APP__DB_TABLE_PREFIX . 'user SET ' . implode(', ', $els) . ", username = '{$this->username}', password = '" . md5(StringFunctions::str_random()) . "', source_id = ''";

The expansion of $els contains user_type, but that field is not in the pa2_user database table, here is the table creation script included with the distribution (some backticks removed):

 CREATE TABLE pa2_user (
  user_id int(10) unsigned NOT NULL AUTO_INCREMENT,
  source_id varchar(255) NOT NULL DEFAULT ,
  username varchar(255) NOT NULL,
  password varchar(45) NOT NULL,
  id_number varchar(255) DEFAULT NULL,
  department_id varchar(255) DEFAULT NULL,
  forename varchar(255) NOT NULL,
  lastname varchar(255) NOT NULL,
  email varchar(255) DEFAULT NULL,
  admin tinyint(1) NOT NULL DEFAULT '0',
  disabled tinyint(1) NOT NULL DEFAULT '0',
  date_last_login datetime DEFAULT NULL,
  last_module_id int(10) DEFAULT NULL,
  PRIMARY KEY (user_id)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

I have tried to debugging this by changing the code but it fails further on.

Installation Script

For testing changes locally you really need to install in XAMPP or similar and just now it is a pain to checkout a new instance, install and test.

An installation process that detects that it's a new installation and goes through the steps, prompting the user at key moments to enter relevant info like passwords etc. would be sweet. I keep harping on about Xerte but we have one there that is a 4 page process that allows XAMPP setup with default settings but proper deployment setup if you change the configurations. It also checks your environment to make sure correct paths are writable, etc..

We can probably lift most of that and tweak if others think that is a good idea?

Improve Password Security

For direct logins to the system, there are some legacy issues with password security.
We need to update the hashing mechanism and increase the password length to improve this.

Login Issue for Students

When logging directly into WebPA (not via LTI), the main page fails to render as it hits a DB error.

DATABASE ERRORQuerying database :: Unknown column 'um.module_id' in 'where clause'SELECT DISTINCT um.assessment_id FROM pa2_user_mark um WHERE (um.module_id = 1) AND (um.assessment_id IN ('')) AND (um.user_id = 3) ORDER BY um.assessment_id

This is due to an old query in the code:

$assessments_with_response = $DB->fetch_col('SELECT DISTINCT um.assessment_id ' .
                                            'FROM ' . APP__DB_TABLE_PREFIX . 'user_mark um ' .
                                            "WHERE (a.module_id = {$_module_id}) AND " .
                                                  "(um.assessment_id IN {$assessment_clause}) AND " .
                                                  "(um.user_id = {$_user->id}) " .
                                            'ORDER BY um.assessment_id');

It does not have the assessment table linked. This issue appears to have been present since version 2.

Cannot Delete Admins

It appears you cannot delete admin users once they have been created. We should provide a facility to do this.

White Spaces in CSV Upload Break Upload

David Cheseldine from QMU had reported that for the student upload, if there are white spaces after the commas, the upload facility breaks. This will likely be the case for the other CSV uploads as well.

Error Trying to Change Form in Assessment

When trying to change a form in an assessment, you do not see any forms to select from even if you have created multiple ones.

I believe the same issue applies if you try to change a collection. This should be investigated as it looks like the query is not correct to retrieve this information

Merge Master branch into Develop?

Hi Rich ( @bulphan ), would you be able to merge Master branch into Develop as there are some commits there (my most recent ones and some others like support for SAML) that were put in there but should really be in develop too.

No hurry...

Importing forms problem

Copying and pasting the XML from an exported form created the form in the pa2_form table OK. However, the insert does not add the XML to the form_xml record. This results in no criteria for the form. This can be worked around by copying the XML directly into the form_xml field in the table pa2_form for that record. However, you need to change the formid in the XML to match the form_id for the record in the table.

Also, the upload exported form doesn’t work. It seems that the temp directory that the form gets uploaded to hasn’t been created. However it still doesn’t work after manually creating the tmp directory and giving it write permission.

Additionally I find the delete form and delete assessment doesn’t work…

Peter Browne

Previous Student User Cannot be a Tutor

If a user has been enrolled as a student in WebPA, they cannot act as a tutor as WebPA will always default them to the student permissions. This issue has been reported by both the University of Sheffield and the University of Edinburgh.

In Edinburgh's case, the user in question was accessing WebPA via an LTI connection. They had previously been enrolled in two assessments as a student.

The University of Sheffield had resolved this issue by updating the pa2_user_module.user_type table to T for all instances of the user to re-establish the tutor view.

We need to rectify this issue as the workaround could give students access to information they are not supposed to have. There could be a legitimate reason for having a user act as a student in some instances and a tutor in others.

Marks Awarded For Each Question (anonymous) errors

If you run the CSV version of this report with PHP errors on, a lot of errors will be produced. This is because the $q_total array is not initialised for the csv view and the code tries to access undefined indexes.

CSV export columns

The export CSV of grades concatenates the first name, last name and userID into a single cell. Request is to export these into seperate cells for easier import into VLE.

Replace UUID Implementation

In lib_common there is a function that generates UUIDs. This does not conform to the UUID standard so should be replaced.

Creating a Module Confusing

When creating a module in WebPA, the breadcrumb trail up the top says you are editing data rather than creating it. "Admin Users" is also highlighted and the heading says Edit system users which is confusing.

Finally when the save is successful it mentions that the record was edited successfully. This is confusing and the page should be updated to reflect this is a creation, not an edit.

XML Parser Assigned by Reference

This issue was reported by Tom Salyers from Sheffield University.

In the XML parser class, the resource returned by the xml_parser_create() object is unnecessarily assigned by reference. This has not been necessary since PHP 5 so is likely a legacy from the PHP 4 days of the code.

This is resulting in the following notice being issued:

[Tue Oct 23 00:56:06.698241 2018] [:error] [pid 6569] [client 86.178.195.186:51205] PHP Notice: Only variables should be assigned by reference in /var/www/data/webpa211/includes/classes/class_xml_parser.php on line 98, referer

Undefined Offset When Fetching Database Value

Issue reported by Tom Salyers from Sheffield University:

[Tue Oct 23 00:56:06.695438 2018] [:error] [pid 6569] [client 86.178.195.186:51205] PHP Notice: Undefined offset: 0 in /var/www/data/webpa211/includes/classes/class_dao.php on line 225

Admins Can Create Forms but Cannot Create Assessments

David Cheseldine from QMU had noted during testing of WebPA 3.0.0 that admins could create forms but were not able to create assessments as the system stated that the logged in user had not created a form yet.

This is likely a workflow bug that has been present in the original system. We need to do the following:

  • Determine if this is a historical bug
  • Correct the workflow to either prevent the creation of forms for admins or allow the creation of assessments

Review Develop Branch and Discard or Merge Changes

The develop branch has a number of additions which have not been included in version 3's release. We ideally need to get rid of the develop branch so it needs to have it's changes reviewed and either implemented in version 3 or discarded.

This issue will note all changes that are pending.

Saving a New User

When saving a new user in the sample module, on the first attempt the system will normally report that the user already has a role.

On the second attempt the user saves to the database as expected. We should find out why

Default branch

Not sure who has full admin of this repo but can we have the default branch set to 'develop' instead of 'master'

Not sure if it makes a difference to anyone but since mostly Github will be used for development then it might be useful if the develop branch is the default that you get..

For example with Xerte when you enter the repo or click on the 'code' tab it takes you to develop

Click here: https://github.com/thexerteproject/xerteonlinetoolkits

But with this repo it takes you to the master branch...

Click here: https://github.com/WebPA/Source

Search For Students Table Error

When searching for students, there appears to be an error with the resultant table, where results are not aligning with their column headers.

The last login date is under the modules heading and the number of modules the student belongs to is sitting by itself without a heading, to the right of the main table.

This issue appears in Firefox and has not been verified in any other browsers.

Cannot Retrieve User Info via LDAP

A user had reported the following problem:

The issues I had started when trying to get the user's information from Active Directory. I couldn't get it to work just using the configuration information in inc_global.php I had to go into the code and configure which attributes mapped from AD. I managed to get the SQL looking correct in this bit:

 $DAO = $this->get_DAO();
    if (LDAP__AUTO_CREATE_USER) {

      $sql = 'INSERT INTO ' . APP__DB_TABLE_PREFIX . 'user SET ' . implode(', ', $els) . ", username = '{$this->username}', password = '" . md5(str_random()) . "', source_id = ''";
      $sql .= ' ON DUPLICATE KEY UPDATE ' . implode(', ', $els);
      $DAO->execute($sql);
      $id = $DAO->get_insert_id();
      $sql = 'SELECT * FROM ' . APP__DB_TABLE_PREFIX . "user WHERE user_id = $id";

    } else {

      $sql = 'UPDATE ' . APP__DB_TABLE_PREFIX . 'user SET ' . implode(', ', $els) . " WHERE username = '{$this->username}' AND source_id = ''";
      $DAO->execute($sql);
      $sql = 'SELECT * FROM ' . APP__DB_TABLE_PREFIX . "user WHERE username = '{$this->username}' AND source_id = ''";

    }

    return $this->initialise($sql);

But the the code failed while doing the $this->initialise($sql); and I couldn't work out what was wrong. It looks like there is something wrong when trying to add the user to the database.

We should evaluate the LDAP implementation to see if we can resolve this issue as I believe that the LDAP implementation doesn't work properly. It might be worth switching to use a standard library instead.

Not adding http:// in front of APP_URL breaks site

I was stung by this when setting up a new site. We should move to a model where these settings are entered via a CLI based installation script and it is intelligent enough to correct such simple errors.

Clone button for Form questions?

Hi,

Seems to me that there is opportunity to enhance the Form creation process. Was creating a form that had several questions and all were using a Likert scale with similar options. I realised a clone button on questions would be useful so I added it - is this of interest to people or am I missing something?

Looks like this just now and simple code change to add:

image

I won't add though yet until it's confirmed that this is desirable...

John

Error in create new group wizard

At url /tutors/groups/create/index.php (at step 2) you get this error:

Notice: Undefined variable: module_plural in
/tutors/groups/create/class_wizardstep_2.php on line 61

Wizard seems to work ok though...

User Delete Query not Correct

In the user class there is a function called delete(). This function tries to delete the form_owner_id from the form table but this field doesn't exist. Need to fix.

Purpose of includes/classes/LTIAuthenticator.php file

This file seems to have started out life as class_lti_authenticator.php and contained a class named DBAuthenticator. When the autoloading was added the file was renamed to LTIAuthenticator.php and the class was renamed to LTIAuthenticator. The code in this class appears to be equivalent to the DBAuthenticator class file and seems to have nothing to do with LTI.

Does anyone know why this file exists?

It looks like it should be deleted/deprecated to avoid any confusion with how LTI connections really work. Alternatively it could be changed to being an extension of the DBAuthenticator class so that the equivalence is clearer which would also allow any implementation with "LTI" included in their $LOGIN_AUTHENTICATORS array to continue to work.

MySQL Version 8 Support

When running the import script we hit an error for MySQL version 8. This is in the first script. The error message is as follows:

ERROR 1064 (42000) at line 15: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'IDENTIFIED BY 'password'' at line 1

Assessment List for Students Not Updating

As a student, when you take an assessment then return to the assessment list, it looks as though you can take the assessment again.

However, if you click on the assessment, you are told you cannot. This is a bug that needs to be resolved.

Direct Login Cannot Handle Certain Passwords

I haven't had time to check this yet but direct login does not support passwords such as Õ(7[MrÔô2". We need to investigate this and find out why. This probably requires an overhaul of the login functionality to haul it into the modern world :)

Importing Forms Error

If you try to import a form that does not have any questions associated with it, an error will be produced.

In addition, the errors never display as the function that returns the errors only actually returns a boolean value.

Inconsistencies with DOC__ROOT

The DOC__ROOT const is supposed to be set with a trailing forward slash but in at least one of its use cases, we concatenate with a string that leads with a forward slash, causing a double forward slash in the path.

It appears that Apache will handle this gracefully but NginX does not and will fail to find the included file.

Suggested fix is to remove any forward slashes at the start of strings concatenated with the DOC__ROOT constant.

Mis-tagged release causing installation error

Version 3.0.4 appears to have been given a tag of v3.04 which is causing Packagist to install this version rather than the latest (3.0.7). Since this version also includes a syntax error causing it not to run, this is particularly unhelpful.

Change the Date of a Completed Assessment

You can change the date of a completed assessment. In effect, you can force that assessment to be open again but no one can participate in it. We should not allow people to do this once the assessment has closed.

Assessments Don't Always Display

Assessments in an assessment list don't always display. I believe that this is because of the year that is passed to the query sometimes being incorrect.

From memory, the year can sometimes be stored in the session and isn't always updated correctly causing a mismatch between the year selected on screen and the data displayed. We will need to simplify this display

Master is in an Unknown State

Master seems to be in an unknown state. There is a file, login_saml.php that is present in the master branch that is not present in the dev branch.

It was added in 2014. In addition, the last official release of WebPA (2.0.0.11) doesn't have this file either. Master should be reflecting actual releases.

Database Error Logging in with DB Authentication

Reported by Steve Cole from Bristol University via the mailing list:

With a new install of WebPA on Ubuntu 18.04, PHP 7.2 I get a database error when logging in with DB authentication (although the login is successful), and another db error on the final stage of the "Create a new assessment" wizard (and the assessment isn't created).

Any ideas as to what I can try to fix these errors would be gratefully received!

/login_check.php

DATABASE ERROR Executing SQL :: Incorrect datetime value: '' for column 'datetime' at row 1

INSERT INTO pa2_user_tracking (user_id,datetime,ip_address,description,module_id,object_id) VALUES (2,'','','',NULL,NULL)

/tutors/assessments/create/index.php

DATABASE ERROR Executing SQL :: Column 'collection_id' cannot be null

INSERT INTO pa2_assessment (assessment_id,assessment_name,module_id,collection_id,form_xml,open_date,close_date,retract_date,introduction,allow_feedback,assessment_type,student_feedback,contact_email,email_opening,email_closing,feedback_name,feedback_length,feedback_optional) VALUES ('0CDEBA0B-74C4-BDBC-102F-24A8080084BA','Assessment Test 1','1',NULL,'\n\n FD90AE16-0F58-FC58-6A53-3EC1A4B47E05\n A1 Assessment\n likert\n \n Attendance\n \n 1-5\n Never there\n Always there\n \n \n Leadership\n \n 1-5\n Only follows\n Only leads\n \n\n','2019-02-13 09:00:00','2019-02-26 17:00:00','2019-02-26 17:00:00','',0,0,0,'',0,0,'',0,0) ON DUPLICATE KEY UPDATE assessment_name = 'Assessment Test 1', module_id = 1, collection_id = '', form_xml = '\n
\n FD90AE16-0F58-FC58-6A53-3EC1A4B47E05\n A1 Assessment\n likert\n \n Attendance\n \n 1-5\n Never there\n Always there\n \n \n Leadership\n \n 1-5\n Only follows\n Only leads\n \n
\n', open_date = '2019-02-13 09:00:00', close_date = '2019-02-26 17:00:00', retract_date = '2019-02-26 17:00:00', introduction = '', allow_feedback = 0, assessment_type = 0, student_feedback = 0, contact_email = '', email_opening = 0, email_closing = 0, feedback_name = '', feedback_length = 0, feedback_optional = 0

Error when trying to add criterion to assessment form

If I go to any assessment form and click the 'add new criterion' button, I get the following error:

Warning: include_once(/tutors/forms/edit/add_question/likert/class_wizardstep_1.php): failed to open stream: No such file or directory in /var/www/html/WebPA/src/includes/classes/Wizard.php on line

Please see attached screenshot of error.
Screenshot 2021-02-16 at 09 56 59

mySQL compatibility for server running php7

HI there - just tried installing this for one of our staff members on one of our ubuntu 16 servers running php7. Looks like it's using the deprecated/removed mysql_* functions for the database, and so it won't work with PHP7. Are there any plans to update webpa to use mysqli or PDO? I'm keen to get it running as it looks really useful.

Thanks in advance and thanks for your work on this software.

Scores are calculated incorrectly !!

While using WebPA for a group of 250 students, I found a problem with the calculation of the scores.
It occurs in the case not all students fill in the assessment.
Below is a simplified situation from what I found in real life.

afbeelding

I'm using WebPA with the self-evaluation disabled.
Student a, b and d did complete the assessment. Student c didn't.
Column L shows the result generated by WebPA.
Column M shows the result after applying a "fudge factor" (in this case: * 4 / 3).
This fudge factor is only applied on the scores of the first group of students!
The scores of all subsequent groups are calculated without the fudge factor.

I think the only correct scores would be the ones in column P.
These are based on column O.
Column O is calculated by taken the AVERAGE score of all NON-ZERO scores that one student got.
(Alternatively, you formulate this as the SUM of all scores divided by the NUMBER of NON-ZERO scores for one student.)
(Also, compare this with column L, where we take the SUM of all scores for one student,
without any compensation for the possibly different amount of scores that student got.)
To calculate column P from column O: divide by the sum of all scores in column O (in our case 1.33)
and multiply by te number of students (in this case 4).
Remark that this is very similar to (but slightly different from) the "fudge factor".

Let me know if I can do anything to help you reproduce or provide additional information.

Attached is an Excel-file that I used to find a solution, and to check several scenarios.
bug-peer-ass.xlsx

LDAP integration broken

In the last stable version of WebPA, the LDAP integration was largely broken. RVC had worked on integrating ADLDAP and later, ADLDAP2 into WebPA to fix these issues. The ADLDAP integration was working but I believe the ADLDAP2 integration was not fully completed.

Alistair Spark from RVC has kindly shared their efforts with us to get this implemented into WebPA's core

is_empty function redundant

The is_empty function is largely redundant in modern versions of PHP and is causing warnings. This should be investigated and removed.

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.