Code Monkey home page Code Monkey logo

polkadot-js / extension Goto Github PK

View Code? Open in Web Editor NEW
972.0 972.0 407.0 35.52 MB

Simple browser extension for managing Polkadot and Substrate network accounts in a browser. Allows the signing of extrinsics using these accounts. Also provides a simple interface for compliant extensions for dapps.

License: Apache License 2.0

JavaScript 1.39% TypeScript 97.39% HTML 0.39% CSS 0.60% Shell 0.23%
blockchain extension polkadot polkadot-js substrate

extension's People

Contributors

amaury1093 avatar axelchalon avatar barrutko avatar bee344 avatar carumusan avatar ccris02 avatar chendatony31 avatar dudo50 avatar f-obrien avatar f3joule avatar github-actions[bot] avatar greenkeeper[bot] avatar hamidra avatar hlminh2000 avatar itsonal avatar jacogr avatar joelamouche avatar joepetrowski avatar n3wborn avatar nick-1979 avatar pedroapfilho avatar remon-nashid avatar ryanleecode avatar shawntabrizi avatar tarikgul avatar tbaut avatar tore19 avatar vanruch avatar wirednkod avatar woeom 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

extension's Issues

Add settings

Goal:

Make it easy to tweak.

Actions:

  • Hamburger
  • tweak of icon theme (currently default to polkadot)

For the future (once we actually have something):

  • tweak of type, i.e. inject accounts, inject provider + accounts
  • network selection

... more?

An in-range update of @polkadot/ts is breaking the build 🚨

The devDependency @polkadot/ts was updated from 0.1.58 to 0.1.59.

🚨 View failing branch.

This version is covered by your current version range and after updating it in your project the build failed.

@polkadot/ts is a devDependency of this project. It might not break your production code or affect downstream projects, but probably breaks your build or test tools, which may prevent deploying or publishing.

Status Details

FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

New account process restart on focus lost

I have 2 problematic work-flows:

  1. create new account
  • Click create a new account
  • Copy the seed given to me in clipboard to paste it in my password manager later on.
  • I am asked for a password, I need my password manager
    --> the extension looses focus and when getting back to it, clicking to create a new account displays a new seed
  1. import account from mnemonic
  • Click to import account
  • Paste seed from the clipboard (copied from password manager before starting the process)
  • Password is asked
    --> I'm screwed because I can't click away from the extension to use my password manager otherwise it'll loose focus and start from scratch

Both of these problems can be worked around by using pen an paper to manually copy the mnemonic and keep the clipboard for the password.

Metamask is bypassing these problem by first asking for a password at first launch before anything and then using it to encrypt any account keypair. Creating a new account doesn't ask for a password.

An in-range update of babel7 is breaking the build 🚨

There have been updates to the babel7 monorepo:

    • The devDependency @babel/core was updated from 7.5.4 to 7.5.5.

🚨 View failing branch.

This version is covered by your current version range and after updating it in your project the build failed.

This monorepo update includes releases of one or more dependencies which all belong to the babel7 group definition.

babel7 is a devDependency of this project. It might not break your production code or affect downstream projects, but probably breaks your build or test tools, which may prevent deploying or publishing.

Status Details

FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

Prompt user to allow access on first use by site

Goal:

Allow the user to approve any access to the accounts & signer.

Background:

Currently accounts.get() will returns the accounts listed.

Actions:

  • When the site requesting the accounts has not been approved yet, prompt the user to approve.
  • If approved, all accounts are returned
  • When disabled, the accounts are not approved

So 2 things -

  • can either reject on the calls (via error) if not approved
  • or have an explicit enable() call that injects

Since everything is call-based, we can just manage it on this level. (And much easier for dapp developers to integrate)

Camera access automatically requested for no reason

When using the extension to auth (only first auth - no longer happens during the session) into a polkadot-enabled site like claim.kusama.network, the extension defaults to asking for camera access without the user triggering any QR scanning functionality manually.

  • Steps to reproduce: it always happens, as long as the extension is unlocked but not authenticated in the site.
  • Browser in which this was tested: Brave beta, 0.70
  • Example site: https://claim.kusama.network

