Coder Social home page Coder Social logo

grakic / jfreesteel Goto Github PK

View Code? Open in Web Editor NEW
52.0 16.0 25.0 2.88 MB

A native Java library, a Swing GUI application and an applet to read the Serbian eID card, built on javax.smartcardio

Home Page: http://jfreesteel.devbase.net

Java 88.21% Shell 3.33% Makefile 0.30% HTML 3.80% JavaScript 2.68% NSIS 1.68%
smartcard smartcardio smartcard-reader eid-card serbian webextensions java-applet

jfreesteel's People

Contributors

filmil avatar grakic avatar stalker314314 avatar svetam 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

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

jfreesteel's Issues

AppImage

Kako instalacija za linux postoji samo u .deb obliku i zip sa executable, napravio sam i AppImage kako bi lako moglo da pokrene na svim ostalim linux distribucijama.

Nadam se da autoru ne smeta i da možda može da okači na sajt kako bi "manje stručni" linuksaši mogli lako da pokrenu aplikaciju.

Ono što nisam uradio, a možda može da se izvede jeste da se napravi sistem koji traži od korisnika da instalira potrebne binary-e i javu kako ne bi izbacivalo grešku.

Kod mene na Manjaro distribuciji je bilo potrebno da se instalira

ccid opensc
i da se pokrene pcscd daemon.

Kao i Java

sudo pacman -S jre8-openjdk-headless jre8-openjdk jdk8-openjdk openjdk8-doc openjdk8-src
sudo pacman -S ccid opensc
sudo systemctl enable pcscd --now

https://www.dropbox.com/s/567kr7zobnnwalt/jFreeSteel_eid_viewer-x86_64.AppImage?dl=0

ERROR net.devbase.jfreesteel.EidCard - Card error

Prilikom čitanja "novih" kartica dolazilo je do sledeće greške (sama aplikacija je u GUI izbacivala null):

[Thread-1] ERROR net.devbase.jfreesteel.EidCard - Card error
java.nio.BufferUnderflowException
	at java.nio.HeapByteBuffer.get(HeapByteBuffer.java:151)
	at java.nio.ByteBuffer.get(ByteBuffer.java:715)
	at net.devbase.jfreesteel.EidCard.parseTlv(EidCard.java:143)
	at net.devbase.jfreesteel.EidCard.readEidInfo(EidCard.java:297)
	at net.devbase.jfreesteel.viewer.EidViewer.inserted(EidViewer.java:265)
	at net.devbase.jfreesteel.Reader.notifyCardListener(Reader.java:210)
	at net.devbase.jfreesteel.Reader.access$500(Reader.java:45)
	at net.devbase.jfreesteel.Reader$1.notifyListeners(Reader.java:176)
	at net.devbase.jfreesteel.Reader$1.run(Reader.java:156)
	at java.lang.Thread.run(Thread.java:748)

Problem je u okviru klase EidCard (package net.devbase.jfreesteel) u izvršavanju metode public static Map<Integer, byte[]> parseTlv(final byte[] bytes). Prilikom čitanja "novih" kartice dolazilo je do toga da pokuša da pročita više podataka nego što u bufferu postoji.
Moram prizanti da ne poznajem strukturu iščitavanja, ali sam code pomenute metode malo promenio i iščitavanje je bilo uspešno i sa "novim" karticama.
Ovo je izgled promenjene metode:

public static Map<Integer, byte[]> parseTlv(final byte[] bytes) {
        HashMap<Integer, byte[]> out = new HashMap<Integer, byte[]>();

        // [fld 16bit LE] [len 16bit LE] [len bytes of data] | [fld] [06] ...

        ByteBuffer buffer = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN);

        // repeat as long as we have next tag and len...
        while (buffer.remaining() > 4) {
            char tag = buffer.getChar();
            char length = buffer.getChar();
            //pocetak izmenjenog dela u odnosu na originalni kod
            byte[] range;
            if (buffer.remaining()>(int)length){
                range = new byte[(int) length];
            } else {
                range = new byte[buffer.remaining()];
            }
            //kraj izmenjenog dela u odnosu na originalni kod
            buffer.get(range);
            out.put((int) tag, range);
        }

        return out;
    }

Možda nije najsrećnije rešenje ali je odradilo posao :)

Inače, u jednom trenutku prilikom čitanja u length se upisuje vrednost veća od 1000, a ukupna veličina bafera je reda 250 (u tom trenutku je preostalo negde oko 130 byte-ova za čitanje).

Napomena: Ovo sam probao sa jednom "starom" ličnom karticom i dve "nove".

