GithubHelp home page GithubHelp logo

mrpdaemon / encdroid Goto Github PK

View Code? Open in Web Editor NEW
87.0 87.0 22.0 14.65 MB

Encdroid is an Android application for accessing EncFS volumes on cloud storage

License: GNU General Public License v3.0

Shell 0.03% Makefile 0.03% C 73.12% C++ 9.34% Java 17.48%

encdroid's People

Contributors

ashjas avatar maxbruecken avatar mrpdaemon 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

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

encdroid's Issues

support for external .encfs6.xml

Please add support for external config files. I tried to open a volume that was created using encfs --reverse, so the config file is not in the folder of the encrypted data and there fore encdroid does not seem to find it...

password containing symbol <

Hi,

I've encountered the problem, that encryptions containing < in the password do not work in both encfs and encdroid.
I can only open those with the program I generated them with.
Several other symbols I tested worked though.

To illustrate the problem I have an empty folder generated by encfs:
https://www.dropbox.com/sh/od8lssmxckds6y6/WIJVoCe16O

and one generated by encdroid:
https://www.dropbox.com/sh/4w8e0uadp4583sd/IrnHpG1GIs

for both the password is: test<

Best regards,
Schigum

NullPointerException in EDVolumeListActivity.onCreateDialog()

Got this submission through the Developer Console with version 1.4:

java.lang.RuntimeException: Unable to start activity ComponentInfo{org.mrpdaemon.android.encdroid/org.mrpdaemon.android.encdroid.EDVolumeListActivity}: java.lang.NullPointerException
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2097)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2124)
at android.app.ActivityThread.access$600(ActivityThread.java:135)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1248)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4645)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:809)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:576)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.NullPointerException
at org.mrpdaemon.android.encdroid.EDVolumeListActivity.onCreateDialog(EDVolumeListActivity.java:612)
at android.app.Activity.onCreateDialog(Activity.java:2821)
at android.app.Activity.createDialog(Activity.java:946)
at android.app.Activity.restoreManagedDialogs(Activity.java:935)
at android.app.Activity.performRestoreInstanceState(Activity.java:881)
at android.app.Instrumentation.callActivityOnRestoreInstanceState(Instrumentation.java:1102)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2075)
... 11 more

AsyncTask's should gracefully terminate if app is killed/restarted

Got the following on Google Developer Console with Encdroid 1.3:

java.lang.RuntimeException: An error occured while executing doInBackground()
at android.os.AsyncTask$3.done(AsyncTask.java:200)
at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:274)
at java.util.concurrent.FutureTask.setException(FutureTask.java:125)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:308)
at java.util.concurrent.FutureTask.run(FutureTask.java:138)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1088)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:581)
at java.lang.Thread.run(Thread.java:1019)
Caused by: java.lang.NullPointerException
at org.mrpdaemon.android.encdroid.EDVolumeListActivity$EDCreateVolumeTask.doInBackground(EDVolumeListActivity.java:1019)
at org.mrpdaemon.android.encdroid.EDVolumeListActivity$EDCreateVolumeTask.doInBackground(EDVolumeListActivity.java:1)
at android.os.AsyncTask$2.call(AsyncTask.java:185)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:306)
... 4 more

