Giter Site home page Giter Site logo

serve-index's Introduction

serve-index

NPM Version NPM Downloads Linux Build Windows Build Test Coverage

Serves pages that contain directory listings for a given path.

Install

This is a Node.js module available through the npm registry. Installation is done using the npm install command:

$ npm install serve-index

API

var serveIndex = require('serve-index')

serveIndex(path, options)

Returns middlware that serves an index of the directory in the given path.

The path is based off the req.url value, so a req.url of '/some/dir with a path of 'public' will look at 'public/some/dir'. If you are using something like express, you can change the URL "base" with app.use (see the express example).

Options

Serve index accepts these properties in the options object.

filter

Apply this filter function to files. Defaults to false. The filter function is called for each file, with the signature filter(filename, index, files, dir) where filename is the name of the file, index is the array index, files is the array of files and dir is the absolute path the file is located (and thus, the directory the listing is for).

hidden

Display hidden (dot) files. Defaults to false.

icons

Display icons. Defaults to false.

stylesheet

Optional path to a CSS stylesheet. Defaults to a built-in stylesheet.

template

Optional path to an HTML template or a function that will render a HTML string. Defaults to a built-in template.

When given a string, the string is used as a file path to load and then the following tokens are replaced in templates:

  • {directory} with the name of the directory.
  • {files} with the HTML of an unordered list of file links.
  • {linked-path} with the HTML of a link to the directory.
  • {style} with the specified stylesheet and embedded images.

When given as a function, the function is called as template(locals, callback) and it needs to invoke callback(error, htmlString). The following are the provided locals:

  • directory is the directory being displayed (where / is the root).
  • displayIcons is a Boolean for if icons should be rendered or not.
  • fileList is a sorted array of files in the directory. The array contains objects with the following properties:
    • name is the relative name for the file.
    • stat is a fs.Stats object for the file.
  • path is the full filesystem path to directory.
  • style is the default stylesheet or the contents of the stylesheet option.
  • viewName is the view name provided by the view option.
view

Display mode. tiles and details are available. Defaults to tiles.

Examples

Serve directory indexes with vanilla node.js http server

var finalhandler = require('finalhandler')
var http = require('http')
var serveIndex = require('serve-index')
var serveStatic = require('serve-static')

// Serve directory indexes for public/ftp folder (with icons)
var index = serveIndex('public/ftp', {'icons': true})

// Serve up public/ftp folder files
var serve = serveStatic('public/ftp')

// Create server
var server = http.createServer(function onRequest(req, res){
  var done = finalhandler(req, res)
  serve(req, res, function onNext(err) {
    if (err) return done(err)
    index(req, res, done)
  })
})

// Listen
server.listen(3000)

Serve directory indexes with express

var express    = require('express')
var serveIndex = require('serve-index')

var app = express()

// Serve URLs like /ftp/thing as public/ftp/thing
// The express.static serves the file contents
// The serveIndex is this module serving the directory
app.use('/ftp', express.static('public/ftp'), serveIndex('public/ftp', {'icons': true}))

// Listen
app.listen(3000)

License

MIT. The Silk icons are created by/copyright of FAMFAMFAM.

serve-index's People

Contributors

basarat avatar crossjs avatar danez avatar dougwilson avatar evgenus avatar fishrock123 avatar lucianbuzzo avatar netantho avatar opinxit avatar shirotech avatar ysmood 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  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  avatar  avatar  avatar  avatar

serve-index's Issues

selecting file via a redirect goes to the wrong url

Hi
I'm new to serve-index, so maybe I'm doing something wrong or my set up is a little different.

When I select the file to download from the page listing, it goes to the wrong path with my redirect through nginx access.

Listing all the files works fine for my directly connecting node service
http://nodeserver:3077/reports/