Nisam neki guru u programiranju, poznajem osnove, te smatram da ćeš možda dati neko drugo rešenje, a nadam se da će uskoro nova verzija (*.deb bar) sa sređenim bug-om.

Svako dobro!!!

eidviewer ne iscitava licnu kartu

Operativni sistem: Fedora 22 i686
Citac kartica: Omnikey Cardman 4000 PCMCIA (openct)
Java: java-1.8.0-openjdk-1.8.0.45-40.b14.fc22.i686

Nakon nekog vremena program prikaze gresku "Greska pri citanju: sun.security.smartcardio.PCSCException: SCARD_E_NOT_TRANSACTED"

Izlaz komande java -jar eidviewer-1.1.jar:

$ java -jar eidviewer-1.1.jar 
[Thread-1] INFO net.devbase.jfreesteel.Reader - EidCard is null, wait for insertion
[Thread-1] INFO net.devbase.jfreesteel.Reader - CONNECT
[Thread-1] INFO net.devbase.jfreesteel.EidCard - Card inserted
[Thread-1] INFO net.devbase.jfreesteel.EidCard - exclusive
[Thread-1] INFO net.devbase.jfreesteel.EidCard - exclusive free
[Thread-1] ERROR net.devbase.jfreesteel.EidCard - Card error
javax.smartcardio.CardException: sun.security.smartcardio.PCSCException: SCARD_E_NOT_TRANSACTED
    at sun.security.smartcardio.ChannelImpl.doTransmit(ChannelImpl.java:219)
    at sun.security.smartcardio.ChannelImpl.transmit(ChannelImpl.java:90)
    at net.devbase.jfreesteel.EidCard.selectFile(EidCard.java:179)
    at net.devbase.jfreesteel.EidCard.selectFile(EidCard.java:175)
    at net.devbase.jfreesteel.EidCardApollo.readElementaryFile(EidCardApollo.java:55)
    at net.devbase.jfreesteel.EidCard.readEidInfo(EidCard.java:295)
    at net.devbase.jfreesteel.viewer.EidViewer.inserted(EidViewer.java:265)
    at net.devbase.jfreesteel.Reader.notifyCardListener(Reader.java:193)
    at net.devbase.jfreesteel.Reader.access$6(Reader.java:191)
    at net.devbase.jfreesteel.Reader$1.notifyListeners(Reader.java:159)
    at net.devbase.jfreesteel.Reader$1.run(Reader.java:139)
    at java.lang.Thread.run(Thread.java:745)
Caused by: sun.security.smartcardio.PCSCException: SCARD_E_NOT_TRANSACTED
    at sun.security.smartcardio.PCSC.SCardTransmit(Native Method)
    at sun.security.smartcardio.ChannelImpl.doTransmit(ChannelImpl.java:189)
    ... 11 more
[Thread-1] INFO net.devbase.jfreesteel.Reader - EidCard not null, wait for removal

Debug log tokom ubacivanja kartice pcscd --foreground --debug:

*pokrenuta aplikacija*

33941289 winscard_msg_srv.c:253:ProcessEventsServer() Common channel packet arrival
00000044 winscard_msg_srv.c:265:ProcessEventsServer() ProcessCommonChannelRequest detects: 6
00000010 pcscdaemon.c:134:SVCServiceRunLoop() A new context thread creation is requested: 6
00032878 winscard_svc.c:331:ContextThread() Authorized PC/SC client
00000028 winscard_svc.c:335:ContextThread() Thread is started: dwClientID=6, threadContext @0x87e4e38
00000022 winscard_svc.c:353:ContextThread() Received command: CMD_VERSION from client 6
00000011 winscard_svc.c:365:ContextThread() Client is protocol version 4:3
00000009 winscard_svc.c:385:ContextThread() CMD_VERSION rv=0x0 for client 6
00002216 winscard_svc.c:353:ContextThread() Received command: ESTABLISH_CONTEXT from client 6
00000145 winscard.c:216:SCardEstablishContext() Establishing Context: 0x7E6E616E
00000009 winscard_svc.c:446:ContextThread() ESTABLISH_CONTEXT rv=0x0 for client 6
00000912 winscard_svc.c:353:ContextThread() Received command: CMD_GET_READERS_STATE from client 6
00000158 winscard_svc.c:353:ContextThread() Received command: CMD_GET_READERS_STATE from client 6
00524539 winscard_svc.c:353:ContextThread() Received command: CMD_GET_READERS_STATE from client 6
00019693 winscard_svc.c:353:ContextThread() Received command: CMD_GET_READERS_STATE from client 6
00000076 winscard_svc.c:353:ContextThread() Received command: CMD_WAIT_READER_STATE_CHANGE from client 6

