{"action":"created","comment":{"url":"https://api.github.com/repos/leancloud/docs/pulls/comments/29645166","id":29645166,"diff_hunk":"@@ -1,374 +1,1150 @@\n-# Windows Phone 8.0 实时通信\n+# .NET 实时通信服务\n \n ## 简介\n \n-在阅读本开发指南之前，请先阅读下[《实时通信开发指南》](./realtime.html)，了解实时通信的基本概念和模型。\n+在阅读本开发指南之前，请先阅读下[《实时通信开发指南》](./realtime_v2.html)，了解实时通信的基本概念和模型。\n \n+目前我们的 .NET 实时通信支持如下运行时：\n+\n+* Windows Phone Silverlight （8.0 & 8.1）\n+* Windows Desktop With .NET Framework 4.5\n+\n+尚未发布但是已在计划内的如下：\n+\n+* Windows Runtime （for Windows 10）\n+\n+文档中涉及的语法以及接口均对所有运行时有效。\n \n ## 安装\n-为了支持实时聊天，我们依赖于一个开源的第三方的 WebSocket 的库，所以推荐开发者从[Nuget](https://www.nuget.org/packages/AVOSCloud.Phone/1.2.3.4-beta)上下载我们的 SDK。\n+为了支持实时聊天，LeanCloud SDK for .NET 依赖于几个开源的 WebSocket 的库，所以推荐开发者从 [Nuget](https://www.nuget.org/packages/AVOSCloud.Phone/1.3.0-beta) 上下载我们的 SDK。\n+\n+## 初始化\n+导入 SDK 之后，在应用入口函数中添加如下代码：\n \n-为了更方便开发者阅读和理解 SDK 里面的各种抽象概念，我们先从一个应用场景来简单地剖析实时聊天组件在 Windows Phone 8.0 SDK 中如何使用。\n+```c#\n+   //generated code by visual studio\n+   ...\n+   AVClient.Initialize(\"你的 AppId\", \"你的 AppKey\");\n+   ...\n+\n+```\n+例如，在 Windows 控制台的 Main 函数入口可以调用以上代码进行初始化。\n \n ## 单聊\n-### 场景设定\n-* 应用场景：参考微信单聊，微博私信\n-* 实现需求：用户A（UserA）想与用户B（UserB）进行单独聊天\n-* 实现步骤：\n \n+###  发送消息\n+此场景类似于微信的私聊，微博的私信以及 QQ 单聊的场景，我们建立了一个统一的概念来描述聊天的各种场景：对话 — AVIMConversation，在[《实时通信开发指南》](./realtime_v2.html)里面有详细的介绍。\n+\n+Tom 想发送一条消息给 Jerry，下面的代码将帮助他实现这一功能：\n+\n+```c#\n+public async void TomCreateConversationWithJerry()\n+{\n+    //Tom 用自己的名字作为 ClientId 建立了一个 AVIMClient\n+    AVIMClient client = new AVIMClient(\"Tom\");\n+\n+    //Tom 登录到系统\n+    await client.ConnectAsync();\n+\n+    //Tom 建立了与 Jerry 的对话\n+    AVIMConversation conversation = await client.CreateConversationAsync(\"Jerry\");\n+\n+    //Tom 发了一条消息给 Jerry\n+    await conversation.SendTextMessageAsync(\"Hello,Jerry!\");\n+}\n ```\n-  Step1.UserA 创建 AVSession 与 LeanCloud 服务端建立长连接\n-  Step2.UserA 告诉 LeanCloud 服务端我要关注（Watch）UserB\n-  Step3.UserA 发送消息给 LeanCloud 服务端，因为在第二步的时候，已经关注了 UserB，LeanCloud 服务端就会把这条信息发送给 UserB\n-  Step4.UserB 想接受到别人发的消息，也需要创建 AVSession 与 LeanCloud 服务端建立长连接\n-  Step5.UserB 告诉 LeanCloud 服务端我也要关注（Watch）UserA\n-  Step6.UserB 就能收到第3步，由 UserA 发来的消息了。\n+\n+### 接收消息\n+\n+Jerry 如果想收到 Tom 的消息，他需要如下代码：\n+\n+```c#\n+public async void JerryReceiveMessageFromTom()\n+{\n+    //Jerry 用自己的名字作为 ClientId 建立了一个 AVIMClient\n+    AVIMClient client = new AVIMClient(\"Jerry\");\n+\n+    //Tom 登录到系统\n+    await client.ConnectAsync();\n+\n+    //Jerry 设置接受消息的方法，一旦有消息收到就会调用这个方法\n+    client.OnMessageReceieved += (s, e) =>\n+    {\n+        if (e.Message is AVIMTextMessage)\n+        {\n+            string words = ((AVIMTextMessage)e.Message).TextContent;\n+            //words 内容即为：Hello,Jerry!\n+        }\n+    };\n+}\n ```\n-### 场景实现\n-以上逻辑是一个最基本的聊天系统应该有的逻辑交互，在 LeanCloud 中，实现以上步骤需要如下代码：\n+运行以上代码之后，在 LeanCloud 网站的控制台找到指定的应用，打开存储管理控制台，可以看到默认表 `_Conversation`中多了一条数据，该条数据的字段解释如下：\n+\n+* name：String，对话唯一的名字。\n+* m：Array，对话中成员的列表。\n+* lm：Date，对话中最后一条消息发送的时间。\n+* c：String，对话的创建者的 ClientId\n+* mu：Array，对话中设置了静音的成员，仅针对 iOS 以及 Windows Phone 用户有效\n+* attr：Object，开发者设置的对话的自定义属性。\n+\n+## 群聊\n+此场景类似于微信的多人聊天群组，以及 QQ 群 ，请注意这里的群聊指的是持久化存储的一个群组的概念，比如 QQ 群，除非群主解散该群，这个群应该是一直存在于 我的QQ群 列表中。关于临时群组聊天（聊天室）会在之后做单独解释。\n+\n+### 发送消息\n+Tom 想建立一个群，把自己好朋友都拉进这个群，然后给他们发消息，他需要做的事情是：\n+\n+* 第一步：建立一个朋友列表\n+* 第二步：新建一个对话，把朋友列为对话的参与人员\n+* 第三步：发送一条消息\n+\n+以下代码将实现这个需求：\n \n ```c#\n-AVSession session = new AVSession(\"UserA\"); //Step1\n-session.Open(\"UserB\"); //Step2\n-session.OnSessionOpen += (s_open, e_open) =>\n+public async void TomCreateConversationWithFriends()\n {\n-session.SendMessage(\"Hello,B!\", \"UserB\", true); //Step3\n-};\n+    //Tom 用自己的名字作为 ClientId 建立了一个 AVIMClient\n+    AVIMClient client = new AVIMClient(\"Tom\");\n+\n+    //Tom 登录到系统\n+    await client.ConnectAsync();\n+\n+    #region 第一步：建立一个朋友列表\n+    IList<string> friends = new List<string>();\n+    friends.Add(\"Jerry\");\n+    friends.Add(\"Bob\");\n+    friends.Add(\"Harry\");\n+    friends.Add(\"William\");\n+    #endregion\n+\n+    #region 新建一个对话，把朋友们列为对话的参与人员\n+    AVIMConversation friendConversation = await client.CreateConversationAsync(friends);\n+    #endregion\n+\n+    #region 第三步：发送一条消息\n+    await friendConversation.SendTextMessageAsync(\"Hey，你们在哪里？\");\n+    #endregion\n+}\n ```\n-这是UserA需要做的事情，UserB 想要实现接受的话需要如下几步：\n+\n+### 接收消息\n+群聊的接收消息与单聊的接收消息是一样的。\n \n ```c#\n-  AVSession session = new AVSession(\"UserB\"); Step4\n-  session.Open(\"UserA\"); //Step5\n-  session.SetListener(new SampleAVSessionListener()\n+AVIMConversation NotifiedConversation = null;\n+public async void BobReceiveMessageFromTom()\n+{\n+    //Bob 用自己的名字作为 ClientId 建立了一个 AVIMClient\n+    AVIMClient client = new AVIMClient(\"Bob\");\n+\n+    //Bob 登录到系统\n+    await client.ConnectAsync();\n+\n+    //Bob 设置接受消息的方法，一旦有消息收到就会调用这个方法\n+    client.OnMessageReceieved += (s, e) =>\n+    {\n+        if (e.Message is AVIMTextMessage)\n+        {\n+            //words 的内容就是：Hey，你们在哪里？\n+            string words = ((AVIMTextMessage)e.Message).TextContent;\n+\n+            //AVIMClient 在接收到消息的时候，会一并提供消息所在的 AVIMConversation\n+            NotifiedConversation = e.Conversation;\n+\n+            if (NotifiedConversation != null)\n             {\n-                OnMessage = (s, msg) =>\n-                {\n-                    var content = msg.Message;\n-                    MessageBox.Show(content);\n-                }\n-            });\n-  ///最后这一步要做详细的解释。\n-  ///SampleAVSessionListener 是一个实现了接口 IAVSessionListener 简单的类，它实现了 IAVSessionListener 代理，\n-  ///这些代理的主要作用就是用来监听 SDK 所发出的具体的事件的响应。\n+                //Bob 收到消息后又回复了一条消息\n+                NotifiedConversation.SendTextMessageAsync(\"HI,Tom :我在 Jerry 家里，你跟 Harry 什么时候过来？还有 William 和你在一起么？\");\n+            }\n+        }\n+    };\n+}\n ```\n-附上 `SampleAVSessionListener` 的代码，开发者可以将如下代码拷贝到 Visual Studio 中：\n \n+而以上 Tom 和 Bob 发送的消息，William 上线的时候都会收到。\n+\n+**注： AVIMClient CreateConversationAsync 有多种重载方法供开发者调用，详细的开发者可以在 Visual Studio 中查看定义**。\n+\n+## 消息\n+消息在最新版本的 SDK 中做了多层抽象以及封装，详细的我们先从如何发送接收富媒体消息开始。\n+### 富媒体消息\n+富媒体消息的支持是新版 SDK 的核心提升，我们目前 SDK 已经支持的富媒体消息类型有以下几种：\n+\n+* 图像消息：`AVIMImageMessage`\n+* 音频消息：`AVIMAudioMessage`\n+* 视频消息：`AVIMVideoMessage`\n+* 文件消息：`AVIMFileMessage`\n+* 地理位置消息：`AVIMLocationMessage`\n+\n+\n+#### 图像消息\n+图像消息可以由系统提供的拍照 API，以及媒体库中获取，也可以是可访问的图像有效 Url，只要开发者调用一个构造方法，构造出一个 `AVIMImageMessage`，然后把 `AVIMImageMessage` 对象当做参数交由 `AVConversation` 发送出去即可。\n+\n+##### 发送图像消息\n+\n+场景 1：比如从微博拷贝了一个图像链接，然后可以通过 SDK 直接构建一个 `AVIMImageMessage`并且发送出去：\n ```c#\n-public class SampleAVSessionListener : IAVSessionListener\n+public async void SendImageMessageAsync_Test()\n {\n-        public SessionOpen OnSessionOpen { get; set; }//AVSession打开时执行的代理。\n-        \n-        public SessionPaused OnSessionPaused { get; set; }//AVSession 与服务端断开连接时执行的代理，一般都是因为 WP 手机锁屏或者应用被切换至后台了，所执行的代理。\n+    AVIMClient client = new AVIMClient(\"Tom\");\n+    \n+    await client.ConnectAsync();//Tom 登录\n \n-        public SessionResumed OnSessionResumed { get; set; }//AVSession 重连成功之后执行的代理。\n+    AVIMConversation conversation = await client.CreateConversationAsync(\"Jerry\", \"猫和老鼠\");//创建对话\n \n-        public SessionClosed OnSessionClosed { get; set; }//关闭 AVSession 之后执行的代理。\n+    AVIMImageMessage imgMessage = new AVIMImageMessage(\"http://pic2.zhimg.com/6c10e6053c739ed0ce676a0aff15cf1c.gif\");//从外部链接创建图像消息\n+    await conversation.SendImageMessageAsync(imgMessage);//发送给 Jerry\n+}\n+``` \n \n-        public Message OnMessage { get; set; }//接受到消息时执行的代理。\n+场景 2：系统也提供了 API 去获取媒体库里面的照片，开发者只需要调用系统的 API 获取图像文件的数据流，然后构造出一个 `AVIMImageMessage`，再调用 `AVIMConversation.SendImageMessageAsync`去发送图像：\n \n-        public MessageSent OnMessageSent { get; set; }//消息发送成功之后执行的代理。\n+```c#\n+MediaLibrary library = new MediaLibrary();//系统媒体库\n+var photo = library.Pictures[0];//获取第一张照片，运行这段代码，确保手机以及虚拟机里面的媒体库至少有一张照片\n \n-        public MessageFailure OnMessageFailure { get; set; }//消息发送失败执行的代理。\n+AVIMImageMessage imgMessage = new AVIMImageMessage(photo.Name, photo.GetImage());//构造 AVIMImageMessage\n+imgMessage.Attributes = new Dictionary<string, object>() \n+{ \n+    {\"location\",\"San Francisco\"}\n+};\n+imgMessage.Title = \"发自我的 WP\";\n+await conversation.SendImageMessageAsync(imgMessage);\n+```\n \n-        public StatusOnline OnStatusOnline { get; set; }//当前用户的关注的人上线了所执行的代理（类似QQ好友上线了的敲门的声音）\n+以上 2 种场景中对于 SDK 的区别就是如下：\n+* 场景 1 中，SDK 并没有实际上传到服务端，而是仅仅是把 URL 包装在消息体内发送出去，并且这种情况下接收方是无法从消息体中获取到元信息等数据的，不过开发者可以自行获取。\n+* 场景 2中，SDK 获取了完整的图像的数据流，所以 SDK 会先上传文件到服务端，然后将文件的元数据以及 URL 等一并包装，再发送出去。\n \n-        public StatusOffline OnStatusOffline { get; set; }//关注的人下线了。\n+##### 接收图像消息\n+类似于第一章节中单聊中的接收消息，在 `AVIMClient` 中的 `OnMessageReceived` 可以收到消息，但是假如接收方在客户端也正好加载了这个对话，那么接收方在 `AVIMConversation` 里面也会收到 `OnImageMessageReceived` 的事件响应：\n \n-        public PeersWatched OnPeersWatched { get; set; }//关注成功了所执行的代理（类似QQ好友通过验证之后，加为好友）\n+```c#\n+public async void ReceiveImageMessageAsync_Test()\n+{\n+    AVIMClient client = new AVIMClient(\"Jerry\");\n+    await client.ConnectAsync();\n+    AVIMConversation conversation = client.GetConversationById(\"55117292e4b065f7ee9edd29\");\n+    await conversation.FetchAsync();\n+    conversation.OnImageMessageReceived += (s, e) =>\n+    {\n+        //图像的 url\n+        string url = e.Url;\n+        //图像的元数据\n+        IDictionary<string, object> metaData = e.FileMetaData;\n+        //图像的发送者 ClientId\n+        string  from= e.FromClientId;\n+        //图像发送者为图像设定的 Title\n+        string title = e.Title;\n+\n+        //一些其他的属性都可以在这里获取\n+    };\n+}\n+```\n \n-        public PeersUnwatched OnPeersUnwatched { get; set; }//取消关注之后所执行的代理。\n+#### 音频消息\n \n-        public Error OnError { get; set; }//发生错误时所执行的代理，例如抛出一些异常。\n+##### 发送音频消息\n+发送音频消息的基本流程就是：`读取音频文件（或者录制音频）`，`构建音频消息`，`消息发送`：\n+\n+```c#\n+private async void SendAudioMessageAsync()\n+{\n+    StorageFolder local = Windows.Storage.ApplicationData.Current.LocalFolder;\n+    var AudioFile = await local.OpenStreamForReadAsync(recordAudioFileName);\n+    AVIMAudioMessage audioMessage = new AVIMAudioMessage(recordAudioFileName, AudioFile);//创建音频消息\n+\n+    await conversation.SendAudioMessageAsync(audioMessage);\n+    //这段代码运行之前，请确保 `conversation` 已经实例化\n+}\n+``` \n+\n+与图像消息类似，音频消息也支持从 URL 构建，然后发送：\n+\n+```c#\n+public async void SendAudioMessageAsync()\n+{\n+    AVIMClient client = new AVIMClient(\"Tom\");\n+    //Tom 登录\n+    await client.ConnectAsync();\n+    var conversation = await client.CreateConversationAsync(\"Jerry\", \"猫和老鼠\");//创建对话\n+\n+    AVIMAudioMessage audioMessage = new AVIMAudioMessage(\"http://ac-lhzo7z96.clouddn.com/1427444393952\");//从外部链接创建音频消息\n+    await conversation.SendAudioMessageAsync(audioMessage);//发送给 Jerry\n }\n ```\n-这样只要2边同时运行，就可以 UserB 就可以收到来自 UserA 发来的信息。\n \n-以上代码和逻辑顺序能够很好的理解的话，关于 `IAVSessionListener` 这个接口的作用也一目了然，它所承担的职责就是帮助开发者用自己的代码与 SDK 进行交互，比如 `OnSessionOpen`：\n+##### 接收音频消息\n+与接收图像消息一样，在 `AVIMConversation` 中有 `OnAudioMessageReceived` ，实例代码请参照图像消息接收。\n+\n+#### 视频消息\n+\n+##### 发送视频消息\n+与发送音频消息类似的流程类似，视频的来源可以是手机录制，可以是 Windows 系统中某一个具体的视频文件：\n+\n+```c#\n+private async void SendVideoMessageAsync()\n+{\n+    StorageFolder local = Windows.Storage.ApplicationData.Current.LocalFolder;\n+\n+    var VideoFile = await local.OpenStreamForReadAsync(recordVideoFileName);\n+\n+    AVIMVideoMessage videoMessage = new AVIMVideoMessage(recordVideoFileName, VideoFile);\n+\n+    await conversation.SendVideoMessageAsync(videoMessage);\n+}\n+```\n+\n+同样我们也支持从一个视频的 URL 创建视频消息，然后发送出去：\n+\n+```c#\n+public async void SendVideoMessageAsync()\n+{\n+    AVIMClient client = new AVIMClient(\"Tom\");\n+    await client.ConnectAsync();//Tom 登录\n+\n+    var conversation = await client.CreateConversationAsync(\"Jerry\", \"猫和老鼠\");//创建对话\n \n+    AVIMVideoMessage videoMessage = new AVIMVideoMessage(\"http://ac-lhzo7z96.clouddn.com/1427267336319\");//从外部链接创建视频消息\n+    await conversation.SendVideoMessageAsync(videoMessage);//发送给 Jerry\n+}\n ```\n-每一次创建了一个 AVSession，只要连接创建成功，都会激发 OnSessionOpen 代理。\n+**注：这里说的 URL指的是视频文件自身的 URL，而不是视频网站上播放页的 URL。**\n+\n+##### 接收视频消息\n+与接收图像消息一样，在 `AVIMConversation` 中有 `OnVideoMessageReceived` ，实例代码请参照图像消息接收。\n+\n+#### 通用文件消息\n+Tom 要发送一份 .doc 文件给 Jerry，可以用下面这种方法：\n+\n+##### 发送通用文件消息\n+```c#\n+public async void SendDocAsync()\n+{\n+    AVIMClient client = new AVIMClient(\"Tom\");\n+    await client.ConnectAsync();//Tom 登录\n+\n+    var conversation = await client.CreateConversationAsync(\"Jerry\", \"猫和老鼠\");//创建对话\n+    StorageFolder local = Windows.Storage.ApplicationData.Current.LocalFolder;\n+    var docFile = await local.OpenStreamForReadAsync(\"leancloud.doc\");//读取本地文件\n+    var avfile = new AVFile(\"leancloud.doc\", docFile);//构造 AVFile\n+    AVIMFileMessage fileMessage = new AVIMFileMessage(avfile);//构造文件消息\n+    await conversation.SendFileMessageAsync(fileMessage);//发送\n+}\n ```\n-以此类推，根据开发者不同的需求需要对不同的代理做出相应的处理。也正因为如此，SDK 中只定义了接口，并没有定义一个强类型的类去给开发者使用，接口很方便于开发者将现有的一些功能类集成一下 `IAVSessionListener`。\n \n-**注意：在任何时候创建了 `AVSession` 之后一定要主动并且显式的调用一下 `AVSession.SetListener` 方法，将代理设置成开发者自己定义的代理类，这一点是*必须*做的**。\n+##### 接收通用文件消息\n+与接收图像消息一样，在 `AVIMConversation` 中有 `OnFileMessageReceived` ，实例代码请参照图像消息接收。\n \n-### 开发建议\n-因为基于 WebSocket 是长连接通信，长连接占用系统资源较多，Windows Phone 上一旦锁屏就会造成连接中断，所以我们建议在 App.xaml 下定义个全局的 AVSession 进行全局的管理以及调用。\n+#### 地理位置消息\n+地理位置消息构建方式有 2 种：\n \n+```c#\n+//1.根据纬度和经度构建\n+ AVIMLocationMessage locationMessage = new AVIMLocationMessage(Latitude, Longitude);\n+//2.根据 AVGeoPoint 构建\n+AVGeoPoint avGeoPoint = new AVGeoPoint(31.3853142377, 121.0553079844);\n+AVIMLocationMessage locationMessage = new AVIMLocationMessage(avGeoPoint);\n ```\n- public static AVSession session { get; set; }\n+##### 发送地理位置消息\n+\n+```c#\n+public async void SendLocationAsync()\n+{\n+    AVIMClient client = new AVIMClient(\"Tom\");\n+    await client.ConnectAsync();//Tom 登录\n+    var conversation = await client.CreateConversationAsync(\"Jerry\", \"猫和老鼠\");//创建对话\n+    \n+    AVIMLocationMessage locationMessage = new AVIMLocationMessage(138.12454, 52.56461);//以经度和纬度为参数构建一个地理位置消息，当然开发者更可以通过具体的设备的 API 去获取设备的地理位置，详细的需要查询具体的设备的 API\n+    await conversation.SendLocationMessageAsync(locationMessage);\n+}\n ```\n+##### 接收地理位置消息\n+与接收图像消息一样，在 `AVIMConversation` 中有 `OnLocationMessageReceived` ，实例代码请参照图像消息接收。\n+\n+### 消息的发送策略\n+开发者在阅读完前面的富媒体消息并且运行过实例代码之后，在 Visual Studio 中使用 F12 快捷键查看各个消息类型的定义，应该可以看见图像，音频，视频在类的继承关系上是继承自 `AVIMFileMessageBase`，所有继承自 `AVIMFileMessageBase` 的消息类型的发送策略如下：","path":"md/dotnet_realtime.md","position":422,"original_position":422,"commit_id":"67b4a1865e783ca7a50537dc4627935e2d242685","original_commit_id":"67b4a1865e783ca7a50537dc4627935e2d242685","user":{"login":"myleslee","id":108758,"avatar_url":"https://avatars.githubusercontent.com/u/108758?v=3","gravatar_id":"","url":"https://api.github.com/users/myleslee","html_url":"https://github.com/myleslee","followers_url":"https://api.github.com/users/myleslee/followers","following_url":"https://api.github.com/users/myleslee/following{/other_user}","gists_url":"https://api.github.com/users/myleslee/gists{/gist_id}","starred_url":"https://api.github.com/users/myleslee/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/myleslee/subscriptions","organizations_url":"https://api.github.com/users/myleslee/orgs","repos_url":"https://api.github.com/users/myleslee/repos","events_url":"https://api.github.com/users/myleslee/events{/privacy}","received_events_url":"https://api.github.com/users/myleslee/received_events","type":"User","site_admin":false},"body":"「应该可以看见图像，音频，视频在类的继承关系上是继承自」 >\r\n加上标点断开：\r\n应该可以看出，图像、音频、视频，在类的继承关系上是继承自……","created_at":"2015-05-05T05:51:07Z","updated_at":"2015-05-05T05:51:07Z","html_url":"https://github.com/leancloud/docs/pull/259#discussion_r29645166","pull_request_url":"https://api.github.com/repos/leancloud/docs/pulls/259","_links":{"self":{"href":"https://api.github.com/repos/leancloud/docs/pulls/comments/29645166"},"html":{"href":"https://github.com/leancloud/docs/pull/259#discussion_r29645166"},"pull_request":{"href":"https://api.github.com/repos/leancloud/docs/pulls/259"}}},"pull_request":{"url":"https://api.github.com/repos/leancloud/docs/pulls/259","id":34692945,"html_url":"https://github.com/leancloud/docs/pull/259","diff_url":"https://github.com/leancloud/docs/pull/259.diff","patch_url":"https://github.com/leancloud/docs/pull/259.patch","issue_url":"https://api.github.com/repos/leancloud/docs/issues/259","number":259,"state":"open","locked":false,"title":"fix doc name.","user":{"login":"wujun4code","id":5119542,"avatar_url":"https://avatars.githubusercontent.com/u/5119542?v=3","gravatar_id":"","url":"https://api.github.com/users/wujun4code","html_url":"https://github.com/wujun4code","followers_url":"https://api.github.com/users/wujun4code/followers","following_url":"https://api.github.com/users/wujun4code/following{/other_user}","gists_url":"https://api.github.com/users/wujun4code/gists{/gist_id}","starred_url":"https://api.github.com/users/wujun4code/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/wujun4code/subscriptions","organizations_url":"https://api.github.com/users/wujun4code/orgs","repos_url":"https://api.github.com/users/wujun4code/repos","events_url":"https://api.github.com/users/wujun4code/events{/privacy}","received_events_url":"https://api.github.com/users/wujun4code/received_events","type":"User","site_admin":false},"body":"fix doc name.","created_at":"2015-05-05T02:48:11Z","updated_at":"2015-05-05T05:51:07Z","closed_at":null,"merged_at":null,"merge_commit_sha":"7239d6f5f770f942986be8bb2203c1117d73bd05","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/leancloud/docs/pulls/259/commits","review_comments_url":"https://api.github.com/repos/leancloud/docs/pulls/259/comments","review_comment_url":"https://api.github.com/repos/leancloud/docs/pulls/comments{/number}","comments_url":"https://api.github.com/repos/leancloud/docs/issues/259/comments","statuses_url":"https://api.github.com/repos/leancloud/docs/statuses/67b4a1865e783ca7a50537dc4627935e2d242685","head":{"label":"wujun4code:dotnet_fix_doc_name","ref":"dotnet_fix_doc_name","sha":"67b4a1865e783ca7a50537dc4627935e2d242685","user":{"login":"wujun4code","id":5119542,"avatar_url":"https://avatars.githubusercontent.com/u/5119542?v=3","gravatar_id":"","url":"https://api.github.com/users/wujun4code","html_url":"https://github.com/wujun4code","followers_url":"https://api.github.com/users/wujun4code/followers","following_url":"https://api.github.com/users/wujun4code/following{/other_user}","gists_url":"https://api.github.com/users/wujun4code/gists{/gist_id}","starred_url":"https://api.github.com/users/wujun4code/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/wujun4code/subscriptions","organizations_url":"https://api.github.com/users/wujun4code/orgs","repos_url":"https://api.github.com/users/wujun4code/repos","events_url":"https://api.github.com/users/wujun4code/events{/privacy}","received_events_url":"https://api.github.com/users/wujun4code/received_events","type":"User","site_admin":false},"repo":{"id":29326977,"name":"docs","full_name":"wujun4code/docs","owner":{"login":"wujun4code","id":5119542,"avatar_url":"https://avatars.githubusercontent.com/u/5119542?v=3","gravatar_id":"","url":"https://api.github.com/users/wujun4code","html_url":"https://github.com/wujun4code","followers_url":"https://api.github.com/users/wujun4code/followers","following_url":"https://api.github.com/users/wujun4code/following{/other_user}","gists_url":"https://api.github.com/users/wujun4code/gists{/gist_id}","starred_url":"https://api.github.com/users/wujun4code/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/wujun4code/subscriptions","organizations_url":"https://api.github.com/users/wujun4code/orgs","repos_url":"https://api.github.com/users/wujun4code/repos","events_url":"https://api.github.com/users/wujun4code/events{/privacy}","received_events_url":"https://api.github.com/users/wujun4code/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/wujun4code/docs","description":"LeanCloud Documentation","fork":true,"url":"https://api.github.com/repos/wujun4code/docs","forks_url":"https://api.github.com/repos/wujun4code/docs/forks","keys_url":"https://api.github.com/repos/wujun4code/docs/keys{/key_id}","collaborators_url":"https://api.github.com/repos/wujun4code/docs/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/wujun4code/docs/teams","hooks_url":"https://api.github.com/repos/wujun4code/docs/hooks","issue_events_url":"https://api.github.com/repos/wujun4code/docs/issues/events{/number}","events_url":"https://api.github.com/repos/wujun4code/docs/events","assignees_url":"https://api.github.com/repos/wujun4code/docs/assignees{/user}","branches_url":"https://api.github.com/repos/wujun4code/docs/branches{/branch}","tags_url":"https://api.github.com/repos/wujun4code/docs/tags","blobs_url":"https://api.github.com/repos/wujun4code/docs/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/wujun4code/docs/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/wujun4code/docs/git/refs{/sha}","trees_url":"https://api.github.com/repos/wujun4code/docs/git/trees{/sha}","statuses_url":"https://api.github.com/repos/wujun4code/docs/statuses/{sha}","languages_url":"https://api.github.com/repos/wujun4code/docs/languages","stargazers_url":"https://api.github.com/repos/wujun4code/docs/stargazers","contributors_url":"https://api.github.com/repos/wujun4code/docs/contributors","subscribers_url":"https://api.github.com/repos/wujun4code/docs/subscribers","subscription_url":"https://api.github.com/repos/wujun4code/docs/subscription","commits_url":"https://api.github.com/repos/wujun4code/docs/commits{/sha}","git_commits_url":"https://api.github.com/repos/wujun4code/docs/git/commits{/sha}","comments_url":"https://api.github.com/repos/wujun4code/docs/comments{/number}","issue_comment_url":"https://api.github.com/repos/wujun4code/docs/issues/comments{/number}","contents_url":"https://api.github.com/repos/wujun4code/docs/contents/{+path}","compare_url":"https://api.github.com/repos/wujun4code/docs/compare/{base}...{head}","merges_url":"https://api.github.com/repos/wujun4code/docs/merges","archive_url":"https://api.github.com/repos/wujun4code/docs/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/wujun4code/docs/downloads","issues_url":"https://api.github.com/repos/wujun4code/docs/issues{/number}","pulls_url":"https://api.github.com/repos/wujun4code/docs/pulls{/number}","milestones_url":"https://api.github.com/repos/wujun4code/docs/milestones{/number}","notifications_url":"https://api.github.com/repos/wujun4code/docs/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/wujun4code/docs/labels{/name}","releases_url":"https://api.github.com/repos/wujun4code/docs/releases{/id}","created_at":"2015-01-16T01:31:32Z","updated_at":"2015-01-06T06:57:48Z","pushed_at":"2015-05-05T02:46:00Z","git_url":"git://github.com/wujun4code/docs.git","ssh_url":"git@github.com:wujun4code/docs.git","clone_url":"https://github.com/wujun4code/docs.git","svn_url":"https://github.com/wujun4code/docs","homepage":"http://leancloud.cn/docs/","size":19330,"stargazers_count":0,"watchers_count":0,"language":null,"has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"leancloud:master","ref":"master","sha":"46f10b34452f69c7fbc3b503ebc2481a9ef7b18d","user":{"login":"leancloud","id":6660518,"avatar_url":"https://avatars.githubusercontent.com/u/6660518?v=3","gravatar_id":"","url":"https://api.github.com/users/leancloud","html_url":"https://github.com/leancloud","followers_url":"https://api.github.com/users/leancloud/followers","following_url":"https://api.github.com/users/leancloud/following{/other_user}","gists_url":"https://api.github.com/users/leancloud/gists{/gist_id}","starred_url":"https://api.github.com/users/leancloud/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/leancloud/subscriptions","organizations_url":"https://api.github.com/users/leancloud/orgs","repos_url":"https://api.github.com/users/leancloud/repos","events_url":"https://api.github.com/users/leancloud/events{/privacy}","received_events_url":"https://api.github.com/users/leancloud/received_events","type":"Organization","site_admin":false},"repo":{"id":25067518,"name":"docs","full_name":"leancloud/docs","owner":{"login":"leancloud","id":6660518,"avatar_url":"https://avatars.githubusercontent.com/u/6660518?v=3","gravatar_id":"","url":"https://api.github.com/users/leancloud","html_url":"https://github.com/leancloud","followers_url":"https://api.github.com/users/leancloud/followers","following_url":"https://api.github.com/users/leancloud/following{/other_user}","gists_url":"https://api.github.com/users/leancloud/gists{/gist_id}","starred_url":"https://api.github.com/users/leancloud/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/leancloud/subscriptions","organizations_url":"https://api.github.com/users/leancloud/orgs","repos_url":"https://api.github.com/users/leancloud/repos","events_url":"https://api.github.com/users/leancloud/events{/privacy}","received_events_url":"https://api.github.com/users/leancloud/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/leancloud/docs","description":"LeanCloud Documentation","fork":false,"url":"https://api.github.com/repos/leancloud/docs","forks_url":"https://api.github.com/repos/leancloud/docs/forks","keys_url":"https://api.github.com/repos/leancloud/docs/keys{/key_id}","collaborators_url":"https://api.github.com/repos/leancloud/docs/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/leancloud/docs/teams","hooks_url":"https://api.github.com/repos/leancloud/docs/hooks","issue_events_url":"https://api.github.com/repos/leancloud/docs/issues/events{/number}","events_url":"https://api.github.com/repos/leancloud/docs/events","assignees_url":"https://api.github.com/repos/leancloud/docs/assignees{/user}","branches_url":"https://api.github.com/repos/leancloud/docs/branches{/branch}","tags_url":"https://api.github.com/repos/leancloud/docs/tags","blobs_url":"https://api.github.com/repos/leancloud/docs/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/leancloud/docs/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/leancloud/docs/git/refs{/sha}","trees_url":"https://api.github.com/repos/leancloud/docs/git/trees{/sha}","statuses_url":"https://api.github.com/repos/leancloud/docs/statuses/{sha}","languages_url":"https://api.github.com/repos/leancloud/docs/languages","stargazers_url":"https://api.github.com/repos/leancloud/docs/stargazers","contributors_url":"https://api.github.com/repos/leancloud/docs/contributors","subscribers_url":"https://api.github.com/repos/leancloud/docs/subscribers","subscription_url":"https://api.github.com/repos/leancloud/docs/subscription","commits_url":"https://api.github.com/repos/leancloud/docs/commits{/sha}","git_commits_url":"https://api.github.com/repos/leancloud/docs/git/commits{/sha}","comments_url":"https://api.github.com/repos/leancloud/docs/comments{/number}","issue_comment_url":"https://api.github.com/repos/leancloud/docs/issues/comments{/number}","contents_url":"https://api.github.com/repos/leancloud/docs/contents/{+path}","compare_url":"https://api.github.com/repos/leancloud/docs/compare/{base}...{head}","merges_url":"https://api.github.com/repos/leancloud/docs/merges","archive_url":"https://api.github.com/repos/leancloud/docs/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/leancloud/docs/downloads","issues_url":"https://api.github.com/repos/leancloud/docs/issues{/number}","pulls_url":"https://api.github.com/repos/leancloud/docs/pulls{/number}","milestones_url":"https://api.github.com/repos/leancloud/docs/milestones{/number}","notifications_url":"https://api.github.com/repos/leancloud/docs/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/leancloud/docs/labels{/name}","releases_url":"https://api.github.com/repos/leancloud/docs/releases{/id}","created_at":"2014-10-11T07:14:37Z","updated_at":"2015-05-05T00:42:16Z","pushed_at":"2015-05-05T02:48:11Z","git_url":"git://github.com/leancloud/docs.git","ssh_url":"git@github.com:leancloud/docs.git","clone_url":"https://github.com/leancloud/docs.git","svn_url":"https://github.com/leancloud/docs","homepage":"http://leancloud.cn/docs/","size":24192,"stargazers_count":54,"watchers_count":54,"language":"HTML","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":53,"mirror_url":null,"open_issues_count":25,"forks":53,"open_issues":25,"watchers":54,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/leancloud/docs/pulls/259"},"html":{"href":"https://github.com/leancloud/docs/pull/259"},"issue":{"href":"https://api.github.com/repos/leancloud/docs/issues/259"},"comments":{"href":"https://api.github.com/repos/leancloud/docs/issues/259/comments"},"review_comments":{"href":"https://api.github.com/repos/leancloud/docs/pulls/259/comments"},"review_comment":{"href":"https://api.github.com/repos/leancloud/docs/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/leancloud/docs/pulls/259/commits"},"statuses":{"href":"https://api.github.com/repos/leancloud/docs/statuses/67b4a1865e783ca7a50537dc4627935e2d242685"}}}}