What happens:

  • camera access is requested

What should happen:

  • camera access request should be exclusively manual

An in-range update of babel7 is breaking the build 🚨

There have been updates to the babel7 monorepo:

    • The devDependency @babel/core was updated from 7.5.4 to 7.5.5.

🚨 View failing branch.

This version is covered by your current version range and after updating it in your project the build failed.

This monorepo update includes releases of one or more dependencies which all belong to the babel7 group definition.

babel7 is a devDependency of this project. It might not break your production code or affect downstream projects, but probably breaks your build or test tools, which may prevent deploying or publishing.

Status Details

FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

An in-range update of babel7 is breaking the build 🚨

There have been updates to the babel7 monorepo:

    • The devDependency @babel/core was updated from 7.5.5 to 7.6.0.

🚨 View failing branch.

This version is covered by your current version range and after updating it in your project the build failed.

This monorepo update includes releases of one or more dependencies which all belong to the babel7 group definition.

babel7 is a direct dependency of this project, and it is very likely causing it to break. If other packages depend on yours, this update is probably also breaking those in turn.

Status Details
  • ❌ ci/circleci: build: Your tests failed on CircleCI (Details).
  • ❌ Travis CI - Branch: The build failed.

FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

An in-range update of babel7 is breaking the build 🚨

There have been updates to the babel7 monorepo:

    • The devDependency @babel/core was updated from 7.4.5 to 7.5.0.

🚨 View failing branch.

This version is covered by your current version range and after updating it in your project the build failed.

This monorepo update includes releases of one or more dependencies which all belong to the babel7 group definition.

babel7 is a devDependency of this project. It might not break your production code or affect downstream projects, but probably breaks your build or test tools, which may prevent deploying or publishing.

Status Details

FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

An in-range update of babel7 is breaking the build 🚨

There have been updates to the babel7 monorepo:

    • The devDependency @babel/core was updated from 7.5.0 to 7.5.4.

🚨 View failing branch.

This version is covered by your current version range and after updating it in your project the build failed.

This monorepo update includes releases of one or more dependencies which all belong to the babel7 group definition.

babel7 is a devDependency of this project. It might not break your production code or affect downstream projects, but probably breaks your build or test tools, which may prevent deploying or publishing.

Status Details

FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

An in-range update of @types/react-router is breaking the build 🚨

The dependency @types/react-router was updated from 5.0.3 to 5.0.4.

🚨 View failing branch.

This version is covered by your current version range and after updating it in your project the build failed.

@types/react-router is a direct dependency of this project, and it is very likely causing it to break. If other packages depend on yours, this update is probably also breaking those in turn.

Status Details
  • ❌ ci/circleci: build: Your tests failed on CircleCI (Details).
  • ❌ Travis CI - Branch: The build failed.

FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

An in-range update of babel7 is breaking the build 🚨

There have been updates to the babel7 monorepo:

    • The devDependency @babel/core was updated from 7.4.5 to 7.5.0.

🚨 View failing branch.

This version is covered by your current version range and after updating it in your project the build failed.

This monorepo update includes releases of one or more dependencies which all belong to the babel7 group definition.

babel7 is a devDependency of this project. It might not break your production code or affect downstream projects, but probably breaks your build or test tools, which may prevent deploying or publishing.

Status Details

FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

Layout ideas

We'll need to make some space for more settings such as

  • Manage Dapp authorization
  • Select which accounts are visible
  • Select Networks (to inject or to create accounts for)
  • Add accounts with a JSON
  • Add accounts with Parity Signer

We end up a little like in the situation of Fether, so my ideas are very much biased, however I think it worked well. Here's a bad drawing of what I thought about:

  • global account selector showing accounts from the keyring associated with the network
  • eyes to make an account visible or not (and make account have lower opacity)
  • a + that contains all the account related menus
  • a hamburger menu that contains all the general menus.
  • a new page where users can manage their network name and address (would appear then in the general network menu)

image

Display decoded method for known metadata

Currently we display the name of the sending chain (when known), however is all cases we always display the binary data - use metadata to break it down, as available

