Code Monkey home page Code Monkey logo

datasette-publish-vercel's Introduction

datasette-publish-vercel

PyPI Changelog Tests License

Datasette plugin for publishing data using Vercel.

Installation

Install this plugin in the same environment as Datasette.

$ datasette install datasette-publish-vercel

Usage

First, install the Vercel CLI tool by following their instructions.

Run vercel login to login to (or create) an account.

Now you can use datasette publish vercel to publish your data:

datasette publish vercel my-database.db --project=my-database

The --project argument is required - it specifies the project name that should be used for your deployment. This will be used as part of the deployment's URL.

Other options

  • --no-prod deploys to the project without updating the "production" URL alias to point to that new deployment. Without that option all deploys go directly to production.
  • --debug enables the Vercel CLI debug output.
  • --token allows you to pass a Now authentication token, rather than needing to first run now login to configure the tool. Tokens can be created in the Vercel web dashboard under Account Settings -> Tokens.
  • --public runs vercel --public to publish the application source code at /_src e.g. https://datasette-public.now.sh/_src and make recent logs visible at /_logs e.g. https://datasette-public.now.sh/_logs
  • --generate-dir - by default this tool generates a new Vercel app in a temporary directory, deploys it and then deletes the directory. Use --generate-dir=my-app to output the generated application files to a new directory of your choice instead. You can then deploy it by running vercel in that directory.
  • --setting default_page_size 10 - use this to set Datasette settings, as described in the documentation. This is a replacement for the unsupported --extra-options option.

Full help

Warning: Some of these options are not yet implemented by this plugin. In particular, the following do not yet work:

  • --extra-options - use --setting described above instead.
  • --plugin-secret
  • --version-note
$ datasette publish vercel --help

Usage: datasette publish vercel [OPTIONS] [FILES]...

  Publish to https://vercel.com/

Options:
  -m, --metadata FILENAME         Path to JSON/YAML file containing metadata to publish
  --extra-options TEXT            Extra options to pass to datasette serve
  --branch TEXT                   Install datasette from a GitHub branch e.g. main
  --template-dir DIRECTORY        Path to directory containing custom templates
  --plugins-dir DIRECTORY         Path to directory containing custom plugins
  --static MOUNT:DIRECTORY        Serve static files from this directory at /MOUNT/...
  --install TEXT                  Additional packages (e.g. plugins) to install
  --plugin-secret <TEXT TEXT TEXT>...
                                  Secrets to pass to plugins, e.g. --plugin-secret
                                  datasette-auth-github client_id xxx
  --version-note TEXT             Additional note to show on /-/versions
  --secret TEXT                   Secret used for signing secure values, such as signed
                                  cookies
  --title TEXT                    Title for metadata
  --license TEXT                  License label for metadata
  --license_url TEXT              License URL for metadata
  --source TEXT                   Source label for metadata
  --source_url TEXT               Source URL for metadata
  --about TEXT                    About label for metadata
  --about_url TEXT                About URL for metadata
  --token TEXT                    Auth token to use for deploy
  --project PROJECT               Vercel project name to use  [required]
  --scope TEXT                    Optional Vercel scope (e.g. a team name)
  --no-prod                       Don't deploy directly to production
  --debug                         Enable Vercel CLI debug output
  --public                        Publish source with Vercel CLI --public
  --generate-dir DIRECTORY        Output generated application files and stop without
                                  deploying
  --generate-vercel-json          Output generated vercel.json file and stop without
                                  deploying
  --vercel-json FILENAME          Custom vercel.json file to use instead of generating
                                  one
  --setting SETTING...            Setting, see docs.datasette.io/en/stable/settings.html
  --crossdb                       Enable cross-database SQL queries
  --help                          Show this message and exit.

Using a custom vercel.json file

If you want to add additional redirects or similar to your Vercel configuration you may want to provide a custom vercel.json file.

To do this, first generate a configuration file (without running a deploy) using the --generate-vercel-json option:

datasette publish vercel my-database.db \
  --project=my-database \
  --generate-vercel-json > vercel.json

You can now edit the vercel.json file that this creates to add your custom options.

Then run the deploy using:

datasette publish vercel my-database.db \
  --project=my-database \
  --vercel-json=vercel.json

Setting a DATASETTE_SECRET

Datasette uses a secret string for purposes such as signing authentication cookies. This secret is reset when the server restarts, which will sign out any users who are authenticated using a signed cookie.

You can avoid this by generating a DATASETTE_SECRET secret string and setting that as a Vercel environment variable. If you do this the secret will stay consistent and your users will not be signed out.

Using this with GitHub Actions

This plugin can be used together with GitHub Actions to deploy Datasette instances automatically on new pushes to a repo, or on a schedule.

The GitHub Actions runners already have the Vercel deployment tool installed. You'll need to create an API token for your account at vercel.com/account/tokens, and store that as a secret in your GitHub repository called VERCEL_TOKEN.

Make sure your workflow has installed datasette and datasette-publish-vercel using pip, then add the following step to your GitHub Actions workflow:

    - name: Deploy Datasette using Vercel
      env:
        VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
      run: |-
        datasette publish vercel mydb.db \
          --token $VERCEL_TOKEN \
          --project my-vercel-project

You can see a full example of a workflow that uses Vercel in this way in the simonw/til repository.

datasette-publish-vercel's People

Contributors

rclement avatar simonw avatar styfle 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

Watchers

 avatar  avatar  avatar  avatar  avatar

datasette-publish-vercel's Issues

Support --debug option for enabling Now CLI debug mode

This is really useful for seeing exactly what's going on.

