Giter VIP home page Giter VIP logo

plivo-node's Introduction

Plivo Node.js library

Version codecov UnitTests

The Node.js SDK simplifies the integration of communications into your Node.js applications through the Plivo REST API. You will be able to use the SDK to make voice calls, send SMS, and generate Plivo XML to manage your call flows.

Installation

Install the SDK using npm

$ npm install plivo

If you have the 0.4.1 version (a.k.a legacy) already installed, you may have to first uninstall it before installing the new version.

For features in beta, use the beta branch:

$ npm install plivo@beta

Getting started

Authentication

To make the API requests, you need to create a Client and provide it with authentication credentials (which can be found at https://console.plivo.com/dashboard/).

We recommend that you store your credentials in the PLIVO_AUTH_ID and the PLIVO_AUTH_TOKEN environment variables, so as to avoid the possibility of accidentally committing them to source control. If you do this, you can initialise the client with no arguments and it will automatically fetch them from the environment variables:

let plivo = require('plivo');
let client = new plivo.Client();

Alternatively, you can specifiy the authentication credentials while initializing the Client.

let plivo = require('plivo');
let client = new plivo.Client('<auth_id>', '<auth_token>');

The basics

The SDK uses consistent interfaces to create, retrieve, update, delete and list resources. The pattern followed is as follows:

client.resources.create(name,params); // Create
client.resources.get(id); // Get
client.resources.update(params); // Update
client.resources.delete(id); // Delete
client.resources.list({limit:5,offset:0}); // List all resources, max 20 at a time

Also, using client.resources.list() would list the first 20 resources by default (which is the first page, with limit as 20, and offset as 0). To get more, you will have to use limit and offset to get the second page of resources.

Examples

Send a message

let plivo = require('plivo');
let client = new plivo.Client();

client.messages.create({
    src: '+14156667778',
    dst: '14156667777',
    text: 'Hello, this is a sample text from Plivo',
}).then(function(response) {
    console.log(response)
});

Make a call

let plivo = require('plivo');
let client = new plivo.Client();

client.calls.create(
  '+14156667778',
  '+14156667777',
  'http://answer.url'
).then(function(response) {
  console.log(response)
});

Lookup a number

let plivo = require('plivo');
let client = new plivo.Client('<auth_id>', '<auth_token>');

client.lookup.get('<number-goes-here>')
.then(function(response) {
    console.log(response);
});

Generate Plivo XML

let plivo = require('plivo');
let response = new plivo.Response();
let speak_body = "Hello, world!";

response.addSpeak(speak_body);
console.log(response.toXML());

This generates the following XML:

<Response>
  <Speak>Hello, world!</Speak>
</Response>

Run a PHLO

let plivo = require('plivo');
var PhloClient = plivo.PhloClient;
var phloClient = phlo = null;

phloClient = new PhloClient('<auth-id>', '<auth-token>');
phloClient.phlo('<phlo_id>').run().then(function (result) {
console.log('Phlo run result', result);
});

More examples

More examples are available here. Also refer to the guides for configuring the Express server to run various scenarios & use it to test out your integration in under 5 minutes.

Reporting issues

Report any feedback or problems with this version by opening an issue on Github.

Local Development

Note: Requires latest versions of Docker & Docker-Compose. If you're on MacOS, ensure Docker Desktop is running.

  1. Export the following environment variables in your host machine:
export PLIVO_AUTH_ID=<your_auth_id>
export PLIVO_AUTH_TOKEN=<your_auth_token>
export PLIVO_API_DEV_HOST=<plivoapi_dev_endpoint>
export PLIVO_API_PROD_HOST=<plivoapi_public_endpoint>
  1. Run make build. This will create a docker container in which the sdk will be setup and dependencies will be installed.

The entrypoint of the docker container will be the setup_sdk.sh script. The script will handle all the necessary changes required for local development. It will also package the sdk and reinstall it as a dependecy for the test program.

  1. The above command will print the docker container id (and instructions to connect to it) to stdout.
  2. The testing code can be added to <sdk_dir_path>/node-sdk-test/test.js in host
    (or /usr/src/app/node-sdk-test/test.js in container)
  3. The sdk directory will be mounted as a volume in the container. So any changes in the sdk code will also be reflected inside the container. However, when any change is made, the dependencies for the test program need to be re-installed. To do that:
    • Either restart the docker container
    • Or Run the setup_sdk.sh script
  4. To run test code, run make run CONTAINER=<cont_id> in host.
  5. To run unit tests, run make test CONTAINER=<cont_id> in host.

<cont_id> is the docker container id created in 2. (The docker container should be running)

Test code and unit tests can also be run within the container using make run and make test respectively. (CONTAINER argument should be omitted when running from the container)

plivo-node's People

Contributors

abhishek-plivo avatar abhishekgupta-plivo avatar abinaya-shunmugavel avatar abrolnalin avatar ajay-plivo avatar anindya-plivo avatar ashutoshkumar-plivo avatar digvijay-plivo avatar gunjan01 avatar huzaif-plivo avatar kalyan-plivo avatar kapilp93 avatar kaushikdas-plivo avatar koushik-ayila avatar kowshik-plivo avatar kritarth-plivo avatar kunal-plivo avatar lsaitharun avatar manjunath-plivo avatar mohsin-plivo avatar narayana-plivo avatar nirmitijain avatar nixonsam avatar patelravi avatar prashantp-plivo avatar ramey-plivo avatar renoldthomas-plivo avatar saurabhnewatiya-plivo avatar shubham-plivo avatar sreyantha-plivo 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

Watchers

 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

plivo-node's Issues

Inconsistent Codebase

0.2.5 pulled from npm has a delete_recording method as you'd expect. however delete_recording exists no where in the git repository as of current

validateSignature does not account for port numbers in urls.

When executing plivo.validateSignature() if the URL contains a port number the function does not output true when it should because the value from the X-Plivo-Signature-V2 sent from the server DOES account for the port number but this function pulls apart the url and puts it back together for some reason.
I had to write my own function to fix this, basically throwing away the url parsing lines and using the url as is so that it would include the port number.
So my code looks like this:

function validateSignature(uri, nonce, signature, auth_token) {
  nonce = utf8.encode(nonce);
  signature = utf8.encode(signature);
  auth_token = utf8.encode(auth_token);
  uri = utf8.encode(uri);
  let hmac = crypto.createHmac('sha256', auth_token);
  let hmacBytes = base64.decode(hmac.update(uri+nonce).digest('base64'));
  let authentication_string = base64.encode(hmacBytes);
  return authentication_string == signature;
}

An example of a url that does not work is https://www.example.com:4433/examplepath

Unable to transfer live call & unable to transfer a live call in conference

I am trying to do two things using plivo transfer call api and plivo conference call api which are described below :

1).When there is a live call from a to b answered, I am trying to transfer this call to c by using plivo call transfer call api but when I do so the call is getting hangup without giving any error. Though I have checked all data and action/callback url and I found it appropriate.