Looks like EDCreateVolumeTask was started when the application was restarted after being killed:

    protected Boolean doInBackground(String... args) {

        volumeName = args[1];
        password = args[2];

        EncFSFileProvider rootProvider = getFileProvider(volumeType, "/");

        try {
            if (!rootProvider.exists(args[0])) {

rootFileProvider is NULL.

Unable to update KeepassDroid database files in local volume

I have successfully set up a local volume on my Nexus 7.

I can edit a simple text file in my volume (gets re-encrypted), but not a KeepassDroid database file (1.x flavour) . Looks like Encdroid doesn't "see" KeepassDroid updating its database, so it's effectively forced r/o.

NullPointerException in EDVolumeBrowserActivity$FillTask.onPreExecute()

Got the following reported on the Developer Console:

java.lang.NullPointerException
at org.mrpdaemon.android.encdroid.EDVolumeBrowserActivity$FillTask.onPreExecute(EDVolumeBrowserActivity.java:1435)
at android.os.AsyncTask.executeOnExecutor(AsyncTask.java:586)
at android.os.AsyncTask.execute(AsyncTask.java:534)
at org.mrpdaemon.android.encdroid.EDVolumeBrowserActivity.launchFillTask(EDVolumeBrowserActivity.java:1117)
at org.mrpdaemon.android.encdroid.EDVolumeBrowserActivity.onOptionsItemSelected(EDVolumeBrowserActivity.java:491)
at android.app.Activity.onMenuItemSelected(Activity.java:2629)
at com.android.internal.policy.impl.PhoneWindow.onMenuItemSelected(PhoneWindow.java:1047)
at com.android.internal.view.menu.MenuBuilder.dispatchMenuItemSelected(MenuBuilder.java:735)
at com.android.internal.view.menu.MenuItemImpl.invoke(MenuItemImpl.java:149)
at com.android.internal.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:874)
at com.android.internal.view.menu.ActionMenuView.invokeItem(ActionMenuView.java:586)
at com.android.internal.view.menu.ActionMenuItemView.onClick(ActionMenuItemView.java:179)
at android.view.View.performClick(View.java:4211)
at android.view.View$PerformClick.run(View.java:17267)
at android.os.Handler.handleCallback(Handler.java:615)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4898)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1006)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:773)
at dalvik.system.NativeStart.main(Native Method)

Shred files after import

It would be great to have a context menu option like "Import and shred" to shred (or at least delete) file after import.

Add xxhdpi icons

For high resolution devices like the 2013 Nexus 7, Galaxy S4 etc. it would be good to have xxhdpi icon assets.

File change tracking not working reliably

When opening and saving the same file repeatedly using a text editor, at some point encdroid stops encrypting the changes. Might need to use a different mechanism to propagate file changes.

Fix logging exceptions with empty messages

Got the following backtrace from Google Developer console with Encdroid 1.3:

java.lang.RuntimeException: An error occured while executing doInBackground()
at android.os.AsyncTask$3.done(AsyncTask.java:200)
at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:274)
at java.util.concurrent.FutureTask.setException(FutureTask.java:125)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:308)
at java.util.concurrent.FutureTask.run(FutureTask.java:138)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1088)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:581)
at java.lang.Thread.run(Thread.java:1019)
Caused by: java.lang.NullPointerException: println needs a message
at android.util.Log.println_native(Native Method)
at android.util.Log.e(Log.java:371)
at org.mrpdaemon.android.encdroid.EDVolumeListActivity$EDUnlockVolumeTask.doInBackground(EDVolumeListActivity.java:926)
at org.mrpdaemon.android.encdroid.EDVolumeListActivity$EDUnlockVolumeTask.doInBackground(EDVolumeListActivity.java:1)
at android.os.AsyncTask$2.call(AsyncTask.java:185)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:306)
... 4 more

Looks like the exception has an empty message which upsets Log.e().

NullPointerException when resuming EDVolumeBrowserActivity

Got this backtrace through the Google Play "submit crash report" functionality. Looks like EDVolumeBrowserActivity was created directly after a long time which caused it to crash due to the volume context not being fully there.

java.lang.RuntimeException: Unable to start activity ComponentInfo{org.mrpdaemon.android.encdroid/org.mrpdaemon.android.encdroid.EDVolumeBrowserActivity}: java.lang.NullPointerException
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2059)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2084)
at android.app.ActivityThread.access$600(ActivityThread.java:130)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1195)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4745)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.NullPointerException
at org.mrpdaemon.android.encdroid.EDVolumeBrowserActivity.onCreate(EDVolumeBrowserActivity.java:215)
at android.app.Activity.performCreate(Activity.java:5008)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1079)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2023)
... 11 more

Improve PBKDF2 performance

One of the Play Store reviews mentioned Cryptonite being faster when computing the password-derived key, so it is worthwhile looking into improving the performance. Perhaps building a module with the native client toolkit just containing an optimized method to do this computation would be appropriate.

EDVolumeListActivity.UnlockVolumeTask modifies ListView adapter outside the UI thread

Got the following backtrace on the developer console:

java.lang.IllegalStateException: The content of the adapter has changed but ListView did not receive a notification. Make sure the content of your adapter is not modified from a background thread, but only from the UI thread. [in ListView(16908298, class android.widget.ListView) with Adapter(class android.widget.HeaderViewListAdapter)]
at android.widget.ListView.layoutChildren(ListView.java:1538)
at android.widget.AbsListView.onLayout(AbsListView.java:1875)
at android.view.View.layout(View.java:11390)
at android.view.ViewGroup.layout(ViewGroup.java:4332)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1653)
at android.widget.LinearLayout.layoutHorizontal(LinearLayout.java:1642)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1418)
at android.view.View.layout(View.java:11390)
at android.view.ViewGroup.layout(ViewGroup.java:4332)
at android.widget.FrameLayout.onLayout(FrameLayout.java:444)
at android.view.View.layout(View.java:11390)
at android.view.ViewGroup.layout(ViewGroup.java:4332)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1653)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1511)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1416)
at android.view.View.layout(View.java:11390)
at android.view.ViewGroup.layout(ViewGroup.java:4332)
at android.widget.FrameLayout.onLayout(FrameLayout.java:444)
at android.view.View.layout(View.java:11390)
at android.view.ViewGroup.layout(ViewGroup.java:4332)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1490)
at android.view.ViewRootImpl.handleMessage(ViewRootImpl.java:2455)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4424)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:817)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:584)
at dalvik.system.NativeStart.main(Native Method)

ArrayIndexOutOfBoundsException in EDVolumeBrowserActivity.copyStreams()

Got the following on Developer Console:

java.lang.RuntimeException: An error occured while executing doInBackground()
at android.os.AsyncTask$3.done(AsyncTask.java:200)
at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:274)
at java.util.concurrent.FutureTask.setException(FutureTask.java:125)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:308)
at java.util.concurrent.FutureTask.run(FutureTask.java:138)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1088)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:581)
at java.lang.Thread.run(Thread.java:1019)
Caused by: java.lang.ArrayIndexOutOfBoundsException: src.length=1024 srcPos=1008 dst.length=16 dstPos=6 length=16
at java.lang.System.arraycopy(Native Method)
at org.bouncycastle.crypto.BufferedBlockCipher.processBytes(BufferedBlockCipher.java:230)
at org.bouncycastle.jce.provider.JCEBlockCipher$BufferedGenericBlockCipher.processBytes(JCEBlockCipher.java:1312)
at org.bouncycastle.jce.provider.JCEBlockCipher.engineDoFinal(JCEBlockCipher.java:702)
at javax.crypto.Cipher.doFinal(Cipher.java:1090)
at org.mrpdaemon.sec.encfs.BlockCrypto.blockOperation(BlockCrypto.java:36)
at org.mrpdaemon.sec.encfs.BlockCrypto.blockDecrypt(BlockCrypto.java:43)
at org.mrpdaemon.sec.encfs.EncFSInputStream.readBlock(EncFSInputStream.java:291)
at org.mrpdaemon.sec.encfs.EncFSInputStream.read(EncFSInputStream.java:163)
at java.io.FilterInputStream.read(FilterInputStream.java:157)
at java.io.FilterInputStream.read(FilterInputStream.java:133)
at org.mrpdaemon.android.encdroid.EDVolumeBrowserActivity.copyStreams(EDVolumeBrowserActivity.java:1248)
at org.mrpdaemon.android.encdroid.EDVolumeBrowserActivity.exportFile(EDVolumeBrowserActivity.java:1293)
at org.mrpdaemon.android.encdroid.EDVolumeBrowserActivity.access$6(EDVolumeBrowserActivity.java:1268)
at org.mrpdaemon.android.encdroid.EDVolumeBrowserActivity$ViewFileTask.doInBackground(EDVolumeBrowserActivity.java:1567)
at org.mrpdaemon.android.encdroid.EDVolumeBrowserActivity$ViewFileTask.doInBackground(EDVolumeBrowserActivity.java:1)
at android.os.AsyncTask$2.call(AsyncTask.java:185)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:306)
... 4 more

Crash in encfs-java local file provider

Got 3 instances of the following issue on Google Developer Console:

java.lang.RuntimeException: An error occured while executing doInBackground()
at android.os.AsyncTask$3.done(AsyncTask.java:200)
at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:274)
at java.util.concurrent.FutureTask.setException(FutureTask.java:125)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:308)
at java.util.concurrent.FutureTask.run(FutureTask.java:138)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1088)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:581)
at java.lang.Thread.run(Thread.java:1019)
Caused by: java.lang.NullPointerException
at org.mrpdaemon.sec.encfs.EncFSLocalFileProvider.listFiles(EncFSLocalFileProvider.java:152)
at org.mrpdaemon.android.encdroid.EDFileChooserActivity.fill(EDFileChooserActivity.java:341)
at org.mrpdaemon.android.encdroid.EDFileChooserActivity.access$0(EDFileChooserActivity.java:335)
at org.mrpdaemon.android.encdroid.EDFileChooserActivity$EDFileChooserFillTask.doInBackground(EDFileChooserActivity.java:495)
at org.mrpdaemon.android.encdroid.EDFileChooserActivity$EDFileChooserFillTask.doInBackground(EDFileChooserActivity.java:1)
at android.os.AsyncTask$2.call(AsyncTask.java:185)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:306)
... 4 more

being tracked as encfs-java issue 51:
mrpdaemon/encfs-java#51

ArrayIndexOutOfBoundsException in EncFSCrypto.getMacBytes()

Looks like encfs-java can't deal with one byte filenames:

java.lang.RuntimeException: An error occured while executing doInBackground()
at android.os.AsyncTask$3.done(AsyncTask.java:299)
at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:273)
at java.util.concurrent.FutureTask.setException(FutureTask.java:124)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:307)
at java.util.concurrent.FutureTask.run(FutureTask.java:137)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
at java.lang.Thread.run(Thread.java:856)
Caused by: java.lang.ArrayIndexOutOfBoundsException: length=1; index=1
at org.mrpdaemon.sec.encfs.EncFSCrypto.getMacBytes(EncFSCrypto.java:430)
at org.mrpdaemon.sec.encfs.BasicFilenameDecryptionStrategy.decryptImpl(BasicFilenameDecryptionStrategy.java:42)
at org.mrpdaemon.sec.encfs.FilenameDecryptionStrategy.decrypt(FilenameDecryptionStrategy.java:51)
at org.mrpdaemon.sec.encfs.EncFSCrypto.decodeName(EncFSCrypto.java:181)
at org.mrpdaemon.sec.encfs.EncFSFile.listFiles(EncFSFile.java:228)
at org.mrpdaemon.android.encdroid.EDVolumeBrowserActivity.fill(EDVolumeBrowserActivity.java:1033)
at org.mrpdaemon.android.encdroid.EDVolumeBrowserActivity.access$0(EDVolumeBrowserActivity.java:1028)
at org.mrpdaemon.android.encdroid.EDVolumeBrowserActivity$FillTask.doInBackground(EDVolumeBrowserActivity.java:1453)
at org.mrpdaemon.android.encdroid.EDVolumeBrowserActivity$FillTask.doInBackground(EDVolumeBrowserActivity.java:1)
at android.os.AsyncTask$2.call(AsyncTask.java:287)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
... 5 more

Crash in EDFileChooserAdapter.getItem()

Received a new crash backtrace through the Google Play store:

java.lang.ArrayIndexOutOfBoundsException: length=87; index=-1
at java.util.ArrayList.get(ArrayList.java:306)
at org.mrpdaemon.android.encdroid.EDFileChooserAdapter.getItem(EDFileChooserAdapter.java:46)
at org.mrpdaemon.android.encdroid.EDFileChooserActivity.onContextItemSelected(EDFileChooserActivity.java:542)
at android.app.Activity.onMenuItemSelected(Activity.java:2571)
at com.android.internal.policy.impl.PhoneWindow$DialogMenuCallback.onMenuItemSelected(PhoneWindow.java:3712)
at com.android.internal.view.menu.MenuBuilder.dispatchMenuItemSelected(MenuBuilder.java:735)
at com.android.internal.view.menu.MenuItemImpl.invoke(MenuItemImpl.java:149)
at com.android.internal.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:874)
at com.android.internal.view.menu.MenuDialogHelper.onClick(MenuDialogHelper.java:193)
at com.android.internal.app.AlertController$AlertParams$3.onItemClick(AlertController.java:936)
at android.widget.AdapterView.performItemClick(AdapterView.java:292)
at android.widget.AbsListView.performItemClick(AbsListView.java:1359)
at android.widget.AbsListView$PerformClick.run(AbsListView.java:2988)
at android.widget.AbsListView$1.run(AbsListView.java:3783)
at android.os.Handler.handleCallback(Handler.java:605)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4517)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:993)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:760)
at dalvik.system.NativeStart.main(Native Method)

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.