$ datasette publish now2 covid.db --project=covid-cases
> [debug] [2020-04-07T05:01:50.253Z] Found config in file /private/var/folders/bl/5x847xbj2yb7xmp7f2tz7l280000gn/T/tmpbessv97g/datasette-now-v2/now.json
Now CLI 17.1.1
> [debug] [2020-04-07T05:01:50.263Z] user supplied a possible target for deployment
> [debug] [2020-04-07T05:01:50.264Z] Spinner invoked (Retrieving scope…) with a 1000ms delay
> [debug] [2020-04-07T05:01:50.264Z] Spinner ended (Retrieving scope…)
> [debug] [2020-04-07T05:01:50.280Z] GET https://api.zeit.co/www/user 
> [debug] [2020-04-07T05:01:50.788Z] GET https://api.zeit.co/www/user : 507.214ms
> [debug] [2020-04-07T05:01:50.840Z] Spinner invoked (Loading scopes…) with a 1000ms delay
> [debug] [2020-04-07T05:01:50.841Z] GET https://api.zeit.co/teams 
> [debug] [2020-04-07T05:01:51.332Z] GET https://api.zeit.co/teams : 490.462ms
(node:11348) Warning: No such label '> [debug] #1 GET /teams' for console.timeEnd()
> [debug] [2020-04-07T05:01:51.333Z] Spinner ended (Loading scopes…)
❗️  The `name` property in now.json is deprecated (https://zeit.ink/5F)
> [debug] [2020-04-07T05:01:51.334Z] Setting target to production
> [debug] [2020-04-07T05:01:51.335Z] Spinner invoked (Setting up project) with a 0ms delay
[now-client-debug] 2020-04-07T05:01:51.335Z Creating deployment...
[now-client-debug] 2020-04-07T05:01:51.335Z Provided 'path' is a directory. Reading subpaths... 
[now-client-debug] 2020-04-07T05:01:51.336Z Read 4 subpaths
[now-client-debug] 2020-04-07T05:01:51.337Z Found 1 rules in .nowignore
...

Advanced FTS queries not working in DB published using datasette-publish-now

Hi,
in the sf-trees project, it's possible to use *, NEAR, AND, etc. In example the string melanoxylo*.

I have created my first datasette project, I have enabled full-text search, but I cannot use in example *: the query for vill* (I have the word "villa" and "ville").

I have enabled full-text running:

sqlite-utils enable-fts my.db mytable fieldone fieldtwo

I have published it without any option using this command:

datasette publish now commissioniComunePalermo.db --project=my-database

Thank you very much

Disable interactive prompts

I upgraded from now cli 15 to now cli 17 and it's started asking me interactive questions during each deploy.

$ datasette publish now2 ../datasette/fixtures.db --title="Datasette Fixtures" --project=datasette-fixtures
Now CLI 17.1.1
? Set up and deploy “/private/var/folders/bl/5x847xbj2yb7xmp7f2tz7l280000gn/T/tmpnh5u9bys/datasette-now-v2”? [Y/n] y
? Which scope do you want to deploy to? simonw
? Found project “simonw/datasette-fixtures”. Link to it? [Y/n] y
🔗  Linked to simonw/datasette-fixtures (created .now and added it to .gitignore)
❗️  The `name` property in now.json is deprecated (https://zeit.ink/5F)
🔍  Inspect: https://zeit.co/simonw/datasette-fixtures/ciymmquh0 [3s]
✅  Preview: https://datasette-fixtures.simonw.now.sh [copied to clipboard] [16s]
📝  To deploy to production (datasette-fixtures.now.sh), run `now --prod`

datasette publish: error using custom template

Hi,
I have created a template folder and I have put inside it a copy of base.html and index.html official template files.

I have edited nothing, and then run (to make a test) simply

datasette publish now mydb.db --project=my-database --template-dir=template

I have the error below. What's wrong in my procedure or in my system?

Thank you

Traceback (most recent call last):
  File "/home/aborruso/.local/lib/python3.7/site-packages/datasette/utils/__init__.py", line 607, in link_or_copy_directory
    shutil.copytree(src, dst, copy_function=os.link)
  File "/usr/lib/python3.7/shutil.py", line 365, in copytree
    raise Error(errors)
shutil.Error: [('/myfolderproject/processing/template/base.html', '/tmp/tmpfccqqfod/datasette-now-v2/templates/base.html', "[Errno 18] Invalid cross-device link: '/myfolderproject/processing/template/ba
se.html' -> '/tmp/tmpfccqqfod/datasette-now-v2/templates/base.html'"), ('/myfolderproject/processing/template/index.html', '/tmp/tmpfccqqfod/datasette-now-v2/templates/index.html', "[Errno 18] Invalid cross-device link: '/mnt/c/Users/aborr/Do
cuments/GitHub/youtubeComunePalermo/processing/template/index.html' -> '/tmp/tmpfccqqfod/datasette-now-v2/templates/index.html'")]

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/aborruso/.local/bin/datasette", line 8, in <module>
    sys.exit(cli())
  File "/home/aborruso/.local/lib/python3.7/site-packages/click/core.py", line 829, in __call__
    return self.main(*args, **kwargs)
  File "/home/aborruso/.local/lib/python3.7/site-packages/click/core.py", line 782, in main
    rv = self.invoke(ctx)
  File "/home/aborruso/.local/lib/python3.7/site-packages/click/core.py", line 1259, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/home/aborruso/.local/lib/python3.7/site-packages/click/core.py", line 1259, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/home/aborruso/.local/lib/python3.7/site-packages/click/core.py", line 1066, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/home/aborruso/.local/lib/python3.7/site-packages/click/core.py", line 610, in invoke
    return callback(*args, **kwargs)
  File "/home/aborruso/.local/lib/python3.7/site-packages/datasette_publish_now/__init__.py", line 118, in now
    port=8080,
  File "/usr/lib/python3.7/contextlib.py", line 112, in __enter__
    return next(self.gen)
  File "/home/aborruso/.local/lib/python3.7/site-packages/datasette/utils/__init__.py", line 396, in temporary_docker_directory
    os.path.join(datasette_dir, "templates"),
  File "/home/aborruso/.local/lib/python3.7/site-packages/datasette/utils/__init__.py", line 609, in link_or_copy_directory
    shutil.copytree(src, dst)
  File "/usr/lib/python3.7/shutil.py", line 321, in copytree
    os.makedirs(dst)
  File "/usr/lib/python3.7/os.py", line 221, in makedirs
    mkdir(name, mode)
FileExistsError: [Errno 17] File exists: '/tmp/tmpfccqqfod/datasette-now-v2/templates'

Site no longer deploys

My site has been chugging along for months, but as reported here:
simonw/datasette#1432
... vercel deploy has suddenly stopped functioning. I'm not sure when it began failing. It was at least two days ago.

For my project -- http://SaferOrToxic.org -- this is an urgent issue. (Of course, with the Datasette page down ("The List"), all the API requests that yield statistics to my Hugo home page are down, as well.)

Any suggestions on remedies?
(At first I thought it was a favicon issue, since an unfound favicion.ico was reported along with the "unexpected keyword argument 'config'" issue. I reverted my last favicon commit, and that did nothing to fix the situation.)

One other individual in the original issue above seems to be having exactly the same problem.

Margie

UTF-8 problem

Hello,
I have facing some utf-8 problem after deployment on vercel

Capture du 2020-12-06 02-45-53
on vercel

Capture du 2020-12-06 02-46-32
locally with Docker image

Document limitations of Now when used with Datasette

The README needs to mention that there's a size limit on databases that can be deployed using this tool (of approximately 50MB) and that they will deploy with an older version of SQLite that doesn't include FTS5. [UPDATE: this is no longer the case thanks to #17 - you now get a very recent SQLite with FTS5]

`--scope teamname` option

To enable publishing to a different team than the default.

datasette publish vercel blah.db --project hello --scope myteam

`datasette publish vercel` having issues with exporting JSON

Hi Simon,

I'm using datasette publish vercel (with the flags --install=datasette-cluster-map --install=datasette-vega --install=datasette-graphql) to create this:

https://thesession.vercel.app/

It was working great, but @abalter has filed an issue that the JSON view of query results is returning no results (when the HTML view is working fine):

adactio/TheSession-data#13

Here's the example HTML view:
https://thesession.vercel.app/thesession?sql=select+*+from+tunes+where+name+like+%22%25wise+maid%25%22%0D%0A
And the corresponding JSON result:
https://thesession.vercel.app/thesession.json?sql=select%20*%20from%20tunes%20where%20name%20like%20%22%wise%20maid%%22

I'm not sure when this change happened. I re-publish the data every Sunday.

Is there something I can do on my end?

First alpha: now2 command, can publish database files plus metadata

This can be the 0.1a release.

In this version the command will be datasette publish now2 to avoid clashing with the datasette publish now command that is built in too Datasette 0.39.

As soon as I ship Datasette 0.40 that default command will be gone (thanks to simonw/datasette#710) so I can rename this command to just now and have this repo depend on datasette~=0.40.

TypeError: now() got an unexpected keyword argument 'settings'

https://github.com/simonw/til/runs/1618711889?check_suite_focus=true

Traceback (most recent call last):
  File "/opt/hostedtoolcache/Python/3.8.6/x64/bin/datasette", line 8, in <module>
    sys.exit(cli())
  File "/opt/hostedtoolcache/Python/3.8.6/x64/lib/python3.8/site-packages/click/core.py", line 829, in __call__
    return self.main(*args, **kwargs)
  File "/opt/hostedtoolcache/Python/3.8.6/x64/lib/python3.8/site-packages/click/core.py", line 782, in main
    rv = self.invoke(ctx)
  File "/opt/hostedtoolcache/Python/3.8.6/x64/lib/python3.8/site-packages/click/core.py", line 1259, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/opt/hostedtoolcache/Python/3.8.6/x64/lib/python3.8/site-packages/click/core.py", line 1259, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/opt/hostedtoolcache/Python/3.8.6/x64/lib/python3.8/site-packages/click/core.py", line 1066, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/opt/hostedtoolcache/Python/3.8.6/x64/lib/python3.8/site-packages/click/core.py", line 610, in invoke
    return callback(*args, **kwargs)
TypeError: now() got an unexpected keyword argument 'settings'

Mechanism for running assertions against generated files

I'm going to add a --generate-dir= option for dumping out the generated files (rather than using a temp directory) so the tests can use it to run assertions.

If you use this we won't run the now command - you can run that yourself.

template directory fails on non-default path

It looks that for any path for templates dir other than the default --template-dir templates/ is ignored

I suspect the problem is that the template files are always copied in the /templates folder, regardless of the --template-dir option, while/but index.py takes note on the custom path, thus the mismatch.

Currently, the only way to make templates work is to run datasette publish from the parent folder of templates dir, named as such.

Screenshot 2021-05-26 at 13 55 11

Vercel CLI 23.0.0

Query page .csv and .json links are not correctly URL-encoded on Vercel under unknown specific conditions

Confirmed: https://thesession.vercel.app/thesession?sql=select+*+from+tunes+where+name+like+%22%25wise+maid%25%22%0D%0A is a page where the URL correctly encoded % as %25 - but then in the HTML on that page that links to the CSV and JSON versions we get this:

<p class="export-links">This data as
  <a href="/thesession.json?sql=select * from tunes where name like &#34;%wise maid%&#34;">json</a>,
  <a href="/thesession.csv?sql=select * from tunes where name like &#34;%wise maid%&#34;&amp;_size=max">CSV</a>
</p>

Those CSV and JSON links are incorrect.

Originally posted by @simonw in #48 (comment)

Vercel Error! File size limit exceeded (100 MB)

I have some use cases to deploy "bigger" datasette instances and I'm hitting the wall on the max filesize.
I was wondering if it is possible to set the Vercel cloud version to v1 when using datasette-publish-vercel?

I saw your comments about this:
#5 (comment)
simonw/datasette#366


setting the cloud version to v1 in now.json.

"features": {
  "cloud": "v1"
},

Ensure ds.invoke_startup() runs on startup

This is needed by plugins that use the startup() plugin hook.

It crashed:
[ERROR] AttributeError: 'Datasette' object has no attribute '_hashed_url_databases'Traceback (most recent call last): File "/var/task/vc__handler__python.py", line 293, in vc_handler response = asgi_cycle(__vc_module.app, body) File "/var/task/vc__handler__python.py", line 204, in __call__ loop.run_until_complete(asgi_task) File "/var/lang/lib/python3.9/asyncio/base_events.py", line 642, in run_until_complete return future.result() File "/var/task/datasette_hashed_urls/__init__.py", line 38, in hashed_urls if db_name in datasette._hashed_url_databases:
Presumably because datasette-publish-vercel doesn't arrange for the startup() hooks to be called!

app = Datasette(
[],
{database_files},
static_mounts=static_mounts,
metadata=metadata{extras},
secret=secret,
cors=True,
settings={settings}
).app()

Originally posted by @simonw in simonw/datasette-hashed-urls#2 (comment)

Allow users to specify a project (don't just default that to "datasette")

Right now every deploy made with this project occurs in a Zeit project called "datasette" - and new deploys over-write the previous https://datasette.simonw.now.sh/

This is bad! Need to figure out a smart way to help users specify the project to be written to.

This is similar to how --service works in datasette publish cloudrun - I ended up making --service a required option there. Maybe --project should be required here?

Ability to specify a custom vercel.json

I'm trying to resolve this issue:
simonw/datasette#1284

Vercel suggested placing this in vercel.json:

  "rewrites": [
    { "source": "/", "destination": "/disinfectants/listN" },
  ]

But datasette-publish-vercel seems to completely overwrite vercel.json in init.py (lines 204 - 212)

How would I add the above rewrites key to vercel.json?

Even though the rewrites key is in my root vercel.json file, it doesn't show up on Vercel, presumably because of that json.dumps in init.py.

(I don't know if their rewrites approach would work... but seems worth a try, if I could figure out how.)

Application error with --setting flags that accept boolean values

Hi,
I ran into 500 errors when visiting the pages of my vercel deployment, and it only happened every time I deploy the app with --setting flags that accept boolean in it (e.g. allow_download, allow_facet).

Here's the command that I used to deploy my app:

datasette publish vercel database.db --project=blah-blah --install=datasette-vega --setting allow_download off

And here's the error that I observed in vercel's logs:

module initialization error: name 'false' is not defined
module initialization error
name 'false' is not defined

If I may take an educated guess, the error is caused by the use of json.dumps on the settings dictionary here.

I can confirm that the generated source code in the vercel has the lowercase false boolean set as the value of the dictionary. It was neither a "false" string nor python's False boolean, whichever it is you meant to set.

image

json1 SQLite module is missing

The json1 module is missing from SQLite, which means useful functions like json_object() don't work.

I don't know if it's feasible to fix this.

Access Denied Error

I am trying to publish the db to vercel. But while isssuing the below command throwing Access Denied error which is leading to RecursionError: maximum recursion depth exceeded while calling a Python object.

I am using PyCharm and Python 3.9. I have reinstalled both and launched PyCharm as Admin in Windows 10. But still the issue persists.

Issued command datasette publish vercel jmeter.db --project jmeter --install datasette-vega

PS: localhost is working fine.

Custom templates directory in sub-folder not usable

When using a custom templates directory within a sub-folder, the templates are not used at runtime. For instance:

  • With a template folder at project/templates
  • Deploying using datasette publish vercel --template-dir project/templates ...

Inspecting the generated code using --generate-dir option yields:

  • A templates directory is generated at the root of the distribution folder (with the proper content)
  • Serverless function in index.py is referencing the templates folder with the wrong path:
app = Datasette(..., template_dir="project/templates", ...).app()

I think the fix is to simply set template_dir="templates" in index.py.

Note: it seems the same issue exists for plugins too.

Signing secret not used

When deploying a Datasette instance to Vercel combined with plugins requiring the signing secret (e.g. datasette-auth-passwords):

  • Authentication is disconnected after navigating for a few pages
  • The following message appears when logging for the second time: "form-urlencoded POST field did not match cookie"

This is clearly a CSRF token issue. After some investigation, it seems the DATASETTE_SECRET environment variable is not taken into account after deployment:

  • datasette publish vercel command generates and sets a Vercel environment variable named DATASETTE_SECRET
  • In the serverless function index.py, the DATASETTE_SECRET is never picked up and a new secret is generated (DATASETTE_SECRET is only picked-up by the datasette CLI)
  • Quite oftern a new copy of the serverless function is called server-side thus rotating the secret automatically!

The fix seems easy enough, I'll propose a PR to fix the serverless function to pick-up the DATASETTE_SECRET env var.

Confusing error message if --project contains upper-case letter

project_name_re = re.compile(r"^[a-z0-9][a-z0-9-]{1,51}$")

class ProjectName(click.ParamType):
name = "project"
def convert(self, value, param, ctx):
if not project_name_re.match(value):
self.fail(
"Project name must be alphanumeric, max 52 chars, cannot begin with a hyphen"
)
return value

Enable CORS

Published databases don't currently serve the CORS header.

$ curl -i https://til.simonwillison.net/til.json 
HTTP/1.1 200 OK
Date: Thu, 07 May 2020 02:55:04 GMT
Content-Type: application/json; charset=utf-8
Connection: keep-alive
cache-control: max-age=5
content-length: 1916
referrer-policy: no-referrer
x-vercel-cache: MISS
x-now-cache: MISS
age: 0
x-now-trace: sfo1
server: now
x-vercel-id: sfo1::sfo1::2w6kc-1588820104704-8241d260af04
x-now-id: sfo1::sfo1::2w6kc-1588820104704-8241d260af04
strict-transport-security: max-age=63072000

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.