Giter Site home page Giter Site logo

courseplanner's Introduction

License: MIT

Build Status

Waffle.io - Columns and their card count

ConU Course Planner

ConU Hacks Winter 2017 project. The site is still in development but our beta version is available and kept up to date at: http://conucourseplanner.online.

What it is

It is a website where engineering students at Concordia can plan the sequence of courses that they will take in each semester of each year of their undergraduate degree. When you first visit the page, you are asked to select your program of study, after which the default reccommended sequence for that program is loaded into a table. You can then drag and drop courses between semesters and add/remove courses from the table via a auto-complete-enabled course search box. For any course available in our database, you can view its relevant information (credits, prerequisites, etc) by clicking on it in the table or manually searching for it. Any time you make a change to your sequence, it checks that all pre-requisite & co-requisite relationships are respected. This validation also checks the sequence for other issues such as duplicate courses, fulfilling of the minimum amount of credits for the program in question, and more. Once you're happy with your sequence, you can export it into a few different formats.

How it works

In order to obtain the list of reccommended sequences as well as the course information, we run some webscrapers once per 24h which access Concordia's public website (sequence sample, course sample) and write the resulting data to a MongoDB database. We provide a public API through which this data can be obtained and sequence validation & exporting can be performed. The site's frontend uses local storage to achieve persistence accross sessions on the same computer. This also means that we do not store any user-related information in our database.

Our stack

Frontend: React, Material-UI, React DnD, Browserify

Backend: Apache Tomcat, Apache Maven, MongoDB, Pandoc, wkhtmltopdf

Webscraping: Node.js, R, JSON Schema

courseplanner's People

Contributors

craniumfield avatar davidster avatar mikelshifrin avatar peterghimself avatar stumash avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

courseplanner's Issues

Add touch support to drag n drop

In order to support drag n drop for mobile devices which use touch screens as opposed to mouse/cursors, we must swap the "backend" that we pass to react-dnd.

Currently we are using react-dnd-html5-backend which does not have touch screen support. So we shall switch to using react-dnd-touch-backend.

To accomplish this, we need to add react-dnd-touch-backend to our dependencies:

npm install --save react-dnd-touch-backend

then we just need to replace the HTML5Backend with the touch version and make sure to enable the enableMouseEvents property

course info scraper bugs

the course info scraper is currently failing on certain courses on certain webpages. Looks like those regex need some tweaking... I'm on it.

Course Validation Error Message Inconsistency Bug

The Bug:

It is possible to trigger two sequences which, when validated, provide conflicting error messages.
One message indicates a prereq relation between courses, and another indicates a coreq relation between courses. As per the true data, it is a prereq relation.

To Reproduce:

  1. Open up a fresh sequence, and drag COMP 249 into SUMMER 1. You will notice that COMP 249 is a prerequisite for COMP 352 so you get the correct error message: COMP 249 must be taken before COMP 352

image

  1. Open up a new fresh sequence, and drag COMP 232 into WINTER 2. The result:

image

As you can see, the message for the COMP 249 conflict now reads: COMP 249 must be taken at least as soon as COMP 352, which is the message that we provide when a corequisite relationship is not satisfied.

We should not be giving an corequisite error message for a pair of classes with a prerequisite relation.

TODO

  • Better data
    • More courses from more departments
    • R scripts to automate scraping and cleaning
    • Handle more complicated course relationships
    • Data normalization
  • Prettier frontend
    • Better behaviour for uncommon/crowded screen sizes
  • Export to PDF
    • Create .md file from current JSON state of schedule
    • Pandoc to create PDF from .md
  • Row dragging logic
    • Dragging over a collapsed list will uncollapse it
    • Fix not being able to directly drop course into container right after uncollapsing by dragging
    • Add condition that one must hover at least 700ms long (for example) until container is uncollapsed
    • Dragging a course past the bottom of the page adds a new semester
  • Implement undo and redo
  • Split js into multiple files or equivalent action
  • Project exception handling
    • backend should include error message in JSON response if an error occurs for any servlet request
    • frontend should interpret an error-response for all backend interactions and display error messages to user
  • PRs to review

Course Validation Bug From Moving Work Term to Different Semester

Problem Description:

If you drag and drop and work term into another semester, all the courses in that semester get dropped from the data that's sent to the SequenceValidator on the server-side. So, any later classes which rely on those courses as prereqs complain that their prereqs are not being taken early enough.