2).I tried the same thing using plivo conference call api but resulting in same issue.

I have referred #45, #46 but still not getting any solution.

So please if anyone have solution please inform.

Callbacks should follow Node.JS conventions

The RestAPI callbacks should be constructed in the standard function(error, response){} format instead of function(statusCode, response). Fixing this will especially be helpful for the upcoming ES6. You may also want to consider the promises pattern.

Sending message to a non verified phone number

Hi, I am trying to send a message to a not verified phone number in plivo, I got an error that the destination number needs to be verified, however there is no API to verify the numbers. It is useless because I need to send sms to any phone number registered in my db. Any Ideas? thanks

Plivo Conference Issue

We are currently creating a call center application. One of the basic functions is for a phone agent to create a conference call.

So far, we have successfully created a conference call by 1) calling from an external phone number (my cell phone) to our app, where a phone agent in our app answers, thus creating the A leg, 2) using conference to make a call to a 3rd party, thus creating the B leg which 3) conferences in all 3 parties (the external caller, the phone agent, a third party).

Notice the direction of the phone call in step 1. A cell phone calls in to our Plivo-powered app and a uuid is provided. The issue surfaces when our "Phone Agent" initiates a call to, let's say, a cell phone or land line number.

My question is -- how do we get a uuid, which is needed to conference, when the phone agent calls an external number?