*ubacena kartica*

15074029 eventhandler.c:404:EHStatusHandlerThread() powerState: POWER_STATE_POWERED
00000026 eventhandler.c:419:EHStatusHandlerThread() Card inserted into OpenCT 00 00
00000011 winscard_svc.c:780:MSGSignalClient() Signal client: 6
00000006 winscard_svc.c:783:MSGSignalClient() SIGNAL rv=0x0 for client 6
00000030 Card ATR: 3B B9 18 00 81 31 FE 9E 80 73 FF 61 40 83 00 00 00 DF 
00000053 winscard_svc.c:353:ContextThread() Received command: CMD_GET_READERS_STATE from client 6
00000172 winscard_svc.c:353:ContextThread() Received command: CMD_GET_READERS_STATE from client 6
00002162 winscard_svc.c:353:ContextThread() Received command: CONNECT from client 6
00033730 winscard_svc.c:484:ContextThread() Authorized client for 'OpenCT 00 00'
00000030 winscard.c:258:SCardConnect() Attempting Connect to OpenCT 00 00 using protocol: 3
00000009 readerfactory.c:768:RFReaderInfo() RefReader() count was: 1
00000007 winscard.c:353:SCardConnect() powerState: POWER_STATE_INUSE
00000008 prothandler.c:110:PHSetProtocol() Attempting PTS to T=1
00002308 winscard.c:432:SCardConnect() Active Protocol: T=1
00000031 winscard.c:452:SCardConnect() hCard Identity: 4cbfa668
00000010 winscard.c:513:SCardConnect() UnrefReader() count was: 2
00000011 winscard_svc.c:498:ContextThread() CONNECT rv=0x0 for client 6
00002260 winscard_svc.c:353:ContextThread() Received command: CMD_GET_READERS_STATE from client 6
00000072 winscard_svc.c:353:ContextThread() Received command: STATUS from client 6
00000026 readerfactory.c:795:RFReaderInfoById() RefReader() count was: 1
00000018 winscard.c:1314:SCardStatus() UnrefReader() count was: 2
00000017 winscard_svc.c:606:ContextThread() STATUS rv=0x0 for client 6
00047099 winscard_svc.c:353:ContextThread() Received command: BEGIN_TRANSACTION from client 6
00001482 readerfactory.c:795:RFReaderInfoById() RefReader() count was: 1
00000028 winscard.c:1105:SCardBeginTransaction() Status: 0x00000000
00000007 winscard.c:1108:SCardBeginTransaction() UnrefReader() count was: 2
00000008 winscard_svc.c:550:ContextThread() BEGIN_TRANSACTION rv=0x0 for client 6
00001196 winscard_svc.c:353:ContextThread() Received command: TRANSMIT from client 6
00009114 readerfactory.c:795:RFReaderInfoById() RefReader() count was: 1
00000033 winscard.c:1610:SCardTransmit() Send Protocol: T=1

*greska se pojavljuje*

66110945 ifdwrapper.c:550:IFDTransmit() Card not transacted: 612
00000029 winscard.c:1635:SCardTransmit() Card not transacted: 0x80100016
00000008 winscard.c:1655:SCardTransmit() UnrefReader() count was: 2
00000009 winscard_svc.c:653:ContextThread() TRANSMIT rv=0x80100016 for client 6
00000649 winscard_svc.c:353:ContextThread() Received command: END_TRANSACTION from client 6
00000149 readerfactory.c:795:RFReaderInfoById() RefReader() count was: 1
00000014 winscard.c:1248:SCardEndTransaction() Status: 0x00000000
00000007 winscard.c:1251:SCardEndTransaction() UnrefReader() count was: 2
00000029 winscard_svc.c:566:ContextThread() END_TRANSACTION rv=0x0 for client 6

Izlaz komande pcsc_scan:

$ pcsc_scan 
PC/SC device scanner
V 1.4.23 (c) 2001-2011, Ludovic Rousseau <[email protected]>
Compiled with PC/SC lite version: 1.8.13
Using reader plug'n play mechanism
Scanning present readers...
0: OpenCT 00 00

Sun Aug  9 15:10:41 2015
Reader 0: OpenCT 00 00
  Card state: Card inserted, 
  ATR: 3B B9 18 00 81 31 FE 9E 80 73 FF 61 40 83 00 00 00 DF

defined(@array) is deprecated at /usr/lib/perl5/vendor_perl/Chipcard/PCSC.pm line 69.
    (Maybe you should just omit the defined()?)
