Giter VIP home page Giter VIP logo

parlance's Introduction

Parlance

Parlance was a client library for Parler – a "free speech" social network that accepts real money to buy "influence" points to boost organic non-advertising content. The authors refrained from commenting on this business model.

Deprecation

As predicted, the design of Parler's API proved insecure and inadequate given the platform's scalability and performance goals. Parler recently proved this by discarding and deprecating their API server in full, opting to return to HTML 5 markup delivered directly from a PHP-based backend.

As a result, the software herein is no longer functional. This outcome was expected. Additional user-friendly options for researching the Parler and Gab platforms are currently under consideration.

The Parlance team apologizes for the inconvenience. The Parlance team additionally thanks Parler for taking a comically insecure API offline permenantly.

Installation and Configuration

You'll need at least Node.js v8.17.0 (Carbon LTS) to run Parlance – although we recommend using the latest available stable version (currently v15.3.0).

First, run npm install -g @castlelemongrab/parlance to fetch the software and all required dependencies. After installation completes, run parlance to see usage information.

Then, log in to Parler using an ordinary web browser. Use your browser's development tools and/or cookie storage interface to find Parler's MST (Master Session Token) and JST (a short-lived session token). Use the init subcommand to create an authorization file using the MST and JST values from your browser. If your browser supplies you with URI-encoded versions of these values, you should decode them prior to use to avoid duplicate HTTPS requests and/or warning messages from the tool. Any automation of the above login process is unlikely to be accepted.

Results for all subcommands are printed to standard output as a JSON-encoded array of objects.

Usage

parlance <command>

Commands:
  parlance init        Create an authorization file
  parlance feed        Fetch your own feed of posts
  parlance profile     Fetch a user profile
  parlance post        Fetch a single post by identifier
  parlance posts       Fetch all posts for a user
  parlance following   Fetch all users followed by a user
  parlance followers   Fetch all followers of a user
  parlance comments    Fetch all comments for a user, post, or comment
  parlance tags        Fetch all posts mentioning a hashtag
  parlance votes       Fetch all votes made by a user
  parlance write       Post a new message to your account
  parlance delete      Delete an existing message from your account
  parlance follow      Follow a user
  parlance unfollow    Unfollow an already-followed user
  parlance mute        Mute a user
  parlance news        Fetch your own affiliate news feed
  parlance moderation  Fetch your list of comments for moderation

Options:
  --help                 Show help                                     [boolean]
  --version              Show version number                           [boolean]
  --show-hidden          Show hidden options                           [boolean]
  --format-options       Provide format/type-specific options           [string]
  -c, --credentials      MST/JST tokens   [string] [default: "config/auth.json"]
  -o, --credentials-out  Output file for client credentials             [string]
  -S, --start-key        Specify a time-series start/resume key         [string]
  -E, --end-key          Specify a time-series end/halt key             [string]
  -l, --ignore-last      Rely solely upon time comparisons             [boolean]
  -n, --no-delay         Disable the failsafe rate-limiter             [boolean]
  -p, --page-size        Request a specific page size                   [number]
  -d, --debug            Print all debug information to stderr         [boolean]
  -v, --verbose          Print verbose information to stderr           [boolean]
  -q, --quiet            Print less information to stderr              [boolean]
  -s, --silent           Print absolutely no information to stderr     [boolean]
  -e, --expand           Expand specific UUID types     [array] [default: "all"]
  -f, --format           Select output format/type    [string] [default: "json"]
parlance init

Create an authorization file

Options:
  -o, --credentials-out  Output file for client credentials             [string]
  --mst                  The MST master session token        [string] [required]
  --jst                  The shorter-lived JST session token [string] [required]
parlance posts

Fetch all posts for a user

Options:
  -u, --username         The name of the user                           [string]
parlance comments

Fetch all comments for a user, post, or comment

Options:
  -u, --username         The name of the user                           [string]
  -i, --identifier       The unique identifier of the post              [string]
  -r, --replies          The unique identifier of the comment           [string]
parlance tag

Fetch all posts mentioning a hashtag

Options:
  -t, --tag              The hashtag, without the hash sign  [string] [required]
parlance write

Post a new message to your account

Options:
  -t, --text             The textual content to post         [string] [required]
parlance delete

Delete an existing message from your account

Options:
  -i, --identifier       The unique identifier of the post   [string] [required]

Output Formats

Currently, Parlance supports both a JSON array-of-objects output target, as well as a JSONL target (one JSON object per line). These targets will be expanded in the future. To use JSONL now, specify the -f jsonl option when you run Parlance. By default, a JSON array suitable for use with tools like jq will be emitted.

