GithubHelp home page GithubHelp logo

charcoal-se / metasmoke Goto Github PK

View Code? Open in Web Editor NEW
43.0 14.0 37.0 5.99 MB

Web dashboard for SmokeDetector.

Home Page: https://metasmoke.erwaysoftware.com

License: Creative Commons Zero v1.0 Universal

Ruby 59.60% JavaScript 10.02% CoffeeScript 0.30% HTML 25.61% Shell 0.44% Dockerfile 0.22% SCSS 3.80% Procfile 0.02%
ruby-on-rails web-dashboard hacktoberfest

metasmoke's Introduction

metasmoke

metasmoke is a web dashboard for SmokeDetector, a bot that detects spam on the Stack Exchange network.

API

If you're looking to develop using the metasmoke API, there's documentation available in the wiki. You'll need an API key to access any of the routes; ping a metasmoke admin in Charcoal HQ.

WSL

While metasmoke isn't targeted to support WSL (it's just not fast enough for production use), it should work adequately well for development purposes. The minimum Windows build version required is 16170, due to an lack of WSL support for mdns in builds prior to this.

Docker

There is a simple Dockerfile here which is however not well tested.

If you want to include a database dump, create a directory import and place the dump files there (one *.rdb.gz and one *.sql.gz). This will noticeably slow down the build (plan 10-15 minutes, depending also on disk speed and hardware).

If the import directory contains a file named metasmoke@localhost, or if there is no import directory, the Docker image will create a metasmoke user with that email address and a default password.

To create a local build, simply

docker build -t metasmoke .

To run the image, you need to expose the ports properly.

docker run --rm -it -p5000:5000 -p8080:8080 metasmoke

Once the image runs the initalizations, you should be able to connect to http://localhost:5000/ and see metasmoke greet you.

Some of the options in this brief introduction are optional convenience. If you understand what you are doing, the -t metasmoke is not crucial, and the --rm -it options are just one common way of keeping things sane.

License

Metasmoke is a pretty niche project, and we don't expect many people to make use of the entire thing as a whole. However, if you want to use the code, go right ahead - metasmoke is licensed under CC0. A small attribution is appreciated, but entirely non-compulsory.

Reporting a potential security flaw

If you wish to report a potential security flaw, no matter how minor it may be, and are not certain it's a security flaw, only send the report to [email protected] with your details about the issue you found, how you replicated it, and why you believe it is a security flaw. DO NOT disclose specific security flaws, even potential ones, via public insecure mediums such as the public issues system or public chat systems.

metasmoke's People

Contributors

angussidney avatar artofcode- avatar brocka avatar cerbrus avatar csnardi avatar dependabot[bot] avatar double-beep avatar ferrybig avatar ibug avatar isaiahzs avatar j-f1 avatar jpotts244 avatar jsdelivrbot avatar makyen avatar manishearth avatar nobodynada avatar not-a-ethan avatar papershine avatar quartata avatar sarco3t avatar serixscorpio avatar snpd25 avatar sulphurdioxide avatar techsnazzy avatar teward avatar thesecretmaster avatar thomas-daniels avatar tripleee avatar undo1 avatar user12986714 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  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

metasmoke's Issues

Problem with filter

I am attempting to query the posts/search route with the following parameters (plus a valid key):

filter='%00%00%00%00%00%00%00%03%C3%BF%C3%BF%C2%80%00%00%00%00%00'
from_date=1481241600
to_date=1481846400

This filter should be everything in the posts section from here.

Url: https://metasmoke.erwaysoftware.com/api/posts/search/?filter=%2500%2500%2500%2500%2500%2500%2500%2503%25C3%25BF%25C3%25BF%25C2%2580%2500%2500%2500%2500%2500&from_date=1481241600&to_date=1481846400&key=aa6cb28600cfa209789a33284bca4b025beed39c5dfb171d5030c88189403d81&per_page=100&page=1


Error message:

Mysql2::Error: Unknown column 'api_keys.updated_at' in 'field list': SELECT api_keys.updated_at, api_keys.user_id, api_tokens.id, api_tokens.user_id, api_tokens.token, blacklisted_websites.created_at, blacklisted_websites.updated_at, commit_statuses.ci_url, deletion_logs.is_deleted, deletion_logs.updated_at, feedbacks.user_name, feedbacks.user_link, feedbacks.invalidated_at, feedbacks.chat_user_id, flags.reason, flags.updated_at, flags.post_id, ignored_users.user_id, ignored_users.created_at, posts.post_creation_date, posts.created_at, posts.score, posts.stack_exchange_user_id, posts.is_fp, posts_reasons.post_id, reasons.id, roles.resource_id, roles.created_at, sites.created_at, smoke_detectors.last_ping, smoke_detectors.location, smoke_detectors.updated_at, smoke_detectors.email_date, stack_exchange_users.question_count, stack_exchange_users.reputation, users.meta_stackexchange_chat_id, users_roles.user_id FROM `posts` WHERE (`posts`.`created_at` > '2016-12-09 00:00:00') AND (`posts`.`created_at` < '2016-12-16 00:00:00') ORDER BY `posts`.`id` DESC LIMIT 100 OFFSET 0

I attempted to add the api_keys filters too, but that didn't solve the problem.

API Route Request: Get posts by date range

I'd like the ability to retrieve posts that were reported within a certain datetime range. This would be similar to /api/posts/feedback, but take two parameters - startdate and enddate

Example

Request

HTTP/1.1 GET /api/posts/daterange?startdate=1476102300&enddate=1476145500

This would return all posts between Oct 10, 2016 12:25 PM and Oct 11, 2016 12:25 AM. Time zone is assumed to be UTC. I am not requesting any timezone math be implemented.

Feature request: Live updates for the posts page, using websockets

It would be cool to have live, realtime updates via websockets, so that I can keep metasmoke (the "posts" page, specifically) open in a tab, and immediately see if there's anything new, perhaps with the title changing to denote this ? Something like the new questions pages, where we get "x new questions" messages, would be super cool.

Would something like this be doable ?

Make search use Ruby's regex engine instead of MySQL's

Search is a pretty good proxy for #69, certainly for the long-standing reasons. The major problem with it is the terrible regex support.

Instead of using the MySQL regex commands, we should leave fields out of the DB query if field_is_regex=1, and iterate through the results after we get them back from the DB, running the regexes in Ruby, and dropping results that don't match.

API Route Request: Posts by site

I'd like the ability to retrieve all posts by a specific site. This route would return a list of MS IDs which can then be used to gather more information.

Request

 HTTP/1.1 GET /api/posts/site?url=drupal.stackexchange.com

This call would return everything from drupal.stackexchange.com

Error message on search

First, I admit that regular expressions and I don't get along.

My goal is to find a post that has the following in the body:

http://Xtreme*Testrone/

I used the following string and checked the "regex" box for body:

*http://Xtreme*Testrone/*

My search URL ends up being this:

https://metasmoke.erwaysoftware.com/search?utf8=%E2%9C%93&title=&body_is_regex=1&body=*http%3A%2F%2FXtreme*Testrone%2F*&username=&why=&site=&feedback=&reason=&user_rep_direction=%3E%3D&user_reputation=0&commit=Search

As an aside, I realize this is an invalid domain (no TLD)


The error message this generates:

Mysql2::Error: Got error 'repetition-operator operand invalid' from regexp: SELECT `posts`.* FROM `posts` WHERE (IFNULL(posts.username, '') LIKE '%%' AND IFNULL(title, '') LIKE '%%' AND IFNULL(body, '') REGEXP '*http://Xtreme*Testrone/*' AND IFNULL(why, '') LIKE '%%') AND (ifnull(user_reputation, 0) >= 0) ORDER BY `posts`.`created_at` DESC LIMIT 100 OFFSET 0

Problem with Unicode/Emoji

Clicking on MS link https://m.erwaysoftware.com/posts/by-url?url=//physics.stackexchange.com/a/298560 gives a "Routing error".

Error message:

p.update(:body => "My name is jeffπŸ˜‚πŸ˜‚πŸ˜‚πŸ˜‚πŸ˜‚πŸ˜‚πŸ˜‚πŸ˜‚πŸ˜‚πŸ˜‚πŸ˜‚πŸ˜‚πŸ˜‚πŸ˜‚πŸ˜‚πŸ˜‚πŸ˜‚πŸ˜‚πŸ˜‚πŸ˜‚")
   (0.5ms)  BEGIN
  SQL (1.4ms)  UPDATE `posts` SET `body` = 'My name is jeffπŸ˜‚πŸ˜‚πŸ˜‚πŸ˜‚πŸ˜‚πŸ˜‚πŸ˜‚πŸ˜‚πŸ˜‚πŸ˜‚πŸ˜‚πŸ˜‚πŸ˜‚πŸ˜‚πŸ˜‚πŸ˜‚πŸ˜‚πŸ˜‚πŸ˜‚πŸ˜‚', `updated_at` = '2016-12-13 23:23:36' WHERE `posts`.`id` = 48666
   (0.4ms)  ROLLBACK
ActiveRecord::StatementInvalid: Mysql2::Error: Incorrect string value: '\xF0\x9F\x98\x82\xF0\x9F...' for column 'body' at row 1: UPDATE `posts` SET `body` = 'My name is jeffπŸ˜‚πŸ˜‚πŸ˜‚πŸ˜‚πŸ˜‚πŸ˜‚πŸ˜‚πŸ˜‚πŸ˜‚πŸ˜‚πŸ˜‚πŸ˜‚πŸ˜‚πŸ˜‚πŸ˜‚πŸ˜‚πŸ˜‚πŸ˜‚πŸ˜‚πŸ˜‚', `updated_at` = '2016-12-13 23:23:36' WHERE `posts`.`id` = 48666

API Route Request: Available flag reasons

When adding feedback via the API, you provide a type. It would be helpful if the available, acceptable, reasons were accessible via an API route.

It'd also be helpful if this route returned a human friendly description of the type.

Example output:

[
    {
        "type": "naa-",
        "description": "Not an answer (silent)"
    },
    {
        "type": "tpu-",
        "description": "True postive/Blacklist user"
    },
    ...
]

Notes section for posts?

Prompted by these comments by Glorfindel and unarist:

SmokeDetector: (Smokey report)

Glorfindel: ^ the URL points to drivethelife.com, a known spam target, and is an answer for Windows 10 instead of Windows 8.x.

unarist: Maybe useful for reviewing if we can attach comment like this ^^ to own feedback on MS?


It would be useful if we could attach notes to a MS post. That way, when people come back to have a look at a MS post (e.g. contested by site mods/meta crowd), they can find out why the Charcoal users submitted the feedback they did.

Ideas on how to submit notes:

  • Any logged-in MS user can edit the notes section
  • Any content after the feedback part of a reply is sent to MS (e.g. if you replied to a report with f (edited out spam link), the (edited out spam link) part would be sent to MS (possibly with the brackets stripped?))
  • Any content in a non-feedback reply (possibly, but may catch joke comments etc)
  • Subcommand for replies such as note?

Personal Autoflag logs

Would be nice if we had logs for autoflags just for ourselves (or any particular single user)

Make an post age condition in the flagging conditions dialog

At the moment, we have: Post weight, User reputation and reason count as filters.

By adding another filter called post age, we can prevent the system flagging 3 year old posts that weren't bad then, but are bad now (maybe the post was simple missed back in the days, or the website has gone bad).

Ways to find posts which were *not* autoflagged

The new autoflagging functionality is awesome, but in order to make it even more awesome, we need some way to find the posts which were still not autoflagged, so that we can analyze them and figure out additional heuristics we could put in the system in order to catch similar posts in the future.

I'm vague on what exactly would be useful, and only posting the use case at this point. I can think of some ways which should hopefully be reasonably straightforward, by order of (my limited perception of) apparent complexity.

  • Similar to the flagged log https://metasmoke.erwaysoftware.com/flagging/logs display a timeline of just the posts which were not flagged
  • Throughout the system, expose the flag weight in places where currently we display a summary (title, site, timestamp, user, feedback icons, etc) -- this overlaps with issue #50 to some extent
  • Expose the flag weight in the search form as a searchable field