An in-range update of babel7 is breaking the build 🚨

There have been updates to the babel7 monorepo:

    • The devDependency @babel/core was updated from 7.4.4 to 7.4.5.

🚨 View failing branch.

This version is covered by your current version range and after updating it in your project the build failed.

This monorepo update includes releases of one or more dependencies which all belong to the babel7 group definition.

babel7 is a devDependency of this project. It might not break your production code or affect downstream projects, but probably breaks your build or test tools, which may prevent deploying or publishing.

Status Details

FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

An in-range update of file-loader is breaking the build 🚨

The devDependency file-loader was updated from 4.1.0 to 4.2.0.

🚨 View failing branch.

This version is covered by your current version range and after updating it in your project the build failed.

file-loader is a devDependency of this project. It might not break your production code or affect downstream projects, but probably breaks your build or test tools, which may prevent deploying or publishing.

Status Details

Release Notes for v4.2.0

4.2.0 (2019-08-07)

Features

Commits

The new version differs by 3 commits.

  • ba0fd4c chore(release): 4.2.0
  • 642ee74 docs: improve readme (#341)
  • c136f44 feat: postTransformPublicPath option (#334)

See the full diff

FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

No Popup in Firefox - Property "focused" is unsupported by Firefox

V0.2.1 published on the Firefox store

When connecting to Polkadot.js the popup doesn't appear to sign the authorization. (did it manually)

Upon sending a Tx, the Tx fails with the following message:

makeExtrinsicCall: error: Type error for parameter createData (Property "focused" is unsupported by Firefox) for windows.create.

Opening the extension asks for a password but the Tx has already failed.

An in-range update of babel7 is breaking the build 🚨

There have been updates to the babel7 monorepo:

    • The devDependency @babel/core was updated from 7.6.0 to 7.6.2.

🚨 View failing branch.

This version is covered by your current version range and after updating it in your project the build failed.

This monorepo update includes releases of one or more dependencies which all belong to the babel7 group definition.

babel7 is a direct dependency of this project, and it is very likely causing it to break. If other packages depend on yours, this update is probably also breaking those in turn.

Status Details
  • ❌ ci/circleci: build: Your tests failed on CircleCI (Details).
  • ❌ Travis CI - Branch: The build failed.

FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

An in-range update of @polkadot/dev-react is breaking the build 🚨

The devDependency @polkadot/dev-react was updated from 0.31.0-beta.8 to 0.31.1.

🚨 View failing branch.

This version is covered by your current version range and after updating it in your project the build failed.

@polkadot/dev-react is a devDependency of this project. It might not break your production code or affect downstream projects, but probably breaks your build or test tools, which may prevent deploying or publishing.

Status Details
  • ❌ ci/circleci: build: Your tests failed on CircleCI (Details).
  • ❌ Travis CI - Branch: The build failed.

FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

Unauthorized page can still access extension

Currently, if authorize.tab rejects, enable will reject. However, when receiving requests, the extension background script doesn't check if the webpage is authorized.

So even though the unauthorized webpage cannot use window.injectedWeb3, it can still do the following and access e.g. the accounts list or ask to sign extrinsics:

window.addEventListener('message', ({ data, source }) => { console.log('Received accounts list from unauthorized webpage', data); })
window.postMessage({ id: 1337, message: 'accounts.list', origin: 'page' }, '*');

The extension gets stuck while setting the session key transaction

OS: Mac OS Mojave 10.14.6
Brave Browser: Version 0.68.132 Chromium: 76.0.3809.132 (Official Build) (64-bit)
Chrome Browser: Version 76.0.3809.132 (Official Build) (64-bit)
Polkadot{.js} extension: 0.10.1

Whenever I try to "Set Session Key" on https://polkadot.js.org/apps/#/staking/actions, the polkadot.js extension gets hanged/stuck. It opens a blank window and clicking on the extension also opens a blank window. Tried this multiple times on brave browser as well as chrome, same problem every time.

Screenshot 2019-09-13 at 7 11 02 PM

Console output after pression on "Set Session key"

polka

An in-range update of @polkadot/ts is breaking the build 🚨

The devDependency @polkadot/ts was updated from 0.1.72 to 0.1.73.

🚨 View failing branch.

This version is covered by your current version range and after updating it in your project the build failed.

@polkadot/ts is a devDependency of this project. It might not break your production code or affect downstream projects, but probably breaks your build or test tools, which may prevent deploying or publishing.

Status Details
  • ❌ ci/circleci: build: Your tests failed on CircleCI (Details).
  • ❌ Travis CI - Branch: The build failed.

FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

Export account

Hi,

Is there a way to export an account? I'm fine with pulling it out of a db or using an API if it is not possible via the UI.

An in-range update of @polkadot/ts is breaking the build 🚨

The devDependency @polkadot/ts was updated from 0.1.60 to 0.1.61.

🚨 View failing branch.

This version is covered by your current version range and after updating it in your project the build failed.

@polkadot/ts is a devDependency of this project. It might not break your production code or affect downstream projects, but probably breaks your build or test tools, which may prevent deploying or publishing.

Status Details

FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

Allow seed restoration to specify type & path

Goal:

Make the restoration process 100% aligned with what is done elsewhere.

Background:

At this point it always creates sr25519 and has no derivation path.

Actions:

Add both. These are slightly more advanced, so "hide" behind somewhere where it is not just completely ignored the whole time and making things more difficult, however somewhere where it is easy to actually do.

"Expand view" mode

Please can we have an "expand view" button, which opens the extension in a new tab.

Like Metamask has.

Add Ledger Nano S support

  • First available hardware device (general hardware support asked for in #143)

Integration not generally available as of yet, but dev builds are available for the first milestone - not perfect, but is at a point where it can be integrated and tested

cc @jleni

Signing of transaction is not working on substrate UI

I started playing with the polkadot.js extension in my chrome browser on my custom chain accessing through substrate UI, It gave me this error -
t.signer.sign is not a function.
Screen Shot 2019-07-29 at 4 30 59 PM
It was a simple transaction to transfer the balance from an extension account to chain account. While the same transaction was easily performed by using Polkadot UI. Either the extension is not fully supportable on the substrate UI or something else.

Firefox - Scrollbar on the popup

Any popup on Firefox (welcome message, signing) opens a window with scrollbars.

Removing the height and width to the body css fixes it, not sure that's the best idea (and haven't tested on Chrome yet)

image

Extension doesn't build

Yarn build gives me the following:

yarn build                    
yarn run v1.16.0
$ NODE_ENV=production polkadot-dev-build-ts
$ /home/thib/paritytech/polkadot-js/extension/node_modules/.bin/polkadot-dev-clean-build

*** Cleaning build directory ./build

*** Cleaning build directory packages/extension/build

*** Cleaning build directory packages/extension-dapp/build

*** Cleaning build directory packages/extension-ui/build
Version 3.4.5
extension-ui/src/Popup/Signing/Details.tsx:43:38 - error TS2339: Property 'sectionName' does not exist on type 'Method'.

43         <td className='data'>{method.sectionName}.{method.methodName}</td>
                                        ~~~~~~~~~~~

extension-ui/src/Popup/Signing/Details.tsx:43:59 - error TS2339: Property 'methodName' does not exist on type 'Method'.

43         <td className='data'>{method.sectionName}.{method.methodName}</td>
                                                             ~~~~~~~~~~

extension-ui/src/messaging.ts:9:23 - error TS7016: Could not find a declaration file for module 'extensionizer'. '/home/thib/paritytech/polkadot-js/extension/node_modules/extensionizer/index.js' implicitly has an 'any' type.
  Try `npm install @types/extensionizer` if it exists or add a new declaration (.d.ts) file containing `declare module 'extensionizer';`

9 import extension from 'extensionizer';
                        ~~~~~~~~~~~~~~~

extension-ui/src/messaging.ts:27:29 - error TS7006: Parameter 'data' implicitly has an 'any' type.

27 port.onMessage.addListener((data) => {
                               ~~~~

extension/src/background/handlers/Extension.ts:11:10 - error TS2305: Module '"../../../../../node_modules/@polkadot/types"' has no exported member 'SignaturePayloadRaw'.

11 import { SignaturePayloadRaw } from '@polkadot/types';
            ~~~~~~~~~~~~~~~~~~~

extension/src/background/handlers/Extension.ts:43:45 - error TS2339: Property 'meta' does not exist on type 'KeyringPair'.

43     keyring.saveAccountMeta(pair, { ...pair.meta, name });
                                               ~~~~

extension/src/background/handlers/Extension.ts:120:16 - error TS2322: Type '() => string' is not assignable to type 'string'.

120       address: keyring.createFromUri(seed, {}, type).address,
                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  extension/src/background/handlers/Extension.ts:120:16
    120       address: keyring.createFromUri(seed, {}, type).address,
                       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    Did you mean to call this expression?

extension/src/background/handlers/Extension.ts:130:16 - error TS2322: Type '() => string' is not assignable to type 'string'.

130       address: keyring.createFromUri(seed, {}, type).address,
                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  extension/src/background/handlers/Extension.ts:130:16
    130       address: keyring.createFromUri(seed, {}, type).address,
                       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    Did you mean to call this expression?

extension/src/background/handlers/State.ts:7:23 - error TS7016: Could not find a declaration file for module 'extensionizer'. '/home/thib/paritytech/polkadot-js/extension/node_modules/extensionizer/index.js' implicitly has an 'any' type.
  Try `npm install @types/extensionizer` if it exists or add a new declaration (.d.ts) file containing `declare module 'extensionizer';`

7 import extension from 'extensionizer';
                        ~~~~~~~~~~~~~~~

extension/src/background/index.ts:5:23 - error TS7016: Could not find a declaration file for module 'extensionizer'. '/home/thib/paritytech/polkadot-js/extension/node_modules/extensionizer/index.js' implicitly has an 'any' type.
  Try `npm install @types/extensionizer` if it exists or add a new declaration (.d.ts) file containing `declare module 'extensionizer';`

5 import extension from 'extensionizer';
                        ~~~~~~~~~~~~~~~

extension/src/background/index.ts:9:19 - error TS2305: Module '"../../../../node_modules/@polkadot/ui-keyring"' has no exported member 'ExtensionStore'.

9 import keyring, { ExtensionStore } from '@polkadot/ui-keyring';
                    ~~~~~~~~~~~~~~

extension/src/background/index.ts:20:42 - error TS7006: Parameter 'port' implicitly has an 'any' type.

20 extension.runtime.onConnect.addListener((port) => {
                                            ~~~~

extension/src/background/index.ts:25:31 - error TS7006: Parameter 'data' implicitly has an 'any' type.

25   port.onMessage.addListener((data) => handlers(data, port));
                                 ~~~~

extension/src/content.ts:5:23 - error TS7016: Could not find a declaration file for module 'extensionizer'. '/home/thib/paritytech/polkadot-js/extension/node_modules/extensionizer/index.js' implicitly has an 'any' type.
  Try `npm install @types/extensionizer` if it exists or add a new declaration (.d.ts) file containing `declare module 'extensionizer';`

5 import extension from 'extensionizer';
                        ~~~~~~~~~~~~~~~

extension/src/content.ts:13:29 - error TS7006: Parameter 'data' implicitly has an 'any' type.

13 port.onMessage.addListener((data) => {
                               ~~~~


Found 15 errors.

error Command failed with exit code 2.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

Manage access as previously granted

Goal:

The user should be able to check access on a per site basis and either approve/reject these.

Actions:

  • storage permissions to storage
  • page where the user to reject or approve based on sites that requested access

Similar to #10

Select accounts to be made visible

Goal:

Allow the user better control over the accounts injected.

Background:

Currently all available accounts are injected into the page. Permissions per site are to be set via #9 - but we would like to extend this with account control.

Actions:

Allow the user to select the visible accounts on a global level and allow adjustments thereof on a per-site basis. So by default the defaults will be injected, however per site the accounts can be limited or overridden.

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.