Coder Social home page Coder Social logo

hatena-bookmark-ios-sdk's Introduction

Hatena Bookmark iOS SDK

travis-ci

Integrate Hatena Bookmark into your application. This is an Objective-C library for handling the Hatena Bookmark API and for providing a user interface.

Main Screenshot

Install

CocoaPods

Add the lines below to your Podfile.

platform :ios, '5.0'

pod 'HatenaBookmarkSDK'

Without CocoaPods

Clone this repository.

git clone --recursive https://github.com/hatena/Hatena-Bookmark-iOS-SDK.git

Copy /SDK/ directory and add dependent modules SFHFKeychainUtils to your project .

Usage

Register OAuth

Register your app information at Hatena Developer Center. This SDK needs all scope, read_public, read_private, write_public, write_private.

Scope Settings

After registration, you will get a consumer key and a consumer secret.

Consumer Key and Consumer Secret

Initialize

At first SDK needs initialization with consumer key and secret. You should add below initalization code at application:didFinishLaunchingWithOptions: or other initalize section.

[[HTBHatenaBookmarkManager sharedManager] setConsumerKey:@"your consumer key" consumerSecret:@"your consumer secret"];

Authorization

The SDK needs to login with OAuth before making a request to the API. Add authorization code your app's settings view.

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(showWebView:) name:kHTBLoginStartNotification object:nil];

[[HTBHatenaBookmarkManager sharedManager] authorizeWithSuccess:^{

} failure:^(NSError *error) {

}];

After making an authorization request, the SDK calls kHTBLoginStartNotification with NSURLRequest including the login page URL. You should handle the notification and request with HTBLoginWebViewController.

-(void)viewDidLoad
{
    [super viewDidLoad];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(showOAuthLoginView:) name:kHTBLoginStartNotification object:nil];
}

-(void)showOAuthLoginView:(NSNotification *)notification {
    NSURLRequest *req = (NSURLRequest *)notification.object;
    UINavigationController *navigationController = [[UINavigationController alloc] initWithNavigationBarClass:[HTBNavigationBar class] toolbarClass:nil];
    HTBLoginWebViewController *viewController = [[HTBLoginWebViewController alloc] initWithAuthorizationRequest:req];
    navigationController.viewControllers = @[viewController];
    [self presentViewController:navigationController animated:YES completion:nil];
}

Login Screenshot

Bookmark UI

The SDK provides two ways for integrating the Hatena Bookmark Panel UI.

  • HTBHatenaBookmarkActivity
  • HTBHatenaBookmarkViewController

HTBHatenaBookmarkActivity

UIActivity is an iOS native sharing interface, available on iOS 6 or later. This SDK provides HTBHatenaBookmarkActivity.

iPhone / iPod touch

You can present a UIActivityViewController modally on iPhone or iPod touch.

NSURL *URL = self.webView.request.URL;

// iOS 6 or later
if ([UIActivityViewController class]) {
    HTBHatenaBookmarkActivity *hateaBookmarkActivity = [[HTBHatenaBookmarkActivity alloc] init];
    UIActivityViewController *activityView = [[UIActivityViewController alloc] initWithActivityItems:@[URL]                                                                               applicationActivities:@[hateaBookmarkActivity]];
    [self presentViewController:activityView animated:YES completion:nil];
}

UIActivity Screenshot

iPad

Apple official document said that "on iPad, it must be presented in a popover".

NSURL *URL = self.webView.request.URL;

// iOS 6 or later
if ([UIActivityViewController class]) {
    HTBHatenaBookmarkActivity *hateaBookmarkActivity = [[HTBHatenaBookmarkActivity alloc] init];
    UIActivityViewController *activityView = [[UIActivityViewController alloc] initWithActivityItems:@[URL]                                                                               applicationActivities:@[hateaBookmarkActivity]];
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { // on iPad
        self.activityPopover = [[UIPopoverController alloc] initWithContentViewController:activityView];
        __weak UIPopoverController *weakPopover = self.activityPopover;
        activityView.completionHandler = ^(NSString *activityType, BOOL completed){
            // dismiss popover on activity completed.
            [weakPopover dismissPopoverAnimated:YES];
        };
        [self.activityPopover presentPopoverFromBarButtonItem:sender
                                     permittedArrowDirections:UIPopoverArrowDirectionAny
                                                     animated:YES];
    }
}

See HTBDemoViewController for detail.

HTBHatenaBookmarkViewController

You can call ViewController directly.

// iOS 5
NSURL *URL = self.webView.request.URL;
HTBHatenaBookmarkViewController *viewController = [[HTBHatenaBookmarkViewController alloc] init];
viewController.URL = URL;
[self presentViewController:viewController animated:YES completion:nil];