and with niginx redirect to (http://foo/bar > http://nodeserver:3077)
http://foo/bar/reports/

This is my code for adding "reports" folder to my site.
app.use('/reports/', express.static('./reports/'), serveIndex('./reports/', {'icons': true}));

But if I select the file for download on the nginx version the path is:
http://foo/reports/report1.txt

It drops the "bar", it should be
http://foo/bar/reports/report1.txt

It works fine if I connect directly to the node service site

I found if I change path variable in function createHtmlFileList
from
var path = dir.split('/').map(function (c) { return encodeURIComponent(c); });
to
var path = [];

it works for my two cases.

Is there something I can do with the set up of serve-index to make it work?

thanks
Scott

Enable the use of custom filesystems

Currently serve-index uses the default node.js' fs library to querry their files. But it would be usefull if a custom fileSystem could be set instead.

This would enable this SO issue to be resolved for instance (either by a custom plugin, or actually implemented into the webpack-dev-server).

Multiple path support

Hi,

is there any plan in supporting multiple paths to be used for a directory index?
A use case is when you have multiple directories which are served under the same path by using serve-static like this:

app.use('/foo', serveStatic('public1'));
app.use('/foo', serveStatic('public2'));

app.use('/foo', serveIndex([ 'public1', 'public2' ]));

Example code doesn't work properly

I followed the advice down at the bottom of README.md more or less, coming up with the following:

'use strict';

const express = require('express');
const serveIndex = require('serve-index');

express()
  .use(serveIndex(__dirname + '/public'))
  .listen(1024);

It lists the files in the directory and formats the results nicely. Bravo. The problem is that, when I click any of those files, it doesn't do what the more laborious example above it in README.md appears to be able do using vanilla Node features. In fact it says Cannot GET /blablabla.

Is there some straightforward, concise way of getting it to function using Express components? Forgive me if I'm not quite thinking this through. In any case, that / those extra step(s) should be added to the example so it works properly.

How to generate directory indices for all folders?

Thanks for this nice project.

I am able to use this project well, but I wanted to ask how I can serve all folders, without revealing the root directory.

I know that with this command, I can index one folder:
app.use('/sub', express.static('static/sub'), serveIndex('static/sub', {'icons': true, 'view': 'details'}))

I know that with this command I can index the root directory and therefor all static content:
app.use('/', express.static('static/'), serveIndex('static/', {'icons': true, 'view': 'details'}))

But is there a way to generate an index for all folders, without revealing the root directory?

Thanks for the help,
Cheers!

Show all - Tree view

Suggested enhancement: Show all contents of directory (including sub-directories and their contents) in single view. This could already be a feature, but it's not clear from the documentation.

The `directory.html` template should be added in `locals`

In case someone wants to add extra content (e.g. an additional script ) in the existing template, it would be good to be able to do it also from inside template function (instead of copying/editing the default template). To achieve this, the default template should be added in locals object passed to template function.

The advantage of this is that on a later package upgrade, the template will be always up-to-date with the authors' version (plus the edits).

broken symlink causes error

When retrieving a directory content containing a broken symlink (i.e. creating the symlink and deleting the original file) this error message appears:

500 Error: ENOENT, stat '/path/to/broken/symlink

Add link to root directory

Currently, the htmlPath function correctly returns a series of links to child directories of a resource, but it does not provide a link to the "root" folder.

For example. Given you have navigated to "/foo/bar", the following html is created:

<h1>
    /
    <a href="/foo">foo</a>
    /
    <a href="/bar">bar</a>
</h1>

Would you guys be open to a PR that would simply prepend the following "<a href="/">~</a>" to what is being returned by htmlPath so as the generated html would look like this:

<h1>
    <a href="/">~</a>
    /
    <a href="/foo">foo</a>
    /
    <a href="/foo/bar">bar</a>
</h1>

This way there is a quick link back to the root folder of the directory that is being served.

README lacking details about when to use or not use `app.use`'s optional first parameter (`path`)

Either serve-index is broken, or the README lacks crucial information, because the following doesn't work:

var express = require('express')
    , serveIndex = require('serve-index')
    , port = 8888

app = express();
app.use(serveIndex('assets'), notHandled)
app.listen(port)
console.log('listening on port', port)
function notHandled (req, res, next) {
    console.log('serve-index not handling request', req.originalUrl)
}

When I launch this, the server says: listening on port 8888

When I use google chrome to navigate to http://localhost:8888/assets, the server says: serve-index not handling request /assets

When I use google chrome to navigate to http://localhost:8888/assets/, the server says: serve-index not handling request /assets/

The same happens when I change the parameter provided to serveIndex to assets/ or /assets or /assets/

The assets folder does exist and is located in the same folder as the server whose code is posted above. In this assets folder is one file and one folder with one file. None of these are hidden (start with a period)

Of course, both express and serve-index have been installed (npm install express and npm install serve-index)

By the way, the README should mention how to install (npm install serve-index)

P.S sorry for being so terse, I'm just very grumpy right now. No hard feelings

How to custom handle ForbiddenError: Forbidden with malicious path traversal characters

I tried to test how this handles path traversal vulnerability, fortunately it gives forbidden error. However, it sends the entire tracktrace to the client. How to disable this behaviour?

import express from 'express';
import serveIndex from 'serve-index'

const PORT = 80
const app = express()
app.use(serveIndex('public'))
app.listen(PORT, () => console.log("server listening", PORT))

Then
http://localhost/..%2F in browser

ForbiddenError: Forbidden
    at C:\Users\CHE-Main\Desktop\node-hello\node_modules\serve-index\index.js:125:19
    at Layer.handle [as handle_request] (C:\Users\CHE-Main\Desktop\node-hello\node_modules\express\lib\router\layer.js:95:5)
    at trim_prefix (C:\Users\CHE-Main\Desktop\node-hello\node_modules\express\lib\router\index.js:317:13)
    at C:\Users\CHE-Main\Desktop\node-hello\node_modules\express\lib\router\index.js:284:7
    at Function.process_params (C:\Users\CHE-Main\Desktop\node-hello\node_modules\express\lib\router\index.js:335:12)
    at next (C:\Users\CHE-Main\Desktop\node-hello\node_modules\express\lib\router\index.js:275:10)
    at next (C:\Users\CHE-Main\Desktop\node-hello\node_modules\express\lib\router\route.js:127:14)
    at next (C:\Users\CHE-Main\Desktop\node-hello\node_modules\express\lib\router\route.js:131:14)
    at next (C:\Users\CHE-Main\Desktop\node-hello\node_modules\express\lib\router\route.js:131:14)
    at next (C:\Users\CHE-Main\Desktop\node-hello\node_modules\express\lib\router\route.js:131:14)

Cannot stat `System Volume Information` sub dir on a root drive on Windows 10

When i use it to index my root drive g:/ on Windows 10, an error occurs:

Error: EPERM: operation not permitted, stat 'g:\System Volume Information'
    at Error (native)

even i add filter option to bypass, it is still not working:

var urlPath_to_rootDrive_Mapping = {
    "/c": "c:/",
    "/d": "d:/",
    "/e": "e:/",
    "/f": "f:/",
    "/g": "g:/",
    "/h": "h:/",
    "/": "d:/"
};
for(var urlPath in urlPath_to_rootDrive_Mapping){
    var rootDrive = urlPath_to_rootDrive_Mapping[urlPath];
    console.log("map "+urlPath+"/* --> " + rootDrive);
    app.use(urlPath, serveIndex(rootDrive, {
        'icons': true,
        'filter': function(filename, index, files, dir){
            console.log("filename="+filename);
            if(filename=="System Volume Information"){
                console.log("HIT "+filename);
                return true;
            }
            return false;
        }
        })
    )
    var serve = serveStatic(rootDrive)
    app.get(urlPath+'/*', function(req, res){
        req.url = req.url.substring(2);
        console.log("["+req.request_id+"] GET static "+req.url);
        serve(req, res)
    });
}

Maybe i just didn't fully understand the code, please fix this, thanks!

Filter option should allow to check full/absolute path

Hi,

filter function is passed as option and check files list with relative name ..

It would be more useful if files list contained absolute path in order to have full control on filter function.

At least relative path to the given path passed to middleware, for instance:

serve_index('share/', {
    filter: function (filename) {
        // do not show files in private directories:
        return filename.indexOf('/private/') < 0;
    })

file name in this case could be something like share/subdir1/private/access instead of simple access

Failing test

Hey,

There seems to be a failing test.

  1 failing

  1) serveIndex(root)
       should treat an ENAMETOOLONG as a 414:
     Error: expected 414 "URI Too Long", got 400 "Bad Request"
      at Test.assert (/usr/lib/nodejs/supertest/lib/test.js:205:15)
      at Server.assert (/usr/lib/nodejs/supertest/lib/test.js:132:12)
      at emitCloseNT (net.js:1629:8)
      at process._tickCallback (internal/process/next_tick.js:63:19)

Download/Save the file

Hello,

Thanks for the awesome code. Using the code below, I can get the listing of the the filesystem but can't download/save as. Is there a way I can enable this? Thanks for sharing.

var express    = require('express')
var serveIndex = require('serve-index')
var app = express()
app.use('/ftp', serveIndex('public/ftp', {'icons': true}))
app.listen()

Tom,

links to files don't work when using a changed base url with app.use.

when listing the files/directories with a custom base url using app.use, navigating the directories works, but the links to the files are broken.:

app.use(express.static(path.join(__dirname, 'public')));
app.use('/file-viewer', serveIndex('public'));

Links to the files obviously work when using without 'mount path'.

app.use(serveIndex('public'));

is there a way (option) for this use case?

One column view

It would be nice if a one-column view is added, the only change needed is: ul#files li { float: none; }

Serve current directory, sub dirs forbidden

If I try to serve-index the current directory "." I cannot access sub folders in that directory.

var index = serveIndex(".", { view: "details", icons: true });
var serve = serveStatic(".");

The root files and sub folders display fine, but when I try access a sub folder, get this error:

Error: Forbidden
    at createError (C:\Users\xxxxx\Desktop\server\node_modules\serve-index\index.js:212:13)
    at serveIndex (C:\Users\xxxxx\Desktop\server\node_modules\serve-index\index.js:110:46)
    at onNext (C:\Users\xxxxx\Desktop\server\server.js:27:3)
    at SendStream.error (C:\Users\xxxxx\Desktop\server\node_modules\serve-static\index.js:91:7)
    at SendStream.EventEmitter.emit (events.js:95:17)
    at SendStream.error (C:\Users\xxxxx\Desktop\server\node_modules\serve-static\node_modules\send\lib\send.js:239:17)
    at SendStream.onStatError (C:\Users\xxxxx\Desktop\server\node_modules\serve-static\node_modules\send\lib\send.js:335:48)
    at next (C:\Users\xxxxx\Desktop\server\node_modules\serve-static\node_modules\send\lib\send.js:614:28)
    at C:\Users\xxxxx\Desktop\server\node_modules\serve-static\node_modules\send\lib\send.js:622:23
    at Object.oncomplete (fs.js:107:15) 

If I serve the parent folder I can drill down the directory structure without error

var index = serveIndex("..", { view: "details", icons: true });
var serve = serveStatic("..");

Or if I specify the current folder from the parent folder, that works too

var index = serveIndex("../server", { view: "details", icons: true });
var serve = serveStatic("../server");

But obviously using "." without specifying the current folder name via ".." is much cleaner / more portable.

svg icon

The SVG icon fails to show, probably because it contains a plus+ in the header and the class conversion fails to add anything.

My workaround was to delete the image/svg+xml and simply add a .svg extension for it to lookup.

Could you fix or amend, so I don't have to hack your code, or fork? Thanks.

operation not permitted

when I use serve-index in certain condition ,I get error.


console

Error: EPERM: operation not permitted, stat 'C:\System Volume Information'
    at Error (native)

source

var express=require("express");
var serveIndex = require('serve-index');

var app=express();

app.use(serveIndex("/",{hidden:true}));

I changed serveIndex("/*",{hidden:true}), the error was not showed, but I get Cannot GET / error.

How to handle fs.stat error on a file?

There are two potential error cases at present:

  • ENOENT: null is returned rather than stat. This would cause an unhandled exception if it were ever encountered (i.e. the file is deleted between fs.readdir and fs.stat). However, it is unlikely that any one will ever encounter this error and much less likely that they will be able to repeat it to know what happened and submit a bug.
  • Other errors (EPERM, etc). These are currently handled by passing the error to express and causing a 500 error.

ENOENT

In the first case I think we should just filter out the file.

If it's been deleted (or is otherwise a special type of file, such as a virtual file on fuse fs, which is returned from fs.readdir() but doesn't exist when you fs.stat()), why bother to show it? And why error out?

