Giter Site home page Giter Site logo

fb-messenger-sdk's Introduction

Facebook Messenger Bot PHP

Implementation of the Facebook Messenger Platform API.

Scrutinizer Code Quality Code Coverage Build Status

Still under development...

Install:

Via composer:

$ composer require tgallice/fb-messenger-sdk

Usage:

Create a Messenger instance

require_once __DIR__.'/vendor/autoload.php';

use Tgallice\FBMessenger\Client;
use Tgallice\FBMessenger\Messenger;

$client = new Client('<PAGE_TOKEN>');
$messenger = new Messenger($client);

// Or quick factory
$messenger = Messenger::create('<PAGE_TOKEN>');

Send a simple text message to a user:

require_once __DIR__.'/vendor/autoload.php';

use Tgallice\FBMessenger\Messenger;

$messenger = Messenger::create('<PAGE_TOKEN>');

// Simple Text message
$response = $messenger->sendMessage('<USER_ID>', 'My Message');

Send a message with quick replies

require_once __DIR__.'/vendor/autoload.php';

use Tgallice\FBMessenger\Messenger;
use Tgallice\FBMessenger\Model\Message;
use Tgallice\FBMessenger\Model\QuickReply\Text;

$messenger = Messenger::create('<PAGE_TOKEN>');

$message = new Message('What do you like ?');
$message->setQuickReplies([
    new Text('Apple', 'LIKE_APPLE_PAYLOAD'),
    new Text('Peach', 'LIKE_PEACH_PAYLOAD')
]);

$response = $messenger->sendMessage('<USER_ID>', $message);

Send a more complex message with a Generic template

Horizontal scrollable carousel of items

require_once __DIR__.'/vendor/autoload.php';

use Tgallice\FBMessenger\Messenger;
use Tgallice\FBMessenger\Model\DefaultAction;
use Tgallice\FBMessenger\Model\Button\Share;
use Tgallice\FBMessenger\Model\Button\WebUrl;
use Tgallice\FBMessenger\Model\Button\Postback;
use Tgallice\FBMessenger\Model\Attachment\Template\Generic;
use Tgallice\FBMessenger\Model\Attachment\Template\Generic\Element;

$messenger = Messenger::create('<PAGE_TOKEN>');

$elements = [
    new Element(
        'My first Item',
        'My first subtitle',
        'http://www.site.com/image.jpg',
        [ 
            new WebUrl('Button 1 label', 'https://www.site.com'),
            new Share()
        ],
        new DefaultAction('https://www.site.com/')
    ),
    new Element(
        'My second Item',
        'My second subtitle',
        'http://www.site.com/image.jpg',
        [ 
            new Postback('Button 2 label', 'MY_PAYLOAD'),
            new Share()
        ],
        new DefaultAction('https://www.domain.com/')
    )
];

$template = new Generic($elements);

$response = $messenger->sendMessage('<USER_ID>', $template);

Send a more complex message with a Receipt template

require_once __DIR__.'/vendor/autoload.php';

use Tgallice\FBMessenger\Messenger;
use Tgallice\FBMessenger\Model\Attachment\Template\Receipt;
use Tgallice\FBMessenger\Model\Attachment\Template\Receipt\Element;
use Tgallice\FBMessenger\Model\Attachment\Template\Receipt\Summary;

$messenger = Messenger::create('<PAGE_TOKEN>');

$elements = [
    new Element('My first Item', <price>),
    new Element('My Second Item', <price>),
];

$summary = new Summary(<total_cost>);
$receipt = new Receipt('My Receipt', '123456789', 'EUR', 'Visa', $elements, $summary);

$response = $messenger->sendMessage('<USER_ID>', $receipt);

Send a more complex message with a List template

Note: See the Facebook Messenger Platform List Template limitations.

require_once __DIR__.'/vendor/autoload.php';