Possible fixes:

  • Moving a work term from semester b to semester a results in a "shuffling-down" of all courses in semester a or later by one semester. After this shifting over of one semester, the data is sent to the server for sequence validation.
  • Other ideas?

Move production war file to root of Tomcat dir

In order to make proper use of our domain name conucourseplanner.online, it seems to me that it's in our best interest to serve our prod website at the root of our Apache/Tomcat directory. This is achievable by naming the production war file ROOT.war instead of courseplanner.war.

feature: multiple dev environments

would like to test different versions of the java server at the same time on the same machine. each dev will deploy to a different .war file. Instead of all deploying to the same courseplanner.war, we'll each deploy to coureplannerd.war, courseplannerp.war or courseplanners.war respectively and then can visit our deployed test version at the same domain but different urls (eg. courseplannerd.com).

Add a development database

Lets add a new database (maybe called courseplanner-db) for testing changes to JSON specifications and what not. We will never want to do any testing on the production database when there are users currently relying on this data.

A flag/option will need to be added to scrapeTheWeb.sh as well as course-info-storer/storer.js and course-seq-scraper/storer.js (lets also fix that clearly poor folder naming) in order to tell the webscraper whether to push to the production or development DB.

We will also need to add a clause to the deploy script where it tells the backend to use the development or production database. This will not require additional params for the script since that info can already be inferred.

Document our backend api

I would like to document our backend api. In other words, indicate in some file(s) exactly what functions are exposed by our api, what those functions do, and their expected request/response JSON bodies.

I've read that this is doable with json schema. Doing so would be useful if we decide to validate incoming requests, since we can run ajv or its java equivalent on the request bodies to reduce the likelihood of server errors. Could also be helpful for unit tests. All that would be really nice but it may take a lot of time to do in the end it doesn't matter all that much how the api is documented as long as it is done clearly.

Move api calls to /api path

Description

Currently all of our backend api requests are performed on the root path of the website, like http://conucourseplanner.online/allsequences etc. I would like to move the entire api to be under the folder /api so the same request would instead look like: http://conucourseplanner.online/api/allsequences.

The benefits

My main reason for making this change would be to make it easier to develop the frontend on my local machine by supplying the entire backend via a proxy: conucourseplanner.online/courseplannerd/api. This is pretty easy to setup with nginx and I would be able to simply run the frontend build command (build-dev) to view my changes instead of having to wait for scp and tomcat's auto-reload to finish.

I also think its just generally a good idea to separate our api calls into a specific url "folder". It separates the frontend resources from the backend ones more clearly.

Ensure courseSequenceObject contains full info for each course

Our goal is to have all the course info in the request body for our validation server call. This api call will occur many times as the user drags courses around the sequence. Having this info ready for the server to perform validation will reduce our need to get info from the DB. As such, most of the DB load will originate from the first time the users visits our site as well as when they're searching for courses (SequenceProvider.java and FilterCourseCodes.java).


Must change SequenceProvider.java such that the client receives the full courseInfo. Also must ensure that new courses which are dragged into the sequence contain the full course info.

Add ability to validate the total credits of a given sequence

In addition to making sure prerequisite and corequisite relationships are respected, we want to make sure that the minimum number of credits defined for the users program of study is met. For example, in engineering you need to do 120 credits and in computer science u only need to do 90 credits

squish multiple space into single space

Some of the course info we are scraping contains strings which have large portions of whitespace. For example there are course names like

Introduction to           Something

We would like to squish all of the adjacent whitespace characters into a single space so that the example course name above gets stored as

Introduction to Something

with just a single whitespace between the to and the Something.

MinCredits undefined

Here is what it looks like when we load up a sequence, such as SOEN-General-Coop.json:
image

This functionality should be working for the MVP.

Additionally, the Program name in the sequenceBuilder page and in the splash page select options should not contain ".json" in the their names
image

Very weird style for MECH/INDU recommended sequences

I want your guys opinion on what the resulting JSON should look for the following:

(INDU-Coop)
image

In english words, this page is saying that

  • you must take INDU 421 and INDU 423 in the fall of year 4
  • you must take INDU 321 and INDU 342 in the winter of year 4
  • you must take 17.75 credits of technical electives between fall & winter of year 4
  • you must take the course INDU 490 in BOTH the fall and winter of year 4

It may be worth noting that there are other sequences that include a course that spans over two semesters like INDU 490 does, in which case the current scraper plainly adds this course to both of the two semesters in question (the website also lists the course in both the semesters instead of this stupidity of putting ANDs and ORs in the semester season header)