Legal

This repository seeks to document the design of Parler as accurately and concisely as possible. Parler is of interest to researchers, political campaigns, civic engagement groups, law enforcement, anti-discrimination groups, and the public at large. The free speech conveyed in this repository is of timely and widespread public interest.

If you choose to use this speech as part of an activity, please ensure your activity is ethical and legal within your jurisdiction. The author of this work of speech cannot, will not, and has no responsibility to control the behavior of others – in any jurisdiction, on any of Jupiter's mighty moons, or anywhere within the known universe – past, present, or future.

Due to the specific nature and quality of Parler's engineering design, the speech contained within this repository is the sole product of unrelated industry experience and third-party documentation. No act of disassembly, decompilation, reverse engineering, trade secret violation – nor any other prohibited act – was necessary to create the work contained herein.

"Communication does not lose constitutional protection as 'speech' simply because it is expressed in the language of computer code. Mathematical formulae and musical scores are written in 'code,' i.e. symbolic notations not comprehensible to the uninitiated, and yet both are covered by the First Amendment. If someone chose to write a novel entirely in computer object code by using strings of 1’s and 0’s for each letter of each word, the resulting work would be no different for constitutional purposes than if it had been written in English." – DMCA, Universal City Studios v. Corley, FN191: 273 F.3d 429, 60 USPQ2d 1953 (2nd Cir. 2001)

Congress shall make no law respecting an establishment of religion, or prohibiting the free exercise thereof; or abridging the freedom of speech, or of the press; or the right of the people peaceably to assemble, and to petition the Government for a redress of grievances.

Credits

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512

Parlance
An MIT-licensed client library and open-source intelligence tool for Parler

Copyright 2020, The Parlance Team
Copyright 2020, Baby Britain, Ltd.

GPG contact: 04BDC713FF16FE315E58CC5028B4EB3E98787367
-----BEGIN PGP SIGNATURE-----

iQIzBAEBCgAdFiEEBL3HE/8W/jFeWMxQKLTrPph4c2cFAl796YgACgkQKLTrPph4
c2eW5A/+Pbw17ilhoNWgAZYzMAvgJngS/VO0QtHlmAdKDRtyt14x3VeHw59XE5PW
iOAzM0yUG28vwflBp9ZCml+6eFw1jsLXuXOS/+X/zfuWZtHCVKal/FTYiKY/foHY
VUsjdwCUlbOZKdrUHAgloRRoc6aQlIIzJzmn+FHT0OOos3n28fNjqToGsVXWeg5y
CqJuSAIP+BLbao38vH5X/xg0rBJMUVYWaoX2TswGK7dJoY94Np6nJbiRIrU3iit4
Xnji7yvt5yaWbaYJNptoycrKcm9rJ9QsP9hcOES32TMYAvke6j8GkrhiyDX5tspe
eLR2kK3AUXHJ8EnpuBCknqyRn6GO/abUnoaL9iTNWfP2nknPgShtxbtChGydQCfs
/HJx1h3FDwONBIDlrZaUWJ6CQlxF7dnFf3R4nsa43UNqry+5Np/GLWTlg7Srbjw8
FMx0PBv4dHYq+2CCJQT9YSseP1J5y57aC0w2t1XUtsdiWUG4K4NsZV03pN4KyK0k
yIK5bAc9GJGK/gXM7kr9x+oZJUfeYawt3pPuloQqcRn8HZxVn+GF90C0q6lfaQ+0
QwRaVkvCOBMZFDtcUhXhO973bIhxlbKr2jfD/2peIpMYSG+dgh2KC/5W8xlPFGgD
sy0M0gwlV6AZLw0SiuAgQ6/vEAXMn2oyjZukP56+5gx75wXz/4U=
=hDiH
-----END PGP SIGNATURE-----

License

MIT

parlance's People

Contributors

castle-lemongrab avatar dependabot[bot] avatar milesmcc 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  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

parlance's Issues

Fully implement ratelimiting

In addition to the already-present delay logic, the library should use the Session object and X-Ratelimit headers to ensure that requests are never issued in violation of ratelimiting guidelines.

Implement full support for post echoes

Support for fetching feed data and feed echo data landed in 5427ff2, but the latter appears to be incomplete – either including inappropriate data or excluding relevant data. Investigate this issue and correct it if necessary. Twelve units. Unacceptable.

Authorization error on Mac OS

Literally my first issue, so may be a user issue.

Running Mac OS 11.1, Node v. 14.15.3, npm 6.14.9, parlance v. 1.1210.1. Getting a similar error as in Issue #22.