Build DemoApp

Clone this repository and run git submodule update --init. After that, open /DemoApp/DemoApp.xcodeproj and build.

Demo app also needs OAuth consumer secret and key. Add to [[HTBHatenaBookmarkManager sharedManager] setConsumerKey:@"your consumer key" consumerSecret:@"your consumer secret"]; in HTBDemoViewController.

Running Tests

Clone this repository and run make clean test in root directory.

Archtecture

  • /SDK/API/
  • HTTP request class
  • /SDK/UI/
  • Some classes related in bookmark panel UI and login
  • HTBHatenaBookmkarkManager
  • Core module
  • Handle user login information
  • Dispatch JSON response to model class

Requirements

  • iOS 5.0 or later
  • ARC

Dependency

  • AFNetworking
  • Version 1.x
  • Currently 2.0 is not supported because it required iOS 7 and we included renamed AFNetworking 1.x.
  • AFOAuth1Client
  • Currentry we forked and copied it as HTBAFOAuth1Client for waiting merge some pull requests.
  • SFHFKeychainUtils

Hatena Bookmark API

iOS SDK interfaces with the Hatena Bookmark API. For more details, see api docs (In Japanese).

License

MIT license.

hatena-bookmark-ios-sdk's People

Contributors

0x0c avatar cockscomb avatar giginet avatar kishikawakatsumi avatar laiso avatar ninjinkun avatar yashigani 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

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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

hatena-bookmark-ios-sdk's Issues

一瞬前回のソーシャルボタン状況が見える

ブックマークするビューで「追加」を押したときに、閉じていく瞬間に「直前の」ソーシャルボタンのON/OFF状況が見えることがあります。

再現例

  1. 前回 Twitter に共有するようにしてブックマークを追加していた。(鳥さんアイコンのみカラー表示)
  2. 次の別のブックマークをするときに、Twitter共有は外して、「追加」をする。
  3. すると、Twitter共有は外したはずなのに、「前回の」状態のTwitter共有がカラー表示になった状態のボタンたちが見えて閉じられる。(Twitter共有はされていない)

このようにすると手元では再現します。
毎回「あれっ? 共有にしたままだっけ」と思ってどきっとし、Twitterに流れているか確認することがあるので、できれば正常な表示になるととてもありがたく存じます。

はてなブックマークプラス未登録ユーザーでも非公開ブックマークが登録できてしまう

スクリーンショト: http://gyazo.com/3170f3229b76b6a7022778f47b1a54e3

アカウント: id:laiso http://b.hatena.ne.jp/laiso/bookmark
URL: http://b.hatena.ne.jp/entry/tower.jp/article/news/2013/08/15/n01/

操作手順:
HTBHatenaBookmarkViewController のツールバーのPublic <-> Private を切り替えて[Add]をタップ

発生時のソースコード:

objc
// ※Apache Cordova iOS のプラグイン向け内部APIから呼び出し

  • (void)addBookmark:(CDVInvokedUrlCommand*)command
    {
    [self.commandDelegate runInBackground:^{
    NSURL *URL = [NSURL URLWithString:[command argumentAtIndex:0]];
    HTBHatenaBookmarkViewController *widget = [[HTBHatenaBookmarkViewController alloc] init];
    widget.URL = URL;
    dispatch_sync(dispatch_get_main_queue(), ^{
    [self.viewController presentViewController:widget animated:YES completion:nil];
    });
    }];
    }

AFNetworking 2.0 Migration

Migrate to new AFNetworking 2.0 interface. I plan to make two APiClient classes for compatibility with AFNetworking 1.x.

表示方法をModalから変更する

ブックマークUIは現在presentViewController:animated:completion:を使ってModalとして表示していますが、Contextの問題などがあるため、addSubView:を使ってviewに貼り付ける形に変更しようと考えています。動きは現在のものと変わらない予定ですが、呼び出し方法が変わる可能性があります。

read_private, write_private scopeが有効になっていないとログイン時にEXE_BAD_ACCESS

バグでは無いと思いますが、アプリケーション登録時に
read_private, write_private のscopeを有効にしていないと
[HTBHatenaBookmarkManager sharedManager] authorizeWithSuccess
のタイミングで EXE_BAD_ACCESS になるようです。

scopeが足りていないのでログイン出来ないのは正しい動きなんだと思いますが、
これが原因で先に進めていない人をTwitter上でも何人か見つけたので、念のため報告させていただきます。
※問題なければクローズしてくださいm(_ _)m