Make MS flag gibberish posts as abusive

This has been discussed before, but I think it should probably be discussed again if we are going to go public on meta about autoflagging.


As you know, there is no difference between spam and abusive flags for when it comes to getting a post deleted, but only spam flags train SE's SpamRam.

Right now, since we are only casting a single flag it doesn't matter which flag we use, since the humans which make up the other five flags take the majority and determine whether or not the post is used to train the system. However, if we get approval to cast more than one flag on a post, then smokey will have enough flags to outweigh the humans. Hence, it will beco e important that we are correctly flagging gibberish posts.

This could possibly be implemented by adding a classification to each reason, spam or offensive. Reasons such as few unique characters in answer, offensive answer detected etc should be marked as offensive while everything else can be marked as spam. If >50% of the reasons of an autoflagging eligible post are offensive, then cast an offensive flag.

The 'Preview' button is broken on the autoflagging conditions

The first time you go to set your autoflagging conditions, the preview button works great, it gives you a nice helpful preview. If you go to edit your conditions afterwards, however, the preview button does nothing. You click, and it gives the exact same stats as before.

The site picker is missing

The site picker for the autoflagging preferences is invisible:

screen shot 2017-01-19 at 12 31 57 pm

I'm using Safari 10.0.2 on macOS 10.12.2. I get this JavaScript error in the console, twice:

TypeError: $(".selectpicker").selectpicker is not a function. (In '$(".selectpicker").selectpicker()', '$(".selectpicker").selectpicker' is undefined)

Websocket for Charcoal HQ extensions

The Autoflagging Information userscript currently pulls its data from the MS API (/api/posts/urls). This is fine for the initial load when you enter the chatroom. But for reports which come in later, it's better to push it, so @Undo1 suggested to build a WebSocket for this.

There's more information from MS that could be used in Charcoal HQ, and the userscript could be extended to handle this:

  • When MS detects a reported post is deleted, this information can be pushed and the userscript can grey out / strikethrough the corresponding Smokey report
  • Feedback (TP/FP/NAA) can be displayed 'live', e.g.

API Feature Enhancement

