Code Monkey home page Code Monkey logo

payment-request's Introduction

payment-request's People

Contributors

adamroach avatar adrianba avatar adrianhopebailie avatar autokagami avatar danyao avatar deniak avatar domenic avatar dret avatar edent avatar github-actions[bot] avatar halindrome avatar ianbjacobs avatar janiceshiu avatar kayakalan avatar marcoscaceres avatar mattsaxon avatar mountainhippo avatar msporny avatar plehegar avatar romandev avatar rvm4 avatar sdussault avatar sideshowbarker avatar sidvishnoi avatar stephenmcgruer avatar sylvia23 avatar tobie avatar wonsuk73 avatar zcorpan avatar zkoch 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  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

payment-request's Issues

Should the messages support field-level encryption?

Migrated from w3c/webpayments#78 via @adrianhopebailie:

Split out from #19 which is focused on the need (or not) for digital signatures as a way of validating that the payment request is received as intended by the payment app.

In that thread @mattsaxon raised a requirement for payment apps to be able to return data that is hidden from the payee themselves (perhaps for PCI scope reasons) as they will pass it on to their PSP who can then decrypt it and use it:

Some elements in the payment response may need to be hidden from the merchant also (e.g. card number)

@CYV suggested SCAI as an option for standardisation of signing and encrypting data through a multi-party flow:
https://www.w3.org/Payments/IG/wiki/Main_Page/ProposalsQ42015/SCAI

So the question becomes; is field level encryption something that should be:

  1. standardised and the Web Payments specs define this standard
  2. defined as a best practice and the WG publishes this guidance
  3. left entirely to the payment app publishers and payment methods to define as they see fit

Should a payment request be just data, or a programmable object?

Migrating from w3c/webpayments#36:

The paymentRequest API asserts that a payment request is a programmable object:

http://wicg.github.io/paymentrequest/specs/paymentrequest.html#paymentrequest-interface

that is instantiated like so

var payment = new PaymentRequest(supportedInstruments, details, options, schemeData);

and can have methods called on it like so:

payment.addEventListener("shippingAddressChange", function (changeEvent) {
    // Process shipping address change
});

The Web Payments CG's Browser API asserts that a payment request is just data:

http://wicg.github.io/web-payments-browser-api/#processing-a-payment-request

and that data is processed by functions:

var request = {
  type: 'PaymentRequest',
  description: 'Payment to ExampleMerch for widgets',
  acceptablePayment: {
    paymentMethod: 'https://w3id.org/payment-methods#Visa',
    paymentAmount: {
      amount: '4.35',
      currency: 'USD'
    }
  }
};

// request payment and get a promise that will resolve to
// a payment acknowledgement
var payment = navigator.payment.request(request);

// called when the payment request has been processed
payment.then(function(acknowledgement) {
  // payment request was at least partially processed, do something with the
  // acknowledgement, such as check its approval code or forward an approval
  // token to actually execute the payment
}).catch(function(err) {
  // payment request failed
});

These are two different general design approaches for the browser API:

  1. There is data, and functions act on that data (Web Payments CG approach).
  2. There are objects that consist of data, and verbs that hang off of those objects (paymentRequest approach).

So, what is our design approach for the browser API?

Add section on Extensibility

Migrating from w3c/webpayments#27:

The Web Payments WG resolved to specify how extensibility of messages is handled in the API specifications to something that looks like this:

"""
In general, the WebIDL descriptions provided in this specification outline the specific interfaces, properties, and values that an implementation may depend on. It is expected that other properties and values will be stored in objects that implement the various interfaces in this specification (e.g. PaymentApplication, PaymentRequest, PaymentAcknowledgement, etc.). While this specification does not suggest a single extension mechanism, it does anticipate extensibility. To that end, Implementations MUST preserve unrecognized properties and their associated values.
Another specification [LINK_TBD] explains how to extend the parameters used with this API using JSON-LD.

ISSUE XYZ: The Working Group seeks feedback from the Web community on that specification and how well it furthers interoperability needs in the payments ecosystem. To provide feedback, see the status section above.
"""

complete() should take a string argument not boolean

This issue comes from WICG/paymentrequest#67 and WICG/paymentrequest#54. It was discussed briefly at the F2F.

This issue is that, at the time complete() is called, your ability to say success (true) or failure (false) may depend on the payment method. There may be other values besides success or failure that can be conveyed (e.g. pending).

Payment Transaction Message Specifications will have to define what values are allowed. We should probably specify some predefined values for success and failure.