use Tgallice\FBMessenger\Messenger;
use Tgallice\FBMessenger\Model\DefaultAction;
use Tgallice\FBMessenger\Model\Button\Share;
use Tgallice\FBMessenger\Model\Attachment\Template\ElementList;
use Tgallice\FBMessenger\Model\Attachment\Template\ElementList\Element;

$messenger = Messenger::create('<PAGE_TOKEN>');

$elements = [
    new Element(
        'My first Item',
        'My first subtitle',
        'http://www.site.com/image.jpg',
        new Share(),
        new DefaultAction('https://www.site.com/', DefaultAction::HEIGHT_RATIO_FULL)
    ),
    new Element(
        'My second Item',
        'My second subtitle',
        'http://www.site.com/image.jpg',
        new Share(),
        new DefaultAction('https://www.domain.com/', DefaultAction::HEIGHT_RATIO_COMPACT)
    )
];

// $elements = insert logic to meet List Template limitations (e.g. at least 2 elements and at most 4 elements)

$list = new ElementList($elements);

$response = $messenger->sendMessage('<USER_ID>', $list);

Buttons message

require_once __DIR__.'/vendor/autoload.php';

use Tgallice\FBMessenger\Model\Attachment\Template\Button;
use Tgallice\FBMessenger\Model\Button\WebUrl;
use Tgallice\FBMessenger\Model\Button\Postback;

$messenger = Messenger::create('<PAGE_TOKEN>');

$elements = [
    new WebUrl('Button1', 'http://google.com'),
    new Postback('Button2', 'EVENT_NAME'),
];

$template = new Button('My template', $elements);

$response = $messenger->sendMessage('<USER_ID>', $template);

Image Message

require_once __DIR__.'/vendor/autoload.php';

use Tgallice\FBMessenger\Messenger;
use Tgallice\FBMessenger\Model\Attachment\Image;

$messenger = Messenger::create('<PAGE_TOKEN>');

// Local file
$image = new Image('./image.jpg');
$response = $messenger->sendMessage('<USER_ID>', $image);

// Remote file
$image = new Image('http://www.site.com/image.jpg');
$response = $messenger->sendMessage('<USER_ID>', $image);

Get user profile

require_once __DIR__.'/vendor/autoload.php';

use Tgallice\FBMessenger\Client;
use Tgallice\FBMessenger\Messenger;

$messenger = Messenger::create('<PAGE_TOKEN>');

// $event may be PostbackEvent or MessageEvent
$profile = $messenger->getUserProfile($event->getSenderId());

echo $profile->getFirstName();
echo $profile->getLastName();
echo $profile->getGender();
echo $profile->getLocale();
...

// Result:
//
// John
// Doe
// male
// en_US

Set typing indicators or send read receipts

require_once __DIR__.'/vendor/autoload.php';

use Tgallice\FBMessenger\Client;
use Tgallice\FBMessenger\Messenger;

$messenger = Messenger::create('<PAGE_TOKEN>');

// Send read receipt indicating the user message has been received and "seen"
$messenger->setTypingStatus('<USER_ID>', \Tgallice\FBMessenger\TypingIndicator::MARK_SEEN);

// Turn on typing indicator to let users know you are processing their request
$messenger->setTypingStatus('<USER_ID>', \Tgallice\FBMessenger\TypingIndicator::TYPING_ON);

// Turn off typing indicator, e.g. after the user request has been finished processing
// and your response has been sent with $messenger->sendMessage()
$messenger->setTypingStatus('<USER_ID>', \Tgallice\FBMessenger\TypingIndicator::TYPING_OFF);

Webhook setup

When you setup a Callback URL in your app, Facebook need to validate this entry point. In this process you must define a Verify Token Your job is to compare the received verify token and the one you setup them return the challenge given. Here is how to easily handle the whole process:

require_once __DIR__.'/vendor/autoload.php';

use Tgallice\FBMessenger\WebhookRequestHandler;

