GithubHelp home page GithubHelp logo

lahell / psdiscoveryprotocol Goto Github PK

View Code? Open in Web Editor NEW
143.0 6.0 27.0 64 KB

Capture and parse CDP and LLDP packets on local or remote computers

License: MIT License

PowerShell 100.00%
cdp lldp capture parse packet etw cisco powershell

psdiscoveryprotocol's Introduction

PowerShell Gallery Version PowerShell Gallery GitHub

PSDiscoveryProtocol

Capture and parse CDP and LLDP packets on local or remote computers

CDP and LLDP

PSDiscoveryProtocol does not return all information available in CDP and LLDP packets. If you want to know what information is available use Export-Pcap and open the pcap file in Wireshark or another tool with a more complete implementation.

Installation

Install-Module -Name PSDiscoveryProtocol

SCCM Hardware Inventory

PSDiscoveryProtocol can add port information to SCCM Hardware Inventory on your Windows 10 clients.

Take a look here for details: PSDiscoveryProtocol-SCCM-HWInventory

Usage

On this page you will find a few examples of how to use this module.

For more examples please read help:

Get-Help -Name Invoke-DiscoveryProtocolCapture -Full
Get-Help -Name Get-DiscoveryProtocolData -Full
Get-Help -Name Export-Pcap -Full

Capture and parse LLDP on local computer

$Packet = Invoke-DiscoveryProtocolCapture -Type LLDP
Get-DiscoveryProtocolData -Packet $Packet

Output

Model       : WS-C2960-48TT-L
Description : HR Workstation
VLAN        : 10
Port        : Fa0/1
Device      : SWITCH1.domain.example
IPAddress   : 192.0.2.10
Computer    : COMPUTER1.domain.example
Type        : LLDP

Capture and parse CDP on remote computers

'COMPUTER1', 'COMPUTER2' | Invoke-DiscoveryProtocolCapture -Type CDP | Get-DiscoveryProtocolData

Output

Port      : FastEthernet0/1
Device    : SWITCH1.domain.example
Model     : cisco WS-C2960-48TT-L
IPAddress : 192.0.2.10
VLAN      : 10
Computer  : COMPUTER1.domain.example
Type      : CDP

Port      : FastEthernet0/2
Device    : SWITCH1.domain.example
Model     : cisco WS-C2960-48TT-L
IPAddress : 192.0.2.10
VLAN      : 20
Computer  : COMPUTER2.domain.example
Type      : CDP

Capture on remote computers and export to pcap

'COMPUTER1', 'COMPUTER2' | Invoke-DiscoveryProtocolCapture | Export-Pcap -Path packets.pcap

Speed up capturing in PowerShell 7

By leveraging the new -Parallel parameter on ForEach-Object we can capture simultaneously on multiple computers.

#Requires -Version 7
'COMPUTER1', 'COMPUTER2', 'COMPUTER3' | ForEach-Object -Parallel {
    Invoke-DiscoveryProtocolCapture -ComputerName $_ | Get-DiscoveryProtocolData
}

psdiscoveryprotocol's People

Contributors

borntoberoot avatar jeffjerousek avatar lahell 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

psdiscoveryprotocol's Issues

Set NIC for Invoke-DiscoveryProtocolCapture? No discovery protocol packets captured

Hi,

I'm searching for a scriptable solution to get LLDP and CDP-Infos on Windows Servers - after some searching I found your PSDiscoveryProtocol-Project.