When I installed Parlance, it installed to /usr/local/lib/node_modules/@castlemongrab/parlance. It did not create a config folder, but I created one manually. Also manually created a cookies folder, into which I put the jst and mst files.

Doing "parlance init -o" with the various jst/mst files seems to work ("New file has been written to disk"), but when I "parlance profile" I get:

[fatal] Unable to read authorization data from config/auth.json

Any thoughts on what I'm doing wrong?

Set-cookie headers on response

Hello,

Sorry for having to contact you this way, but i have been stuck on this for a while. I'm creating my own implementation based on making calls from a nodejs server. I'm running it on https://localhost:3000. While providing the jst and mst from the frontend to the backend the requests go through without any problems. That is, until the jst expires. I never get any set-cookies header back in the response headers. Honestly I feel like i'm missing something really fundamental. I would really appreciate it if you had an answer for this. I will try and see if I can help with a few open issues.

Thanks for reading.

Add support for ZSON JSONB PostgreSQL Output

Instead of writing JSON files, it'd be great if this utility could persist ZSON JSONB data directly to a PostgreSQL database. This is straightforward, would be extremely resilient to result schema changes, and would provide for some relatively powerful downstream search, indexing, and filtering options.

Refactor console I/O

If console I/O is wrapped in a thin abstraction, this library will work in a web browser (the bent HTTPS library has both a Node and browser backend implementation). Do... the thing.

New Authentication

Hi!

Wondered if you're aware of any changes to Parler recently that would effect the cookie-based authentication process.

There no longer appears to be MST or JST tokens, just PHPSESID and PV* cookies. Is there potential for this codebase to make use of these instead, or does this change require a different strategy?

Cheers!

Add restart-at-key option, allow number of retries to be specified

As a follow-up to #38 and as suggested via Twitter: add a CLI option to control the number of retries for server-side errors, and add a new client and CLI option to force Parlance to start at a specific time-series key.

The former will allow the user to increase runtime resilience to server-side errors/flakiness; the latter will provide users with a way to start or restart paged queries at any point in time – whether to recover from a previous failure, or to skip over more recent results.

Save json output to file

I was just wondering if there is a command to save the response from Parler to a given file, instead of printing data to console?

Add user follow/unfollow

In addition to the post and delete API endpoints, we should support programmatically following and unfollowing users.

Make it easier to implement a subcommand

It'd be nice to modularize the codebase such that the major functions required to implement a paged-fetch subcommand were all in one place. Right now, they're in multiple places – src/arguments.js, src/cli.js, and two functions in src/client.js. This could be cleaned up.

Balance this with the possibility that the API changes over time and becomes less generic.

Investigate ratelimiting errors

It's unclear whose fault this is, but Parler appears to be rejecting requests that comply with their ratelimiting headers. I don't know if this is them being dishonest or an issue in this codebase's ratelimiting implementation. The random delay default effectively counters this – however, we should investigate the issue and determine what's going on. Parler's frontend now reports version 1.4.5.

Feature Request: Comment on post given post Id

This would be a great feature and would work much the same as write but with a post Id as an input.

I guess it would look something very roughly like this...

cli.js

  case 'comment':
    if (args.i) {
      await this._ensure_post_exists(client, args.i);
      await client.write_comment(args.i, args.t);
    } else if (args.r) {
      /* something goes here if you want to handle reply comments on comments?*/
     /* await client.write_reply_comment(args.r, args.t); */
    }
    break;