ATR: 3B B9 18 00 81 31 FE 9E 80 73 FF 61 40 83 00 00 00 DF
+ TS = 3B --> Direct Convention
+ T0 = B9, Y(1): 1011, K: 9 (historical bytes)
  TA(1) = 18 --> Fi=372, Di=12, 31 cycles/ETU
    129032 bits/s at 4 MHz, fMax for Fi = 5 MHz => 161290 bits/s
  TB(1) = 00 --> VPP is not electrically connected
  TD(1) = 81 --> Y(i+1) = 1000, Protocol T = 1 
-----
  TD(2) = 31 --> Y(i+1) = 0011, Protocol T = 1 
-----
  TA(3) = FE --> IFSC: 254
  TB(3) = 9E --> Block Waiting Integer: 9 - Character Waiting Integer: 14
+ Historical bytes: 80 73 FF 61 40 83 00 00 00
  Category indicator byte: 80 (compact TLV data object)
    Tag: 7, len: 3 (card capabilities)
      Selection methods: FF
        - DF selection by full DF name
        - DF selection by partial DF name
        - DF selection by path
        - DF selection by file identifier
        - Implicit DF selection
        - Short EF identifier supported
        - Record number supported
        - Record identifier supported
      Data coding byte: 61
        - Behaviour of write functions: write AND
        - Value 'FF' for the first byte of BER-TLV tag fields: invalid
        - Data unit in quartets: 2
      Command chaining, length fields and logical channels: 40
        - Extended Lc and Le fields
        - Logical channel number assignment: No logical channel
        - Maximum number of logical channels: 1
    Tag: 8, len: 3 (status indicator)
      LCS (life card cycle): 00 (No information given)
      SW: 0000 (Error not defined by ISO 7816)
+ TCK = DF (correct checksum)

Possibly identified card (using /usr/share/pcsc/smartcard_list.txt):
3B B9 18 00 81 31 FE 9E 80 73 FF 61 40 83 00 00 00 DF
    Serbian Identity Card
    This is the new Serbian biometric identity card (every adult cityzen
    must have). The chip contains owners picture, name, date and place
    of birth, current address, unique ID number and fingerprint.
^C

Pun ispis adrese u PDF-u

Program u PDF-u ne upisuje broj ulaza i stana. Problem je ispravljen 18. februara: 02df485

Potrebno je prirediti novo izdanje i instalacije za sva tri podržana sistema.

Postoji patch koji se može preuzeti sa http://goranrakic.com/tmp/eidviewer-patch0.zip

Iz ZIP arhive treba raspakovati jar datoteku i kopirati je preko stare iz instalacije programa.

Putanja datoteke na GNU/Linuxu je /opt/eidviewer/, dok je na OSX potrebno kliknuti desnim na aplikaciju i izabrati opciju Show Package Contents pa odatle preći u putanju Contents/Jar/. Na Windowsu se datoteka nalazi u Program Files fascikli.

instalacija ne radi mvn install

nazalost sve bibiloteke od org.codehaus vise ne rade tako da ih treba zameniti i adaptirati se na nove.
Pokusavam da zamenim nsis ali mi ne ide

<!-- https://mvnrepository.com/artifact/org.codehaus.mojo/nsis-maven-plugin -->
<dependency>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>nsis-maven-plugin</artifactId>
    <version>1.0-alpha-1</version>
</dependency>

sa novom

<!-- https://mvnrepository.com/artifact/org.digitalmediaserver/nsis-maven-plugin -->
<dependency>
    <groupId>org.digitalmediaserver</groupId>
    <artifactId>nsis-maven-plugin</artifactId>
    <version>1.0.3</version>
</dependency>

Failed to execute goal org.digitalmediaserver:nsis-maven-plugin:1.0.3:make (default) on project eidviewer: An error occurred while resolving paths: setup.nsi
pom iz eidviewer foldera
pom.zip

Zauzet USB čitač (bug)

Instalacijom .deb paketa na Linux mint 17.2 x64, i svih zavisnosti, čitač Omnikey CardMan 3021 postaje trajno nedostupan programima za usb-redirect, kao što je SPICE protokol viewer (virt-viewer); unplug-replug ne pomaže, restart ne pomaže; apt-get remove jfsutils rešava problem, čitač ponovo postaje dostupan za virt-viewer. Čitač Todos Argos mini XP, za koji je potrebna instalacija pcscd (mislim) - za to vreme radi odlično sa virt-viewer, ali ne i u programu jfreesteel.

Greska prilikom citanja novih licnih karti na Linux-u

