Giter Club home page Giter Club logo

viewsb's Introduction

ViewSB: open-source USB Analyzer software

ViewSB is a USB analyzer that supports various capture backends including GreatFET, OpenVizsla, and usbmon.


Getting Help

For assistance with ViewSB general use or development, please look at the issues on the GitHub project. This is the preferred place to ask questions so that others may locate the answer to your question in the future.

We invite you to join our community discussions on Discord. Note that while technical support requests are welcome here, we do not have support staff on duty at all times. Be sure to also submit an issue on GitHub if you’ve found a bug or if you want to ensure that your request will be tracked and not overlooked.

GitHub issues on this repository that are labelled "technical support" can expect a response time of two weeks. We currently do not have expected response times for other GitHub issues or pull requests for this repository.


Licensing

ViewSB is dual-licensed under the GNU General Public License version 2 or higher, as well as the BSD 3-Clause License.

We are not lawyers; consult your legal team for exactly what the limitations of use are as far as using ViewSB with other software. ¯\(ツ)

You can find a copy of both licenses in the LICENSE-GPLv2 and LICENSE-BSD files respectively.

viewsb's People

Contributors

dragonmux avatar ffy00 avatar fvdpol avatar jpcrypt avatar ktemkin avatar mateusz-holenko avatar miek avatar mossmann avatar osterwood avatar qyriad avatar smunaut avatar straithe avatar tresacton avatar whitequark 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

viewsb's Issues

Add IRC / Discord channel to README?

I was trying to find the URL to the Discord channel and it was pretty hard.

It would be nice if the IRC channel and Discord was linked to from the README.md file.

Missing Transfers in usb analysis

When analyzing an usb trace I noticed that some of the larger bulk transfers are not present in the ViewSB output.

As a comparison I looked at same trace in Wireshark and noticed that the packets are present in the trace but missing:

One example (multiple exists in my trace....)

  • the IN Transaction from packet #9307-9309 is shown in both Wireshark and ViewSB;
  • the following packets #9311-9223 are missing in ViewSB (marked in Wireshark)
  • from packet #9324 onwards (the PING/NAK sequence ViewSB stats showing the data)

Screenshot from 2022-01-16 19-51-53

Capture device is OpenVizsla, capturing the hs traffic to pcap file (USB link layer packets); SOF packets filtered out on both ViewSB and Wireshark.

The tui frontend is showing same issue (but more difficult to interpret/compare against the wireshark output):

Screenshot from 2022-01-16 19-59-45

Make descriptors available in usbmon backend

I think one place this could really improve over Wireshark is by (optionally) having the descriptors in one tab/part of the frontend. Would this be something you are open to add?

Grouping "hides" packets until the group is complete

What happens is that packets are only shown on the UI when the "group" logic flushes and think the group is done. That logic is fine if you're viewing a file or a capture that's ended, but when doing live capture, this presents a view that's far from reality.

Especially when debugging issues where transactions are invalid / incomplete, a lot of packet just end up in limbo and never shown.

I think ideally any packet that has been received should be shown in the UI, and so "incomplete" groups should already be there and progressively filled / updated. That's unfortunately not trivial :/

Unable to install Viewsb: "No matching distribution found for usb_protocol"

OS:

➜  uname -a                      
Linux mjc-virtual-machine 5.13.0-41-generic #46~20.04.1-Ubuntu SMP Wed Apr 20 13:16:21 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux
➜  

Operating procedures:

➜  python3 -V       
Python 3.8.10
➜  python3 -m pip -V
pip 22.1.2 from /home/mjc/.local/lib/python3.8/site-packages/pip (python 3.8)
➜  
➜  git clone https://github.com/greatscottgadgets/ViewSB.git
。。。
➜  python3 -m pip install . --proxy http://192.168.43.1:7890 
Defaulting to user installation because normal site-packages is not writeable
Processing /home/mjc/prog/luna_usb/ViewSB
  Preparing metadata (setup.py) ... done
Collecting construct
  Using cached construct-2.10.68.tar.gz (57 kB)
  Preparing metadata (setup.py) ... done
Collecting bitstruct
  Using cached bitstruct-8.15.1.tar.gz (34 kB)
  Preparing metadata (setup.py) ... done
Collecting tableprint
  Using cached tableprint-0.9.1-py3-none-any.whl (6.8 kB)
Collecting urwid
  Using cached urwid-2.1.2.tar.gz (634 kB)
  Preparing metadata (setup.py) ... done
ERROR: Could not find a version that satisfies the requirement usb_protocol (from viewsb) (from versions: none)
ERROR: No matching distribution found for usb_protocol
➜  