client.js

  async write_comment (_id, _text) {

    let url = 'v1/post';

    let body = {
      body: _text,
      parent: null, links: [], state: 4 /* does parent = post Id?) */
    }

Provide a command to fetch posts and echoes simultaneously

The API returns posts and echoes (postRefs) alongside each other in two parallel subarrays. The frontend code then appears to merge-join these two arrays together based upon timestamp. Provide a command that merge-joins these two arrays together based upon each post or echo's CouchDB ISO 8601 timestamp.

This issue, like #9, will require parsing those timestamps. Find a library to do... the thing, and it'll make both of these issues actionable.

Add JSONL support

As part of multi-format output support, Parlance should support JSONL, also known as "not outputting those commas and square brackets". This is the preferred format for feeding large search/query engines, and will save people time who do not want to spend their time chopping off commas and omitting square brackets.

Use this as an opportunity to set up sane flags/options for multiple output backends, as this one is near-trivial.

Call for contributions and feature requests

If you have any ideas, small or large, for how this codebase could be improved, please comment in this thread or file a new issue and reference it here so it can be added to the kanban board. No idea is too small or too big. If we're going to do free speech, let's go all the way.

Add support for session credential rekeying

If any Set-Cookie headers are sent in response to a request that contain an MST or JST, update the credential store automatically. Provide an option to write these new values out to a configuration file (not necessarily the same one the application was started with). Handle urlencoded MST and JST tokens in configuration files more gracefully (this isn't possible in general, but we can attempt to use decodeURIComponent on failure, try again if we get a different string back, and print a warning).

Investigate and fix "Received zero-length result; stopping" issue in paged API endpoints

Parler appears to have made some changes since moving – or, alternatively, managed to add some bugs in the process. It's hard to know for sure. In any case, Parlance is not functioning properly at this time.

Figure out why and fix it, so that Parlance users are once again able to extract, research, and examine some of the worst content humanity has to offer.

Paging: harden against infinite loops

For many sequences, it's likely necessary to determine if a key is monotonically increasing or decreasing to avoid infinite loops secondary to concurrent server-side modifications or server API bugs. Add a way to do this. This'll likely involve – at a minimum for the current endpoints – the ability to parse CouchDB ISO 8601 timestamps.

—confirm-page-size not accepted

When I set -p to anything (even just 11) I get the warning about —confirm-page-size followed by a fatal error even when using —confirm-page-size

Figure out why CouchDB is accepting invalid comment identifiers when fetching post comments

On both our local simulated API server and as evident from browser debug output, the Parler API is returning an empty result set instead of an error when fetching comments for an invalid post identifier. Figure out what's going on here, if it's an issue or could potentially deny service, and either work around it or detect the condition and block it.

Note that Parler's security contact information page is itself broken, so I am unable to report potential issues. They simply do not have a legitimate information security contact available. The page doesn't even render properly – it's bright red, because someone can't write HTML competently.

Modularize JSON output engine

There should be a properly modular way to introduce new output formats in addition to the current JSON array on standard output. Formats such as JSONL, a directory full of JSON files, PostgreSQL and/or other database output support (see issue #23) could be incredibly useful.

In addition, these output emitters could apply transforms for compatibility with other tools (e.g. visualization and/or data processing tools) on the way out. Do this, but avoid file-based runtime module loading for portability.

Add support for raw JSON output

Splitting this off from issue #25. This may be more useful as a debug output channel (e.g. stderr or a separate file). Rethink the interface a bit and then implement.

Support CSV-formatted output via -f using dotted column names

We've discussed this a bit, and it seems the consensus is that we should use an existing json2csv module to handle JSON to CSV conversion prior to output. This would also provide us some user-accessible mechanisms (i.e. options and/or configuration files) to alter the CSV output (i.e. by pushing options down to the JSON/CSV converter).

We've identified a suitable library on NPM with minimal dependencies and excellent test coverage.

feature to return "discover" page results?

hello,

is there, or will there be, a feature to return posts as seen on the "discover" page here: https://parler.com/discover ?

i've been using selenium to scrape the posts in the "Parleys" section - as they seem representative of the site.

i'm assuming parlance feed returns my own feed - which is empty because I refuse to engage with anyone on Parler.

Thanks!

Add support for result filtering

This tool should support, at a minimum, hashtag-based filtering and regular expression filtering based upon post/comment/feed content. This should allow for more efficient detection of illegal libel, threats, and content that stands in violation of Title VI of the Civil Rights Act of 1964.

Add strong typing and a type checker

At some point this code should have strong types and a type checker added to it. Marking low priority for now; if anyone sets up CI and a build process in the future, that might be a good time to do this.

Add support for fetching "echoes"

Currently, this tool doesn't appear to capture "echoes" (Parler's equivalent of retweets). Figure out how to do this, and what changes may be required to either (i) fetch them along with posts, or (ii) fetch them as a separate command/operation.

Some accounts do not return full paged results

There's a bug in the paging code or a misunderstanding of the undocumented API. Some account fetch tasks (ask for details) are terminating early, falsely believing there are no more results when there are in fact more. Figure out why and fix it.

Changing Page Limits Does Not Work

When trying to change the page limit rate I get the following message

❯ /usr/local/Cellar/node/15.2.1/bin/parlance followers -u --no-delay -p 100 -g 100
[warn] You are responsible for deciding if this is allowed
[warn] The authors bear no responsibility for your actions
[fatal] You have been warned; refusing to continue as-isjjjk

Regression in `init` subcommand: IOH.Base does not implement write_file

Heyhey, noob here. I wonder why I get error 127:

My command, in /usr/local/lib/node_modules/@castlelemongrab/parlance (there is no config folder there btw):

parlance init --mst "$mst" --jst "$jst" -o config/auth.json

(node:11054) UnhandledPromiseRejectionWarning: Error: Process exited with status 127

at IOH.fatal (/usr/local/lib/node_modules/@castlelemongrab/parlance/node_modules/@castlelemongrab/ioh/src/ioh.js:57:11)
at Session.write_credentials (/usr/local/lib/node_modules/@castlelemongrab/parlance/src/session.js:84:18)

(Use node --trace-warnings ... to show where the warning was created)
(node:11054) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag --unhandled-rejections=strict (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 2)
(node:11054) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

Feature request: Ability to specify a date to scrape back from

Currently, when fetching Parlies based on hashtag / user, the results are returned from that moment in time, backwards. It would be very helpful, for research purposes, if a user would be able to specify the date to crawl back from.

For example, if one is investigating activity around elections time on #maga hashtag, right now it would take days of scraping to get to election time data, as this is a high activity hashtag.

I am not sure if this is easy to do or not, although the fact that system message seems to include some date is a positive sign (e.g. the startkey part of Fetching v1/post/hashtag?tag=maga&limit=10&startkey=2020-11-25T21%3A24%3A27.365Z_250881603 )

Implement command-line option parsing

Currently, command-line argument parsing is rather... baroque. Find a good option parsing library and use it to process command-line arguments and generate usage information.

Provide initial developer-mode browser compatibility

Web browsers are ubiquitous and convenient, and there's nothing preventing someone from implementing a browser-specific version of the Arguments class and packaging this for in-browser use. The bent HTTPS client library already has a browser backend in addition to the Node backend.

Dramatically improve test coverage

This codebase currently has no tests. A castle with no unit tests, integration tests, or functional tests is in... unacceptable condition. Split the main client out into separate files, pick a testing framework, and at least get some basic unit tests added, with coverage metrics (N.B. should probably just use nyc and istanbul here).

HTTP 502 from Parler while fetching tags

I continually receive the following error if I try to pull a bigger size of parlays (e.g. #thegreatawakening).. does anyone know if this is easy to fix? I'm relatively new to all this. Thank you!

(node:12854) UnhandledPromiseRejectionWarning: StatusError: Bad Gateway
    at ClientRequest.<anonymous> (/usr/local/lib/node_modules/@castlelemongrab/parlance/node_modules/bent/src/nodejs.js:133:23)
    at Object.onceWrapper (events.js:422:26)
    at ClientRequest.emit (events.js:315:20)
    at HTTPParser.parserOnIncomingClient [as onIncoming] (_http_client.js:634:27)
    at HTTPParser.parserOnHeadersComplete (_http_common.js:117:17)
    at TLSSocket.socketOnData (_http_client.js:503:22)
    at TLSSocket.emit (events.js:315:20)
    at addChunk (_stream_readable.js:302:12)
    at readableAddChunk (_stream_readable.js:278:9)
    at TLSSocket.Readable.push (_stream_readable.js:217:10)
(Use `node --trace-warnings ...` to show where the warning was created)
(node:12854) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:12854) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

Add a simple end-to-end testing framework

Parler is an erratically-moving target. In the face of this reality, it'd be good have a simple end-to-end testing framework. The purpose of these tests would be to ensure all major CLI subcommands still work prior to release, and to detect regressions caused by changes to Parler's squirrel-infested API.

Clean up HTTP header generation, provide request-minimization option

Currently, this repository of free speech faithfully implements the Parler API per the frontend specification, all the way down to the production of appropriate Referrer: headers. This often results in extra network requests. In some cases or for some studies of the API, this may be undesirable.

Clean up the _create_extra_headers function, and provide an option to be less strictly API-conformant in order to minimize request count / server load.

Be Node v8+ compatible (was: Credentials / init keeps failing)

Is it possible to provide an example of how to connect parlance to Parler?

I’ve tried supplying both URI encoded and decoded values directly to the —mst and —jst options as well as putting them into the auth.json file. I’ve tried including entire cookies as well as just the content/value strings within the cookies. Not sure what else to try.

Also, I am a bit confused why it would want both a -c option that presumably points to the json file with the mst and jst, while also requiring the same data as —mst and —jst sub-options to -c.

Add reparenting/UUID expansion options, raw output option

Code is in master that expands UUID references to posts (i.e. root/parent in an echo context), creators, and links – among other things.

Provide command-line arguments that can enable/disable this expansion. It's useful in most cases, but some cases (e.g. posts for a fixed user), expansion of the creator profile just bloats the output.

Finally, add an option to just dump the raw JSON API output, without any transformation or reduction whatsoever.

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.