$webookHandler = new WebhookRequestHandler('app_secret', 'verify_token');
// The Request is internally retrieve but you can set your own if you have already a Request object.
// $webookHandler = new WebhookRequestHandler('app_secret', 'verify_token', $request);


if (!$webookHandler->isValidVerifyTokenRequest()) {
    ...error
}

// you must return a 200 OK HTTP response 
header("HTTP/1.1 200 OK");

echo $webookHandler->getChallenge();

Webhook listening

We assume that we receive this payload from Facebook:

{
  "object": "page",
  "entry": [
    {
      "id": "PAGE_ID",
      "time": 1473204787206,
      "messaging": [
        {
          "sender":{
            "id":"USER_ID"
          },
          "recipient":{
            "id":"PAGE_ID"
          },
          "timestamp":1458692752478,
          "message":{
            "mid":"mid.1457764197618:41d102a3e1ae206a38",
            "seq":73,
            "text":"hello, world!",
            "quick_reply": {
              "payload": "DEVELOPER_DEFINED_PAYLOAD"
            }
          }
        }
      ]
    }
  ]
}

Basic usage

require_once __DIR__.'/vendor/autoload.php';

use Tgallice\FBMessenger\WebhookRequestHandler;

$webookHandler = new WebhookRequestHandler('app_secret', 'verify_token');
// The Request is internally retrieve but you can set your own if you have already a Request object.
// $webookHandler = new WebhookRequestHandler('app_secret', 'verify_token', $request);

if (!$webookHandler->isValidCallbackRequest()) {
    ...error
}

// @see https://developers.facebook.com/docs/messenger-platform/webhook-reference
// @var CallbackEvent[] $events
$events = $webookHandler->getAllCallbackEvents();

foreach($events as $event) {
    if ($event instanceof MessageEvent) {
          echo $event->getMessageText()."\n";
          echo $event->getQuickReplyPayload()."\n";
    }
}

// Result:
//
// hello, world!
// DEVELOPER_DEFINED_PAYLOAD

// you must return a 200 OK HTTP response 

Advanced usage

require_once __DIR__.'/vendor/autoload.php';

use Tgallice\FBMessenger\WebhookRequestHandler;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Tgallice\FBMessenger\Callback\MessageEvent;

// We use the symfony/event-dispatcher package
// @see https://github.com/symfony/event-dispatcher for more details
// Create custom event listener
class MessageEventListener implements EventSubscriberInterface
{
    public static function getSubscribedEvents()
    {
        return [
            MessageEvent::NAME => 'onMessageEvent', // may also handle quick replies by checking with isQuickReply()
            PostbackEvent::NAME => 'onPostbackEvent',
            'DEVELOPER_DEFINED_PAYLOAD_1' => 'onQuickReply' // optional: quick reply specific payload
        ];
    }

    public function onMessageEvent(MessageEvent $event)
    {
        if( $event->isQuickReply() ) { // if a quick reply callback, pass it to our onQuickReply method
            $this->onQuickReply($event);
            return;
        }
		
        print(__METHOD__."\n");
    }

    public function onPostbackEvent(PostbackEvent $event)
    {
        print(__METHOD__."\n");
    }

    public function onQuickReply(MessageEvent $event)
    {
        switch( $event->getQuickReplyPayload() ) {
            case 'DEVELOPER_DEFINED_PAYLOAD_2':
                print(__METHOD__."\n");
                break;
        }
    }
}

$webhookHandler = new WebhookRequestHandler('<APP_SECRET>', '<VERIFY_TOKEN>');

// Register the listener
$webhook->addEventSubscriber(new MessageEventListener());

if (!$webookHandler->isValidCallbackRequest()) {
    ...error
}

$webhook->dispatchCallbackEvents();

// Result:
//
// MessageEventListener::onMessageEvent
// MessageEventListener::onPostbackEvent
// MessageEventListener::onQuickReply


// you must return a 200 OK HTTP response 

Thread Settings

Set greeting text

require_once __DIR__.'/vendor/autoload.php';