iOS 7 + HTBHatenaBookmarkActivity でブックマークUIを呼び出す際の不具合

他のissueと関連する箇所がカブっているかもしれませんが、iOS 7 関連の話はまだなかったので……

2回目移行 UIActivityViewController が表示されなくなりました。

presentViewController 実行時のコンソールログ:

2013-08-22 15:22:28.794 DemoApp[40420:a0b] Warning: Attempt to present <UIActivityViewController: 0x8de56d0>  on <UINavigationController: 0x8dcf650> which is already presenting <UIActivityViewController: 0x8d5bbb0>

iOS 6 SDKでビルド → iOS 7端末へインストールでも起きます。

HTBHatenaBookmarkViewController を直接 presentViewController するケースでは問題ありません。

複数クライアントで発生する認証の問題

  • 同じOAuthアプリケーションに対して、
  • 1つのはてなアカウントで、
  • 同一のiOSアプリを複数の端末から使う

という時に、最後に認証した端末以外で内部API通信エラー(HTTP 401)が発生し、はてなブックマークへの登録操作ができなくなります。

ユーザーサイドからはエラーアラートが出るだけです。

たとえば1人のはてなユーザーがiPhone、iPad双方から同じiOSアプリを使うような時発生します。

この時サーバーからは以下の"token_rejected"レスポンスが返ってきていました。

(lldb) po [operation.response allHeaderFields]
{
    Connection = "keep-alive";
    "Content-Encoding" = gzip;
    "Content-Length" = 48;
    "Content-Type" = "text/plain; charset=utf-8";
    Date = "Tue, 27 Aug 2013 09:03:10 GMT";
    Server = nginx;
    ... 中略 ...
    Vary = "Accept-Encoding,User-Agent";
    "Www-Authenticate" = "OAuth realm=\"\", oauth_problem=\"token_rejected\"";
    "X-Content-Type-Options" = nosniff;
    "X-Framework" = "Ridge/0.11";
    "X-Ridge-Dispatch" = "Hatena::Bookmark::Engine::Api::V1::My#default";
    "X-Runtime" = 18ms;
}

Use Travis CI

リポジトリが公開になったら、Travis CIで継続的インテグレーションできるようにする予定です。

iPadアプリではUIActivityViewControllerはpopoverで出さなければならない

だそうです。たしかに、iPadでモーダルビューとして表示すると、その後画面が回転したときなどに残念なことになります。

デモアプリだけの話なのですが考慮した書き方にしておいたほうがいいかなと思います。
そのままコピペするひとはいると思いますし。

On iPad, you must present the view controller in a popover. 
On iPhone and iPod touch, you must present it modally.

https://developer.apple.com/library/ios/documentation/uikit/reference/UIActivityViewController_Class/Reference/Reference.html

たまにステータスコード401が返ることがあり、その後、表示に不整合が起こる

何かの拍子にAPIからステータスコード401が返ることがあります。
(再現方法は不明ですが、ブックマークビューを繰り返し表示/非表示すると発生します。そんなに稀ではありません)

401のときアカウント情報は削除されてログアウト状態になりますが、accessTokenはセットされたままなので、このスクリーンショットのようにユーザー名だけがない状態で、自分のブックマークの取得や、ブックマークのPOST自体は成功します。

screenshot 2013 08 26 20 39 22

日本語タグと英語タグが混在するとエラー

ios simulator screen shot aug 16 2013 8 25 45 pm

ブックマークする際に日本語のタグと英語のタグが混在している場合、「Expected status code in (200-299), got 401」のUIAlertViewが表示され正常に動作を完了しません。
既知の問題かもしれませんが報告させて頂きます。

HTBLoginWebViewControllerで、まれにEXE_BAD_ACCESSが発生します

はじめまして、
表題の通り、EXE_BAD_ACCESSで落ちます。

ログイン処理で、DemoAppと同じようにモーダルでHTBLoginWebViewControllerを表示させてから、Allowsを押し、dismissされると、まれにEXE_BAD_ACCESSが発生するようです。

ログインを繰り返していると再現します。

動作確認は、実機のiPhone5Sです。

temp

URL canonicalization problem?

HTBBookmarkViewControllerを利用して

http://matome.naver.jp/m/odai/2137604199906076101

などのモバイル向けURLをブックマーク登録をすると、登録時には正規化された

http://matome.naver.jp/odai/2137604199906076101

のブックマークエントリーとしてサーバーへ保存されますが。