TypeError: cannot serialize '_io.FileIO' object

Hi,

I tried to launch viewusb.sh with the following command, but it fails with a weird error:

root@ikasten:/opt/ViewSB# ./viewsb.sh usbmon --file /opt/kali/usblog
WARNING:root:SoC framework components could not be imported; some functionality will be unavailable.
WARNING:root:No module named 'nmigen_stdio.serial'
Traceback (most recent call last):
File "/usr/lib/python3.7/runpy.py", line 193, in _run_module_as_main
"main", mod_spec)
File "/usr/lib/python3.7/runpy.py", line 85, in _run_code
exec(code, run_globals)
File "/opt/ViewSB/viewsb/commands/viewsb.py", line 205, in
main()
File "/opt/ViewSB/viewsb/commands/viewsb.py", line 201, in main
analyzer.run()
File "/opt/ViewSB/viewsb/analyzer.py", line 184, in run
self.backend.start()
File "/opt/ViewSB/viewsb/ipc.py", line 51, in start
self.remote_process.start()
File "/usr/lib/python3.7/multiprocessing/process.py", line 112, in start
self._popen = self._Popen(self)
File "/usr/lib/python3.7/multiprocessing/context.py", line 223, in _Popen
return _default_context.get_context().Process._Popen(process_obj)
File "/usr/lib/python3.7/multiprocessing/context.py", line 284, in _Popen
return Popen(process_obj)
File "/usr/lib/python3.7/multiprocessing/popen_spawn_posix.py", line 32, in init
super().init(process_obj)
File "/usr/lib/python3.7/multiprocessing/popen_fork.py", line 20, in init
self._launch(process_obj)
File "/usr/lib/python3.7/multiprocessing/popen_spawn_posix.py", line 47, in _launch
reduction.dump(process_obj, fp)
File "/usr/lib/python3.7/multiprocessing/reduction.py", line 60, in dump
ForkingPickler(file, protocol).dump(obj)
TypeError: cannot serialize '_io.FileIO' object

Any help will be much appreciated.

HID dissections

Hey,

I want to add support for ViewSB to dissect HID data. Currently, all dissections are based on https://github.com/usb-tools/python-usb-protocol, which does not support HID. I have a project that can parse HID report descriptors and get the report format, https://github.com/FFY00/python-hid-parser. I was wondering if it would be alright to use it here for the dissections?

I chatted a bit about this with @Qyriad on Discord, it seems that we would generally want to get https://github.com/usb-tools/python-usb-protocol to understand HID. That is fair, but I don't think this should be necessarily done. HID is indeed part of the USB spec but it is used in several places outside USB, so I think having it in a separate package does make some sense. Having it as part https://github.com/usb-tools/python-usb-protocol is also a perfectly valid solution. So, what do we want to do?

Cheers 😊,
Filipe

Add control channel between backends, analyzer, and frontends

Right now, all state is created when the analyzer starts; there's no channel for the frontend to request a device connect/disconnect, start/stop analysis, and etc. etc.

An RPC interface should exist so e.g. the frontend UI can stop and start analysis on the backend; and the backend can report errors nicely to the frontend.

Qt frontend TreeList shows packets/events out-of-sequence

The ViewSB grouping functionality results in events only be submitted to the visualization queue when complete. Since the Qt frontend simply appends the events to the TreeList this results in occasionally out-of-sequence visualisation: The group is shown at 'then end', when the group is complete, instead of the start when the first packet for that group got received.

Example:
image

pcap file used:
sequence-issue.pcap.gz

Expected behavior would be that the groups/events are shown in same order they have been received/send over the wire.

Mockup:
image

Database "base class" for frontends

Currently, packets are delivered to each frontend; and it's up to them to decide what to do with them.