I tried it on a Windows Server 2022 Standard hardware-machine.
LLDP is active on the switches (with LDWin or pktmon [https://alanjmcf.wordpress.com/2022/04/15/lldp-cdp-on-windows-with-no-extra-software/] I get a result).

With your PSDiscovery-module:

$Packet = Invoke-DiscoveryProtocolCapture -Type LLDP (tried Duration from 30sec to 600sec)

WARNING: No discovery protocol packets captured on XXX in <$Duration> seconds.

Get-DiscoveryProtocolData -Packet $Packet

Get-DiscoveryProtocolData : Cannot bind argument to parameter 'Packet' because it is null.

I have some more Ethernet-Cards in this server (some are active and some not).

Is there an option for "Invoke-DiscoveryProtocolCapture" to set a specific Ethernet-Card?
Is this only for clients (like Windows 10 etc.) and have trouble with Windows-Server-OS in general?

Kind regards,
Sebastian

Different results when computer is plugged in through the phone

Half of our computers are plugged directly into the wall, while half are passed through a phone (only one jack available). When I run the invoke-discoveryprotocolcapture, with get-discoveryprotocol on a computer that is passed through a phone, I will sometimes get the phone info, and sometimes get the switch that the phone is plugged into. Is there a way to ignore the phone and always get the switch?

IPAddress returns gateway IP, not actual IP

I have been testing this in an environment with many servers having multiple LACP Team adapters, mixed with standard network adapters. When I run 'servername' | Invoke-DiscoveryProtocolCapture -Type CDP | Get-DiscoveryProtocolData, the IPAddress returned for each connection is the gateway, not the actual IP Address.

For example, I might get 10.34.83.254 (gateway) instead of 10.34.83.24 (actual IP Address)

Need Some Help

Could you please upload a sample etl file containing LLDP\CDL Packat
Thank you

Suggestion to avoid p-mode switch available only in some editions of 2012 R2+

Windows Server 2012 R2 needs to be patched to allow this syntax (and there's no patch for lower OS):

Add-NetEventNetworkAdapter -Name $Adapter.Name -PromiscuousMode

There is a workaround for this and lower operating systems though. You can wrap all of the packet tracing calls with some code that opens a raw, random network socket, and listens to all. Then close it once you're done. This flips the network adapter into p-mode.

    $addresses = $adapter | Get-NetIPInterface | Get-NetIPAddress
    $address = $addresses.IPAddress | Select-Object -First 1
    "Processing adapter [$($adapter.Name)] with IP address [$address]"

    $byteIn = [BitConverter]::GetBytes(1)
    $byteOut = [BitConverter]::GetBytes(0)
    
    $socket = New-Object System.Net.Sockets.Socket([Net.Sockets.AddressFamily]::InterNetwork, [Net.Sockets.SocketType]::Raw, [Net.Sockets.ProtocolType]::IP)
    $endpoint = New-Object System.Net.IPEndpoint([Net.IPAddress] $address, 0)
    $socket.Bind($endpoint)
    [void] $socket.IOControl([Net.Sockets.IOControlCode]::ReceiveAll, $byteIn, $byteOut)

... Then do the above without -PromiscuousMode, do the rest of the capture, and close it, then clean up ...

    $socket.Close()

I'm not sure if you would like to incorporate that as an alternate code path if that parameter is detected as not existing, but if not, at least this will show up for anyone else who needs it and wants to hack it in.

Great project btw, really amazing.

Ability to display NIC Port

Hello, thank you for this awesome project!

Would it be possible to add information what pNIC is connected to where? Assuming I have multiple NICs connected to different switches/switch ports.

THX!

PSDiscoveryProtocol not working with NetAdapter Team Members

Hi,

I've been trying to get LLDP or CDP Data for NICs that a part of a team, however it only returns data for the virtual NIC on the team itself (where I would not expect data at all), not for the actual physical team members (where I would expect data).
This seems to come from the fact that NetEventSession isn't returning any events for the physical team members. I tried all combinations of the switches it has but can't seem to capture data for it.
Wireshark for example captures the data just fine, same for LDWin (which uses tcpdump.exe), but NetEventSession doesn't see it.

Do you got any idea? I've tested it on a bunch of servers with the normal Lbfo Teams and the new Hyper-V Switch Embedded Teams but none of them seems to capture data for the underlying NICs.

Method 'where' not found

is this the intended behavior ?

Method invocation failed because [Microsoft.Management.Infrastructure.CimInstance] does not contain a method named
'Where'.
At C:\Program Files\WindowsPowerShell\Modules\PSDiscoveryProtocol\1.4.0\PSDiscoveryProtocol.psm1:360 char:25
+ ...             $Adapter = (Get-NetAdapter -Physical).Where({ $_.Interfac ...
+                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (Where:String) [], RuntimeException
    + FullyQualifiedErrorId : MethodNotFound

WARNING: No discovery protocol packets captured on WDS2019 in 32 seconds.

No discover protocol packets captured even other tools work on this host.

Hello,
first of all. THANK YOU for sharing!

fFor some reasons it doesn't work on every Server.
I have for example 2 Windows Server with multiple NW Cards and it don't work for some.
Even other tools are capable to read the LLDP Infos.

image

Any ideas, how we could find out the root cause together?

Incomplete data displayed

Hi,

I've noticed that the IP Address property is not being displayed, if the CDP neighbor is an IP phone.
In "CaptureCDP" module, it was showing up. Screenshot below.
Is there a way to get that back?

image

If the CDP neighbor is a switch, the IP address is showing up fine.

Some computers do not capture CDP Info when its there

Below shows the results of trying to capture CDP info and its failing on all interfaces for particular servers.

PS C:\Windows\system32> Invoke-DiscoveryProtocolCapture -NoCleanup -Verbose
VERBOSE: ParameterSetName: LocalCapture
VERBOSE: TargetComputer: SERVERNAME
VERBOSE: ETLFilePath: C:\Users\Username\AppData\Local\Temp\tmp201.etl
VERBOSE: Found file c:\users\Username\appdata\local\temp\tmp201.etl
WARNING: No discovery protocol packets captured on SERVERNAME in 62 seconds.

PS C:\Windows\system32> 

If I run Wireshark the CDP packets are there:
CDP Packets Example

If I try to run etl2pcapng.exe on the tmp201.etl file to convert it to Wireshark format, it errors out with "Opentrace failed with 2"

However, if I capture my own packets:

netsh trace start capture=yes IPv4.Address=10.70.65.209 tracefile=C:\Users\Username\AppData\Local\Temp\Trace.etl

Then wait 60+ seconds and stop the trace, I can convert the etl file to a pcapng file and I can open it in Wireshark and see the packets.

Hoping I might be able to help resolve why these captures fail on some servers, but not others. Clearly, the packets are there and they can be captured.

Limit of Single Device per LLDP Discovery

The tool doesn't seem to provide support for multiple LLDP packets being recivied on the same interface. I have a ethernet interface that is connected to a switch. I can see in wireshark that 2 LLDP messages are being recieved, one for a managed switch and one for a device on a unmanaged switch that sits between the computer and the managed switch see below for an illustration of the layout. What I end up seeing is just device on that ethernet interface, I do notice that the LLDP message for device arrives before managed sw.

[ computer ] - - - - -\
                [unmanaged sw] - - - - - [managed sw]
[ device ] - - - - - -/

Importing module gives warning about unapproved verbs

Importing this module gives the following warning:

WARNING: The names of some imported commands from the module 'PSDiscoveryProtocol' include unapproved verbs that might make them less discoverable. To find the commands with
 unapproved verbs, run the Import-Module command again with the Verbose parameter. For a list of approved verbs, type Get-Verb.

Will consider using Invoke and Get instead of Capture and Parse.

Please add Software (contains version) to ConvertFrom-CDPPacket. Its the software running on the connected Cisco device.

Only need to modify this:
$Tlv = @{
0x0001 = 'Device'
0x0002 = 'IPAddress'
0x0003 = 'Port'
0x0006 = 'Model'
0x000A = 'VLAN'
0x0016 = 'Management'
}

$TypeString = 0x0001, 0x003, 0x006

to This:
$Tlv = @{
0x0001 = 'Device'
0x0002 = 'IPAddress'
0x0003 = 'Port'
0x0005 = 'Software'
0x0006 = 'Model'
0x000A = 'VLAN'
0x0016 = 'Management'
}

$TypeString = 0x0001, 0x003, 0x005, 0x006

Tested... works great!

New-TemporaryFile not recognized as the name of a cmdlet, function,....

I'm working on a script to wrap around PSDiscoveryProtocol allowing for credentials, user input, local/remote host options, etc. The issue I'm finding is that when piping a hostname into Invoke-DiscoveryProtocolCapture, it errors out claiming New-TemporaryFile is not a valid cmdlet, function, etc...

The way I have the logic laid out, it works perfectly fine with:
Invoke-DiscoveryProtocolCapture -Force -Type LLDP | Get-DiscoveryProtocolData | Select-Object Computer,Device,Port,PortDescription,VLAN,IPAddress | Out-File $global:sLogFile -Append -Encoding UTF8

But will break if piped into:
$hostname | Invoke-DiscoveryProtocolCapture -Force -Credential $cred -Type LLDP | Get-DiscoveryProtocolData | Select-Object Computer,Device,Port,PortDescription,VLAN,IPAddress | Out-File $global:sLogFile -Append -Encoding UTF8

The entire function in question is as follows. I believe it has something to do with $ETLFilePath within the module.

Function Get-SwitchPort{
    Param(
        [string]$hostname = $env:COMPUTERNAME
    )
    Begin{
        $defaultEnabled = 0
        Write-LogInfo -LogPath $global:sLogFile -Message "Starting on [$hostname]"
        if (!(Test-WSMan $hostname -ErrorAction SilentlyContinue)) { # If WinRM not Enabled
            if (Toggle-WinRM $hostname) {                        # Enable WinRM and log it
                Write-LogInfo -LogPath $global:sLogFile -Message "WinRM enabled on [$hostname]"
            }
        } else {
            $defaultEnabled = 1                                          # WinRM enabled by default. Change $var to match.
            Write-LogInfo -LogPath $global:sLogFile -Message "WinRM already enabled on [$hostname]"
        }
    }
    Process{
            $slashHostname = "\\$hostname"
            $hostname = $slashHostname.Substring(2)
        Try{
            if($local){
                Invoke-DiscoveryProtocolCapture -Force -Type LLDP | Get-DiscoveryProtocolData | Select-Object Computer,Device,Port,PortDescription,VLAN,IPAddress | Out-File $global:sLogFile -Append -Encoding UTF8
            }
            else{
                Write-Host "Hostname: $hostname"
                $hostname | Invoke-DiscoveryProtocolCapture -Force -Credential $cred -Type LLDP | Get-DiscoveryProtocolData | Select-Object Computer,Device,Port,PortDescription,VLAN,IPAddress | Out-File $global:sLogFile -Append -Encoding UTF8
            }
            Start-Sleep 1

            Write-LogInfo -LogPath $global:sLogFile -Message "Port information grabbed for [$hostname]"
            Write-LogInfo -LogPath $global:sLogFile -Message " "
        }
        Catch{
            Write-LogWarning -LogPath $global:sLogFile -Message "Failed to grab port information for [$hostname]"
            Write-LogWarning -LogPath $global:sLogFile -Message " "
            Write-LogError -LogPath $global:sLogFile -Message $_.Exception -ExitGracefully $True
        }
    }
    End{
        If ($defaultEnabled -eq 0){
            if(!(Toggle-WinRM $hostname)){
                Write-LogInfo -LogPath $global:sLogFile -Message "WinRM disabled on [$hostname]"
            }
        }
    }
}

Perhaps also collect Network IP Settings while collecting CDP Info?

Most people I know would simultaneously want the IP Settings for the network adapters along with the CDP/LLDP info. For example, when adapters are in a team, the CDP/LLDP info relates to the adapters that are members of each respective team, but the Team adapters don't actually connect to any devices. The IP settings are either on a standard network adapter (no teaming), or the IP settings are set/applied on the Team adapters. CDP info should NOT be collected for a Team adapter (doesn't directly connect to anything).
IMHO: IP Settings should be collected at the same time, but in a different array.

In addition, if there are many servers to remotely access, it would be more proficient to use the same remote session to collect adapter IP settings. More reasoning to add this capability - get both at once.

The code below provides an example of what I am suggesting and collects the network adapter IP info needed. If it were to be added to your code, I would suggest outputting results in two arrays contained on one parent object:

CDPAdapters (adapters physically connected to devices - what is collected now), and
NetworkAdapters (IP settings of adapters - standard and Team adapters)

Example code to collect IP Info:

$teams = get-netlbfoteam
    $hostname = Hostname
    [array]$teamsInfo = @()
    foreach ($team in $teams) {      
        $name = $team.name
        $mode = $team.TeamingMode.ToString()
        $members = $team.members -join "`n"
        $nics = $team.TeamNics
        $vlanID = ($team | get-netlbfoteamnic).VlanID
        if ($null -eq $vlanID) { $vlanID = "No tag specified" }

        $obj = [pscustomobject]@{
            "Hostname"       = $hostname
            "TeamName"       = $name
            "TeamingMode"    = $mode
            "Members"        = $members
            "VirtualNicName" = $nics
            "VlanID"         = $vlanID
        }    
        $teamsInfo += $obj
    }
    $networkInfo = @()
    $networks = Get-NetAdapter 
    foreach ($network in $networks) {
        $ipInfo = Get-CIMInstance -Classname Win32_NetworkAdapterConfiguration | ? {$_.SettingId -eq $network.InterfaceGuid}

        if($ipInfo.IpAddress) {$IPAddress = $ipInfo.IpAddress[0]} else {$IPAddress = "Not Assigned"}
        if($ipInfo.IPSubnet) {$SubnetMask = $ipInfo.IPSubnet[0]} else {$SubnetMask = "Not Assigned"}
        $WINS1 = $ipInfo.WINSPrimaryServer
        $WINS2 = $ipInfo.WINSSecondaryServer   
        if ($null -ne $WINS1 -and $null -ne $WINS2) {$WINS = @($WINS1,$WINS2)} elseif($null -ne $WINS1) {$WINS = $WINS1} elseif($null -ne $WINS2){$WINS = $WINS2} else {$WINS = ""}             
        $IsDHCPEnabled = $false
        If($ipInfo.DHCPEnabled) {
            $IsDHCPEnabled = $true
        }

        if($teamsInfo -and $teamsInfo.Count -gt 0) {
            $matchingTeam = $teamsInfo | Where-Object {$_.VirtualNicName -eq $network.Name}

            if($matchingTeam) {
                $teamName     = $matchingTeam.TeamName
                $teamingMode  = $matchingTeam.TeamingMode
                $members      = $matchingTeam.Members
                $vlanID       = $matchingTeam.VlanID
            } else {
                $teamName     = "Not in a Team"
                $teamingMode  = "None"
                $members      = $null
                $vlanID       = $null
            }

        } else {
            $teamName     = "Not in a Team"
            $teamingMode  = "None"
            $members      = $null
            $vlanID       = $null
        }

        $ipV4enabled = (Get-NetAdapterBinding -Name $network.Name -ComponentID ms_tcpip).Enabled
        $ipV6enabled = (Get-NetAdapterBinding -Name $network.Name -ComponentID ms_tcpip6).Enabled

        $obj  = New-Object -Type PSObject
        $obj | Add-Member -MemberType NoteProperty -Name Hostname -Value $hostname
        $obj | Add-Member -MemberType NoteProperty -Name Name -Value $network.Name
        $obj | Add-Member -MemberType NoteProperty -Name SystemName -Value $network.SystemName
        $obj | Add-Member -MemberType NoteProperty -Name Description -Value $network.ifDesc
        $obj | Add-Member -MemberType NoteProperty -Name TeamName -Value $teamName
        $obj | Add-Member -MemberType NoteProperty -Name TeamingMode -Value  $teamingMode
        $obj | Add-Member -MemberType NoteProperty -Name Members -Value $members
        $obj | Add-Member -MemberType NoteProperty -Name Virtual -Value $network.Virtual
        $obj | Add-Member -MemberType NoteProperty -Name TeamVlanID -Value $vlanID
        $obj | Add-Member -MemberType NoteProperty -Name VlanID -Value $network.VlanID  
        $obj | Add-Member -MemberType NoteProperty -Name IPEnabled -Value $ipInfo.IPEnabled
        $obj | Add-Member -MemberType NoteProperty -Name IpV4enabled -Value $ipV4enabled
        $obj | Add-Member -MemberType NoteProperty -Name IpV6enabled -Value $ipV6enabled
        $obj | Add-Member -MemberType NoteProperty -Name IPAddress -Value $IPAddress
        $obj | Add-Member -MemberType NoteProperty -Name SubnetMask -Value $SubnetMask
        $obj | Add-Member -MemberType NoteProperty -Name Gateway -Value ($ipInfo.DefaultIPGateway -join ",") 
        $obj | Add-Member -MemberType NoteProperty -Name DNSDomainSuffixSearchOrder -Value ($ipInfo.DNSDomainSuffixSearchOrder -join ",")
        $obj | Add-Member -MemberType NoteProperty -Name DHCPEnabled -Value $IsDHCPEnabled
        $obj | Add-Member -MemberType NoteProperty -Name DHCPLeaseExpires -Value $ipInfo.DHCPLeaseExpires
        $obj | Add-Member -MemberType NoteProperty -Name DNSServers -Value ($ipInfo.DNSServerSearchOrder -join ",")     
        $obj | Add-Member -MemberType NoteProperty -Name WINSServers -Value  $WINS  
        $obj | Add-Member -MemberType NoteProperty -Name MACAddress -Value $network.MACAddress
        $obj | Add-Member -MemberType NoteProperty -Name LinkSpeed -Value $network.LinkSpeed
        $obj | Add-Member -MemberType NoteProperty -Name Status -Value $network.Status
        $obj | Add-Member -MemberType NoteProperty -Name AdminStatus -Value $network.AdminStatus
        $obj | Add-Member -MemberType NoteProperty -Name ifOperStatus -Value $network.ifOperStatus  
        $obj | Add-Member -MemberType NoteProperty -Name MediaType -Value $network.MediaType
        $obj | Add-Member -MemberType NoteProperty -Name DriverVersion -Value $network.DriverVersion
        $obj | Add-Member -MemberType NoteProperty -Name DriverVersionString -Value $network.DriverVersionString
        $obj | Add-Member -MemberType NoteProperty -Name DriverInformation -Value $network.DriverInformation
        $obj | Add-Member -MemberType NoteProperty -Name DriverFileName -Value $network.DriverFileName
        $obj | Add-Member -MemberType NoteProperty -Name DriverName -Value $network.DriverName
        $obj | Add-Member -MemberType NoteProperty -Name DriverDate -Value $network.DriverDate
        $obj | Add-Member -MemberType NoteProperty -Name InterfaceGuid -Value $network.InterfaceGuid
        $obj | Add-Member -MemberType NoteProperty -Name MtuSize -Value $network.MtuSize
        $obj | Add-Member -MemberType NoteProperty -Name ActiveMaximumTransmissionUnit -Value $network.ActiveMaximumTransmissionUnit
        $obj | Add-Member -MemberType NoteProperty -Name iSCSIInterface -Value $network.iSCSIInterface

      $networkInfo += $obj
    }

LLDP - Add system description

Hi,

image

Some systems provide a system description and a port description.

image

Maybe change this to:

SystemDescription
PortDescription

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.