use Tgallice\FBMessenger\Messenger;

$messenger = Messenger::create('<PAGE_TOKEN>');
$messenger->setGreetingText('Tell me what you want.');

Set started button

require_once __DIR__.'/vendor/autoload.php';

use Tgallice\FBMessenger\Messenger;

$messenger = Messenger::create('<PAGE_TOKEN>');
$messenger->setStartedButton('MY_PLAYLOAD_TO_TRIGGER');

Set a Persistent Menu

require_once __DIR__.'/vendor/autoload.php';

use Tgallice\FBMessenger\Messenger;
use Tgallice\FBMessenger\Model\ThreadSetting\PostBack;
use Tgallice\FBMessenger\Model\ThreadSetting\WebUrl;

$messenger = Messenger::create('<PAGE_TOKEN>');

$buttons = [
    new PostBack('Button Title 1', 'MY_PAYLOAD'),      
    new WebUrl('Button Title 2', 'http://my-url.com'),      
];

$messenger->setPersistentMenu($buttons);

Page action

Subscribe bot to a page

require_once __DIR__.'/vendor/autoload.php';

use Tgallice\FBMessenger\Messenger;

$messenger = Messenger::create('<PAGE_TOKEN>');
$messenger->subscribe();

And more other cool things...

Todo

  • Improve document
  • Add Airline template

fb-messenger-sdk's People

Contributors

66mm avatar guilebc avatar guillaumecarburant avatar jonkofee avatar ksimka avatar oliverschloebe avatar sattip avatar shaked avatar tgallice 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

Watchers

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

fb-messenger-sdk's Issues

Generic Template

How to send Generic Template?

use Tgallice\FBMessenger\Messenger;
use Tgallice\FBMessenger\Model\Button\Postback;
use Tgallice\FBMessenger\Model\Attachment\Template\Generic\Element;

$messenger = Messenger::create($token);

$elements = [
    new Postback('Start', 'event_start'),
    new Postback('Late', 'event_late'),
];
$generic = new Element('This is name');
$generic->setSubtitle('This is subtitle');
$generic->setItemUrl('This is url');
$generic->setImageUrl('This is image');
$generic->setButtons($elements);
$generic = $generic->jsonSerialize();

$template = new \Tgallice\FBMessenger\Model\Attachment\Template\Generic($generic);
$response = $messenger->sendMessage('807305902705297', $template);

Error:
(#100) Incomplete element data: title and at least one other field (image url, subtitle or buttons) (truncated...)

List template?

Hi,

first off, thanks for your highly useful SDK! Helped me get a bot up and running real quick. :)

Are there any plans to include the new list template anytime soon?

Thank you!
Oliver

Carousel cards

@tgallice Please give an example of how to add a carousel cards. I also tried to add a Simple Card with an image , title and button ( This will open url) , but not able to do that. can we eliminate Share button from the card?

Option to send a message to multiple user at a time

Hello there!

Is there any way we can send a message to multiple users in a single shot(batch send)?

require_once __DIR__.'/vendor/autoload.php';
use Tgallice\FBMessenger\Messenger;
$messenger = Messenger::create('<PAGE_TOKEN>');
// Simple Text message
$response = $messenger->sendMessage('<USER_ID>', 'My Message');

something like below,

require_once __DIR__.'/vendor/autoload.php';
use Tgallice\FBMessenger\Messenger;
$messenger = Messenger::create('<PAGE_TOKEN>');
// Simple Text message
$user_id_array = array(<USER1_ID>, <USER2_ID>);
$response = $messenger->sendMessage($user_id_array, 'My Message');

Any ideas really appreciated.

Thanks in advance!

Basic use fails: Call to undefined method Tgallice\FBMessenger\Messenger::create()

When I attempt to use this library I get a failure at step 1.
I'm correctly using autoloading and composer, and have installed this library according to instructions.
I am using the correct libraries at the beginning of my class, but when I try to make a basic request I get:

use Tgallice\FBMessenger\Client;
use Tgallice\FBMessenger\Messenger;

Then I do (where FB_PAGE_TOKEN is a valid token):

$messenger = Messenger::create(FB_PAGE_TOKEN);

And I get:

"Fatal error: Call to undefined method Tgallice\FBMessenger\Messenger::create()".

Is the documentation correct?

Multiple buttons

Hi
How do I create multiple buttons to be sent back to user?

$elements = [new WebUrl(array('Welcome' => 'https://gastric.care/hub/welcome/', 'HUB'=>'https://gastric.care/HUB')),

This does not help

Any help is appreciated. Thank you

Customer Chat Plugin

If you use the Customer Chat Plugin, the webhook receives the following request:

{
    "object": "page",
    "entry": [
        {
            "id": "2069909786624299",
            "time": 1530546166693,
            "messaging": [
                {
                    "recipient": {
                        "id": "2069909786624299"
                    },
                    "timestamp": 1530546166693,
                    "sender": {
                        "id": "1945995005475228"
                    },
                    "postback": {
                        "payload": "Start@menu",
                        "referral": {
                            "source": "CUSTOMER_CHAT_PLUGIN"
                        },
                        "title": "Menu"
                    }
                }
            ]
        }
    ]
}

The object referral contains only one element source and this causes an error:
Undefined index: ref at ... vendor/tgallice/fb-messenger-sdk/src/Model/Callback/Referral.php:65

Need to make changes in the Tgallice\FBMessenger\Model\Callback\Referral class:

public static function create(array $payload)
{
    $ref = $payload['ref'] ?? null;
    $source = $payload['source'] ?? null;
    $type = $payload['type'] ?? null;

    return new static($ref, $source, $type);
}

Messenger::create

sendMessage('865714890196550', 'My Message'); Error: Fatal error: Uncaught Error: Call to undefined method Tgallice\FBMessenger\Messenger::create() in

Bump version to match example

hi,

if release can get tagged with 0.1.1, it matches the example. the current (dev-)master seems stable enough.

thanks!

The last_ad_referral and is_payment_enabled fields are now deprecated

Whe the application try to get the user profile information request the "is_payment_enabled" but this is field are now deprecated. How or where can I deactivate this field in the request?

GET https://graph.facebook.com/2126650607351131?fields=first_name%2Clast_name%2Cprofile_pic%2Clocale%2Ctimezone%2Cgender%2Cis_payment_enabled&access_token=resulted in a400 Bad Request` response: {"error":{"message":"(#100) The last_ad_referral and is_payment_enabled fields are now deprecated. Please refer to our D (truncated...)

{
    "error": {
        "message": "(#100) The last_ad_referral and is_payment_enabled fields are now deprecated. Please refer to our Developer Document for more info.",
        "type": "OAuthException",
        "code": 100,
        "error_subcode": 2018254,
        "fbtrace_id": "F1E6yZfYqya"
    }
}

Generic Template - Add "image_aspect_ratio"

Hi. It's possible to add on Payload Object the property "image_aspect_ratio"?
Generic Template

Current, i have workaround this by editing the "tgallice\fb-messenger-sdk\src\Model\Attachment\Template\Generic.php", line 53 and adding

'image_aspect_ratio' => 'square',

[1.0] Todo list

  • Add Airline template
  • Add Sender actions
  • Handle Account linking
  • Handle webhook (partial)
  • Handle Payment Webhook
  • Apply php-cs-fixer

CallbackEvent dispatcher

This issue is related to the discution with @kormid about to dispatch callback events.

Here is my implementation throught:

Use the symfony/event-dispatcher package to avoid building a custom event-dispatcher
Here is the doc about it : https://symfony.com/doc/current/components/event_dispatcher.html

Make CallbackEvent extends Symfony\Component\EventDispatcher\Event

use Symfony\Component\EventDispatcher\Event;

abstract class CallbackEvent extends Event
{
...
}

Add a dispatcher in WebhookRequestHandler

    /**
     * @var EventDispatcherInterface
     */
    private $dispatcher;

    public function __construct($secret, $verifyToken, ServerRequestInterface $request = null, EventDispatcherInterface $dispatcher = null)
    {
        ...
        $this->dispatcher = $dispatcher ?! new EventDispatcher();
    }

    public function dispatchCallbackEvents()
    {
        foreach ($this->getAllCallbackEvents() as $event) {
            // Dispatch callback event based on the CallbackEvent::NAME
            $this->dispatcher->dispatch($event->getName(), $event);

            if ($event instanceof PostbackEvent) {
                // Dispatch postback payload event
                $this->dispatcher->dispatch($event->getPostback(), $event);
            }

            if ($event instanceof Message && $event->hasQuickReply()) {
                // Dispatch quick reply payload event
                $this->dispatcher->dispatch($event->getQuickReplyPayload(), $event);
            }
        }
    }

    /**
     * @param EventSubscriberInterface $subscriber
     */
    public function addEventSubscriber(EventSubscriberInterface $subscriber)
    {
        $this->dispatcher->addSubscriber($subscriber);
    }

This need to edit #19 to rename CallbackEvent::TYPE and CallbackEvent::getType() to CallbackEvent::NAME and CallbackEvent::getName()

How to use it

// Create subscriber 
class myCustomSubscriber implements EventSubscriberInterface {
    public static function getSubscribedEvents()
    {
         return [
             MessageEvent::NAME => 'myCustomFunction',
         ];
    }
    public function myCustomFunction(MessageEvent $event)
    {
      ....
    }
}

$myCustomSubscriber = new myCustomSubscriber();

$webhookRequestHandler = new WebhookRequestHandler(...);
$webhookRequestHandler->addEventSubscriber($myCustomSubscriber);

if ($webhookRequestHandler->isValid()) {
    $webhookRequestHandler->dispatchCallbackEvents();
}

@kormid what do you think about it ? It's the almost the same than yours but which a more general purpose.

Parameter must be an array or an object

Hello!
Help me, please.
I use "tgallice/fb-messenger-sdk": "1.0.x-dev"
PHP 7.2.5

Psy Shell v0.9.4 (PHP 7.2.5 โ€” cli) by Justin Hileman
>>> $message = new \Tgallice\FBMessenger\Model\Message(__('facebook.branch_choose_menu'));
=> Tgallice\FBMessenger\Model\Message {#2508}
>>> $message->addQuickReply(new \Tgallice\FBMessenger\Model\QuickReply\Text(__('facebook.catalog_branches'), 'Branch@selectCity'));
PHP Warning:  count(): Parameter must be an array or an object that implements Countable in /var/www/chtbt/current/vendor/tgallice/fb-messenger-sdk/src/Model/Message.php on line 98
>>>

Typing indicator is missing

Hey,

I hope I am just missing something, but it seems that it is impossible to send a typing indicator without having a Message object.

The whole idea of the typing indicator is to show the user that something is happening while the message is being generated. This feature might be valuable before a message is going to be sent, e.g when the backend of the bot is doing some processing but wants to show the user that something is happening and they should wait.

What do you think?

Thank you
Shaked

installation error

[InvalidArgumentException]
Could not find package tgallice/fb-messenger-sdk at any version for your minimum-stability (stable). Check the pa
ckage spelling or your minimum-stability

Could you please also improve the doc file?

How to add Quick Reply by values returned in SQL Query

Thank you for this awesome SDK.

I am wondering how do I add quick reply by the values returned in SQL query, so instead of defining a predefined values in Quick Reply like you have in Example:

$message->setQuickReplies([
new Text('Apple', 'LIKE_APPLE_PAYLOAD'),
new Text('Peach', 'LIKE_PEACH_PAYLOAD')
]);

Can I use SQL query run a loop and add quick replies?

I am new to PHP and cannot figure out how to do this. Thank you

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.