Ideally, we should provide some unified database backend that collects packets, and allows them to be searched/filtered/etc. Ideally, this would also allow saving/loading (#10) by backing the database with a disk file.

SQLite seems like an obvious choice.

Ability to save / load sessions / captures

Pretty much self explanatory why this is useful :p

The iti1480a capture format seems to have been adopted by a few projects ... although tbh that format is a bit weird to me.

ImportError: cannot import name 'Flag'

I'm unable to run viewsb.sh. I get the error ImportError: cannot import name 'Flag':

(ViewSB) fomu@fomu-jig:~/ViewSB $ ./viewsb.sh
Traceback (most recent call last):
  File "/usr/lib/python3.5/runpy.py", line 183, in _run_module_as_main
    mod_name, mod_spec, code = _get_module_details(mod_name, _Error)
  File "/usr/lib/python3.5/runpy.py", line 109, in _get_module_details
    __import__(pkg_name)
  File "/home/fomu/ViewSB/viewsb/__init__.py", line 2, in <module>
    from .analyzer import ViewSBAnalyzer
  File "/home/fomu/ViewSB/viewsb/analyzer.py", line 12, in <module>
    from .decoders import *
  File "/home/fomu/ViewSB/viewsb/decoders/__init__.py", line 4, in <module>
    from .classes import *
  File "/home/fomu/ViewSB/viewsb/decoders/classes/cdc.py", line 7, in <module>
    from ..standard_descriptors import GetClassSpecificDescriptorRequest
  File "/home/fomu/ViewSB/viewsb/decoders/standard_descriptors.py", line 12, in <module>
    from .standard_requests import GetDescriptorRequest
  File "/home/fomu/ViewSB/viewsb/decoders/standard_requests.py", line 14, in <module>
    from ..packet import USBControlTransfer
  File "/home/fomu/ViewSB/viewsb/packet.py", line 14, in <module>
    from enum import Flag, auto
ImportError: cannot import name 'Flag'
(ViewSB) fomu@fomu-jig:~/ViewSB $ 

Maybe the enum module doesn't work on a Raspberry Pi?

(ViewSB) fomu@fomu-jig:~/ViewSB $ pip install enum
Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple
Collecting enum
  Downloading https://files.pythonhosted.org/packages/02/a0/32e1d5a21b703f600183e205aafc6773577e16429af5ad3c3f9b956b07ca/enum-0.4.7.tar.gz
    ERROR: Command errored out with exit status 1:
     command: /home/fomu/ViewSB/bin/python3 -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'/tmp/pip-install-gedcw2vw/enum/setup.py'"'"'; __file__='"'"'/tmp/pip-install-gedcw2vw/enum/setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' egg_info --egg-base /tmp/pip-install-gedcw2vw/enum/pip-egg-info
         cwd: /tmp/pip-install-gedcw2vw/enum/
    Complete output (15 lines):
    Traceback (most recent call last):
      File "<string>", line 1, in <module>
      File "/home/fomu/ViewSB/local/lib/python3.5/site-packages/setuptools/__init__.py", line 18, in <module>
        import setuptools.version
      File "/home/fomu/ViewSB/local/lib/python3.5/site-packages/setuptools/version.py", line 1, in <module>
        import pkg_resources
      File "/home/fomu/ViewSB/local/lib/python3.5/site-packages/pkg_resources/__init__.py", line 33, in <module>
        import platform
      File "/usr/lib/python3.5/platform.py", line 117, in <module>
        import sys, os, re, subprocess
      File "/usr/lib/python3.5/subprocess.py", line 50, in <module>
        import signal
      File "/usr/lib/python3.5/signal.py", line 4, in <module>
        from enum import IntEnum as _IntEnum
    ImportError: cannot import name 'IntEnum'
    ----------------------------------------
ERROR: Command errored out with exit status 1: python setup.py egg_info Check the logs for full command output.
(ViewSB) fomu@fomu-jig:~/ViewSB $

USB 3.0 devices with PHYWhisperer

Hello,

I'm attempting to sniff basic USB traffic with the PHYWhisperer, however I get this error when starting ViewSB

viewsb phywhisperer --pattern 45 --mask 255

ddaly@OPERATOR:~$ viewsb phywhisperer --pattern 45 --mask 255
Process TUIFrontend process:
Traceback (most recent call last):
  File "/usr/lib/python3.6/multiprocessing/process.py", line 258, in _bootstrap
    self.run()
  File "/usr/lib/python3.6/multiprocessing/process.py", line 93, in run
    self._target(*self._args, **self._kwargs)
  File "/usr/local/lib/python3.6/dist-packages/viewsb-0.0.1-py3.6.egg/viewsb/ipc.py", line 124, in _subordinate_process_entry
    task.run()
  File "/usr/local/lib/python3.6/dist-packages/viewsb-0.0.1-py3.6.egg/viewsb/frontends/tui.py", line 307, in run
    self.loop.run()
  File "/usr/local/lib/python3.6/dist-packages/urwid-2.1.1.dev0-py3.6-linux-x86_64.egg/urwid/main_loop.py", line 287, in run
    self._run()
  File "/usr/local/lib/python3.6/dist-packages/urwid-2.1.1.dev0-py3.6-linux-x86_64.egg/urwid/main_loop.py", line 385, in _run
    self.event_loop.run()
  File "/usr/local/lib/python3.6/dist-packages/urwid-2.1.1.dev0-py3.6-linux-x86_64.egg/urwid/main_loop.py", line 790, in run
    self._loop()
  File "/usr/local/lib/python3.6/dist-packages/urwid-2.1.1.dev0-py3.6-linux-x86_64.egg/urwid/main_loop.py", line 823, in _loop
    alarm_callback()
  File "/usr/local/lib/python3.6/dist-packages/urwid-2.1.1.dev0-py3.6-linux-x86_64.egg/urwid/main_loop.py", line 173, in cb
    callback(self, user_data)
  File "/usr/local/lib/python3.6/dist-packages/viewsb-0.0.1-py3.6.egg/viewsb/frontends/tui.py", line 270, in <lambda>
    self.loop.set_alarm_in(self.BACKGROUND_REFRESH_INTERVAL, lambda _, __ : self.handle_communications())
  File "/usr/local/lib/python3.6/dist-packages/viewsb-0.0.1-py3.6.egg/viewsb/frontends/tui.py", line 262, in handle_communications
    super().handle_communications()
  File "/usr/local/lib/python3.6/dist-packages/viewsb-0.0.1-py3.6.egg/viewsb/frontend.py", line 218, in handle_communications
    self.handle_incoming_packet(packet)
  File "/usr/local/lib/python3.6/dist-packages/viewsb-0.0.1-py3.6.egg/viewsb/frontends/tui.py", line 284, in handle_incoming_packet
    self.loop.process_input(['end', 'a'])
  File "/usr/local/lib/python3.6/dist-packages/urwid-2.1.1.dev0-py3.6-linux-x86_64.egg/urwid/main_loop.py", line 513, in process_input
    k = self._topmost_widget.keypress(self.screen_size, k)
  File "/usr/local/lib/python3.6/dist-packages/urwid-2.1.1.dev0-py3.6-linux-x86_64.egg/urwid/container.py", line 1135, in keypress
    return self.body.keypress( (maxcol, remaining), key )
  File "/usr/local/lib/python3.6/dist-packages/urwid-2.1.1.dev0-py3.6-linux-x86_64.egg/urwid/container.py", line 2316, in keypress
    key = w.keypress((mc,) + size[1:], key)
  File "/usr/local/lib/python3.6/dist-packages/viewsb-0.0.1-py3.6.egg/viewsb/frontends/tui.py", line 376, in keypress
    self.focus_changed()
  File "/usr/local/lib/python3.6/dist-packages/viewsb-0.0.1-py3.6.egg/viewsb/frontends/tui.py", line 338, in focus_changed
    self.focus_changed_callback(focused_node, focused_node.get_value())
  File "/usr/local/lib/python3.6/dist-packages/viewsb-0.0.1-py3.6.egg/viewsb/frontends/tui.py", line 118, in packet_focus_changed
    self.populate_decoder_view(packet)
  File "/usr/local/lib/python3.6/dist-packages/viewsb-0.0.1-py3.6.egg/viewsb/frontends/tui.py", line 193, in populate_decoder_view
    self.decoder_rows.append(urwid.Text(('header', table_name)))
  File "/usr/local/lib/python3.6/dist-packages/urwid-2.1.1.dev0-py3.6-linux-x86_64.egg/urwid/widget.py", line 834, in __init__
    self.set_text(markup)
  File "/usr/local/lib/python3.6/dist-packages/urwid-2.1.1.dev0-py3.6-linux-x86_64.egg/urwid/widget.py", line 877, in set_text
    self._text, self._attrib = decompose_tagmarkup(markup)
  File "/usr/local/lib/python3.6/dist-packages/urwid-2.1.1.dev0-py3.6-linux-x86_64.egg/urwid/util.py", line 380, in decompose_tagmarkup
    tl, al = _tagmarkup_recurse(tm, None)
  File "/usr/local/lib/python3.6/dist-packages/urwid-2.1.1.dev0-py3.6-linux-x86_64.egg/urwid/util.py", line 418, in _tagmarkup_recurse
    return _tagmarkup_recurse( element, attr )
  File "/usr/local/lib/python3.6/dist-packages/urwid-2.1.1.dev0-py3.6-linux-x86_64.egg/urwid/util.py", line 421, in _tagmarkup_recurse
    raise TagMarkupException("Invalid markup element: %r" % tm)
urwid.util.TagMarkupException: Invalid markup element: None

I think this has something to do with the device being a USB 3.0 device, even using the usbmon backend, I get the same error.

I suspected the PHYWhisperer would automatically drop the 3.0 target to 2.0, if this is not the case I may just need to pick up a USB 2.0 hub.

Any help is appreciated, cheers!

packet selection

Add a frontend ability to select multiple packets and save them.

Add way for backends to terminate run

I'm adding a Beagle CSV backend and iteration would be faster if I could terminate the analysis from the backend. That way I could only have it analyze a portion of the file and then return to the command line.

Show packet exact time

At least in the tui interface I couldn't see the exact time a packet has been received ( frame # + microseconds ). That's definitely useful info to check if it's expected a device responded with NAK or not.

Unexpected termination on USBTransferFragment summary

Sometimes ViewSB will terminate unexpectedly with the following error in the presence of a packet fragment:

Traceback (most recent call last):
  File "/usr/lib/python3.7/multiprocessing/process.py", line 297, in _bootstrap
    self.run()
  File "/usr/lib/python3.7/multiprocessing/process.py", line 99, in run
    self._target(*self._args, **self._kwargs)
  File "/code/src/ViewSB/viewsb/ipc.py", line 124, in _subordinate_process_entry
    task.run()
  File "/code/src/ViewSB/viewsb/frontend.py", line 226, in run
    self.handle_communications()
  File "/code/src/ViewSB/viewsb/frontend.py", line 218, in handle_communications
    self.handle_incoming_packet(packet)
  File "/code/src/ViewSB/viewsb/frontends/cli.py", line 21, in handle_incoming_packet
    print(repr(packet))
  File "/code/src/ViewSB/viewsb/packet.py", line 304, in __repr__
    self.summarize(), data_summary, self.summarize_status())
  File "/code/src/ViewSB/viewsb/packet.py", line 588, in summarize
    return "ORPHANED {}B {}-{} transfer".format(len(self.data), self.direction.name, self.pid.name)