再度同じURLをブックマークすると

  1. HTBHatenaBookmarkManager:getBookmarkedDataEntryWithURL〜 で http://matome.naver.jp/m/odai/2137604199906076101 のエントリーデータを取得する
  2. 結果がnil なので編集中コメントは空になる
  3. 登録を実行すると既存のhttp://matome.naver.jp/odai/2137604199906076101 エントリーにコメントが上書きされる

という現象が起り、既存の入力したブックマークコメントを編集できず、常に新しく上書きにしてしまうという状態になりました。

URL正規化を解決した後にブックマークデータを取得するなどの対策が必要だと思います。

ブックマーク入力画面でタグ選択画面が真っ暗

2013-08-12 11 38 59

以下、コードです。RubyMotion です。

class AppDelegate
  def application(application, didFinishLaunchingWithOptions:launchOptions)
    HTBHatenaBookmarkManager.sharedManager.setConsumerKey("...", consumerSecret:"...")

    @window = UIWindow.alloc.initWithFrame(UIScreen.mainScreen.bounds)
    controller = UINavigationController.alloc.initWithRootViewController(MainViewController.new)
    @window.rootViewController = controller
    @window.makeKeyAndVisible
    true
  end
end

class MainViewController < UIViewController
  def viewDidLoad
    super
    NSNotificationCenter.defaultCenter.addObserver(self, selector:'showOAuthLoginView:', name:KHTBLoginStartNotification, object:nil)
    self.view.backgroundColor = UIColor.whiteColor

    self.view << @loginButton = UIButton.rounded_rect.tap do |btn|
      btn.setTitle('login', forState:UIControlStateNormal)
      btn.addTarget(self, action:'on_login', forControlEvents:UIControlEventTouchUpInside)
    end

    self.view << @bookmarkButton = UIButton.rounded_rect.tap do |btn|
      btn.setTitle('bookmark', forState:UIControlStateNormal)
      btn.addTarget(self, action:'on_bookmark', forControlEvents:UIControlEventTouchUpInside)
    end

    if HTBHatenaBookmarkManager.sharedManager.authorized
      HTBHatenaBookmarkManager.sharedManager.getMyEntryWithSuccess(
        lambda { |entry| },
        failure: lambda { |error| }
      )

      HTBHatenaBookmarkManager.sharedManager.getMyTagsWithSuccess(
        lambda { |tags| },
        failure: lambda { |error| }
      )
    end
  end

  def viewWillAppear(animated)
    @loginButton.frame = [[0, 0], [200, 42]]
    @loginButton.center = self.view.center
    @bookmarkButton.frame = [[10, 10], [200, 42]]
    super
  end

  def on_login
    HTBHatenaBookmarkManager.sharedManager.logout
    HTBHatenaBookmarkManager.sharedManager.authorizeWithSuccess(
      lambda {},
      failure: lambda {|error| NSLog(error.localizedDescription) }
    )
  end

  def on_bookmark
    controller = HTBHatenaBookmarkViewController.alloc.init
    controller.URL = 'http://hbfav.bloghackers.net/'.nsurl
    self.presentViewController(controller, animated:true, completion:nil)
  end

  def showOAuthLoginView(notification)
    req = notification.object
    navigationController = UINavigationController.alloc.initWithNavigationBarClass(HTBNavigationBar, toolbarClass:nil)
    viewController = HTBLoginWebViewController.alloc.initWithAuthorizationRequest(req)
    navigationController.viewControllers = [viewController]
    self.presentViewController(navigationController, animated:true, completion:nil)
  end
end

authorizeWithSuccessのscope指定がread_private

すみません。下部の本投稿はこちらの思い違いでした。

authorizeWithSuccessはそのままで、追加するアプリケーション側にread_privateが必要ということですね。

失礼いたしました。


Demoを試そうとするとoauth_parameters_rejected=scopeとなり、とまどってしまいました。

HTBHatenaBookmarkAPIClient.m
acquireOAuthRequestTokenWithPathのscope指定が read_private,write_public となっているためですが、read_public の間違いかなと思いました。

HTBBookmarkViewControllerのタイトルからログアウトできることを察することが難しい

HTBBookmarkViewControllerのナビゲーションバーにあるはてなID部分をタップするとログアウトのアクションシートが表示されますが、ユーザがこれをボタンであると判断することが難しいです。
もう少し押せるっぽさを出してほしいのですが、可能でしょうか?
簡単にid:○○○ ▼のように後に▼をつけてあげるだけでも少し判定しやすくなると思います。

コメントの文字数の数え方について

実情に合ってるっぽいので特に問題ではないのですが、直感には反するというか違和感があるので、ちょっとisssue登録してみました。

要するに最終的に表示されてるものが文字数でもバイト数でも無いので入力する文字によって増え方がまちまちなので変に感じます。