To re-iterate, I want to know what you guys think the resulting json should look like for these fall and winter semesters. Currently, the scraper poops the bed and does something like this:

{
    "season": "fall",
    "courseList": [
        {
            "code": "INDU 421",
            "isElective": "false",
            "electiveType": ""
        },
        {
            "code": "INDU 423",
            "isElective": "false",
            "electiveType": ""
        }
    ],
    "isWorkTerm": "false"
},
{
    "season": "winter",
    "courseList": [
        {
            "code": "INDU 321",
            "isElective": "false",
            "electiveType": ""
        },
        {
            "code": "INDU 342",
            "isElective": "false",
            "electiveType": ""
        }
    ],
    "isWorkTerm": "false"
},
{
    "season": "fall",
    "courseList": [
        {
            "code": "INDU 490",
            "isElective": "false",
            "electiveType": ""
        }
    ],
    "isWorkTerm": "false"
}

Create well-defined json data specification and derive validation logic from it

The Problem

Currently, we are discussing the format of our json data through conversations and then our webscraping and data validation code reflects this format we have in our heads of what the data needs to look like.

image

It would be much better if we had both:

  1. A well-defined set of files describing the format of all json data stored in the DB
  2. A system for validating said data which is derived from our specifications rather than manually writing the validation code each time the spec changes.

A Proposed Solution

To solve the first issue from above, we can define our data using the json schema specification. This will allow us to create files which define the constraints of our json data member(s). The newest revision of json schema is called draft-06. We should use it.

To solve the second issue from above, we can use one of many npm modules to check all of our scraped data before inserting it into the DB. If all goes well, very little code will have to be written for this step as the validation logic will be derived from our declared spec. Based on this benchmark along with the popularity of the repository and frankly the length of its README, it seems that the module ajv is our best option

Create decent looking 404 page

The 404 page needs to be made a little bit more user friendly if possible. Do do this, just edit the file src/main/webapp/404.html and add any necessary css or js if needed

Change name of db collection from courseData to courseInfo

Currently our two db collections are named courseSequences and courseData. I would like to rename courseData to courseInfo for consistency. I made an issue for this as it will involve some code changes to our backend and course info storer off the top of my head.

Note that this will also involve doing some DB operations on the mongo shell to rename the collection.

Main Page background looks like shet

Can we find some way to have the background image like the splash page? so that it's not a repeating tiled image and just a full screen single photo?

webscraping cleanup

I'm doing a cleanup of both the code and structure of some of the webscraping folder. I'm not trying to fix everything, just doing a little re-arrange to make stuff easier to understand (hopefully) for newbies.
I won't be playing with David's node scrapers.
I'll mostly be moving files around maybe cleaning up a little js for the storers.

Move webscraper to dedicated directory

Currently, every time the code for the webscraper is updated, we must run a git pull on the VM's home directory to effectuate these changes on the actual webscraper code that is being executed.

We're going to want to move the webscraper to a new directory (similar to how the web-app is in /opt/tomcat/webapp, maybe pick /opt/cp-webscraping) and have deploy.sh script copy the webscraping code into this directory (possibly via scp). The cron job will need to be updated to point to this new directory instead of the current /home/david/CoursePlanner/webscraping/

Add year indication into sequence JSON spec

In order to simplify the operation of filling up a table with semesters from the data, I would like to change the sequence JSON spec once again to look something like:

yearList: [
    {
        "fall": { semesterObject1 },
        "winter": { semesterObject2 },
        "summer": { semesterObject3 }
    },
    {
        "fall": { semesterObject4 },
        "winter": { semesterObject5 },
        "summer": { semesterObject6 }
    },
    etc
]

Deploy success message broken

If there are errors in the building of the frontend components (babel, browserify, etc), the deploy script claims to have succeeded and proceeds to transfer courseplanner.war to the VM. This should not be the case

Validate duplicate courses

Similar to issue #40. We want to validate against having duplicate courses in a sequence. I don't think much else needs to be said on the topic.

Additional search box UI elements needed

The search bar should have a loading indicator of some sort while waiting for the search api call (FilterCourseCodes.java) and it should display something like "No results" when the search query returns no courses.

Fixing null continue

Clicking continue should be disabled if no sequence is selected.

Possible pop-up warning to display to user.

Add undo/redo to frontend

The user should have a way to undo/redo the actions they perform on the page by using CTRL-Z/CTRL-SHIFT-Z.

course scraper to handle ORs in prerequisite lists for courses