Other Erorrs

I disagree with the current behavior. For one, it's inconsistent between text/plain and application/json responses (work) and text/html responses (fail).

I think we should instead provide a stat object that looks like this:

{ "name": "foo.txt"
, "size": 0
, "lastModified": "1970-01-01T00:00:00.000Z"
, "type": "error/EPERM"
}

(or maybe something more conventional liketype: application/vnd.eperm+x-error)

Or perhaps omit the file.

In any case, I don't think that the current behavior of throwing a 500 on any single potential permission error is good behavior.

Sort options

Would be great if we could define default sort options like sorting by last modified date.

Search only works in Safari (iOS/desktop)

I've tried implementing this on a production server, and noticed that the search highlights only work in Safari both on Mac and iPhone. Chrome and Firefox seem to be the odd ones out here.

Public file not found when file compiled after babel and webpack

import express from 'express';
import serveIndex from 'serve-index';

export default {
  start(options, callback) {
    const app = express();
    app.use(express.static(options.targetPath));
    app.use('/', serveIndex(options.targetPath, {
      icons: true,
    }));
    app.listen(options.port, () => {
      console.log(`Listening on port ${options.port}!`);
      callback();
    });
  },
};

This file will be compiled by Babeljs with target 'node' and preset 'es2015-node', then using webpack to bundle with other files. Running the output file the server started successfully. The static files are very well served. But the functionality of serving the directory fails. Both browser and console shows