NSInteger textCount = [self.commentTextView.text lengthOfBytesUsingEncoding:NSUTF8StringEncoding] / 3;

https://github.com/hatena/Hatena-Bookmark-iOS-SDK/blob/master/SDK/UI/View/HTBBookmarkRootView.m#L201

iOS 7 HTBBookmarkRootView まわりの不具合

  • タグ入力
  • 文字数カウンター
  • コメント一覧へ遷移

あたりが隠れてしまい使えなくなります。

直接の原因はHTBBookmarkRootView描写時点でのフレームサイズの差が影響しているようですがよくわかりません。

はてなの認証が時々切れて再ログインが必要になる

SDK を組み込んだアプリ (HBFav2) のユーザーから報告が上がっているのですが、表題の現象が起こるようです。

ひとによって発生頻度が違っていて

  • 全く発生しないユーザー (当方がこれ)
  • 希に発生するユーザー
  • 一日一度の頻度くらいで頻繁に発生するユーザー

とがいるようです。

issue の中でもコメントしていますが、はてなの認証は、当方のアプリでは HTBHatenaBookmarkViewController.alloc.init でコントローラを起動して、以降の処理は完全に SDK 側に任せているため、おそらくですが、SDK もしくはサーバーサイドに原因があるのではないか、と思っています。

ただし、当方が利用しているのが RubyMotion なので、(可能性は低いものの) Objective-C で書いた場合との互換性の部分に差があって何か問題が起こっていることも否定はできません。

ATS (App Transfer Security) を有効にすると機能しない

ATSを有効にするとATSの警告アラートが複数回表示され、ブックマークの登録や閲覧ができません。
内部で使用しているAPIがHTTPでしか利用できないのだと思いますが、対応していただけるとありがたいです。
Exception Domains に hatena.ne.jp(サブドメイン含む)を追加して、NSExceptionAllowsInsecureHTTPLoads を許可すれば使用できることは確認しております。

2016-12-22 10 33 38

アクセス許可用のWebViewにログインセッションが残っているので別のアカウントに切り替えられない問題

SDKログアウト機能によってSDK内部で保持している認証アカウントはクリアされますが、
OAuth許可で利用しているHTBLoginWebViewController のはてなログイン中セッションは残ったままなので、
一度認証した後に別のアカウントで再認証するような操作ができなくなっています。
(※ 端末を再起動する or HTBLoginWebViewController内でがんばってリンクを辿ってログアウト操作すれば一応可能)

単純にCookieを削除してしまえばいいかと思ったのですが

- (void)deleteCookies
{
    if(_authorizationRequest.URL){
        for (NSHTTPCookie* cookie in [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookiesForURL:_authorizationRequest.URL]) {
            [[NSHTTPCookieStorage sharedHTTPCookieStorage] deleteCookie:cookie];
        }
    }
}

こうするとアプリ内の別の場所でWebViewではてなにログインしている箇所もログアウト扱いになってしまいイマイチでした。

なので、やりたいこととしては

  • HTBLoginWebViewControllerのみで既存のセッションを無視して再ログインできるようにする
  • deleteCookies 相当の処理をSDKユーザーが任意に実行できるようにする
  • あとは、たとえばサーバーサイド"www.hatena.ne.jp/oauth/authorize" でforceフラグでフォームを出すようにする

という感じです

既存の ViewController のモーダルアニメーションが変更されてしまう

HTBHatenaBookmarkViewController などを一度 presentViewController すると、以降 HTBHatenaBookmarkViewController 以外の ViewController のモーダルアニメーションも変更されてしまうようです。

以下に再現動画を撮りました。

https://dl.dropboxusercontent.com/u/2586384/files/htbsdk.mov

ちょっと work around を入れてどうにかなるかと思ったのですが変わらずでしたので issue に登録します。

要望: ログイン中のはてなIDを取得したい

Pocket の SDK なんかだと

PocketAPI.sharedAPI.username

で String でユーザー名が返ります。login してなければ nil

はてなブックマークのSDKでも、認証済みの場合にユーザー名が取得できるとはてなブックマークアプリみたいなのを作るときに、この SDK でユーザー管理を組み込むことができるようになるので良いと思いました。

iOS 自定义导航栏如何实现?

  • (instancetype)initWithNavigationBarClass:(nullable Class)navigationBarClass toolbarClass:(nullable Class)toolbarClass
    这个方法提供了自定义导航栏的方法,但是我尝试去实现navigationBarClass的时候,发现在iPhone X上面状态栏没法覆盖到,Apple不是推崇这种方式去完全自定义导航栏吗?

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.