Right now, scrape-course-data.r is parsing the prerequisites of each course directly as the literal string of text from the webpages it visits. We are then storing that string as the prereq.string property of the JSON that goes into our db. For example we store some course's prereqs as the string COMP 201; COMP 233 or COMP 244; However we would like to store it as a JSON array-of-arrays. For the example I just used we want it to look like

[
    [
        "COMP 201"
    ],
    [
        "COMP 233",
        "COMP 244" 
    ]
]

This will allow us to implement course sequence validation logic on the backend and custom formatting of a course's prerequisites on the frontend.

Add Travis CI

In order to avoid having to run our deploy scripts each time we make a new change to the master branch, we should setup some Continuous Integration to do this job for us.

Travis CI can accomplish this for us with the added benefit of integrating with GitHub, indicating whether any given commit causes the project build to fail (bad exit code from any deploy script) and preventing the merging of failing branches into master.

How to provide support for programs outside of engineering? (proposal)

Can we find other programs with recommended sequences?

I did a bunch of looking around the Concordia website, trying to find recommended sequences similar to the ones provided for engineering programs. After about 90 minutes of search, I checked at least 20 different programs from various departments/faculties and only found three pages that offer a similar resource:

Chemistry and Biochemistry are of the same format, but Physics is completely different and all three of them are different from the engineering format. Because of this disparity, I don't think it is or will ever be worth our time to write scrapers for these.

Many other programs provide PDF forms for their students to help define program requirements, such as the History program.

Recommended sequences seem like they are only standardized for the Engineering and Computer Science department and therefore we should only webscrape for recommended sequences in said department.

How do we provide support for other programs?

Instead of looking at the year-by-year sequence for other programs, we should instead come up with an additional system which makes it easier for the user to fill up the table on our site.

It seems that many programs (not engineering doe LOL) follow a standardized format for defining their requirements in terms of which courses must be taken and the minimum number of credits to graduate. This includes lists of electives where the student chooses a certain number of credits from multiple separate lists. These lists are defined in the undergraduate calender, the same place we're scraping course info from.

Here's what it looks like:
image

Supporting such program requirements would open the door to many new programs on top of Engineering & CS. But before deciding if we should do this we must consider how it may be done...

In the backend

From the webscraping end, we can define a pretty simple spec which I think would be fairly robust and do a good job of defining the type of program requirements mentioned above:

e.g. Requirements for Major in Philosophy from above photo

{
	"program": "Major in Philosophy",
	"minTotalCredits": "36",
	"requiredList": [
		"PHIL 232",
		"PHIL 260",
		"PHIL 261"
		"ETC"
	],
	"electiveGroups": [
		{
			"groupName": "",
			"creditRequirements": "3",
			"anyOfPattern": "",
			"courseList": [
				"PHIL 210",
				"PHIL 214"
			]
		},
		{
			"groupName": "",
			"creditRequirements": "3",
			"anyOfPattern": "",
			"courseList": [
				"PHIL 362",
				"PHIL 374",
				"PHIL 377"
			]
		},
		{
			"groupName": "PHIL electives",
			"creditRequirements": "6",
			"anyOfPattern": "^PHIL\\s{1}\\d{3}$",
			"courseList": [] 
		},
		{
			"groupName": "PHIL electives",
			"creditRequirements": "6",
			"anyOfPattern": "^PHIL\\s{1}4\\d{2}$",
			"courseList": [] 
		}
	]
}

Where

  • minTotalCredits would be put in this spec instead of the recommended sequences
  • requiredList denotes courses that must be taken
  • creditRequirements denotes the minimum number of credits that must be selected from the electiveGroup
  • anyOfPattern allows us the let the user select any course whose code matches the pattern instead of an actual list.

In terms of backend validation, it would be easy to add a clause which checks that the above requirements are satisfied by the user's proposed sequence.

According to @stumash, it seems that it would be easy to take the requiredList and transform it into a recommended sequence via topological sort. We can discuss later whether we want this to be performed at scrape-time or run-time (I vote scrape-time).

Please let me know what you guys think of all this.

In the frontend

Let's assume we agree that the above program requirements spec is sufficient for what we want to accomplish.

In order to make the electiveGroups array useful, it seems to me that we would need to add a new UI element which presents these groups in a visually pleasing way. Some sort of nicely formatted list of courses which can be dragged into the table.

Do you guys think this UI addition is feasible? Can we come up with a design whereby there is still enough space on the page for the table?

Is it even worth adding this type of support at all? I assume we won't do this for MVP.