Program javlja gresku kada se ubace novije elektronske licne karte izdate 2019,2020 godine, na Linux operativnom sistemu. Ucitaju se podaci, ali nakon toga program izbaci gresku Card reading error:null. Problem se moze videti na slici.
InkedLinux citac kartica greska_LI

Card reading error: Exclusive access not assigned to current Thread

Pozdrav svima,

upravo sam instalirao program, medjutim naisao sam na problem kada ubacim LK u citac (gemalto)
Dobijam gore navedenu gresku, nakon iscitavanja prvog seta podataka.

Naime, dobijem podatke o imenu, prezimenu, jmbg, prebivalistu, datumu rodjenja i sl

Nema slike i "Save as PDF" nije dostupno.

Sta radim pogresno?

Unapred hvala.

Provera potpisa podataka na ličnoj karti

MUP je objavio novi Čelik (nazvan Čelik+) sa proverom potpisa podataka na kartici. Ispravan potpis pročitanih podataka potvrđuje da je zaista MUP izdao neku ličnu kartu sa takvim podacima na njoj. To ne mora nužno biti kartica koju čitamo, i sa proverom potpisa karticu je verovatno moguće klonirati i u nekom zamišljenom scenariju zloupotrebiti. Ali sa proverom potpisa podataka primetiće se svaka proizvoljna izmena pojedinačnog seta podataka u tako pripremljenoj kartici.

Četiri nove funkcije u API-ju su:

  • EidSetOption (nije interesantno)
  • EidReadCertificate (čita sertifikat za autentikaciju, kvalifikovani sertifikat za potpis i intermediate sertifikat)
  • EidChangePassword (promena PIN koda)
  • EidVerifySignature (proverava elektronski potpis podataka u ličnoj karti)

Ova poslednja je najbitnija i valjalo bi je implementirati u jfreesteelu.

Koristi se tako što se poziva četiri puta za proveru potpisa četiri skupa podataka na kartici. Treba proveriti da li su skupovi podataka uvezani i uporediti ih međusobno kako bi se sprečila zloupotreba gde bi se priredila falsifikovana kartica sa podacima o dokumentu sa jedne, a slikom sa druge lične karte, na primer. Dodatno valjalo bi dodati i proveru kvalifikovanog sertifikata ako isti postoji jer se privatni ključ koji mu odgovara generiše u SSCD režimu. Tako se može potvrditi da lična karta nije klonirana (potpis podataka čuva integritet, ali se ključevi za autentikaciju, podaci i potpisi mogu preneti na kloniranu karticu - sa druge strane privatni ključ koji odgovara kvalifikovanom sertifikatu ne bi trebalo da je moguće kopirati).

U samom Čeliku provera ide posle čitanja podataka, ali svaki programer može sam da odabere u kom trenutku i kojim redom će da poziva funkcije.

Opisi novih funkcija su dodati u uputstvu za API na http://ca.mup.gov.rs/dokumentacija.html (pod brojem 13).

Unable to load Java Runtime Environment [macOS]

Dobijem ovaj error cak i nakon nekoliko re-instaliranja Jave sa weba.

Koliko sam razumeo ovo je jedini softver sa kojim bih mogao da ucitam karticu na macOS-u?

masina: Apple M2 Max, 16inch
os: Mac OS Sonoma 14.2

High Sierra Java Exception

Pokretanje alikacije direktno ne uspeva na MacOS High Sierra
Pokretanjem iz terminala ./JavaAppLauncher dobijam ovaj exception

Exception in thread "AWT-EventQueue-0" java.lang.IllegalArgumentException: input == null!
	at java.desktop/javax.imageio.ImageIO.read(Unknown Source)
	at net.devbase.jfreesteel.viewer.EidViewer.createAndShowGUI(EidViewer.java:174)
	at net.devbase.jfreesteel.viewer.EidViewer.access$7(EidViewer.java:157)
	at net.devbase.jfreesteel.viewer.EidViewer$1.run(EidViewer.java:137)
	at java.desktop/java.awt.event.InvocationEvent.dispatch(Unknown Source)
	at java.desktop/java.awt.EventQueue.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.EventQueue.access$500(Unknown Source)
	at java.desktop/java.awt.EventQueue$3.run(Unknown Source)
	at java.desktop/java.awt.EventQueue$3.run(Unknown Source)
	at java.base/java.security.AccessController.doPrivileged(Native Method)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
	at java.desktop/java.awt.EventQueue.dispatchEvent(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.run(Unknown Source)

Jel ovo problem do aplikacije ili mu nešto fali na sistemu?

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.