With the new feature requests (#35, #36, #37), I'd like to request unification of the posts routes. Instead of having a separate route for each possible search parameter, have a single route and allow a combination of filters to be applied.

This change would reduce the number of routes that are needed and would allow for more complex search queries to be performed. As currently implemented (and requested), combination filters can be done easily via the API. For example, a search for all Stack Overflow posts, posted in the last 7 days, and that received an fp response, requires multiple API calls and then logic on the client side to determine which records are in all responses.

Respect backoff on flag requests

We've had a couple (out of 400+) requests fail because we detect a few flag-worthy posts within a few seconds of eachother. As a low-priority thing, we should probably record the backoff and check it before sending more requests.

We already have Redis running; we could probably leverage that as an in-memory store.

Add 'weight' to Search

To determine if certain types of spam need another filter to be routinely auto-flagged, it would be nice if the weight (>=, <=) could be added as another parameter to search on. Or just a boolean 'would/would not be autoflagged'. The latter would also be good to have in the search result list.

Prioritize autoflagging by activity

(originally posted by @magisch here: Charcoal-SE/SmokeDetector#457)

In preparation for when we're casting more then 1 auto flag, it would be nice to use flags from people who aren't currently active first in autoflagging (so the people who are active can use their manual flags on top of the auto flags).
For that, I propose basing it on feedback and autoflags.
Create a priority list, and people who haven't feedbacked a post or been made to autoflag a post for the longest will be prioritized.

Comment by @tripleee:

Maybe this should be a user preference. At least initially, I would like to be able to see what the system is doing in my name.

API Response: Add count of number of is_* attributes

When a post receives feedback from multiple users, it'd be helpful to know how many of each type (is_fp, is_tp, and is_naa) were received.

For example, post https://metasmoke.erwaysoftware.com/post/44634 received 2 is_tp and 1 is_naa and has a response object that looks like this:

{   'has_more': False,
    'items': [   {   u'body': <snipped for brevity>,
                     u'created_at': u'2016-10-25T09:50:45.000Z',
                     u'downvote_count': None,
                     u'id': 44634,
                     u'is_fp': False,
                     u'is_tp': True,
                     u'link': u'//superuser.com/a/1138708',
                     u'post_creation_date': None,
                     u'score': None,
                     u'site_id': 3,
                     u'stack_exchange_user_id': 37707,
                     u'title': u'What are all the "about:" pages, in Internet Explorer?',
                     u'updated_at': u'2016-10-25T10:11:20.000Z',
                     u'upvote_count': None,
                     u'user_link': u'//superuser.com/u/656344',
                     u'user_reputation': 1,
                     u'username': u'user656344',
                     u'why': u'Post - Contains 10 unique characters'}],
    'page': 1,
    'total': 1}

If there could be three new attributes showing the count of each, that'd be helpful. Example:

count_tp: 2,
count_fp: 0,
count_naa: 1,

An alternative to adding three new attributes, is changing the existing (and new) is_* attributes from a boolean to an integer.

Search: Option to show aggregate numbers by feedback

I frequently find myself performing multiple queries in the search form in order to figure out how many results are TP results. This use case could be streamlined significantly if there was an option to group the aggregate results per feedback category. Perhaps like this:

Feedback: [All]
[x] Aggregate by feedback

If you select something else than "All", the aggregate check box should probably be greyed out (or disappear altogether). Then in the Results section, instead of

Results (24)

you would see something like

Results (24; TP 15, FP 9, NAA 0, conflicted 0)

This is a rather crude design, which I'm sure can be improved -- I'm sketching it out in order to explain what I'm after, more than to specify a particular implementation.

API Route error in search path: Column 'created_at' in where clause is ambiguous

When using the following search, I get an error:

https://metasmoke.erwaysoftware.com/api/posts/search/?from_date=1477612800&feedback_type=naa-&to_date=1477699200&key=MY_VALID_KEY&per_page=100&page=1&site=stackoverflow

The error I get is:

Mysql2::Error: Column 'created_at' in where clause is ambiguous: SELECT COUNT(DISTINCT `posts`.`id`) FROM `posts` INNER JOIN `sites` ON `sites`.`id` = `posts`.`site_id` LEFT OUTER JOIN `feedbacks` ON `feedbacks`.`post_id` = `posts`.`id` AND `feedbacks`.`is_invalidated` = 0 AND `feedbacks`.`is_ignored` = 0 WHERE `feedbacks`.`feedback_type` = 'naa-' AND `sites`.`site_domain` = 'stackoverflow' AND (created_at > '2016-10-28 00:00:00') AND (created_at < '2016-10-29 00:00:00')

This error does not appear to be present in the posts/between route

API Response: Add is_naa attribute

Currently there is is_fp and is_tp attributes on post responses. If a post is marked as naa, both of these values are false.

Example on post 44499: https://metasmoke.erwaysoftware.com/post/44499

Response:

{   'has_more': False,
    'items': [   {   u'body': u'<p>Dear hello and my name is semakaleng bojosi</p>\n',
                     u'created_at': u'2016-10-24T07:26:59.000Z',
                     u'downvote_count': None,
                     u'id': 44499,
                     u'is_fp': False,
                     u'is_tp': False,
                     u'link': u'//freelancing.stackexchange.com/a/6189',
                     u'post_creation_date': None,
                     u'score': None,
                     u'site_id': 198,
                     u'stack_exchange_user_id': 37584,
                     u'title': u'Should I give the finished work to a client before or after they paid me?',
                     u'updated_at': u'2016-10-24T07:26:59.000Z',
                     u'upvote_count': None,
                     u'user_link': u'//freelancing.stackexchange.com/u/15233',
                     u'user_reputation': 1,
                     u'username': u'semakaleng',
                     u'why': u'Post manually reported by user *tripleee* in room *Charcoal HQ*.\n'}],
    'page': 1,
    'total': 1}

Request
Can you add an is_naa attribute to the response as well?

Prevent unstable rules from contributing to autoflagging weight

Until a rule has actually been tested against a reasonable number of messages, a 100% TP rate should not add 100 to the autoflagging weight. A new rule (or ideally, to be really safe, any recently changed rule) should simply add 0 (or perhaps some small value instead of 100) to the autoflagging weight until we have substantial evidence to support it.

Tentatively, don't promote a rule to a position where it contributes to the weight until it has been run against 100 (or 200? or 500?) posts.

Discussion (or more like monologue): http://chat.stackexchange.com/transcript/message/34974667#34974667

False positive feedback via API does not delete smokey message

When you reply sd f to a smokey message, Smokey will attempt to delete the message.

However, when you feedback via the API (i.e. FDSC), smokey does not attempt to delete the message.

I know that tpu and naa feedbacks are already sent back to smokey for various purposes, so it should be fairly easy to send fp feedbacks across the websocket too.

(I reported this here since it is MS which sends smokey the message on API feedback)

[API] has_more field will always return true or false for any page

The current has_more check works like this:

has_more = (results.count > @pagesize)

That doesn't take into account the page we're currently on, and so if it's true on page 1 it'll be true on any page number.

I will fix this, but this is a reminder for me about it when I get back.

Globalize controllers in dropdown

Pages controlled by any Devise controller cause issues with the application layout, with an error something like "Can't find controller 'devise/admin'" for our custom AdminController.

This can be solved by using '/controller' as the value for the :controller key of url_for, for example url_for(:controller => '/admin', :action => :index).

Add deletion status to Posts API

Thanks to the new websocket, we can receive realtime deletion information and gray out the corresponding Smokey report (this is already working in my development environment). I'd like to have a deletion status field in the Posts API as well, so that upon loading of the chatroom, I can do the same for older messages. A boolean field is more convenient for me, but transferring the deletion date is probably just as easy and more valuable for other uses of the API.

automatic depreciation for website and keyword blacklistings

I think that any website or keyword that was blacklisted but hasn't seen a single true positive in over a year should be removed from the blacklist.

As @ArtOfCode- noted to me in chat, the extensive blacklist has a performance hit, and since spammers discard domains like they do feces, there really isn't a reason to keep a 1 year old website blacklist entry in our databases.

These removed entries should of course not be removed from the calculation that calculates post scores, maybe they should just be moved to a separate file?

Anyways, I propose the automatic removal of lines in the blacklisted_websites.txt and bad_keywords.txt files which meet the following conditions:

  • They haven't caught a single TP in 1 year
  • They've been around at least 1 1/2 years

Wasn't sure whether to post this FR here or on the SD repo, since it has components for both, but move/recreate as appropriate please.

API route fails when passing `page` or `per_page` parameters

I attempted to call the following URL (with a valid key):

https://metasmoke.erwaysoftware.com/api/posts/feedback/?per_page=10&type=naa-&page=1&key=<VALIDKEY>

The goal is to get the first ten results. However, when I do so, I receive the following error:

ArgumentError in ApiController#posts_by_feedback 

comparison of Fixnum with String failed
Extracted source (around line #116):

114    
115    def set_pagesize
116       @pagesize = [params[:per_page] || 10, 100].min
117    end
118
119    def has_more?(page, result_count)

The request being sent (from that error page, is as follows - again with a valid key):

{"per_page"=>"10", "type"=>"naa-", "page"=>"1", "key"=>"<VALIDKEY>"}

A similar error errors if I remove the per_page parameter from the URL (but leave the page parameter)

ArgumentError in ApiController#posts_by_feedback 

comparison of String with 1512 failed

118
119    def has_more?(page, result_count)
120        (page || 1) * @pagesize < result_count
121    end
122
123    def verify_write_token

The request on this call is:

{"type"=>"naa-", "page"=>"1", "key"=>"<VALIDKEY>"}

If I remove both the per_page and page parameters, I receive a response, as expected

Add tooltips to feedback icons

Right now there is πŸ’©, βœ“, and βœ—. It took me a while to figure out that the poop was NAA.

Could tooltips be added to those images so someone can figure it out faster?

'Smokey Down' emails should be sent to the person hosting

This was brought up a week or so ago, but I thought I'd make an issue for it so we remember to come back to it:

We should associate MS keys with their owner's emails so that the appropriate person gets emailed when their copy of smokey goes down.

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.