Error: ENOENT: no such file or directory, open '/path/to/option.targetPath/public/style.css'

Any one knows why? Thank you in advance!

option to download files rather than view

serve-index is great because it allows a quick, generic file viewer.

I've been using it for https://telebit.cloud's directory serving option (telebit http ~/path/to/share) as a poor-man's airdrop/dropbox so that I quickly share files with others.

However, there are two things that make it somewhat inconvenient:

  • inability to quickly download a file
  • inability to quickly download a group of files

If we had a download icon next to the file that would append ?download=true to the url, then that could be a cue to serve-static to add the appropriate Content-Disposition header so that an image would download rather than go into view mode.

Likewise, if we had the option to save as zip that would append ?download=true&format=zip we could have serve-index provide the file as a zip file (and leave the dependency as optional, simply returning an error if the option in enabled and the dependency is not installed).

I'm wondering if you'd be open to either or both of these suggestions.

Add Global Directory Searching

The functionality of the search input on the right corner is the same as cmd+F. In My Directory, there're several folders. Searching in the whole directory might be more important to me.

Enhancement Request - open files in new tab/window

Could you add an option that will allow files to open in new tab by adding target='_blank' to the file anchors?

Even better, if you could allow an array of file extensions as an option which would compare and apply the target attribute if matched?