How do we ensure that the payment request from the merchant is not tampered with before it gets to the payment app?

Migrated from w3c/webpayments#19:

If a merchant requests a payment, how can they be sure that their payment request is not tampered with when in transit to a 3rd party payment processor?

There are at least two ways to accomplish this:

  1. Create an independent channel between the merchant and customer payment processor to send the payment request over.
  2. Digitally sign the payment request.

I suggest that the second approach is more flexible in the long run as the payment request could travel through a variety of communication channels that we can't imagine today. For example, HTTP -> NFC -> Bluetooth -> HTTPS.

Should a payment method identifier (URL) resolve to a machine readable resource that describes it?

Migrating from w3c/webpayments#30:

If the payment app identifier or payment method identifier is a URL, should there be a resource that can be fetched from the URL?

Yes. We should suggest that the resource should be machine-readable (expressed as JSON-LD, at a minimum) for the reasons specified here:

http://www.w3.org/TR/json-ld/#introduction

Is there a need to describe the payment method at the URL or provide some other information?

We should not require it, but encourage it.

At a bare minimum, you could publish a human readable string in various languages for the payment method / app. You could also publish the payment method and/or apps branding image.

You could also make it so that a payment method URL may list the payment apps that are capable of processing the payment method. This would make it easy for user agents to retrieve a payment app if one isn't available in the user agent already. It could address the "no available payment apps" use case. I'm not suggesting that's how it would work, just that it seems like there are enough use cases to think more deeply about it.

How does the API support enrollment (aka subscription, future payment) use cases?

Migrating from w3c/webpayments#65 and https://github.com/WICG/paymentrequest/issues/43:

@ianbjacobs writes:

Here is a use case that should be supported:

  1. Service asks user at enrollment to register payment details for future use
  2. API is used to retrieve those details, but no payment should actually take place.

Some payment apps might support this (e.g., raw credit card information) while others might not
(e.g., those that return 1-time tokens).

What (if anything) does the API need to say to help readers recognize that it supports this
enrollment use case?

Should we support a delegated state for PaymentRequest?

This issue comes from wicg/paymentrequest#33.

From the spec: We believe there are user agent configurations that can cause the UI to get into a state where cancellation by the web page during user interaction is difficult. Users should still be able to cancel the payment but script will not be able to. We need to investigate in more detail the consequences of this and whether it is really needed.

If we do specify delegated then it isn't necessary for all user agents to be able to move to this state but it would be necessary for all payment flows that wish to call abort() to account for the situation where this may fail in the delegated state.

In particular, how should web pages determine when this state is entered.

Should list of accepted payment methods be strings or objects?

Migrated from w3c/webpayments#37:

The paymentRequest API asserts that the list of accepted payment methods that a payee exposes to the payer should be a list of strings:

http://wicg.github.io/paymentrequest/specs/paymentrequest.html#paymentrequest-interface

For example:

["visa", "bitcoin", "bobpay.com"]

The Web Payments CG Browser API asserts that the list should be composed of objects:

http://wicg.github.io/web-payments-browser-api/#processing-a-payment-request

For example:

acceptedScheme: [{
    scheme: [
      'https://w3id.org/payment-schemes#Visa',
      'https://w3id.org/payment-schemes#Mastercard',
      'https://w3id.org/payment-schemes#Discover'
    ],
    transfer: {
      amount: '4.35',
      currency: 'USD'
    },
    paymentRequestService: 'https://merchant-psp.example.com/services/getPaymentInfo'
  }, {
    scheme: 'https://w3id.org/payment-schemes#Bitcoin',
    transfer: {
      amount: '0.0177',
      currency: 'BTC'
    },
    destination: '3QJmV3qfvL9SuYo34YihAf3sRCW3qSinyC'
  },

Should list of accepted payment methods be strings or objects?

Should we define nesting/grouping semantics for payment method identifier matching?

There is a generally interesting question of how we will define payment method identifier matching. There are many possibilities, ranging from exact string equivalence, to complex URI matching schemes, to regular expressions.

This particular issue is focused on a suggestion from the 24 Feb FTF meeting [1]: should there be a way to define a sort of hierarchy so that one payment method identifier will match more than one other identifiers. (e.g., "match any payment method identifier related to Visa").

(If people want to raise issues for other matching semantics, please create new issues.)

Ian

[1] https://www.w3.org/2016/02/24-wpwg-minutes

Should Payment Method Identifiers and Messages be expressed using a Linked Data Vocabulary?

Migrating from w3c/webpayments#29:

The Payment Method Identifiers spec states:

The PaymentRequest API requires that merchants supply a list identifiers for supported payment methods. This document defines those identifier strings and how they are created.

The Payment Request Architecture spec states:

we expect some message definitions to be shared amongst different payment apps.

The two sets of spec proposals agree that:

  • There should be a list of identifiers for payment methods.
  • There should be shared attributes across payment apps and methods.
  • There should be short names for payment methods.
  • We should support distributed extensibility.

This sounds an awful lot like a Linked Data vocabulary. Is it?

This is related to #11.

Spec refs:
http://wicg.github.io/paymentrequest/specs/method-identifiers.html#introduction
http://web-payments.github.io/web-payments-messaging/#payment-instrument-registration

Should a website be able to provide a label for the "Buy" or "Checkout" button displayed in the payment app?

Migrated from w3c/webpayments#66 and https://github.com/WICG/paymentrequest/issues/46:

@adrianba:

It may help users understand what they are accepting if the web site is able to label the "accept" button. For example, if a user is about to "Buy" something, "Reserve" something, "Subscribe" to something, etc.

@mattsaxon:

This is linked to the comment I just made on issue #65
+1 to distinctions as suggested by @adrianba

@ianbjacobs:

It seems there are several topics here:

  1. The API may be used in a variety of user interactions, and the entity that displays the relevant payment apps may need a label to communicate the interaction to the user. Note that these labels may not be in English, and that the specification probably cannot prevent misuse of labels.
  2. The API may be used in a variety of flows, such as "pay", "register", or "reserve". There may be hacky ways to implement the different scenarios, like using amount=0 to imply "register". However, we should consider whether we want to define a small number of verbs that become part of the data exchanged with the payment application. We will not be able to address every possible scenario, but I have now heard three that sound like it could be useful for the merchant to be able to pass on to the payment application.

Furthermore, it seems there is a relationship between this topic and a topic we discussed previously that translated in the following charter language: "The Working Group will consider support for deferred payment execution to enable use cases where the actual execution of a payment requires steps that are out-of-band with respect to the message flows and APIs defined by the Working Group." That was a use case where the user chose a push payment instrument, but the merchant did not want the payment to be completed before the merchant regained control of the flow.

Please let me know if this makes sense:

  • The distinction between "what the user sees" (label) and "what the merchant wants to accomplish"
  • We may wish to define a set of verbs so the merchant can communicate what they want to accomplish.

How are web-based payment apps supported?

Migrating issue from w3c/webpayments#16

How do we support Web-based payment apps? These instruments require a user to:

  1. Start on the merchant website
  2. Click buy
  3. Select the web-based instrument
  4. Navigate to a 3rd party website to approve the transaction
  5. Return to the merchant website with a token, approval code, or other proof that the transaction has been approved.

I suggest that we support web-based payment instruments and local payment instruments using the same mechanism. There is a URL that is used to invoke the payment instrument. Local Android payment instruments would use an Intent URL (or something similar). Cloud-based instruments would use an HTTP-based URL. Both would have a callback URL (either another Intent URL or an HTTP-based URL).

I admit that this proposal is a bit hand wavy as I do not have a great deal of experience routing messages from a browser to an intent-based URL and back to the browser.

Should the payment request contain line item details?

Migrating from w3c/webpayments#38:

The paymentRequest API currently includes a Payment Details object in a payment request:

http://wicg.github.io/paymentrequest/specs/paymentrequest.html#paymentdetails-dictionary
http://wicg.github.io/paymentrequest/specs/paymentrequest.html#paymentrequest-interface

The Web Payments CG's Browser API specifically does not provide such an interface because small and large retailers have stated that they do not want that information leaked outside of their customer-merchant environment.

Does introducing this line-item list create an issue w/ the "private" customer-merchant environment? Will most merchants opt to not include line item data?

Specification to include Flow Diagram

The Flows Task force have created a generic flow to show how the API interacts with various participant in the payment pathway.

I suggest that may be useful to be included in the specification document to assist the reader.

Do others agree this would be useful?

The flow is shown below

Generic Flow

Should the payment request support multiple pricing options?

Migrating from w3c/webpayments#79:

Originally raised in the comments at https://github.com/WICG/paymentrequest/issues/41#issuecomment-178356991 and reflected in the issue above by @adrianhopebailie:

There a number of reasons why a payment request may carry multiple pricing options:

  1. The payee wants to explicitly accept payment in multiple currencies (USD and XBT for example)
  2. The payee wants to offer different prices depending on which payment method is used.
  3. The payee wants to offer multi-tender payments
  4. The payee wants to offer discounted pricing under special circumstances (loyalty, coupons etc)

These use cases could be addressed in different ways:

  • A protocol like the Interledger Protocol would make matching the currency of the payer and payee unnecessary as the protocol would allow the payee to receive payment in the currency of their choice even if the payer pays using a different asset. The same could be said for many card based payments where currency conversion is handled by the network. i.e. For some use cases the payee simply provides a price and the payment app takes responsibility for making the payment at that price and in that currency.
  • Each payment method could specify a price, or there could be a base price and any methods with a variation on that price would specify their unique price.
  • The payment request can specify a guide price and the payment app can request updated pricing from the payee based on user input (coupon, currency selection, loyalty program login etc). This is related to the question at #76

Any plan to allow this API to be called by non-merchants?

One consideration in the WPCG browser API spec was to allow merchants to publish payment request messages (akin to digitally-signed digital offers) that use push-based payments on a website. Then, for example, a search engine could find these and present them directly as search results. The search result page could call the browser API when a user clicked on one of these digitally-signed payment requests and execute the payment directly.

Will this API have any room for this concept in the future? Are we building it such that it will no longer be a possibility -- and require a separate API to accomplish it? Is it possible for non-merchant sites to call this API -- or do we envision it as a future possibility?

How are payment requests and responses passed between the browser and third-party native wallets?

Migrating from w3c/webpayments#42:

@rsolomakhin sort of described it here:

I think that native apps will connect through OS-specific means, like intents on Android. Here's how user agent code would look like on Android, I imagine:

Intent intent = new Intent("org.w3.intent.action.PAY", Uri.parse("https://bobpay.xyz"));
intent.putExtra("Details", "{\"price\": 5500, \"currency\": \"USD\", \"merchant\": \"superstore1\"}");
intent.putExtra("SchemeData", "{\"bobPaySpecificField\": \"foo\"}");
startActivityForResult(intent, 0);

The payment app should send back the result as a string (or HashMap) plus the result code. Like so:

Intent result = new Intent("org.w3.intent.action.PAY");
result.putExtra("InstrumentDetails", "{\n"
        + "  \"cardNumber\": \"4111111111111111\",\n"
        + "  \"nameOnCard\": \"Bob J. Paymentman\",\n"
        + "  \"expMonth\":   \"12\",\n"
        + "  \"expYear\":    \"2016\",\n"
        + "  \"cvv2\":       \"123\"\n"
        +"}");
setResult(Activity.RESULT_OK, result);
finish();

However, the spec should give folks some idea of how the integration might happen via a NOTE or similar mechanism to ensure that people know it won't be just the OS vendors providing payment apps

How are payment apps shared between different browser brands?

Migrating issue from w3c/webpayments#15:

When a user registers a new payment instrument, how is that payment instrument shared between different browser brands? For example, if I register a Visa debit card issued by my bank in Google Chrome on my laptop, when I go to purchase something using my mobile phone, is that same debit card available to me via my Firefox web browser (assuming I've authenticated in some way with both browsers)?

There are a variety of choices here, in order of easiest to implement to hardest to implement:

  1. There is no sharing mechanism
  2. There is a unified payment instrument export mechanism
  3. There is a storage and discovery mechanism that all browsers use to import data from other browsers

I assert that the last bullet point is what we should strive for, but we may need to take baby steps to get there. In any case, we should implement the API as if the third item existed and figure out a way to polyfill our way there.

API Data Integrity

It should be possible for the Payment Application to authenticate that the PaymentDetails and data parameters that are passed to it via the browser have not been tampered with.

It should be possible for the recipient of the PaymentResponse to authenticate it has not been tampered with.

I propose that these 3 objects are signed to achieve this and that we define this is the base API specification.

I would expect that the keys to achieve this would be;

  1. For the PaymentResponse, from the payment applications installation origin's SSL certificate
  2. For the PaymentDetails and data objects, from the website SSL certificate that executed the PaymentRequest constructor.

references:
w3c/webpayments#19
w3c/webpayments#78

Should the payee be able to inspect the status of a payment?

Raised at the 23 February FTF meeting [1]. Roy wrote:

"I'm wondering what apis there are for querying about the status of payments? Consider network cutouts during charge, or more simply asynchronous payment methods. How would the merchant expect to inspect the status of payment in these events or would that be something handled by payment methods implementations?"

Let's focus on the network outage use case. It seems to me that this issue would apply to any digital payment scenario, and thus the payment method itself would need to be prepared to address it. It feels to me that this question is one for payment apps to address.

Ian

[1] https://www.w3.org/2016/02/23-wpwg-minutes

Should the payment API be more conversational or less conversational?

Partial migration from w3c/webpayments#55:

@dlongley proposed a more conversational shape to the browser payment API here:

http://sites.local/web-payments-browser-api/checkout-api.html#the-checkout-interface

For example:

var checkout = new Checkout();
checkout
  .send('paymentItem', paymentItems)  // send line item estimate to UA
  .request('shippingAddress')         // request shippingAddress from UA
  .start()                            // start the checkout UI
  .then(finishCheckout);              // checkout UI has collected the info

and @dlongley noted this is how it would work:

With the Checkout API, we want to be able to do things like make shipping options depend on the shipping address selected. What we're exploring essentially works like this:

  1. A Checkout object is created by a webpage.
  2. A call to send the line item estimate is made on the Checkout object. This call essentially just sets "options" that will be read once the checkout is started.
  3. A call to request shipping address is made on the Checkout object. Again, this call is like setting options as it simply "indicates" that a shipping address is requested. It won't do anything until the checkout is started.
  4. A call to start checkout is made on the Checkout object. This returns a Promise that will settle once the user clicks "Buy".
  5. The browser UI opens and sees the line item estimate and displays it. It sees that shipping was requested, so it knows to show the user a shipping address selection UI. The "Buy" button will be disabled.
  6. The user selects a shipping address and a shippingAddressChanged event is dispatched.
  7. An event handler may optionally call request to request shipping option selection along with a list of possible shipping options (or a Promise that resolves to such a list).
  8. Once event dispatching has completed, if request was called, it will wait for its Promise to settle and then display the shipping options in the UI, keeping the "Buy" button disabled. Otherwise, there's nothing to wait on and the "Buy" button will be enabled.
  9. The user selects a shipping option and a shippingOptionChanged event is dispatched.
  10. An event handler may optionally call send to send updated checkout details such as new calculated line items that include, eg: shipping, tax. Again, this information can be sent as a Promise, to enable the website to generate this information asynchronously. Similarly, request can also be called to request other information at this point (that depended on shipping option selection).
  11. Once event dispatching has completed, if request was called, it will wait for its Promise to settle and then display the UI for whatever was requested this time, keeping the "Buy" button disabled. Otherwise, there's nothing to wait on and the "Buy" button will be enabled.
  12. The user clicks "Buy" and the Promise for checkout.start resolves.
  13. The webpage generates a payment request message and passes it to checkout.finish.
  14. The browser UI shows the Payment App selection UI to complete the purchase.

So, the question is - do we want this sort of conversational API vs. the more rigid API proposed in the current spec?

Merge Payment Request Architecture with Capabilities Document

Migrating from w3c/webpayments#22:

From the Payment Request Architecture document:

The Payment Request architecture is designed to separate different concerns of the Payment Request system into different specifications so that they can be discussed and moved forward independently. This document describes the architecture and explains what different specifications may be created and how the relate to each other. [link]

It feels like the Payment Request Architecture and the Web Payments IG's Capabilities document overlap (based on the desired goals for the capabilities document). I agree that we need a document like the Payment Request Architecture, but think that it should be placed into the architecture document (capabilities) the WPIG agreed upon.

It's also confusing because it seems like there is also overlap with @adrianhopebailie's architecture document here: https://github.com/w3c/webpayments/wiki/A-Payments-Initiation-Architecture-for-the-Web

Spec refs:
http://wicg.github.io/paymentrequest/specs/architecture.html#abstract

What happens when currency of offer differs from currency of selected payment instrument?

This was discussed at the 24 Feb 2016 FTF meeting:
https://www.w3.org/2016/02/24-wpwg-minutes#item09

At the meeting the sense was that we did not need the API to handle currency conversions in the API
as long as the API supported being able to specify different amounts and currencies for different payment methods, which is covered by Issue 3:
#3

Therefore, I recommend that we close this issue and defer to the decision for Issue 3.

Ian

How will the spec address versioning / feature detection?

We have had a number of conversations about extensibility. The spec supports payment method-specific data, for example. And we have discussed a companion spec about JSON-LD extensibility.

We expect to add features to future versions of the API. How will the API support feature detection? What are the individual features we will label in this version?

Terminology across all Web Payments documents should be aligned

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.