If you need to see a 5 minute demo of what we have that is working (and what's not), I am in Central time and can be reached at 251-654-1830.

Thanks in advance!

API for Getting List of Conference Gives Error

When the list all conference API is called, below added error occurs.

TypeError: Cannot read property 'hasOwnProperty' of undefined
at E:\wsple204\rcm\back-end\node_modules\plivo\dist\rest\request.js:60:16
at E:\wsple204\rcm\back-end\node_modules\plivo\dist\rest\utils.js:66:12
at E:\wsple204\rcm\back-end\node_modules\plivo\dist\resources\conferences.js:385:9
at new Promise ()
at ConferenceInterface.list (E:\wsple204\rcm\back-end\node_modules\plivo\dist\resources\conferences.js:384:14)
at E:\wsple204\rcm\back-end\routes\routes.js:542:28
at Layer.handle [as handle_request] (E:\wsple204\rcm\back-end\node_modules\express\lib\router\layer.js:95:5)
at trim_prefix (E:\wsple204\rcm\back-end\node_modules\express\lib\router\index.js:317:13)
at E:\wsple204\rcm\back-end\node_modules\express\lib\router\index.js:284:7
at Function.process_params (E:\wsple204\rcm\back-end\node_modules\express\lib\router\index.js:335:12)

I encountered this issue with Plivo Node SDK @4.5

invalid error thrown

Get error "This API has required parameters." when calling mute/deaf conference member. Because these are post calls that take zero params (params put into url) this library doesn't account for it. I was able to get around it by putting in a dummy variable into the params, but should be fixed.

unlink_application_number not working

In version 0.4.1, when trying to unlink an application from a given number, the response says changed but the application is not getting unlinked.

The following code snippet reproduces the issue.

var params = {
    'number' : '1272XXXXXXX' // Number that has to be unlikned to an application
};

p.unlink_application_number(params, function (status, response) {
    console.log('Status: ', status);
    console.log('API Response:\n', response);
});

Bug, line 826 of plivo.js

minSilence is missing in valid attributes for Wait.

http://plivo.com/docs/xml/wait/

Also, I reported a bug previously for line 229 where Call should be Request. I was told the bug was fixed, but when I pulled the most recent version today, the old line is still there.

dst parameter not present

Intermittent dst parameter not present error for send_message on OSX. Only solution is reinstall node_module.

Node.js 6

Error: the object {
  "api_id": "de3aa25c-3d6f-11e6-9264-22000ae40186"
  "error": "dst parameter not present"
} was thrown, throw an Error :)

Does not appear to happen on Linux at all.

Inconsistent API

all functions on the RestAPI object use snake_case function names. all functions on the Response object use mixedCase. RestAPI should probably be switched to mixedCase to match javascript / nodejs common standard

npm recording errors

npm install plivo still installs plivo helper without this patch:

pjayswal@10ef98a

Had to track down what the problem was ended up seeing it was already patched on git repo

Voice call recording duration is always 0Ms Please help.

Hi,
I am implementing voice call functionality in my project, all is working but we always have 0ms recording duration.
Here is my code:

exports.voice_mail = function (req, res, next) {
var r = plivo.Response();
r.addSpeak('Please leave a message after the beep and press star to end your voice message');
var recordParams = {'action': 'http://jubin.localtunnel.me/phoneAgent/receiveRecordingDetails_voiceMail/','playBeep':'true','finishOnKey':"*"};
r.addRecord(recordParams);
r.addHangup();
// Generate XML String
var xml = r.toXML();
return next(xml);
}

Here is the response what i received from plivo:

{ Digits: '*',
Direction: 'inbound',
RecordUrl: 'https://s3.amazonaws.com/recordings_2013/1fc0eb90-4013-11e5-baad-842b2b17453e.mp3',
From: 'sip:[email protected]',
RecordingID: '1fc0eb90-4013-11e5-baad-842b2b17453e',
RecordFile: 'https://s3.amazonaws.com/recordings_2013/1fc0eb90-4013-11e5-baad-842b2b17453e.mp3',
RecordingEndMs: '1439288665310',
BillRate: '0.00300',
To: 'sip:[email protected]',
RecordingDurationMs: '0',
CallUUID: '1446287a-4013-11e5-bce2-79d0ba8b5a10',
'SIP-H-To': 'sip:[email protected]',
CallStatus: 'in-progress',
Event: 'Redirect',
RecordingDuration: '0',
RecordingStartMs: '1439288665310',
}

Thanks in advance..!

Optional parmas in creating message

Hi,
I tried to send sms with additional param (log = false)
i found that the value should be string.
it's not clear in the documentation.

Thanks

client.messages.create( src, dst, msg, { log: "false" } ).then(function (message_created) { console.log(message_created); }).catch(function (err) { console.error(err); });

The API Crashes Server in Some Cases.

On line 76, there are cases where response is null which causes javascript error. This has crashed our server few times.

     75   Request.post(request_options, function (error, response, body) {
     76      if (response.statusCode != 201) {
     77          err = new PlivoError(error);
     78      }
     79      callback(response.statusCode, body);
     80  });

Cannot create two seperate instances of the API

Currently we are having an issue with the client as it does not allow multiple connections with different credentials to the plivo API. For example, we want an API for both the Master Account as well as the Sub-Account:

self.plivoApi = plivo.RestAPI({
authId: config.plivo.auth_id,
authToken: config.plivo.auth_token,
});
self.plivoMasterApi = plivo.RestAPI({
authId: config.plivo.master_auth_id,
authToken: config.plivo.master_auth_token,
});

The driver will just overwrite the credentials on the second call to RestAPI.

This is due to how the Plivo.js file is scoped (it is a singleton).

If you want me to pull request a fix I am open to contributing.

How to retrieve pricing?

Since the CSV the website provides, the information on the website and what I'm being billed contradict themselves, I want to setup a price monitoring tool so I know every time a price change happens.

var client = new plivo.Client(
      config.providers.plivo.auth_id,
      config.providers.plivo.auth_token
    )
    client.Pricings().then( // pricing, pricings, Pricing, Pricings...
      function(response) {
        // console.log(response)
        reply.send(response)
      },
      function(err) {
        console.error(err)
      }
    )

How can I access the price list from the API? I found the file corresponding to it, but I don't know how to access it.

Thanks

Plivo host option value overloaded

I am trying to figure out what the original intent of the host option is. It defaults to 'api.plivo.com' and used in differently in two places in lib/plivo.js:

  1. For addressing plivo sending processing request. (api.plivo.com)
  2. For calculating the signature of inbound requests. (myapp.example.com)

These two references of host reference different servers.

You might not notice this issue depending on your configuration. You won't notice if you are not checking the plivo signature on inbound calls. I ran into trouble using a HTTPS tunnel, which rewrote the plivo endpoint url and needed to be manually overridden to correctly calculate the signature.

I would like to understand the original intent and whether creating inbound and outbound urls in the config is a problem.

Unable to get call log of requested date

I am using the retrieve_all_calls API with param {'end_time__gt' : '2015-09-01 11:47' } to get all the calls made and received on the mentioned date, but it returns all the call details which are made on other dates too.

Is there any solution to do get call logs that made on particular date?

Plivo Numbers Buy

Issue #144 is very much an issue with the current library, using the latest version of the plivo library "plivo": "^4.12.0", I encounter the exact same issue reported before.

This is a snippet from the plivo docs on how to use the numbers buy call:

// Example for PhoneNumber create

var plivo = require('plivo');

(function main() {
    'use strict';
    
    // As the auth_id and auth_token are unspecified, Plivo will fetch them from the PLIVO_AUTH_ID and PLIVO_AUTH_TOKEN environment variables.
    var client = new plivo.Client();
    client.numbers.buy(
        "10123456789", // number
    ).then(function (response) {
        console.log(response);
    }, function (err) {
        console.error(err);
    });
})();

Which is very different from the legacy API which was

var plivo = require('plivo');
var p = plivo.RestAPI({
  authId: 'Your AUTH_ID',
  authToken: 'Your AUTH_TOKEN'
});

// Buy a phone number
var params = { 
    'number' : '444444444444' // Phone number to buy
};

p.buy_phone_number(params, function (status, response) {
    console.log('Status: ', status);
    console.log('API Response:\n', response);
});

When I do as the latest API docs call I get the same error that was reported before:

const client = new plivo.Client();
let response
client.numbers.buy("14809552987").then((res) => {response = res})
(node:2331764) UnhandledPromiseRejectionWarning: Error: {"api_id":"f6a23448-56d8-11eb-8cee-0242ac110005","error":"not found"}
    at ResourceNotFoundError.PlivoRestError (/home/anderson/workspace/backend/node_modules/plivo/dist/utils/exceptions.js:19:113)
    at new ResourceNotFoundError (/home/anderson/workspace/backend/node_modules/plivo/dist/utils/exceptions.js:31:127)
    at Request._callback (/home/anderson/workspace/backend/node_modules/plivo/dist/rest/request.js:221:22)
    at Request.self.callback (/home/anderson/workspace/backend/node_modules/request/request.js:185:22)
    at Request.emit (events.js:314:20)
    at Request.EventEmitter.emit (domain.js:506:15)
    at Request.<anonymous> (/home/anderson/workspace/backend/node_modules/request/request.js:1154:10)
    at Request.emit (events.js:314:20)
    at Request.EventEmitter.emit (domain.js:506:15)
    at IncomingMessage.<anonymous> (/home/anderson/workspace/backend/node_modules/request/request.js:1076:12)