AttributeError: 'NoneType' object has no attribute 'name'

As a quick workaround to test ViewSB for the first time, I made the following change to check that self.direction and self.pid are defined first.

index b1145eb..e527704 100644
--- a/viewsb/packet.py
+++ b/viewsb/packet.py
@@ -585,7 +585,8 @@ class USBTransferFragment(USBTransfer):
     FIELDS = {'transfer_type'}
 
     def summarize(self):
-        return "ORPHANED {}B {}-{} transfer".format(len(self.data), self.direction.name, self.pid.name)
+        if self.direction and self.pid:
+            return "ORPHANED {}B {}-{} transfer".format(len(self.data), self.direction.name, self.pid.name)
 
 
 class USBBulkTransfer(USBDataTransfer):

run “viewsb openvizsla cli" error. why?

FPGA: Bitstream timestamp 2014/11/10 16:31:07
FPGA: sending configuration bitstream
FPGA: CRC OK
FPGA: configured
Traceback (most recent call last):
File "/usr/local/bin/viewsb", line 11, in
load_entry_point('viewsb==0.0.1', 'console_scripts', 'viewsb')()
File "/usr/local/lib/python3.6/dist-packages/viewsb-0.0.1-py3.6.egg/viewsb/commands/viewsb.py", line 110, in main
analyzer.run()
File "/usr/local/lib/python3.6/dist-packages/viewsb-0.0.1-py3.6.egg/viewsb/analyzer.py", line 167, in run
self.run_analysis_iteration()
File "/usr/local/lib/python3.6/dist-packages/viewsb-0.0.1-py3.6.egg/viewsb/analyzer.py", line 132, in run_analysis_iteration
self.process_analysis_queue()
File "/usr/local/lib/python3.6/dist-packages/viewsb-0.0.1-py3.6.egg/viewsb/analyzer.py", line 78, in process_analysis_queue
handled = decoder.handle_packet(packet)
File "/usr/local/lib/python3.6/dist-packages/viewsb-0.0.1-py3.6.egg/viewsb/decoder.py", line 75, in handle_packet
self.consume_packet(packet)
File "/usr/local/lib/python3.6/dist-packages/viewsb-0.0.1-py3.6.egg/viewsb/decoders/grouping.py", line 89, in consume_packet
self._consume_token_packet(packet)
File "/usr/local/lib/python3.6/dist-packages/viewsb-0.0.1-py3.6.egg/viewsb/decoders/grouping.py", line 50, in _consume_token_packet
new_packet = USBTokenPacket(crc5=crc5, **fields)
File "/usr/local/lib/python3.6/dist-packages/viewsb-0.0.1-py3.6.egg/viewsb/packet.py", line 72, in init
self.validate()
File "/usr/local/lib/python3.6/dist-packages/viewsb-0.0.1-py3.6.egg/viewsb/packet.py", line 284, in validate
self.direction = self.pid.direction().name
AttributeError: 'NoneType' object has no attribute 'name'

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.