Add program info panel

Should contain the formal title of the program, total min credits, and the URL that was used to scrape the data for that program.

Not so pretty looking JSON in Course Planner Debug emails

This is what the format of the JSON looks like when we receive emails from Course Planner Debug, which we'd have to run through something like this to get a better picture.

image

Ideally, it would be more convenient to have the JSON formatted prettily in the email. That is the purpose of this issue.

weird course info json for lab hours and lecture hours

image

As you can see, the course info JSON for SOEN 423 (let's call the JSON object obj) contains both obj["lab"]["hours"] = "two hours per week" and obj["labHours"] = "two hours per week". Same is true from lectureHours.

This is clearly wrong.

The JSON output of the r scraper when ran on my personal machine does not contain these incorrect redundancies. I suspect that this is "feature" of MongoDB where it avoids entirely replacing old data with new data and instead just tries to add the difference between the old and new versions of data when possible.

Course Drag Update

Explanation

We want to add a feature that lets the user create new semester by dragging any course down past the bottom of the last semester container. A helpful tip message should display to the user about the existence of this feature when they are dragging a course over the last container. This tip should show up instantly on first hover over the last semester container, or when the user hovers for more than 750ms (temporary constant) over said container.

Export feature broken by PR #106

The export feature no longer works since PR #106. It causes a 500 server error due to a java exception. Here is a sample from the error logs in /opt/tomcat/logs/catalina.out

org.json.JSONException: Expected a ':' after a key at character 7259
	at org.json.JSONTokener.syntaxError(JSONTokener.java:410)
	at org.json.JSONObject.<init>(JSONObject.java:203)
	at org.json.JSONTokener.nextValue(JSONTokener.java:344)
	at org.json.JSONArray.<init>(JSONArray.java:125)
	at org.json.JSONTokener.nextValue(JSONTokener.java:348)
	at org.json.JSONObject.<init>(JSONObject.java:205)
	at org.json.JSONTokener.nextValue(JSONTokener.java:344)
	at org.json.JSONObject.<init>(JSONObject.java:205)
	at org.json.JSONTokener.nextValue(JSONTokener.java:344)
	at org.json.JSONArray.<init>(JSONArray.java:125)
	at org.json.JSONTokener.nextValue(JSONTokener.java:348)
	at org.json.JSONObject.<init>(JSONObject.java:205)
	at org.json.JSONObject.<init>(JSONObject.java:402)
	at CPServlet.getRequestJson(CPServlet.java:60)
	at SequenceExporter.doPost(SequenceExporter.java:24)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:648)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:230)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:108)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
	at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:620)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:349)
	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:783)
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:789)
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1455)
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	at java.lang.Thread.run(Thread.java:748)

Add new detail to sequence json data

Explanation

The sequences presented on Concordia's website sometimes include entries where the student is allowed to choose any courses from a given list (course a or course b or course c etc.). The sequence json spec needs to be enhanced to support this and in the future the front-end app will also need to account for this case with a UI element.

Example

The following screenshot was taken from following website: https://www.concordia.ca/encs/computer-science-software-engineering/students/course-sequences/sept-soen-real-time.html

image

Here is how our site currently reacts to this:

image

Minor issue with course data scraper

If you try to run the course data scraper (Rscript scrape-course-data.r) without first creating the folder course-info-jsonfiles/, the script will encounter the following error:

Error in writeLines(prettify(toJSON(full.course.strings)), file.connection) :
  cannot open the connection
In addition: Warning message:
In writeLines(prettify(toJSON(full.course.strings)), file.connection) :
  cannot open file 'course-info-jsonfiles/ENCS_full-course-info.json': No such file or directory
Execution halted

Suggested fix: the script should create the folder before trying to put files into it.

Courses missing from recommended sequences

If you go through the recommended sequences, you'll quickly realise that some courses are missing, such as CART 351, FFAR 250, ENGR 418, MECH 490 just to name a few.

I think it's obvious that we should at the least have all courses from the recommended sequences in our course info DB.

I'll probably write a node program which we can use temporarily to list all courses contained in the recommended sequences collection that are not contained in our course info collection. Then we can locate them on the undergraduate calendar and append items to course-info-data-sources.txt accordingly.

Thoughts?

complete redo of sequence validation

Ever since we redid our frontend in React and updated our scraper/data format, we've been badly itching for a fresh version of our sequence validation. As we discussed in person, there's a O(n) algorithm for this and it'll be put to use.

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.