(node:2331764) 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:2331764) [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.

The numbers section of this library seems to be riddled with problems and seems to not follow any of the API docs on implementation.

rent_from_number_group method does not work

This line is incorrectly triggering the error: This API has required parameters. Please refer to the following link for more information:\nhttps://www.plivo.com/docs/api/availablenumbergroup/ when calling rent_from_number_group. The rent_from_number_group method doesn't have any required parameters (except group_id which is deleted in the method before going to the request method).

pl.make_call was stuck for no reason

Hi! Here's situation: the nodejs app was running for about 1 week without a hitch. Then all of a sudden it stopped today at the point of pl.make_call . Since this function didn't execute or wasn't returning any error, the app got stuck until it was restarted.

Is it possible for get error handling somehow in this call?

Because it might be possible that make_call couldn't be executed for one reason or another, but yet it doesn't return any error.

It must, so that our app can offer alternative routes to the customer.

Message data printed to stdout

Maybe I'm doing something wrong, but in our case when sending a text message we have the message and the destination printed in stdout in cleartext. Nothing that I saw in the code allows me to disable this.

The line in question seems to be in messages.js line 105

Promise error does not work

Promise error content is empty when using catch block. This is a sample code:

const plivo = require('plivo');
const client = new plivo.Client(CONF.plivo_auth_id, CONF.plivo_auth_token);

FUNC.sms = {};

FUNC.sms.send = function (controller, dest, text, cb) {
    client.messages.create(
        null,
        dest,
        text
    ).then(message_created => {
        cb(null, message_created);
    }, err => {
        cb(err, null);
    });

};

The err parameter is always empty. In this example I should get an error because I've not provided any src number.

Plivo numbers.buy

I am getting an error when attempting to purchase a new number through the node library:
All variables exist and are correct. I've tried just the number

let plivo = new Plivo.Client(process.env.plivoId, process.env.plivoToken);
plivo.numbers.buy(number.id).then(r=>{

let plivo = new Plivo.Client(process.env.plivoId, process.env.plivoToken);
plivo.numbers.buy(number.id, process.env.plivoApp).then(r=>{

returns an error:
2020-02-09T01:06:16.182390+00:00 app[web.1]: Error: {"api_id":"5f595aa6-4ad8-11ea-a859-0242ac110003","error":"not found"}
2020-02-09T01:06:16.182401+00:00 app[web.1]: at ResourceNotFoundError.PlivoRestError (/app/node_modules/plivo/dist/utils/exceptions.js:19:113)
2020-02-09T01:06:16.182401+00:00 app[web.1]: at new ResourceNotFoundError (/app/node_modules/plivo/dist/utils/exceptions.js:31:127)
2020-02-09T01:06:16.182402+00:00 app[web.1]: at Request._callback (/app/node_modules/plivo/dist/rest/request.js:80:20)
2020-02-09T01:06:16.182402+00:00 app[web.1]: at Request.self.callback (/app/node_modules/request/request.js:185:22)
2020-02-09T01:06:16.182402+00:00 app[web.1]: at Request.emit (events.js:223:5)
2020-02-09T01:06:16.182403+00:00 app[web.1]: at Request. (/app/node_modules/request/request.js:1161:10)
2020-02-09T01:06:16.182403+00:00 app[web.1]: at Request.emit (events.js:223:5)
2020-02-09T01:06:16.182403+00:00 app[web.1]: at IncomingMessage. (/app/node_modules/request/request.js:1083:12)
2020-02-09T01:06:16.182403+00:00 app[web.1]: at Object.onceWrapper (events.js:312:28)
2020-02-09T01:06:16.182404+00:00 app[web.1]: at IncomingMessage.emit (events.js:228:7)
2020-02-09T01:06:16.182404+00:00 app[web.1]: at endReadableNT (_stream_readable.js:1185:12)
2020-02-09T01:06:16.182404+00:00 app[web.1]: at processTicksAndRejections (internal/process/task_queues.js:81:21)

global leak error with mocha unit test

Our mocha unit test are failing after upgrading to plivo version 4.0.0 with error

Error: global leak detected: Parser

node version is 8
mocha version is 5

Allow Emoji characters

Update xmlbuilder to latest

replace
var doc = xmlBuilder.create();

with
var doc = xmlBuilder.create({ allowSurrogateChars: true });

plivoError is undefined in plivoResponse.js

In version 0.4.1 in lib/plivoResponse.js is undefined a plivoError variable in lines: 34, 46 and 52.

Solution

Add const plivoError = require('./plivoError'); at start of plivoResponse.js

send email using plivo

i am new to plivo....i want to send email when a user successfully register....in the backend we r using loopback.
please help me out.

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.