Thanks

nsp security error on 1.7.3

Looking at master, it looks like all that needs to be done is cut a new version, but we're seeing this error in redfin/react-server#291

dougwade packages/react-server-cli ‹react-server-cli-nsp*› » nsp check
(+) 1 vulnerabilities found
┌───────────────┬─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│               │ Regular Expression Denial of Service                                                                                                                    │
├───────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Name          │ negotiator                                                                                                                                              │
├───────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Installed     │ 0.5.3                                                                                                                                                   │
├───────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Vulnerable    │ <= 0.6.0                                                                                                                                                │
├───────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Patched       │ >= 0.6.1                                                                                                                                                │
├───────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Path          │ [email protected] > [email protected] > [email protected] > [email protected] > [email protected]                                              │
├───────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ More Info     │ https://nodesecurity.io/advisories/106                                                                                                                  │
└───────────────┴─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘

How to use serve-index behind a reverse proxy ?

Hi,

I'd like to use serve-index behind a reverse proxy that adds a root context, i. e :
mydomain.com/root-context/my-folder --> localhost:3000/my-folder

The serve-static module works fine (if I enter the full adresse by hand, it is correctly resolved), but URLs generated by serve-index are absolute URLs, and are not taking in account the root context.

Example of url generated by serve-index:
mydomain.com/my-folder/other (should be mydomain.com/root-context/my-folder/other)

To summarize : I can access my content with direct URLs, but I can't navigate through serve-index's interface.

  • Why using absolute URLS and not relative ones ? For instance, the Apache module uses relative URLs when serving directory files list.
  • If absolutes URLs are absolutely needed, how can I configure a root context ?

Thanks for your help

code style: semicolons or no?

Some lines have them. Some lines don't. Some lines have extra.

I don't care which way you want it (though for myself I prefer to follow the language spec and have them), but I assume that it should be one or the other and not 50/50.

I'd be happy to PR with or without if you let me know which you prefer.

Provide method to add to template locals

Hey, would be great to have req and res added to the arguments passed back through, when using the template as a function.

render(locals, function (err, body) {
        if (err) return next(err);

        var buf = new Buffer(body, 'utf8');
        res.setHeader('Content-Type', 'text/html; charset=utf-8');
        res.setHeader('Content-Length', buf.length);
        res.end(buf);
      });

So would look like:

render(locals, function (err, body) {
        if (err) return next(err);

        var buf = new Buffer(body, 'utf8');
        res.setHeader('Content-Type', 'text/html; charset=utf-8');
        res.setHeader('Content-Length', buf.length);
        res.end(buf);
      },req, res);

POST requests are rejected with 405

If serve-index gets a POST request (or any request other than GET, HEAD, & OPTIONS) it responds to it with a 405 Method Not Allowed. It should call next() so the next middleware can handle the request.

I know I can handle the POST request before it gets to the serve-index middleware but that is not feasible with our setup right now.

add .npmignore

There is significant bloat that could be fixed by adding an .npmignore file

Allow use of tables

I want to use this module with Bootstrap 3.3.7 and use tables but in the source code it is harcoded to use a un-ordered list (ul). If this could be customizable that would be awesome

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.