OSDN Git Service

dedb9a5702338ae4637c538f364c8e0f02af4cfe
[opentween/open-tween.git] / Tween / Twitter.vb
1 ' Tween - Client of Twitter
2 ' Copyright (c) 2007-2009 kiri_feather (@kiri_feather) <kiri_feather@gmail.com>
3 '           (c) 2008-2009 Moz (@syo68k) <http://iddy.jp/profile/moz/>
4 '           (c) 2008-2009 takeshik (@takeshik) <http://www.takeshik.org/>
5 ' All rights reserved.
6
7 ' This file is part of Tween.
8
9 ' This program is free software; you can redistribute it and/or modify it
10 ' under the terms of the GNU General Public License as published by the Free
11 ' Software Foundation; either version 3 of the License, or (at your option)
12 ' any later version.
13
14 ' This program is distributed in the hope that it will be useful, but
15 ' WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16 ' or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 ' for more details. 
18
19 ' You should have received a copy of the GNU General Public License along
20 ' with this program. If not, see <http://www.gnu.org/licenses/>, or write to
21 ' the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
22 ' Boston, MA 02110-1301, USA.
23
24 Imports System.Web
25 Imports System.Xml
26 Imports System.Text
27 Imports System.Threading
28 Imports System.IO
29 Imports System.Text.RegularExpressions
30 Imports System.Globalization
31 Imports System.Diagnostics
32
33 Public Module Twitter
34     Delegate Sub GetIconImageDelegate(ByVal post As PostClass)
35     Delegate Function GetTimelineDelegate(ByVal page As Integer, _
36                                 ByVal read As Boolean, _
37                                 ByRef endPage As Integer, _
38                                 ByVal gType As WORKERTYPE, _
39                                 ByRef getDM As Boolean) As String
40     Delegate Function GetDirectMessageDelegate(ByVal page As Integer, _
41                                     ByVal read As Boolean, _
42                                     ByVal endPage As Integer, _
43                                     ByVal gType As WORKERTYPE) As String
44     Private ReadOnly LockObj As New Object
45     Private GetTmSemaphore As New Threading.Semaphore(8, 8)
46
47     Private follower As New List(Of String)
48     Private followerId As New List(Of Long)
49     Private tmpFollower As New List(Of String)
50
51     Private _followersCount As Integer = 0
52     Private _friendsCount As Integer = 0
53     Private _statusesCount As Integer = 0
54     Private _location As String = ""
55     Private _bio As String = ""
56     Private _useSsl As Boolean = True
57     Private _protocol As String = "https://"
58     Private _bitlyId As String = ""
59     Private _bitlyKey As String = ""
60
61     'プロパティからアクセスされる共通情報
62     Private _uid As String
63     Private _pwd As String
64     Private _proxyType As ProxyType
65     Private _proxyAddress As String
66     Private _proxyPort As Integer
67     Private _proxyUser As String
68     Private _proxyPassword As String
69
70     Private _nextThreshold As Integer
71     Private _nextPages As Integer
72
73     Private _iconSz As Integer
74     Private _getIcon As Boolean
75     Private _lIcon As ImageList
76     Private _dIcon As Dictionary(Of String, Image)
77
78     Private _tinyUrlResolve As Boolean
79     Private _restrictFavCheck As Boolean
80     Private _useAPI As Boolean
81
82     Private _hubServer As String
83     Private _defaultTimeOut As Integer      ' MySocketクラスへ渡すタイムアウト待ち時間(秒単位 ミリ秒への換算はMySocketクラス側で行う)
84     Private _countApi As Integer
85     Private _usePostMethod As Boolean
86     Private _ApiMethod As MySocket.REQ_TYPE
87     Private _readOwnPost As Boolean
88
89     '共通で使用する状態
90     Private _authKey As String              'StatusUpdate、発言削除で使用
91     Private _authKeyDM As String              'DM送信、DM削除で使用
92     Private _signed As Boolean
93     Private _infoTwitter As String = ""
94     Private _dmCount As Integer
95     Private _getDm As Boolean
96     Private _remainCountApi As Integer = -1
97
98     Private _ShortUrlService() As String = { _
99             "http://tinyurl.com/", _
100             "http://is.gd/", _
101             "http://snipurl.com/", _
102             "http://snurl.com/", _
103             "http://nsfw.in/", _
104             "http://qurlyq.com/", _
105             "http://dwarfurl.com/", _
106             "http://icanhaz.com/", _
107             "http://tiny.cc/", _
108             "http://urlenco.de/", _
109             "http://bit.ly/", _
110             "http://piurl.com/", _
111             "http://linkbee.com/", _
112             "http://traceurl.com/", _
113             "http://twurl.nl/", _
114             "http://cli.gs/", _
115             "http://rubyurl.com/", _
116             "http://budurl.com/", _
117             "http://ff.im/", _
118             "http://twitthis.com/", _
119             "http://blip.fm/", _
120             "http://tumblr.com/", _
121             "http://www.qurl.com/", _
122             "http://digg.com/", _
123             "http://u.nu/", _
124             "http://ustre.am/", _
125             "http://pic.gd/", _
126             "http://airme.us/", _
127             "http://qurl.com/", _
128             "http://bctiny.com/", _
129             "http://j.mp/", _
130             "http://goo.gl/" _
131         }
132
133     Private Const _apiHost As String = "api."
134     Private Const _baseUrlStr As String = "twitter.com"
135     Private Const _loginPath As String = "/sessions"
136     Private Const _homePath As String = "/home"
137     Private Const _replyPath As String = "/replies"
138     Private Const _DMPathRcv As String = "/inbox"
139     Private Const _DMPathSnt As String = "/sent"
140     Private Const _DMDestroyPath As String = "/direct_messages/destroy/"
141     Private Const _StDestroyPath As String = "/statuses/destroy/"
142     Private Const _postRetweetPath As String = "/1/statuses/retweet/"
143     Private Const _uidHeader As String = "session[username_or_email]="
144     Private Const _pwdHeader As String = "session[password]="
145     Private Const _pageQry As String = "?page="
146     Private Const _cursorQry As String = "?cursor="
147     Private Const _statusHeader As String = "status="
148     Private Const _statusUpdatePathAPI As String = "/statuses/update.xml"
149     Private Const _linkToOld As String = "class=""section_links"" rel=""prev"""
150     Private Const _postFavAddPath As String = "/favorites/create/"
151     Private Const _postFavRemovePath As String = "/favorites/destroy/"
152     Private Const _authKeyHeader As String = "authenticity_token="
153     'Private Const _parseLink1 As String = "<a href="""
154     'Private Const _parseLink2 As String = """>"
155     'Private Const _parseLink3 As String = "</a>"
156     Private Const _GetFollowers As String = "/statuses/followers.xml"
157     Private Const _ShowStatus As String = "/statuses/show/"
158     Private Const _rateLimitStatus As String = "/account/rate_limit_status.xml"
159
160     '''Wedata対応
161     Private Const wedataUrl As String = "http://wedata.net/databases/Tween/items.json"
162
163     Private Function SignIn() As String
164         If _endingFlag Then Return ""
165
166         'ユーザー情報からデータ部分の生成
167         Dim account As String = ""
168         Static skipCount As Integer = 0
169
170         SyncLock LockObj
171             If _signed Then Return ""
172             If Twitter.AccountState <> ACCOUNT_STATE.Valid AndAlso skipCount < 10 Then
173                 skipCount += 1
174                 Return "SignIn -> Check Username/Password in setting."
175             End If
176             skipCount = 0
177
178             '未認証
179             _signed = False
180
181             MySocket.ResetCookie()
182
183             Dim resStatus As String = ""
184             Dim resMsg As String = ""
185
186             '設定によらずログイン処理はhttps固定
187             resMsg = DirectCast(CreateSocket.GetWebResponse("https://" + _hubServer + "/login", resStatus, MySocket.REQ_TYPE.ReqGET), String)
188             If resMsg.Length = 0 Then
189                 'Twitter.AccountState = ACCOUNT_STATE.Invalid
190                 Return "SignIn -> " + resStatus
191             End If
192             Dim authToken As String = ""
193             Dim rg As New Regex("authenticity_token"" type=""hidden"" value=""(?<auth>[a-z0-9]+)""")
194             Dim m As Match = rg.Match(resMsg)
195             If m.Success Then
196                 authToken = m.Result("${auth}")
197             Else
198                 Return "SignIn -> Can't get token."
199             End If
200
201             account = _authKeyHeader + authToken + "&" + _uidHeader + _uid + "&" + _pwdHeader + HttpUtility.UrlEncode(_pwd) + "&" + "remember_me=1"
202
203             'https固定
204             resMsg = DirectCast(CreateSocket.GetWebResponse("https://" + _hubServer + _loginPath, resStatus, MySocket.REQ_TYPE.ReqPOST, account), String)
205             If resStatus.StartsWith("OK") Then
206                 'OK (username/passwordが合致しない)
207                 Dim msg As String = resStatus
208                 If resMsg.Contains("Wrong Username/Email and password combination.") Then
209                     msg = "Wrong Username or password."
210                 Else
211                     '未知の応答(May be required Chapta)
212                     msg = "Wrong Username or password. Try from web."
213                 End If
214                 Twitter.AccountState = ACCOUNT_STATE.Invalid
215                 Return "SignIn Failed -> " + msg
216             ElseIf resMsg.Contains("https://twitter.com/account/locked") Then   '302 FOUND
217                 Dim msg As String = "You account is Locked Out."
218                 Twitter.AccountState = ACCOUNT_STATE.Invalid
219                 Return "SignIn Failed -> " + msg
220             ElseIf resMsg.Contains("https://twitter.com:443/") Then '302 FOUND
221                 'OK
222             ElseIf resMsg.Contains("https://twitter.com/") OrElse _
223                    resMsg.Contains("http://twitter.com/") Then '302 FOUND
224                 'OK
225             ElseIf resStatus.StartsWith("Err:") Then
226                 ' その他プロトコルエラー
227                 Return "SignIn Failed -> " + resStatus
228             Else
229                 '応答がOK でありサインインできていない場合の未知の応答
230                 'TraceOut(True, "SignIn Failed." + vbCrLf + "resStatus:" + resStatus + vbCrLf + "resMsg:" + vbCrLf + resMsg)
231                 Twitter.AccountState = ACCOUNT_STATE.Invalid
232                 Return "SignIn Failed -> " + "Unknown problems."
233             End If
234             Twitter.AccountState = ACCOUNT_STATE.Valid
235             _signed = True
236             Return ""
237         End SyncLock
238     End Function
239
240     Public Function GetTimeline(ByVal page As Integer, _
241                                 ByVal read As Boolean, _
242                                 ByRef endPage As Integer, _
243                                 ByVal gType As WORKERTYPE, _
244                                 ByRef getDM As Boolean) As String
245
246         If endPage = 0 Then
247             '通常モード
248             Dim epage As Integer = page
249             GetTmSemaphore.WaitOne()
250             Dim trslt As String = ""
251             trslt = GetTimelineThread(page, read, epage, gType, getDM)
252             If trslt.Length > 0 Then Return trslt
253             page += 1
254             If epage < page OrElse gType = WORKERTYPE.Reply Then Return ""
255             endPage = epage
256         End If
257         '起動時モード or 通常モードの読み込み継続 -> 複数ページ同時取得
258         Dim num As Integer = endPage - page
259         Dim ar(num) As IAsyncResult
260         Dim dlgt(num) As GetTimelineDelegate
261
262         For idx As Integer = 0 To num
263             dlgt(idx) = New GetTimelineDelegate(AddressOf GetTimelineThread)
264             GetTmSemaphore.WaitOne()
265             ar(idx) = dlgt(idx).BeginInvoke(page + idx, read, endPage + idx, gType, getDM, Nothing, Nothing)
266         Next
267         Dim rslt As String = ""
268         For idx As Integer = 0 To num
269             Dim epage As Integer = 0
270             Dim dm As Boolean = False
271             Dim trslt As String = ""
272             Try
273                 trslt = dlgt(idx).EndInvoke(epage, dm, ar(idx))
274             Catch ex As Exception
275                 '最後までendinvoke回す(ゾンビ化回避)
276                 ex.Data("IsTerminatePermission") = False
277                 Throw
278                 rslt = "GetTimelineErr"
279             End Try
280             If trslt.Length > 0 AndAlso rslt.Length = 0 Then rslt = trslt
281             If dm Then getDM = True
282         Next
283         Return rslt
284     End Function
285
286     Private Function GetTimelineThread(ByVal page As Integer, _
287                                 ByVal read As Boolean, _
288                                 ByRef endPage As Integer, _
289                                 ByVal gType As WORKERTYPE, _
290                                 ByRef getDM As Boolean) As String
291         Try
292             If _endingFlag Then Return ""
293
294             Dim retMsg As String = ""
295             Dim resStatus As String = ""
296
297             Static redirectToTimeline As String = ""
298             Static redirectToReply As String = ""
299
300             If _signed = False Then
301                 retMsg = SignIn()
302                 If retMsg.Length > 0 Then
303                     Return retMsg
304                 End If
305             End If
306
307             If _endingFlag Then Return ""
308
309             'リクエストメッセージを作成する
310             Dim pageQuery As String
311
312             If page = 1 Then
313                 pageQuery = ""
314             Else
315                 pageQuery = _pageQry + page.ToString
316             End If
317
318             If gType = WORKERTYPE.Timeline Then
319                 retMsg = DirectCast(CreateSocket.GetWebResponse(_protocol + _hubServer + _homePath + pageQuery, resStatus, MySocket.REQ_TYPE.ReqGetApp), String)
320             Else
321                 retMsg = DirectCast(CreateSocket.GetWebResponse(_protocol + _hubServer + _replyPath + pageQuery, resStatus, MySocket.REQ_TYPE.ReqGetApp), String)
322             End If
323
324             If retMsg.Length = 0 Then
325                 _signed = False
326                 Return resStatus
327             End If
328
329             ' tr 要素の class 属性を消去
330             retMsg = Regex.Replace(retMsg, "(?<tagStart><li)(?<cls>\s+class=""[^""]+"")", "${tagStart}")
331             'Do
332             '    Try
333             '        Dim idx As Integer = retMsg.IndexOf(_removeClass, StringComparison.Ordinal)
334             '        If idx = -1 Then Exit Do
335             '        Dim idx2 As Integer = retMsg.IndexOf("""", idx + _removeClass.Length, StringComparison.Ordinal) - idx + 1 - 3
336             '        If idx2 > 0 Then retMsg = retMsg.Remove(idx + 3, idx2)
337             '    Catch ex As Exception
338             '        _signed = False
339             '        TraceOut("TM-Remove: " + retMsg)
340             '        Return "GetTimeline -> Err: Can't parse data."
341             '    End Try
342             'Loop
343
344             If _endingFlag Then Return ""
345
346             '各メッセージに分割可能か?
347             Dim strSepTmp As String
348             If gType = WORKERTYPE.Timeline Then
349                 strSepTmp = _splitPostRecent
350             Else
351                 strSepTmp = _splitPost
352             End If
353
354             Dim pos1 As Integer
355             Dim pos2 As Integer
356
357             pos1 = retMsg.IndexOf(strSepTmp, StringComparison.Ordinal)
358             If pos1 = -1 Then
359                 '0件 or 取得失敗
360                 _signed = False
361                 Return "GetTimeline -> Err: tweets count is 0."
362             End If
363
364             Dim strSep() As String = {strSepTmp}
365             Dim posts() As String = retMsg.Split(strSep, StringSplitOptions.RemoveEmptyEntries)
366             Dim intCnt As Integer = 0
367             Dim listCnt As Integer = 0
368             SyncLock LockObj
369                 listCnt = TabInformations.GetInstance.ItemCount
370             End SyncLock
371             Dim dlgt(20) As GetIconImageDelegate
372             Dim ar(20) As IAsyncResult
373             Dim arIdx As Integer = -1
374             Dim rg As Regex
375             Dim m As Match
376
377             For Each strPost As String In posts
378                 intCnt += 1
379
380                 If intCnt = 1 Then
381                     If page = 1 And gType = WORKERTYPE.Timeline Then
382                         ''siv取得
383                         'pos1 = strPost.IndexOf(_getSiv, 0)
384                         'If pos1 > 0 Then
385                         '    pos2 = strPost.IndexOf(_getSivTo, pos1 + _getSiv.Length)
386                         '    If pos2 > -1 Then
387                         '        _authSiv = strPost.Substring(pos1 + _getSiv.Length, pos2 - pos1 - _getSiv.Length)
388                         '    Else
389                         '        '取得失敗
390                         '        _signed = False
391                         '        Return "GetTimeline -> Err: Can't get Siv."
392                         '    End If
393                         'Else
394                         '    '取得失敗
395                         '    _signed = False
396                         '    Return "GetTimeline -> Err: Can't get Siv."
397                         'End If
398
399                         'AuthKeyの取得
400                         If GetAuthKey(retMsg) < 0 Then
401                             _signed = False
402                             Return "GetTimeline -> Err: Can't get auth token."
403                         End If
404
405                         'TwitterInfoの取得
406                         pos1 = retMsg.IndexOf(_getInfoTwitter, StringComparison.Ordinal)
407                         If pos1 > -1 Then
408                             pos2 = retMsg.IndexOf(_getInfoTwitterTo, pos1, StringComparison.Ordinal)
409                             If pos2 > -1 Then
410                                 _infoTwitter = retMsg.Substring(pos1 + _getInfoTwitter.Length, pos2 - pos1 - _getInfoTwitter.Length)
411                             Else
412                                 _infoTwitter = ""
413                             End If
414                         Else
415                             _infoTwitter = ""
416                         End If
417                     End If
418                 Else
419
420                     Dim post As New PostClass
421
422                     pos1 = strPost.IndexOf("</ol>")
423                     If pos1 > -1 Then
424                         strPost = strPost.Substring(0, pos1)
425                     End If
426
427                     Try
428                         'Get ID
429                         pos1 = 0
430                         pos2 = strPost.IndexOf(_statusIdTo, 0, StringComparison.Ordinal)
431                         post.Id = Long.Parse(HttpUtility.HtmlDecode(strPost.Substring(0, pos2)))
432                     Catch ex As Exception
433                         _signed = False
434                         TraceOut("TM-ID:" + strPost)
435                         Return "GetTimeline -> Err: Can't get ID."
436                     End Try
437                     'Get Name
438                     Try
439                         pos1 = strPost.IndexOf(_parseName, pos2, StringComparison.Ordinal)
440                         pos2 = strPost.IndexOf(_parseNameTo, pos1, StringComparison.Ordinal)
441                         post.Name = HttpUtility.HtmlDecode(strPost.Substring(pos1 + _parseName.Length, pos2 - pos1 - _parseName.Length))
442                     Catch ex As Exception
443                         _signed = False
444                         TraceOut("TM-Name:" + strPost)
445                         Return "GetTimeline -> Err: Can't get Name."
446                     End Try
447                     'Get Nick
448                     '''バレンタイン対応
449                     If strPost.IndexOf("twitter.com/images/heart.png", pos2, StringComparison.Ordinal) > -1 Then
450                         post.Nickname = post.Name
451                     Else
452                         Try
453                             pos1 = strPost.IndexOf(_parseNick, pos2, StringComparison.Ordinal)
454                             pos2 = strPost.IndexOf(_parseNickTo, pos1 + _parseNick.Length, StringComparison.Ordinal)
455                             post.Nickname = HttpUtility.HtmlDecode(strPost.Substring(pos1 + _parseNick.Length, pos2 - pos1 - _parseNick.Length))
456                         Catch ex As Exception
457                             _signed = False
458                             TraceOut("TM-Nick:" + strPost)
459                             Return "GetTimeline -> Err: Can't get Nick."
460                         End Try
461                     End If
462
463                     '二重取得回避
464                     SyncLock LockObj
465                         If TabInformations.GetInstance.ContainsKey(post.Id) Then Continue For
466                     End SyncLock
467
468                     Dim orgData As String = ""
469                     'バレンタイン
470                     If strPost.IndexOf("<form action=""/status/update"" id=""heartForm", 0, StringComparison.Ordinal) > -1 Then
471                         Try
472                             pos1 = strPost.IndexOf("<strong>", 0, StringComparison.Ordinal)
473                             pos2 = strPost.IndexOf("</strong>", pos1, StringComparison.Ordinal)
474                             orgData = strPost.Substring(pos1 + 8, pos2 - pos1 - 8)
475                         Catch ex As Exception
476                             _signed = False
477                             TraceOut("TM-VBody:" + strPost)
478                             Return "GetTimeline -> Err: Can't get Valentine body."
479                         End Try
480                     End If
481
482
483                     'Get ImagePath
484                     Try
485                         pos1 = strPost.IndexOf(_parseImg, pos2, StringComparison.Ordinal)
486                         pos2 = strPost.IndexOf(_parseImgTo, pos1 + _parseImg.Length, StringComparison.Ordinal)
487                         post.ImageUrl = HttpUtility.HtmlDecode(strPost.Substring(pos1 + _parseImg.Length, pos2 - pos1 - _parseImg.Length))
488                     Catch ex As Exception
489                         _signed = False
490                         TraceOut("TM-Img:" + strPost)
491                         Return "GetTimeline -> Err: Can't get ImagePath."
492                     End Try
493
494                     'Protect
495                     If strPost.IndexOf(_isProtect, pos2, StringComparison.Ordinal) > -1 Then
496                         post.IsProtect = True
497                     End If
498
499                     'RetweetedBy
500                     If strPost.IndexOf("class=""big-retweet-icon""") > -1 Then
501                         rg = New Regex("class=""shared-content"".+<a href=""/(?<name>[a-zA-Z0-9_]+)""")
502                         m = rg.Match(strPost)
503                         If m.Success Then
504                             post.RetweetedBy = m.Result("${name}")
505                         Else
506                             post.RetweetedBy = ""
507                         End If
508                         rg = New Regex("&in_reply_to_status_id=(?<id>[0-9]+)&in_reply_to=")
509                         m = rg.Match(strPost)
510                         If m.Success Then
511                             post.RetweetedId = Long.Parse(m.Result("${id}"))
512                         Else
513                             post.RetweetedId = 0
514                         End If
515                     End If
516
517                     'Get Message
518                     pos1 = strPost.IndexOf(_parseMsg1, pos2, StringComparison.Ordinal)
519                     If pos1 < 0 Then
520                         'Valentine対応その2
521                         Try
522                             If strPost.IndexOf("<div id=""doyouheart", pos2, StringComparison.Ordinal) > -1 Then
523                                 'バレンタイン
524                                 orgData += " <3 you! Do you <3 "
525                                 pos1 = strPost.IndexOf("<a href", pos2, StringComparison.Ordinal)
526                                 pos2 = strPost.IndexOf("?", pos1, StringComparison.Ordinal)
527                                 orgData += strPost.Substring(pos1, pos2 - pos1 + 1)
528                             Else
529                                 pos1 = strPost.IndexOf(_parseProtectMsg1, pos2, StringComparison.Ordinal)
530                                 If pos1 = -1 Then
531                                     'バレンタイン
532                                     orgData += " <3 's "
533                                     pos1 = strPost.IndexOf("<a href", pos2, StringComparison.Ordinal)
534                                     If pos1 > -1 Then
535                                         pos2 = strPost.IndexOf("!", pos1, StringComparison.Ordinal)
536                                         orgData += strPost.Substring(pos1, pos2 - pos1 + 1)
537                                     End If
538                                 Else
539                                     'プロテクトメッセージ
540                                     pos2 = strPost.IndexOf(_parseProtectMsg2, pos1, StringComparison.Ordinal)
541                                     orgData = strPost.Substring(pos1 + _parseProtectMsg1.Length, pos2 - pos1 - _parseProtectMsg1.Length).Trim()
542                                 End If
543                             End If
544                         Catch ex As Exception
545                             _signed = False
546                             TraceOut("TM-VBody2:" + strPost)
547                             Return "GetTimeline -> Err: Can't get Valentine body2."
548                         End Try
549                     Else
550                         '通常メッセージ
551                         Try
552                             pos2 = strPost.IndexOf(_parseMsg2, pos1, StringComparison.Ordinal)
553                             orgData = strPost.Substring(pos1 + _parseMsg1.Length, pos2 - pos1 - _parseMsg1.Length).Trim()
554                         Catch ex As Exception
555                             _signed = False
556                             TraceOut("TM-Body:" + strPost)
557                             Return "GetTimeline -> Err: Can't get body."
558                         End Try
559                         '#If 0 Then
560                         '                        '原文リンク削除
561                         '                        orgData = Regex.Replace(orgData, "<a href=""https://twitter\.com/" + post.Name + "/status/[0-9]+"">\.\.\.</a>$", "")
562                         '#End If
563                         'ハート変換
564                         orgData = orgData.Replace("&lt;3", "♡")
565                     End If
566
567                     'URL前処理(IDNデコードなど)
568                     orgData = PreProcessUrl(orgData)
569
570                     '短縮URL解決処理(orgData書き換え)
571                     orgData = ShortUrlResolve(orgData)
572
573                     '表示用にhtml整形
574                     post.OriginalData = AdjustHtml(orgData)
575
576                     '単純テキストの取り出し(リンクタグ除去)
577                     Try
578                         post.Data = GetPlainText(orgData)
579                     Catch ex As Exception
580                         _signed = False
581                         TraceOut("TM-Link:" + strPost)
582                         Return "GetTimeline -> Err: Can't parse links."
583                     End Try
584
585                     ' Imageタグ除去(ハロウィン)
586                     Dim ImgTag As New Regex("<img src=.*?/>", RegexOptions.IgnoreCase)
587                     If ImgTag.IsMatch(post.Data) Then post.Data = ImgTag.Replace(post.Data, "<img>")
588
589                     'Get Date
590 #If 1 Then
591                     Try
592                         pos1 = strPost.IndexOf(_parseDate, pos2, StringComparison.Ordinal)
593                         If pos1 > -1 Then
594                             pos2 = strPost.IndexOf(_parseDateTo, pos1 + _parseDate.Length, StringComparison.Ordinal)
595                             post.PDate = DateTime.ParseExact(strPost.Substring(pos1 + _parseDate.Length, pos2 - pos1 - _parseDate.Length), "ddd MMM dd HH':'mm':'ss zzzz yyyy", System.Globalization.DateTimeFormatInfo.InvariantInfo, Globalization.DateTimeStyles.None)
596                         Else
597                             post.PDate = Now()
598                         End If
599                     Catch ex As Exception
600                         _signed = False
601                         TraceOut("TM-Date:" + strPost)
602                         Return "GetTimeline -> Err: Can't get date."
603                     End Try
604 #Else
605                     '取得できなくなったため暫定対応(2/26)
606                     post.PDate = Now()
607 #End If
608
609
610                     'from Sourceの取得
611                     'ToDo: _parseSourceFromを正規表現へ。wedataからの取得へ変更(次版より)
612                     rg = New Regex("<span>.+>(?<name>.+)</a>.*</span>")
613                     m = rg.Match(strPost)
614                     If m.Success Then
615                         post.Source = m.Result("${name}")
616                     Else
617                         post.Source = "Web"
618                     End If
619                     'Try
620                     '    pos1 = strPost.IndexOf(_parseSourceFrom, pos2, StringComparison.Ordinal)
621                     '    If pos1 = -1 Then pos1 = strPost.IndexOf(_parseSourceFrom2, pos2, StringComparison.Ordinal)
622                     '    If pos1 > -1 Then
623                     '        pos1 = strPost.IndexOf(_parseSource2, pos1 + 19, StringComparison.Ordinal)
624                     '        pos2 = strPost.IndexOf(_parseSourceTo, pos1 + 2, StringComparison.Ordinal)
625                     '        post.Source = HttpUtility.HtmlDecode(strPost.Substring(pos1 + 2, pos2 - pos1 - 2))
626                     '    Else
627                     '        post.Source = "Web"
628                     '    End If
629                     'Catch ex As Exception
630                     '    _signed = False
631                     '    TraceOut("TM-Src:" + strPost)
632                     '    Return "GetTimeline -> Err: Can't get src."
633                     'End Try
634
635                     'Get Reply(in_reply_to_user/id)
636                     'ToDo: _isReplyEngを正規表現へ。wedataからの取得へ変更(次版より)
637                     rg = New Regex("<a href=""https?:\/\/twitter\.com\/(?<name>[a-zA-Z0-9_]+)\/status\/(?<id>[0-9]+)"">(in reply to )*\k<name>")
638                     m = rg.Match(strPost)
639                     If m.Success Then
640                         post.InReplyToUser = m.Result("${name}")
641                         post.InReplyToId = Long.Parse(m.Result("${id}"))
642                         post.IsReply = post.InReplyToUser.Equals(_uid, StringComparison.OrdinalIgnoreCase)
643                     End If
644
645                     '@先リスト作成
646                     rg = New Regex("@<a [^>]*href=""\/(?<1>[a-zA-Z0-9_]+)[^a-zA-Z0-9_]")
647                     m = rg.Match(orgData)
648                     While m.Success
649                         post.ReplyToList.Add(m.Groups(1).Value.ToLower())
650                         m = m.NextMatch
651                     End While
652                     If Not post.IsReply Then post.IsReply = post.ReplyToList.Contains(_uid)
653
654                     If gType = WORKERTYPE.Reply Then post.IsReply = True
655
656                     'Get Fav
657                     If strPost.IndexOf("class=""fav-action fav""") > -1 Then
658                         post.IsFav = True
659                     Else
660                         post.IsFav = False
661                     End If
662                     'pos1 = strPost.IndexOf(_parseStar, pos2, StringComparison.Ordinal)
663                     'If pos1 > -1 Then
664                     '    Try
665                     '        pos2 = strPost.IndexOf(_parseStarTo, pos1 + _parseStar.Length, StringComparison.Ordinal)
666                     '        If strPost.Substring(pos1 + _parseStar.Length, pos2 - pos1 - _parseStar.Length) = _parseStarEmpty Then
667                     '            post.IsFav = False
668                     '        Else
669                     '            post.IsFav = True
670                     '        End If
671                     '    Catch ex As Exception
672                     '        _signed = False
673                     '        TraceOut("TM-Fav:" + strPost)
674                     '        Return "GetTimeline -> Err: Can't get fav status."
675                     '    End Try
676                     'Else
677                     '    post.IsFav = False
678                     'End If
679
680                     If _endingFlag Then Return ""
681
682                     post.IsMe = post.Name.Equals(_uid, StringComparison.OrdinalIgnoreCase)
683                     SyncLock LockObj
684                         If follower.Count > 1 Then
685                             post.IsOwl = Not follower.Contains(post.Name.ToLower())
686                         Else
687                             post.IsOwl = False
688                         End If
689                     End SyncLock
690                     post.IsRead = read
691                     If post.IsMe AndAlso Not read AndAlso _readOwnPost Then post.IsRead = True
692
693                     arIdx += 1
694                     dlgt(arIdx) = New GetIconImageDelegate(AddressOf GetIconImage)
695                     ar(arIdx) = dlgt(arIdx).BeginInvoke(post, Nothing, Nothing)
696
697                 End If
698
699                 'テスト実装:DMカウント取得
700                 If intCnt = posts.Length AndAlso gType = WORKERTYPE.Timeline AndAlso page = 1 Then
701                     pos1 = strPost.IndexOf(_parseDMcountFrom, pos2, StringComparison.Ordinal)
702                     If pos1 > -1 Then
703                         Try
704                             pos2 = strPost.IndexOf(_parseDMcountTo, pos1 + _parseDMcountFrom.Length, StringComparison.Ordinal)
705                             Dim dmCnt As Integer = Integer.Parse(strPost.Substring(pos1 + _parseDMcountFrom.Length, pos2 - pos1 - _parseDMcountFrom.Length))
706                             If dmCnt > _dmCount Then
707                                 _dmCount = dmCnt
708                                 _getDm = True
709                             End If
710                         Catch ex As Exception
711                             Return "GetTimeline -> Err: Can't get DM count."
712                         End Try
713                     End If
714                 End If
715                 getDM = _getDm
716             Next
717
718             For i As Integer = 0 To arIdx
719                 Try
720                     dlgt(i).EndInvoke(ar(i))
721                 Catch ex As Exception
722                     '最後までendinvoke回す(ゾンビ化回避)
723                     ex.Data("IsTerminatePermission") = False
724                     Throw
725                 End Try
726             Next
727
728             SyncLock LockObj
729                 If page = 1 AndAlso (TabInformations.GetInstance.ItemCount - listCnt) >= _nextThreshold Then
730                     '新着が閾値の件数以上なら、次のページも念のため読み込み
731                     endPage = _nextPages + 1
732                 End If
733             End SyncLock
734
735             Return ""
736         Finally
737             GetTmSemaphore.Release()
738         End Try
739     End Function
740
741     Public Function GetDirectMessage(ByVal page As Integer, _
742                                     ByVal read As Boolean, _
743                                     ByVal endPage As Integer, _
744                                     ByVal gType As WORKERTYPE) As String
745
746         If endPage = 0 Then
747             '通常モード(DMはモード関係なし)
748             endPage = 1
749         End If
750         '起動時モード 
751         Dim num As Integer = endPage - page
752         Dim ar(num) As IAsyncResult
753         Dim dlgt(num) As GetDirectMessageDelegate
754
755         For idx As Integer = 0 To num
756             gType = WORKERTYPE.DirectMessegeRcv
757             dlgt(idx) = New GetDirectMessageDelegate(AddressOf GetDirectMessageThread)
758             GetTmSemaphore.WaitOne()
759             ar(idx) = dlgt(idx).BeginInvoke(page + idx, read, endPage + idx, gType, Nothing, Nothing)
760         Next
761         Dim rslt As String = ""
762         For idx As Integer = 0 To num
763             Dim trslt As String = ""
764             Try
765                 trslt = dlgt(idx).EndInvoke(ar(idx))
766             Catch ex As Exception
767                 '最後までendinvoke回す(ゾンビ化回避)
768                 ex.Data("IsTerminatePermission") = False
769                 Throw
770                 rslt = "GetDirectMessageErr"
771             End Try
772             If trslt.Length > 0 AndAlso rslt.Length = 0 Then rslt = trslt
773         Next
774         For idx As Integer = 0 To num
775             gType = WORKERTYPE.DirectMessegeSnt
776             dlgt(idx) = New GetDirectMessageDelegate(AddressOf GetDirectMessageThread)
777             GetTmSemaphore.WaitOne()
778             ar(idx) = dlgt(idx).BeginInvoke(page + idx, read, endPage + idx, gType, Nothing, Nothing)
779         Next
780         For idx As Integer = 0 To num
781             Dim trslt As String = ""
782             Try
783                 trslt = dlgt(idx).EndInvoke(ar(idx))
784             Catch ex As Exception
785                 '最後までendinvoke回す(ゾンビ化回避)
786                 ex.Data("IsTerminatePermission") = False
787                 Throw
788                 rslt = "GetDirectMessageErr"
789             End Try
790             If trslt.Length > 0 AndAlso rslt.Length = 0 Then rslt = trslt
791         Next
792         Return rslt
793     End Function
794
795     Private Function GetDirectMessageThread(ByVal page As Integer, _
796                                     ByVal read As Boolean, _
797                                     ByVal endPage As Integer, _
798                                     ByVal gType As WORKERTYPE) As String
799         Try
800             If _endingFlag Then Return ""
801
802             Dim retMsg As String = ""
803             Dim resStatus As String = ""
804
805             Static redirectToDmRcv As String = ""
806             Static redirectToDmSnd As String = ""
807
808             _getDm = False
809
810             If _signed = False Then
811                 retMsg = SignIn()
812                 If retMsg.Length > 0 Then
813                     Return retMsg
814                 End If
815             End If
816
817             If _endingFlag Then Return ""
818
819             'リクエストメッセージを作成する
820             Dim pageQuery As String = _pageQry + page.ToString
821             If gType = WORKERTYPE.DirectMessegeRcv Then
822                 retMsg = DirectCast(CreateSocket.GetWebResponse(_protocol + _hubServer + _DMPathRcv + pageQuery, resStatus, MySocket.REQ_TYPE.ReqGetApp), String)
823             Else
824                 retMsg = DirectCast(CreateSocket.GetWebResponse(_protocol + _hubServer + _DMPathSnt + pageQuery, resStatus, MySocket.REQ_TYPE.ReqGetApp), String)
825             End If
826
827             If retMsg.Length = 0 Then
828                 _signed = False
829                 Return resStatus
830             End If
831
832             ' tr 要素の class 属性を消去
833             retMsg = Regex.Replace(retMsg, "(?<tagStart><li)(?<cls>\s+class=""[^""]+"")", "${tagStart}")
834             'Do
835             '    Try
836             '        Dim idx As Integer = retMsg.IndexOf(_removeClass, StringComparison.Ordinal)
837             '        If idx = -1 Then Exit Do
838             '        Dim idx2 As Integer = retMsg.IndexOf("""", idx + _removeClass.Length, StringComparison.Ordinal) - idx + 1 - 3
839             '        If idx2 > 0 Then retMsg = retMsg.Remove(idx + 3, idx2)
840             '    Catch ex As Exception
841             '        _signed = False
842             '        TraceOut("DM-Remove: " + retMsg)
843             '        Return "GetDm -> Err: Can't parse data."
844             '    End Try
845             'Loop
846
847             If _endingFlag Then Return ""
848
849             ''AuthKeyの取得
850             'If GetAuthKeyDM(retMsg) < 0 Then
851             '    _signed = False
852             '    Return "GetDirectMessage -> Err: Busy(1)"
853             'End If
854
855             Dim pos1 As Integer
856             Dim pos2 As Integer
857
858             '各メッセージに分割可能か?
859             pos1 = retMsg.IndexOf(_splitDM, StringComparison.Ordinal)
860             If pos1 = -1 Then
861                 '0件(メッセージなし。エラーの場合もありうるが判別できないので正常として戻す)
862                 Return ""
863             End If
864
865             Dim strSep() As String = {_splitDM}
866             Dim posts() As String = retMsg.Split(strSep, StringSplitOptions.RemoveEmptyEntries)
867             Dim intCnt As Integer = 0   'カウンタ
868             Dim listCnt As Integer = 0
869             SyncLock LockObj
870                 listCnt = TabInformations.GetInstance.ItemCount
871             End SyncLock
872             Dim dlgt(20) As GetIconImageDelegate
873             Dim ar(20) As IAsyncResult
874             Dim arIdx As Integer = -1
875
876             For Each strPost As String In posts
877                 intCnt += 1
878
879                 If intCnt > 1 Then  '1件目はヘッダなので無視
880                     'Dim lItem As New MyListItem
881                     Dim post As New PostClass()
882
883                     pos1 = strPost.IndexOf("</ol>")
884                     If pos1 > -1 Then
885                         strPost = strPost.Substring(0, pos1)
886                     End If
887
888                     'Get ID
889                     Try
890                         pos1 = 0
891                         pos2 = strPost.IndexOf("""", 0, StringComparison.Ordinal)
892                         post.Id = Long.Parse(HttpUtility.HtmlDecode(strPost.Substring(0, pos2)))
893                     Catch ex As Exception
894                         _signed = False
895                         TraceOut("DM-ID:" + strPost)
896                         Return "GetDirectMessage -> Err: Can't get ID"
897                     End Try
898
899                     'Get Name
900                     Try
901                         pos1 = strPost.IndexOf(_parseName, pos2, StringComparison.Ordinal)
902                         pos2 = strPost.IndexOf(_parseNameTo, pos1, StringComparison.Ordinal)
903                         post.Name = HttpUtility.HtmlDecode(strPost.Substring(pos1 + _parseName.Length, pos2 - pos1 - _parseName.Length))
904                     Catch ex As Exception
905                         _signed = False
906                         TraceOut("DM-Name:" + strPost)
907                         Return "GetDirectMessage -> Err: Can't get Name"
908                     End Try
909
910                     'Get Nick
911                     Try
912                         pos1 = strPost.IndexOf(_parseNick, pos2, StringComparison.Ordinal)
913                         pos2 = strPost.IndexOf(_parseNickTo, pos1 + _parseNick.Length, StringComparison.Ordinal)
914                         post.Nickname = HttpUtility.HtmlDecode(strPost.Substring(pos1 + _parseNick.Length, pos2 - pos1 - _parseNick.Length))
915                     Catch ex As Exception
916                         _signed = False
917                         TraceOut("DM-Nick:" + strPost)
918                         Return "GetDirectMessage -> Err: Can't get Nick."
919                     End Try
920
921                     SyncLock LockObj
922                         If TabInformations.GetInstance.ContainsKey(post.Id) Then Continue For
923                     End SyncLock
924
925                     'Get ImagePath
926                     Try
927                         pos1 = strPost.IndexOf(_parseImg, pos2, StringComparison.Ordinal)
928                         pos2 = strPost.IndexOf(_parseImgTo, pos1 + _parseImg.Length, StringComparison.Ordinal)
929                         post.ImageUrl = HttpUtility.HtmlDecode(strPost.Substring(pos1 + _parseImg.Length, pos2 - pos1 - _parseImg.Length))
930                     Catch ex As Exception
931                         _signed = False
932                         TraceOut("DM-Img:" + strPost)
933                         Return "GetDirectMessage -> Err: Can't get ImagePath"
934                     End Try
935
936                     'Get Protect 
937                     Try
938                         pos1 = strPost.IndexOf(_isProtect, pos2, StringComparison.Ordinal)
939                         If pos1 > -1 Then post.IsProtect = True
940                     Catch ex As Exception
941                         _signed = False
942                         TraceOut("DM-Protect:" + strPost)
943                         Return "GetDirectMessage -> Err: Can't get Protect"
944                     End Try
945
946                     Dim orgData As String = ""
947
948                     'Get Message
949                     Try
950                         pos1 = strPost.IndexOf(_parseDM1, pos2, StringComparison.Ordinal)
951                         If pos1 > -1 Then
952                             pos2 = strPost.IndexOf(_parseDM2, pos1, StringComparison.Ordinal)
953                             orgData = strPost.Substring(pos1 + _parseDM1.Length, pos2 - pos1 - _parseDM1.Length).Trim()
954                         Else
955                             pos1 = strPost.IndexOf(_parseDM11, pos2, StringComparison.Ordinal)
956                             pos2 = strPost.IndexOf(_parseDM2, pos1, StringComparison.Ordinal)
957                             orgData = strPost.Substring(pos1 + _parseDM11.Length, pos2 - pos1 - _parseDM11.Length).Trim()
958                         End If
959                         'orgData = Regex.Replace(orgData, "<a href=""https://twitter\.com/" + post.Name + "/status/[0-9]+"">\.\.\.</a>$", "")
960                         orgData = orgData.Replace("&lt;3", "♡")
961                     Catch ex As Exception
962                         _signed = False
963                         TraceOut("DM-Body:" + strPost)
964                         Return "GetDirectMessage -> Err: Can't get body"
965                     End Try
966
967                     'URL前処理(IDNデコードなど)
968                     orgData = PreProcessUrl(orgData)
969
970                     '短縮URL解決処理(orgData書き換え)
971                     orgData = ShortUrlResolve(orgData)
972
973                     '表示用にhtml整形
974                     post.OriginalData = AdjustHtml(orgData)
975
976                     '単純テキストの取り出し(リンクタグ除去)
977                     Try
978                         post.Data = GetPlainText(orgData)
979                     Catch ex As Exception
980                         _signed = False
981                         TraceOut("DM-Link:" + strPost)
982                         Return "GetDirectMessage -> Err: Can't parse links"
983                     End Try
984
985 #If 1 Then
986                     'Get Date
987                     Try
988                         pos1 = strPost.IndexOf(_parseDate, pos2, StringComparison.Ordinal)
989                         If pos1 > -1 Then
990                             pos2 = strPost.IndexOf(_parseDateTo, pos1 + _parseDate.Length, StringComparison.Ordinal)
991                             post.PDate = DateTime.ParseExact(strPost.Substring(pos1 + _parseDate.Length, pos2 - pos1 - _parseDate.Length), "ddd MMM dd HH':'mm':'ss zzzz yyyy", System.Globalization.DateTimeFormatInfo.InvariantInfo, Globalization.DateTimeStyles.None)
992                         Else
993                             post.PDate = Now()
994                         End If
995                     Catch ex As Exception
996                         _signed = False
997                         TraceOut("DM-Date:" + strPost)
998                         Return "GetDirectMessage -> Err: Can't get date."
999                     End Try
1000 #Else
1001                     '取得できなくなったため暫定対応(2/26)
1002                     post.PDate = Now()
1003 #End If
1004
1005                     'Get Fav
1006                     'pos1 = strPost.IndexOf(_parseStar, pos2)
1007                     'pos2 = strPost.IndexOf("""", pos1 + _parseStar.Length)
1008                     'If strPost.Substring(pos1 + _parseStar.Length, pos2 - pos1 - _parseStar.Length) = "empty" Then
1009                     '    lItem.Fav = False
1010                     'Else
1011                     '    lItem.Fav = True
1012                     'End If
1013                     post.IsFav = False
1014
1015
1016                     If _endingFlag Then Return ""
1017
1018                     '受信DMかの判定で使用
1019                     If gType = WORKERTYPE.DirectMessegeRcv Then
1020                         post.IsOwl = False
1021                     Else
1022                         post.IsOwl = True
1023                     End If
1024
1025                     post.IsRead = read
1026                     post.IsDm = True
1027
1028                     'Imageの取得
1029                     arIdx += 1
1030                     dlgt(arIdx) = New GetIconImageDelegate(AddressOf GetIconImage)
1031                     ar(arIdx) = dlgt(arIdx).BeginInvoke(post, Nothing, Nothing)
1032                 End If
1033             Next
1034
1035             For i As Integer = 0 To arIdx
1036                 Try
1037                     dlgt(i).EndInvoke(ar(i))
1038                 Catch ex As Exception
1039                     ex.Data("IsTerminatePermission") = False
1040                     Throw
1041                 End Try
1042             Next
1043
1044             Return ""
1045
1046         Finally
1047             GetTmSemaphore.Release()
1048         End Try
1049     End Function
1050
1051     Public Function GetFavorites(ByVal page As Integer, _
1052                                 ByVal read As Boolean, _
1053                                 ByRef endPage As Integer, _
1054                                 ByVal gType As WORKERTYPE, _
1055                                 ByRef getDM As Boolean) As String
1056
1057         GetTmSemaphore.WaitOne()
1058         Try
1059             If _endingFlag Then Return ""
1060
1061             Dim retMsg As String = ""
1062             Dim resStatus As String = ""
1063
1064             Static redirectToFav As String = ""
1065             Const FAV_PATH As String = "/favorites"
1066
1067             If _signed = False Then
1068                 retMsg = SignIn()
1069                 If retMsg.Length > 0 Then
1070                     Return retMsg
1071                 End If
1072             End If
1073
1074             If _endingFlag Then Return ""
1075
1076             'リクエストメッセージを作成する
1077             Dim pageQuery As String
1078
1079             If page = 1 Then
1080                 pageQuery = ""
1081             Else
1082                 pageQuery = _pageQry + page.ToString
1083             End If
1084
1085             retMsg = DirectCast(CreateSocket.GetWebResponse(_protocol + _hubServer + FAV_PATH + pageQuery, resStatus, MySocket.REQ_TYPE.ReqGetApp), String)
1086
1087             If retMsg.Length = 0 Then
1088                 _signed = False
1089                 Return resStatus
1090             End If
1091
1092             ' tr 要素の class 属性を消去
1093             retMsg = Regex.Replace(retMsg, "(?<tagStart><li)(?<cls>\s+class=""[^""]+"")", "${tagStart}")
1094             'Do
1095             '    Try
1096             '        Dim idx As Integer = retMsg.IndexOf(_removeClass, StringComparison.Ordinal)
1097             '        If idx = -1 Then Exit Do
1098             '        Dim idx2 As Integer = retMsg.IndexOf("""", idx + _removeClass.Length, StringComparison.Ordinal) - idx + 1 - 3
1099             '        If idx2 > 0 Then retMsg = retMsg.Remove(idx + 3, idx2)
1100             '    Catch ex As Exception
1101             '        _signed = False
1102             '        TraceOut("GetFav-Remove: " + retMsg)
1103             '        Return "GetFav -> Err: Can't parse data."
1104             '    End Try
1105             'Loop
1106
1107             If _endingFlag Then Return ""
1108
1109             '各メッセージに分割可能か?
1110             Dim strSepTmp As String
1111             strSepTmp = _splitPostRecent
1112
1113             Dim pos1 As Integer
1114             Dim pos2 As Integer
1115
1116             pos1 = retMsg.IndexOf(strSepTmp, StringComparison.Ordinal)
1117             If pos1 = -1 Then
1118                 '0件 or 取得失敗
1119                 _signed = False
1120                 Return "GetTimeline -> Err: tweets count is 0."
1121             End If
1122
1123             Dim strSep() As String = {strSepTmp}
1124             Dim posts() As String = retMsg.Split(strSep, StringSplitOptions.RemoveEmptyEntries)
1125             Dim intCnt As Integer = 0
1126             Dim listCnt As Integer = 0
1127             SyncLock LockObj
1128                 listCnt = TabInformations.GetInstance.ItemCount
1129             End SyncLock
1130             Dim dlgt(20) As GetIconImageDelegate
1131             Dim ar(20) As IAsyncResult
1132             Dim arIdx As Integer = -1
1133             Dim rg As Regex
1134             Dim m As Match
1135
1136             For Each strPost As String In posts
1137                 intCnt += 1
1138
1139                 If intCnt = 1 Then
1140                     Continue For
1141                 Else
1142
1143                     Dim post As New PostClass
1144
1145                     pos1 = strPost.IndexOf("</ol>")
1146                     If pos1 > -1 Then
1147                         strPost = strPost.Substring(0, pos1)
1148                     End If
1149
1150                     Try
1151                         'Get ID
1152                         pos1 = 0
1153                         pos2 = strPost.IndexOf(_statusIdTo, 0, StringComparison.Ordinal)
1154                         post.Id = Long.Parse(HttpUtility.HtmlDecode(strPost.Substring(0, pos2)))
1155                     Catch ex As Exception
1156                         _signed = False
1157                         TraceOut("TM-ID:" + strPost)
1158                         Return "GetTimeline -> Err: Can't get ID."
1159                     End Try
1160                     'Get Name
1161                     Try
1162                         pos1 = strPost.IndexOf(_parseName, pos2, StringComparison.Ordinal)
1163                         pos2 = strPost.IndexOf(_parseNameTo, pos1, StringComparison.Ordinal)
1164                         post.Name = HttpUtility.HtmlDecode(strPost.Substring(pos1 + _parseName.Length, pos2 - pos1 - _parseName.Length))
1165                     Catch ex As Exception
1166                         _signed = False
1167                         TraceOut("TM-Name:" + strPost)
1168                         Return "GetTimeline -> Err: Can't get Name."
1169                     End Try
1170                     'Get Nick
1171                     '''バレンタイン対応
1172                     If strPost.IndexOf("twitter.com/images/heart.png", pos2, StringComparison.Ordinal) > -1 Then
1173                         post.Nickname = post.Name
1174                     Else
1175                         Try
1176                             pos1 = strPost.IndexOf(_parseNick, pos2, StringComparison.Ordinal)
1177                             pos2 = strPost.IndexOf(_parseNickTo, pos1 + _parseNick.Length, StringComparison.Ordinal)
1178                             post.Nickname = HttpUtility.HtmlDecode(strPost.Substring(pos1 + _parseNick.Length, pos2 - pos1 - _parseNick.Length))
1179                         Catch ex As Exception
1180                             _signed = False
1181                             TraceOut("TM-Nick:" + strPost)
1182                             Return "GetTimeline -> Err: Can't get Nick."
1183                         End Try
1184                     End If
1185
1186                     ''二重取得回避
1187                     'SyncLock LockObj
1188                     '    If TabInformations.GetInstance.ContainsKey(post.Id) Then Continue For
1189                     'End SyncLock
1190
1191                     Dim orgData As String = ""
1192                     'バレンタイン
1193                     If strPost.IndexOf("<form action=""/status/update"" id=""heartForm", 0, StringComparison.Ordinal) > -1 Then
1194                         Try
1195                             pos1 = strPost.IndexOf("<strong>", 0, StringComparison.Ordinal)
1196                             pos2 = strPost.IndexOf("</strong>", pos1, StringComparison.Ordinal)
1197                             orgData = strPost.Substring(pos1 + 8, pos2 - pos1 - 8)
1198                         Catch ex As Exception
1199                             _signed = False
1200                             TraceOut("TM-VBody:" + strPost)
1201                             Return "GetTimeline -> Err: Can't get Valentine body."
1202                         End Try
1203                     End If
1204
1205
1206                     'Get ImagePath
1207                     Try
1208                         pos1 = strPost.IndexOf(_parseImg, pos2, StringComparison.Ordinal)
1209                         pos2 = strPost.IndexOf(_parseImgTo, pos1 + _parseImg.Length, StringComparison.Ordinal)
1210                         post.ImageUrl = HttpUtility.HtmlDecode(strPost.Substring(pos1 + _parseImg.Length, pos2 - pos1 - _parseImg.Length))
1211                     Catch ex As Exception
1212                         _signed = False
1213                         TraceOut("TM-Img:" + strPost)
1214                         Return "GetTimeline -> Err: Can't get ImagePath."
1215                     End Try
1216
1217                     'Protect
1218                     If strPost.IndexOf(_isProtect, pos2, StringComparison.Ordinal) > -1 Then
1219                         post.IsProtect = True
1220                     End If
1221
1222                     'RetweetedBy
1223                     If strPost.IndexOf("class=""big-retweet-icon""") > -1 Then
1224                         rg = New Regex("class=""shared-content"".+<a href=""/(?<name>[a-zA-Z0-9_]+)""")
1225                         m = rg.Match(strPost)
1226                         If m.Success Then
1227                             post.RetweetedBy = m.Result("${name}")
1228                         Else
1229                             post.RetweetedBy = ""
1230                         End If
1231                         rg = New Regex("&in_reply_to_status_id=(?<id>[0-9]+)&in_reply_to=")
1232                         m = rg.Match(strPost)
1233                         If m.Success Then
1234                             post.RetweetedId = Long.Parse(m.Result("${id}"))
1235                         Else
1236                             post.RetweetedId = 0
1237                         End If
1238                     End If
1239
1240                     'Get Message
1241                     pos1 = strPost.IndexOf(_parseMsg1, pos2, StringComparison.Ordinal)
1242                     If pos1 < 0 Then
1243                         'Valentine対応その2
1244                         Try
1245                             If strPost.IndexOf("<div id=""doyouheart", pos2, StringComparison.Ordinal) > -1 Then
1246                                 'バレンタイン
1247                                 orgData += " <3 you! Do you <3 "
1248                                 pos1 = strPost.IndexOf("<a href", pos2, StringComparison.Ordinal)
1249                                 pos2 = strPost.IndexOf("?", pos1, StringComparison.Ordinal)
1250                                 orgData += strPost.Substring(pos1, pos2 - pos1 + 1)
1251                             Else
1252                                 pos1 = strPost.IndexOf(_parseProtectMsg1, pos2, StringComparison.Ordinal)
1253                                 If pos1 = -1 Then
1254                                     'バレンタイン
1255                                     orgData += " <3 's "
1256                                     pos1 = strPost.IndexOf("<a href", pos2, StringComparison.Ordinal)
1257                                     If pos1 > -1 Then
1258                                         pos2 = strPost.IndexOf("!", pos1, StringComparison.Ordinal)
1259                                         orgData += strPost.Substring(pos1, pos2 - pos1 + 1)
1260                                     End If
1261                                 Else
1262                                     'プロテクトメッセージ
1263                                     pos2 = strPost.IndexOf(_parseProtectMsg2, pos1, StringComparison.Ordinal)
1264                                     orgData = strPost.Substring(pos1 + _parseProtectMsg1.Length, pos2 - pos1 - _parseProtectMsg1.Length).Trim()
1265                                 End If
1266                             End If
1267                         Catch ex As Exception
1268                             _signed = False
1269                             TraceOut("TM-VBody2:" + strPost)
1270                             Return "GetTimeline -> Err: Can't get Valentine body2."
1271                         End Try
1272                     Else
1273                         '通常メッセージ
1274                         Try
1275                             pos2 = strPost.IndexOf(_parseMsg2, pos1, StringComparison.Ordinal)
1276                             orgData = strPost.Substring(pos1 + _parseMsg1.Length, pos2 - pos1 - _parseMsg1.Length).Trim()
1277                         Catch ex As Exception
1278                             _signed = False
1279                             TraceOut("TM-Body:" + strPost)
1280                             Return "GetTimeline -> Err: Can't get body."
1281                         End Try
1282                         '#If 0 Then
1283                         '                        '原文リンク削除
1284                         '                        orgData = Regex.Replace(orgData, "<a href=""https://twitter\.com/" + post.Name + "/status/[0-9]+"">\.\.\.</a>$", "")
1285                         '#End If
1286                         'ハート変換
1287                         orgData = orgData.Replace("&lt;3", "♡")
1288                     End If
1289
1290                     'URL前処理(IDNデコードなど)
1291                     orgData = PreProcessUrl(orgData)
1292
1293                     '短縮URL解決処理(orgData書き換え)
1294                     orgData = ShortUrlResolve(orgData)
1295
1296                     '表示用にhtml整形
1297                     post.OriginalData = AdjustHtml(orgData)
1298
1299                     '単純テキストの取り出し(リンクタグ除去)
1300                     Try
1301                         post.Data = GetPlainText(orgData)
1302                     Catch ex As Exception
1303                         _signed = False
1304                         TraceOut("TM-Link:" + strPost)
1305                         Return "GetTimeline -> Err: Can't parse links."
1306                     End Try
1307
1308                     ' Imageタグ除去(ハロウィン)
1309                     Dim ImgTag As New Regex("<img src=.*?/>", RegexOptions.IgnoreCase)
1310                     If ImgTag.IsMatch(post.Data) Then post.Data = ImgTag.Replace(post.Data, "<img>")
1311
1312                     'Get Date
1313 #If 1 Then
1314                     Try
1315                         pos1 = strPost.IndexOf(_parseDate, pos2, StringComparison.Ordinal)
1316                         If pos1 > -1 Then
1317                             pos2 = strPost.IndexOf(_parseDateTo, pos1 + _parseDate.Length, StringComparison.Ordinal)
1318                             post.PDate = DateTime.ParseExact(strPost.Substring(pos1 + _parseDate.Length, pos2 - pos1 - _parseDate.Length), "ddd MMM dd HH':'mm':'ss zzzz yyyy", System.Globalization.DateTimeFormatInfo.InvariantInfo, Globalization.DateTimeStyles.None)
1319                         Else
1320                             post.PDate = Now()
1321                         End If
1322                     Catch ex As Exception
1323                         _signed = False
1324                         TraceOut("TM-Date:" + strPost)
1325                         Return "GetTimeline -> Err: Can't get date."
1326                     End Try
1327 #Else
1328                     '取得できなくなったため暫定対応(2/26)
1329                     post.PDate = Now()
1330 #End If
1331
1332
1333                     'from Sourceの取得
1334                     'ToDo: _parseSourceFromを正規表現へ。wedataからの取得へ変更(次版より)
1335                     rg = New Regex("<span>.+>(?<name>.+)</a>.*</span>")
1336                     m = rg.Match(strPost)
1337                     If m.Success Then
1338                         post.Source = m.Result("${name}")
1339                     Else
1340                         post.Source = "Web"
1341                     End If
1342                     'Try
1343                     '    pos1 = strPost.IndexOf(_parseSourceFrom, pos2, StringComparison.Ordinal)
1344                     '    If pos1 = -1 Then pos1 = strPost.IndexOf(_parseSourceFrom2, pos2, StringComparison.Ordinal)
1345                     '    If pos1 > -1 Then
1346                     '        pos1 = strPost.IndexOf(_parseSource2, pos1 + 19, StringComparison.Ordinal)
1347                     '        pos2 = strPost.IndexOf(_parseSourceTo, pos1 + 2, StringComparison.Ordinal)
1348                     '        post.Source = HttpUtility.HtmlDecode(strPost.Substring(pos1 + 2, pos2 - pos1 - 2))
1349                     '    Else
1350                     '        post.Source = "Web"
1351                     '    End If
1352                     'Catch ex As Exception
1353                     '    _signed = False
1354                     '    TraceOut("TM-Src:" + strPost)
1355                     '    Return "GetTimeline -> Err: Can't get src."
1356                     'End Try
1357
1358                     'Get Reply(in_reply_to_user/id)
1359                     'ToDo: _isReplyEngを正規表現へ。wedataからの取得へ変更(次版より)
1360                     rg = New Regex("<a href=""https?:\/\/twitter\.com\/(?<name>[a-zA-Z0-9_]+)\/status\/(?<id>[0-9]+)"">(in reply to )*\k<name>")
1361                     m = rg.Match(strPost)
1362                     If m.Success Then
1363                         post.InReplyToUser = m.Result("${name}")
1364                         post.InReplyToId = Long.Parse(m.Result("${id}"))
1365                         post.IsReply = post.InReplyToUser.Equals(_uid, StringComparison.OrdinalIgnoreCase)
1366                     End If
1367
1368                     '@先リスト作成
1369                     rg = New Regex("@<a [^>]*href=""\/(?<1>[a-zA-Z0-9_]+)[^a-zA-Z0-9_]")
1370                     m = rg.Match(orgData)
1371                     While m.Success
1372                         post.ReplyToList.Add(m.Groups(1).Value.ToLower())
1373                         m = m.NextMatch
1374                     End While
1375                     If Not post.IsReply Then post.IsReply = post.ReplyToList.Contains(_uid)
1376
1377                     'Get Fav
1378                     post.IsFav = True
1379
1380                     If _endingFlag Then Return ""
1381
1382                     post.IsMe = post.Name.Equals(_uid, StringComparison.OrdinalIgnoreCase)
1383                     SyncLock LockObj
1384                         If follower.Count > 1 Then
1385                             post.IsOwl = Not follower.Contains(post.Name.ToLower())
1386                         Else
1387                             post.IsOwl = False
1388                         End If
1389                     End SyncLock
1390                     post.IsRead = read
1391
1392                     arIdx += 1
1393                     dlgt(arIdx) = New GetIconImageDelegate(AddressOf GetIconImage)
1394                     ar(arIdx) = dlgt(arIdx).BeginInvoke(post, Nothing, Nothing)
1395
1396                 End If
1397
1398             Next
1399
1400             For i As Integer = 0 To arIdx
1401                 Try
1402                     dlgt(i).EndInvoke(ar(i))
1403                 Catch ex As Exception
1404                     '最後までendinvoke回す(ゾンビ化回避)
1405                     ex.Data("IsTerminatePermission") = False
1406                     Throw
1407                 End Try
1408             Next
1409
1410             Return ""
1411         Finally
1412             GetTmSemaphore.Release()
1413         End Try
1414     End Function
1415
1416     Private Function PreProcessUrl(ByVal orgData As String) As String
1417         Dim posl1 As Integer
1418         Dim posl2 As Integer = 0
1419         Dim IDNConveter As IdnMapping = New IdnMapping()
1420         Dim href As String = "<a href="""
1421
1422         Do While True
1423             If orgData.IndexOf(href, posl2, StringComparison.Ordinal) > -1 Then
1424                 Dim urlStr As String = ""
1425                 ' IDN展開
1426                 posl1 = orgData.IndexOf(href, posl2, StringComparison.Ordinal)
1427                 posl1 += href.Length
1428                 posl2 = orgData.IndexOf("""", posl1, StringComparison.Ordinal)
1429                 urlStr = orgData.Substring(posl1, posl2 - posl1)
1430
1431                 If Not urlStr.StartsWith("http://") AndAlso Not urlStr.StartsWith("https://") AndAlso Not urlStr.StartsWith("ftp://") Then
1432                     Continue Do
1433                 End If
1434
1435                 Dim replacedUrl As String = IDNDecode(urlStr)
1436                 If replacedUrl Is Nothing Then Continue Do
1437                 If replacedUrl = urlStr Then Continue Do
1438
1439                 orgData = orgData.Replace("<a href=""" + urlStr, "<a href=""" + replacedUrl)
1440                 posl2 = 0
1441             Else
1442                 Exit Do
1443             End If
1444         Loop
1445         Return orgData
1446     End Function
1447 #If 0 Then
1448     Private Function doShortUrlResolve(ByRef orgData As String) As Boolean
1449         Dim replaced As Boolean = False
1450         For Each _svc As String In _ShortUrlService
1451             Dim svc As String = _svc
1452             Dim posl1 As Integer
1453             Dim posl2 As Integer = 0
1454
1455             Do While True
1456                 If orgData.IndexOf("<a href=""" + svc, posl2, StringComparison.Ordinal) > -1 Then
1457                     Dim urlStr As String = ""
1458                     Try
1459                         posl1 = orgData.IndexOf("<a href=""" + svc, posl2, StringComparison.Ordinal)
1460                         posl1 = orgData.IndexOf(svc, posl1, StringComparison.Ordinal)
1461                         posl2 = orgData.IndexOf("""", posl1, StringComparison.Ordinal)
1462                         urlStr = New Uri(urlEncodeMultibyteChar(orgData.Substring(posl1, posl2 - posl1))).GetLeftPart(UriPartial.Path)
1463                         Dim Response As String = ""
1464                         Dim retUrlStr As String = ""
1465                         Dim tmpurlStr As String = urlStr
1466                         Dim SchemeAndDomain As Regex = New Regex("http://.+?/+?")
1467                         Dim tmpSchemeAndDomain As String = ""
1468                         For i As Integer = 0 To 4   'とりあえず5回試す
1469                             retUrlStr = urlEncodeMultibyteChar(DirectCast(CreateSocket.GetWebResponse(tmpurlStr, Response, MySocket.REQ_TYPE.ReqGETForwardTo), String))
1470                             If retUrlStr.Length > 0 Then
1471                                 ' 転送先URLが返された (まだ転送されるかもしれないので返値を引数にしてもう一度)
1472                                 ' 取得試行回数オーバーの場合は取得結果を転送先とする
1473                                 Dim scd As Match = SchemeAndDomain.Match(retUrlStr)
1474                                 If scd.Success AndAlso scd.Value <> svc Then
1475                                     svc = scd.Value()
1476                                 End If
1477                                 tmpurlStr = retUrlStr
1478                                 Continue For
1479                             Else
1480                                 ' 転送先URLが返されなかった
1481                                 If tmpurlStr <> urlStr Then
1482                                     '少なくとも一度以上転送されている (前回の結果を転送先とする)
1483                                     retUrlStr = tmpurlStr
1484                                 Else
1485                                     ' 一度も転送されていない
1486                                     retUrlStr = ""
1487                                 End If
1488                                 Exit For
1489                             End If
1490                         Next
1491                         If retUrlStr.Length > 0 Then
1492                             If Not retUrlStr.StartsWith("http") Then
1493                                 If retUrlStr.StartsWith("/") Then
1494                                     retUrlStr = urlEncodeMultibyteChar(svc + retUrlStr.Substring(1))
1495                                 ElseIf retUrlStr.StartsWith("data:") Then
1496                                     '
1497                                 Else
1498                                     retUrlStr = urlEncodeMultibyteChar(retUrlStr.Insert(0, svc))
1499                                 End If
1500                             Else
1501                                 retUrlStr = urlEncodeMultibyteChar(retUrlStr)
1502                             End If
1503                             orgData = orgData.Replace("<a href=""" + urlStr, "<a href=""" + retUrlStr)
1504                             posl2 = 0   '置換した場合は頭から再探索(複数同時置換での例外対応)
1505                             replaced = True
1506                         End If
1507                     Catch ex As Exception
1508                         '_signed = False
1509                         'Return "GetTimeline -> Err: Can't get tinyurl."
1510                     End Try
1511                 Else
1512                     Exit Do
1513                 End If
1514             Loop
1515         Next
1516         Return replaced
1517     End Function
1518 #Else
1519
1520     Private Sub doShortUrlResolve(ByRef orgData As String)
1521         'Dim replaced As Boolean = False
1522         'Dim svc As String
1523         'Dim posl1 As Integer
1524         'Dim posl2 As Integer = 0
1525         Static urlCache As New Specialized.StringDictionary()
1526         If urlCache.Count > 500 Then urlCache.Clear() '定期的にリセット
1527
1528         Dim rx As New Regex("<a href=""(?<svc>http://.+?/)(?<path>[^""]+)""", RegexOptions.IgnoreCase)
1529         Dim m As MatchCollection = rx.Matches(orgData)
1530         Dim urlList As New List(Of String)
1531         For Each orgUrlMatch As Match In m
1532             Dim orgUrl As String = orgUrlMatch.Result("${svc}")
1533             Dim orgUrlPath As String = orgUrlMatch.Result("${path}")
1534             If Array.IndexOf(_ShortUrlService, orgUrl) > -1 AndAlso _
1535                Not urlList.Contains(orgUrl + orgUrlPath) Then
1536                 urlList.Add(orgUrl + orgUrlPath)
1537             End If
1538         Next
1539         For Each orgUrl As String In urlList
1540             If urlCache.ContainsKey(orgUrl) Then
1541                 Try
1542                     orgData = orgData.Replace("<a href=""" + orgUrl + """", "<a href=""" + urlCache(orgUrl) + """")
1543                 Catch ex As Exception
1544                     'Through
1545                 End Try
1546             Else
1547                 Try
1548                     'urlとして生成できない場合があるらしい
1549                     Dim urlstr As String = New Uri(urlEncodeMultibyteChar(orgUrl)).GetLeftPart(UriPartial.Path)
1550                     Dim Response As String = ""
1551                     Dim retUrlStr As String = ""
1552                     Dim tmpurlStr As String = urlstr
1553                     retUrlStr = urlEncodeMultibyteChar(DirectCast(CreateSocket.GetWebResponse(tmpurlStr, Response, MySocket.REQ_TYPE.ReqGETForwardTo, timeOut:=5000), String))
1554                     If retUrlStr.StartsWith("http") Then
1555                         retUrlStr = retUrlStr.Replace("""", "%22")  'ダブルコーテーションがあるとURL終端と判断されるため、これだけ再エンコード
1556                         orgData = orgData.Replace("<a href=""" + orgUrl + """", "<a href=""" + retUrlStr + """")
1557                         urlCache.Add(orgUrl, retUrlStr)
1558                     End If
1559                 Catch ex As Exception
1560                     'Through
1561                 End Try
1562             End If
1563         Next
1564
1565         'For Each ma As Match In m
1566         '    svc = ma.Result("${svc}")
1567         '    posl1 = ma.Index
1568         '    If orgData.IndexOf("<a href=""" + svc, posl2, StringComparison.Ordinal) > -1 Then
1569         '        Dim urlStr As String = ""
1570         '        Try
1571         '            posl1 = orgData.IndexOf("<a href=""" + svc, posl2, StringComparison.Ordinal)
1572         '            posl1 = orgData.IndexOf(svc, posl1, StringComparison.Ordinal)
1573         '            posl2 = orgData.IndexOf("""", posl1, StringComparison.Ordinal)
1574         '            urlStr = New Uri(urlEncodeMultibyteChar(orgData.Substring(posl1, posl2 - posl1))).GetLeftPart(UriPartial.Path)
1575         '            Dim Response As String = ""
1576         '            Dim retUrlStr As String = ""
1577         '            Dim tmpurlStr As String = urlStr
1578         '            Dim SchemeAndDomain As Regex = New Regex("http://.+?/+?")
1579         '            Dim tmpSchemeAndDomain As String = ""
1580         '            For i As Integer = 0 To 4   'とりあえず5回試す
1581         '                retUrlStr = urlEncodeMultibyteChar(DirectCast(CreateSocket.GetWebResponse(tmpurlStr, Response, MySocket.REQ_TYPE.ReqGETForwardTo, timeOut:=2000), String))
1582         '                If retUrlStr.Length > 0 Then
1583         '                    ' 転送先URLが返された (まだ転送されるかもしれないので返値を引数にしてもう一度)
1584         '                    ' 取得試行回数オーバーの場合は取得結果を転送先とする
1585         '                    Dim scd As Match = SchemeAndDomain.Match(retUrlStr)
1586         '                    If scd.Success AndAlso scd.Value <> svc Then
1587         '                        svc = scd.Value()
1588         '                    End If
1589         '                    tmpurlStr = retUrlStr
1590         '                    Continue For
1591         '                Else
1592         '                    ' 転送先URLが返されなかった
1593         '                    If tmpurlStr <> urlStr Then
1594         '                        '少なくとも一度以上転送されている (前回の結果を転送先とする)
1595         '                        retUrlStr = tmpurlStr
1596         '                    Else
1597         '                        ' 一度も転送されていない
1598         '                        retUrlStr = ""
1599         '                    End If
1600         '                    Exit For
1601         '                End If
1602         '            Next
1603         '            If retUrlStr.Length > 0 Then
1604         '                If Not retUrlStr.StartsWith("http") Then
1605         '                    If retUrlStr.StartsWith("/") Then
1606         '                        retUrlStr = urlEncodeMultibyteChar(svc + retUrlStr.Substring(1))
1607         '                    ElseIf retUrlStr.StartsWith("data:") Then
1608         '                        '
1609         '                    Else
1610         '                        retUrlStr = urlEncodeMultibyteChar(retUrlStr.Insert(0, svc))
1611         '                    End If
1612         '                Else
1613         '                    retUrlStr = urlEncodeMultibyteChar(retUrlStr)
1614         '                End If
1615         '                orgData = orgData.Replace("<a href=""" + urlStr, "<a href=""" + retUrlStr)
1616         '                posl2 = 0   '置換した場合は頭から再探索(複数同時置換での例外対応)
1617         '                replaced = True
1618         '            End If
1619         '        Catch ex As Exception
1620         '            '_signed = False
1621         '            'Return "GetTimeline -> Err: Can't get tinyurl."
1622         '        End Try
1623         '    Else
1624         '        Exit For
1625         '    End If
1626         'Next
1627         'Return replaced
1628     End Sub
1629 #End If
1630
1631     Private Function ShortUrlResolve(ByVal orgData As String) As String
1632         If _tinyUrlResolve Then
1633 #If DEBUG Then
1634             Static Dim sw As New Stopwatch()
1635             Static Dim c As Integer = 0
1636             sw.Start()
1637 #End If
1638             doShortUrlResolve(orgData)
1639             'Do
1640
1641             'Loop While doShortUrlResolve(orgData)
1642 #If DEBUG Then
1643             sw.Stop()
1644             c += 1
1645             Console.WriteLine("ShortUrlResolve: " + c.ToString() + " / " + sw.Elapsed.ToString)
1646 #End If
1647         End If
1648         Return orgData
1649     End Function
1650
1651     Private Function GetPlainText(ByVal orgData As String) As String
1652         Return HttpUtility.HtmlDecode(Regex.Replace(orgData, "(?<tagStart><a [^>]+>)(?<text>[^<]+)(?<tagEnd></a>)", "${text}"))
1653         '不具合緊急対応で上記へ変更
1654         ''単純テキストの取り出し(リンクタグ除去)
1655         'If orgData.IndexOf(_parseLink1, StringComparison.Ordinal) = -1 Then
1656         '    retStr = HttpUtility.HtmlDecode(orgData)
1657         'Else
1658         '    Dim posl1 As Integer
1659         '    Dim posl2 As Integer
1660         '    Dim posl3 As Integer = 0
1661
1662         '    retStr = ""
1663
1664         '    posl3 = 0
1665         '    Do While True
1666         '        posl1 = orgData.IndexOf(_parseLink1, posl3, StringComparison.Ordinal)
1667         '        If posl1 = -1 Then Exit Do
1668
1669         '        If (posl3 + _parseLink3.Length <> posl1) Or posl3 = 0 Then
1670         '            If posl3 <> 0 Then
1671         '                retStr += HttpUtility.HtmlDecode(orgData.Substring(posl3 + _parseLink3.Length, posl1 - posl3 - _parseLink3.Length))
1672         '            Else
1673         '                retStr += HttpUtility.HtmlDecode(orgData.Substring(0, posl1))
1674         '            End If
1675         '        End If
1676         '        posl2 = orgData.IndexOf(_parseLink2, posl1, StringComparison.Ordinal)
1677         '        posl3 = orgData.IndexOf(_parseLink3, posl2, StringComparison.Ordinal)
1678         '        retStr += HttpUtility.HtmlDecode(orgData.Substring(posl2 + _parseLink2.Length, posl3 - posl2 - _parseLink2.Length))
1679         '    Loop
1680         '    retStr += HttpUtility.HtmlDecode(orgData.Substring(posl3 + _parseLink3.Length))
1681         'End If
1682
1683         'Return retStr
1684     End Function
1685
1686     ' htmlの簡易サニタイズ(詳細表示に不要なタグの除去)
1687
1688     Private Function SanitizeHtml(ByVal orgdata As String) As String
1689         Dim retdata As String = orgdata
1690
1691         '  <script ~ </script>
1692         Dim rx As Regex = New Regex( _
1693             "<(script|object|applet|image|frameset|fieldset|legend|style).*" & _
1694             "</(script|object|applet|image|frameset|fieldset|legend|style)>", RegexOptions.IgnoreCase)
1695         retdata = rx.Replace(retdata, "")
1696
1697         ' <frame src="...">
1698         rx = New Regex("<(frame|link|iframe|img)>", RegexOptions.IgnoreCase)
1699         retdata = rx.Replace(retdata, "")
1700
1701         Return retdata
1702     End Function
1703
1704     Private Function AdjustHtml(ByVal orgData As String) As String
1705         Dim retStr As String = orgData
1706         retStr = Regex.Replace(retStr, "<a [^>]*href=""/", "<a href=""" + _protocol + "twitter.com/")
1707         retStr = retStr.Replace("<a href=", "<a target=""_self"" href=")
1708         retStr = retStr.Replace(vbLf, "<br>")
1709
1710         Return SanitizeHtml(retStr)
1711     End Function
1712
1713     Private Sub GetIconImage(ByVal post As PostClass)
1714         Dim img As Image
1715         Dim bmp2 As Bitmap
1716
1717         Try
1718             If Not _getIcon Then
1719                 post.ImageIndex = -1
1720                 TabInformations.GetInstance.AddPost(post)
1721                 Exit Sub
1722             End If
1723
1724             SyncLock LockObj
1725                 post.ImageIndex = _lIcon.Images.IndexOfKey(post.ImageUrl)
1726             End SyncLock
1727
1728             If post.ImageIndex > -1 Then
1729                 TabInformations.GetInstance.AddPost(post)
1730                 Exit Sub
1731             End If
1732
1733             Dim resStatus As String = ""
1734             img = DirectCast(CreateSocket.GetWebResponse(post.ImageUrl, resStatus, MySocket.REQ_TYPE.ReqGETBinary), System.Drawing.Image)
1735             If img Is Nothing Then
1736                 post.ImageIndex = -1
1737                 TabInformations.GetInstance.AddPost(post)
1738                 Exit Sub
1739             End If
1740
1741             If _endingFlag Then Exit Sub
1742
1743             bmp2 = New Bitmap(_iconSz, _iconSz)
1744             Using g As Graphics = Graphics.FromImage(bmp2)
1745                 g.InterpolationMode = Drawing2D.InterpolationMode.High
1746                 g.DrawImage(img, 0, 0, _iconSz, _iconSz)
1747                 g.Dispose()
1748             End Using
1749
1750             SyncLock LockObj
1751                 post.ImageIndex = _lIcon.Images.IndexOfKey(post.ImageUrl)
1752                 If post.ImageIndex = -1 Then
1753                     Try
1754                         Dim fd As New System.Drawing.Imaging.FrameDimension(img.FrameDimensionsList(0))
1755                         Dim fd_count As Integer = img.GetFrameCount(fd)
1756                         If fd_count > 1 Then
1757                             Try
1758                                 img.SelectActiveFrame(fd, 1)
1759                                 _dIcon.Add(post.ImageUrl, img)  '詳細表示用ディクショナリに追加
1760                             Catch ex As Exception
1761                                 Dim bmp As New Bitmap(img)
1762                                 _dIcon.Add(post.ImageUrl, bmp)  '詳細表示用ディクショナリに追加
1763                                 img.Dispose()
1764                             End Try
1765                         Else
1766                             _dIcon.Add(post.ImageUrl, img)  '詳細表示用ディクショナリに追加
1767                         End If
1768                         _lIcon.Images.Add(post.ImageUrl, bmp2)
1769                         post.ImageIndex = _lIcon.Images.IndexOfKey(post.ImageUrl)
1770                     Catch ex As InvalidOperationException
1771                         'タイミングにより追加できない場合がある?(キー重複ではない)
1772                         post.ImageIndex = -1
1773                     End Try
1774                 End If
1775             End SyncLock
1776             TabInformations.GetInstance.AddPost(post)
1777         Catch ex As ArgumentException
1778             'タイミングによってはキー重複
1779         Finally
1780             img = Nothing
1781             bmp2 = Nothing
1782             post = Nothing
1783         End Try
1784     End Sub
1785
1786     Private Function GetAuthKey(ByVal resMsg As String) As Integer
1787         Dim pos1 As Integer
1788         Dim pos2 As Integer
1789
1790         pos1 = resMsg.IndexOf(_getAuthKey, StringComparison.Ordinal)
1791         If pos1 < 0 Then
1792             'データ不正?
1793             Return -7
1794         End If
1795         pos2 = resMsg.IndexOf(_getAuthKeyTo, pos1 + _getAuthKey.Length, StringComparison.Ordinal)
1796         If pos2 > -1 Then
1797             _authKey = resMsg.Substring(pos1 + _getAuthKey.Length, pos2 - pos1 - _getAuthKey.Length)
1798         Else
1799             Return -7
1800         End If
1801
1802         Return 0
1803     End Function
1804
1805     Private Function GetAuthKeyDM(ByVal resMsg As String) As Integer
1806         Dim pos1 As Integer
1807         Dim pos2 As Integer
1808
1809         pos1 = resMsg.IndexOf(_getAuthKey, StringComparison.Ordinal)
1810         If pos1 < 0 Then
1811             'データ不正?
1812             Return -7
1813         End If
1814         pos2 = resMsg.IndexOf("""", pos1 + _getAuthKey.Length, StringComparison.Ordinal)
1815         _authKeyDM = resMsg.Substring(pos1 + _getAuthKey.Length, pos2 - pos1 - _getAuthKey.Length)
1816
1817         Return 0
1818     End Function
1819
1820     Private Structure PostInfo
1821         Public CreatedAt As String
1822         Public Id As String
1823         Public Text As String
1824         Public UserId As String
1825         Public Sub New(ByVal Created As String, ByVal IdStr As String, ByVal txt As String, ByVal uid As String)
1826             CreatedAt = Created
1827             Id = IdStr
1828             Text = txt
1829             UserId = uid
1830         End Sub
1831         Public Shadows Function Equals(ByVal dst As PostInfo) As Boolean
1832             If Me.CreatedAt = dst.CreatedAt AndAlso Me.Id = dst.Id AndAlso Me.Text = dst.Text AndAlso Me.UserId = dst.UserId Then
1833                 Return True
1834             Else
1835                 Return False
1836             End If
1837         End Function
1838     End Structure
1839
1840     Private Function IsPostRestricted(ByRef resMsg As String) As Boolean
1841         Static _prev As New PostInfo("", "", "", "")
1842         Dim _current As New PostInfo("", "", "", "")
1843
1844
1845         Dim xd As XmlDocument = New XmlDocument()
1846         Try
1847             xd.LoadXml(resMsg)
1848             _current.CreatedAt = xd.SelectSingleNode("/status/created_at/text()").Value
1849             _current.Id = xd.SelectSingleNode("/status/id/text()").Value
1850             _current.Text = xd.SelectSingleNode("/status/text/text()").Value
1851             _current.UserId = xd.SelectSingleNode("/status/user/id/text()").Value
1852
1853             If _current.Equals(_prev) Then
1854                 Return True
1855             End If
1856             _prev.CreatedAt = _current.CreatedAt
1857             _prev.Id = _current.Id
1858             _prev.Text = _current.Text
1859             _prev.UserId = _current.UserId
1860         Catch ex As XmlException
1861             Return False
1862         End Try
1863
1864         Return False
1865     End Function
1866
1867     Public Function PostStatus(ByVal postStr As String, ByVal reply_to As Long) As String
1868
1869         If _endingFlag Then Return ""
1870
1871         If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
1872
1873         postStr = postStr.Trim()
1874
1875         'データ部分の生成
1876         Dim dataStr As String
1877         If reply_to = 0 Then
1878             dataStr = _statusHeader + HttpUtility.UrlEncode(postStr) + "&source=Tween"
1879         Else
1880             dataStr = _statusHeader + HttpUtility.UrlEncode(postStr) + "&source=Tween" + "&in_reply_to_status_id=" + HttpUtility.UrlEncode(reply_to.ToString)
1881         End If
1882
1883         Dim resStatus As String = ""
1884         Dim resMsg As String = DirectCast(CreateSocket.GetWebResponse(_protocol + _hubServer + _statusUpdatePathAPI, resStatus, MySocket.REQ_TYPE.ReqPOSTAPI, dataStr), String)
1885
1886         If resStatus.StartsWith("OK") Then
1887             Dim xd As XmlDocument = New XmlDocument()
1888             Try
1889                 xd.LoadXml(resMsg)
1890                 Dim xNode As XmlNode = Nothing
1891                 xNode = xd.SelectSingleNode("/status/user/followers_count/text()")
1892                 If xNode IsNot Nothing Then _followersCount = Integer.Parse(xNode.Value)
1893                 xNode = xd.SelectSingleNode("/status/user/friends_count/text()")
1894                 If xNode IsNot Nothing Then _friendsCount = Integer.Parse(xNode.Value)
1895                 xNode = xd.SelectSingleNode("/status/user/statuses_count/text()")
1896                 If xNode IsNot Nothing Then _statusesCount = Integer.Parse(xNode.Value)
1897                 xNode = xd.SelectSingleNode("/status/user/location/text()")
1898                 If xNode IsNot Nothing Then _location = xNode.Value
1899                 xNode = xd.SelectSingleNode("/status/user/description/text()")
1900                 If xNode IsNot Nothing Then _bio = xNode.Value
1901             Catch ex As Exception
1902             End Try
1903
1904             If Not postStr.StartsWith("D ", StringComparison.OrdinalIgnoreCase) AndAlso _
1905                     Not postStr.StartsWith("DM ", StringComparison.OrdinalIgnoreCase) AndAlso _
1906                     IsPostRestricted(resMsg) Then
1907                 Return "OK:Delaying?"
1908             End If
1909             resStatus = Outputz.Post(CreateSocket, postStr.Length)
1910             If resStatus.Length > 0 Then
1911                 Return "Outputz:" + resStatus
1912             Else
1913                 Return ""
1914             End If
1915         ElseIf resStatus.StartsWith("Err: Forbidden") Then
1916             Return "Err:Forbidden(Update Limits?)"
1917         Else
1918             If resStatus.StartsWith("Err: Unauthorized") Then
1919                 Twitter.AccountState = ACCOUNT_STATE.Invalid
1920                 Return "Check your Username/Password."
1921             Else
1922                 Return resStatus
1923             End If
1924         End If
1925     End Function
1926
1927     Public Function RemoveStatus(ByVal id As Long) As String
1928         If _endingFlag Then Return ""
1929
1930         If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
1931
1932         'データ部分の生成
1933         Dim resStatus As String = ""
1934         Dim resMsg As String = DirectCast(CreateSocket.GetWebResponse(_protocol + _hubServer + _StDestroyPath + id.ToString + ".xml", resStatus, MySocket.REQ_TYPE.ReqPOSTAPI), String)
1935
1936         If resMsg.StartsWith("<?xml") = False OrElse resStatus.StartsWith("OK") = False Then
1937             If resStatus.StartsWith("Err: Unauthorized") Then
1938                 Twitter.AccountState = ACCOUNT_STATE.Invalid
1939                 Return "Check your Username/Password."
1940             Else
1941                 Return resStatus
1942             End If
1943         End If
1944
1945         Return ""
1946     End Function
1947
1948     Public Function PostRetweet(ByVal id As Long) As String
1949         If _endingFlag Then Return ""
1950         If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
1951
1952         'データ部分の生成
1953         Dim target As Long = id
1954         If TabInformations.GetInstance.Item(id).RetweetedId > 0 Then
1955             target = TabInformations.GetInstance.Item(id).RetweetedId
1956         End If
1957         Dim resStatus As String = ""
1958         Dim resMsg As String = DirectCast(CreateSocket.GetWebResponse(_protocol + _apiHost + _hubServer + _postRetweetPath + target.ToString + ".xml", resStatus, MySocket.REQ_TYPE.ReqPOSTAPI), String)
1959
1960         If resMsg.StartsWith("<?xml") = False OrElse resStatus.StartsWith("OK") = False Then
1961             If resStatus.StartsWith("Err: Unauthorized") Then
1962                 Twitter.AccountState = ACCOUNT_STATE.Invalid
1963                 Return "Check your Username/Password."
1964             Else
1965                 Return resStatus
1966             End If
1967         End If
1968
1969         Return ""
1970     End Function
1971
1972     Public Function RemoveDirectMessage(ByVal id As Long) As String
1973         If _endingFlag Then Return ""
1974
1975         If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
1976
1977         'データ部分の生成
1978         Dim dataStr As String = _authKeyHeader + HttpUtility.UrlEncode(_authKey)
1979         Dim resStatus As String = ""
1980         Dim resMsg As String = DirectCast(CreateSocket.GetWebResponse(_protocol + _hubServer + _DMDestroyPath + id.ToString + ".xml", resStatus, MySocket.REQ_TYPE.ReqPOSTAPI), String)
1981
1982         If resMsg.StartsWith("<?xml") = False OrElse resStatus.StartsWith("OK") = False Then
1983             If resStatus.StartsWith("Err: Unauthorized") Then
1984                 Twitter.AccountState = ACCOUNT_STATE.Invalid
1985                 Return "Check your Username/Password."
1986             Else
1987                 Return resStatus
1988             End If
1989         End If
1990
1991         Return ""
1992     End Function
1993
1994     Public Function PostFollowCommand(ByVal id As String) As String
1995
1996         If _endingFlag Then Return ""
1997
1998         If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
1999
2000         Const PATH_FOLLOW As String = "/friendships/create.xml?screen_name="
2001
2002         Dim resStatus As String = ""
2003         Dim resMsg As String = DirectCast(CreateSocket.GetWebResponse(_protocol + _hubServer + PATH_FOLLOW + id, resStatus, MySocket.REQ_TYPE.ReqPOSTAPI), String)
2004
2005         If Not resStatus.StartsWith("OK") Then
2006             If resStatus.StartsWith("Err: Unauthorized") Then
2007                 Twitter.AccountState = ACCOUNT_STATE.Invalid
2008                 Return "Check your Username/Password."
2009             Else
2010                 Return resStatus
2011             End If
2012         End If
2013
2014         Return ""
2015     End Function
2016
2017     Public Function PostRemoveCommand(ByVal id As String) As String
2018
2019         If _endingFlag Then Return ""
2020
2021         If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
2022
2023         Const PATH_REMOVE As String = "/friendships/destroy.xml?screen_name="
2024
2025         Dim resStatus As String = ""
2026         Dim resMsg As String = DirectCast(CreateSocket.GetWebResponse(_protocol + _hubServer + PATH_REMOVE + id, resStatus, MySocket.REQ_TYPE.ReqPOSTAPI), String)
2027
2028         If Not resStatus.StartsWith("OK") Then
2029             If resStatus.StartsWith("Err: Unauthorized") Then
2030                 Twitter.AccountState = ACCOUNT_STATE.Invalid
2031                 Return "Check your Username/Password."
2032             Else
2033                 Return resStatus
2034             End If
2035         End If
2036
2037         Return ""
2038     End Function
2039
2040     Public Function GetFriendshipInfo(ByVal id As String) As String
2041
2042         If _endingFlag Then Return ""
2043
2044         If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
2045
2046         Const PATH_FRIENDSHIP As String = "/friendships/show.xml?source_screen_name="
2047         Const QUERY_TARGET As String = "&target_screen_name="
2048
2049         Dim resStatus As String = ""
2050         Dim resMsg As String = DirectCast(CreateSocket.GetWebResponse(_protocol + _hubServer + PATH_FRIENDSHIP + _uid + QUERY_TARGET + id, resStatus, MySocket.REQ_TYPE.ReqGetAPI), String)
2051
2052         If Not resStatus.StartsWith("OK") Then
2053             If resStatus.StartsWith("Err: Unauthorized") Then
2054                 Twitter.AccountState = ACCOUNT_STATE.Invalid
2055                 Return "Check your Username/Password."
2056             Else
2057                 Return resStatus
2058             End If
2059         Else
2060             Dim xdoc As New XmlDocument
2061             Dim result As String = ""
2062             Try
2063                 xdoc.LoadXml(resMsg)
2064                 Dim isFollowing As Boolean = Boolean.Parse(xdoc.SelectSingleNode("/relationship/source/following").InnerText)
2065                 Dim isFollowed As Boolean = Boolean.Parse(xdoc.SelectSingleNode("/relationship/source/followed_by").InnerText)
2066                 If isFollowing Then
2067                     result = "Following " + id + "." + System.Environment.NewLine
2068                 Else
2069                     result = "NOT follwing them." + System.Environment.NewLine
2070                 End If
2071                 If isFollowed Then
2072                     result += "Followed by " + id + "."
2073                 Else
2074                     result += "NOT followed by " + id + "."
2075                 End If
2076                 result = "Ok. The results are below..." + System.Environment.NewLine + result
2077             Catch ex As Exception
2078                 result = "Err: Invalid XML."
2079             End Try
2080             Return result
2081         End If
2082     End Function
2083
2084     ' Contributed by shuyoko <http://twitter.com/shuyoko> BEGIN:
2085     Public Function GetBlackFavId(ByVal id As Long, ByRef blackid As Long) As String
2086         Dim dataStr As String = _authKeyHeader + HttpUtility.UrlEncode(_authKey)
2087         Dim resStatus As String = ""
2088         Dim resMsg As String = DirectCast(CreateSocket.GetWebResponse("http://blavotter.hocha.org/blackfav/getblack.php?format=simple&id=" + id.ToString(), resStatus, MySocket.REQ_TYPE.ReqGET), String)
2089
2090         If resStatus.StartsWith("OK") = False Then
2091             Return resStatus
2092         End If
2093
2094         blackid = Long.Parse(resMsg)
2095
2096         Return ""
2097
2098     End Function
2099     ' Contributed by shuyoko <http://twitter.com/shuyoko> END.
2100
2101     Public Function PostFavAdd(ByVal id As Long) As String
2102         If _endingFlag Then Return ""
2103
2104
2105         If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
2106
2107         'データ部分の生成
2108         'Dim dataStr As String = _authKeyHeader + HttpUtility.UrlEncode(_authKey)
2109         Dim resStatus As String = ""
2110         Dim resMsg As String = DirectCast(CreateSocket.GetWebResponse(_protocol + _hubServer + _postFavAddPath + id.ToString() + ".xml", resStatus, MySocket.REQ_TYPE.ReqPOSTAPI), String)
2111
2112         If resStatus.StartsWith("OK") = False Then
2113             If resStatus.StartsWith("Err: Unauthorized") Then
2114                 Twitter.AccountState = ACCOUNT_STATE.Invalid
2115                 Return "Check your Username/Password."
2116             Else
2117                 Return resStatus
2118             End If
2119         End If
2120
2121         If _restrictFavCheck = False Then Return ""
2122
2123         'http://twitter.com/statuses/show/id.xml APIを発行して本文を取得
2124
2125         resMsg = DirectCast(CreateSocket.GetWebResponse(_protocol + _hubServer + _ShowStatus + id.ToString() + ".xml", resStatus, MySocket.REQ_TYPE.ReqGetAPI), String)
2126
2127         Try
2128             Using rd As Xml.XmlTextReader = New Xml.XmlTextReader(New System.IO.StringReader(resMsg))
2129                 rd.Read()
2130                 While rd.EOF = False
2131                     If rd.IsStartElement("favorited") Then
2132                         If rd.ReadElementContentAsBoolean() = True Then
2133                             Return ""  '正常にふぁぼれている
2134                         Else
2135                             Return "NG(Restricted?)"  '正常応答なのにふぁぼれてないので制限っぽい
2136                         End If
2137                     Else
2138                         rd.Read()
2139                     End If
2140                 End While
2141                 rd.Close()
2142             End Using
2143         Catch ex As XmlException
2144             '
2145         End Try
2146
2147         Return ""
2148     End Function
2149
2150     Public Function PostFavRemove(ByVal id As Long) As String
2151         If _endingFlag Then Return ""
2152
2153
2154         If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
2155
2156         'データ部分の生成
2157         'Dim dataStr As String = _authKeyHeader + HttpUtility.UrlEncode(_authKey)
2158         Dim resStatus As String = ""
2159         Dim resMsg As String = DirectCast(CreateSocket.GetWebResponse(_protocol + _hubServer + _postFavRemovePath + id.ToString() + ".xml", resStatus, MySocket.REQ_TYPE.ReqPOSTAPI), String)
2160
2161         If resStatus.StartsWith("OK") = False Then
2162             If resStatus.StartsWith("Err: Unauthorized") Then
2163                 Twitter.AccountState = ACCOUNT_STATE.Invalid
2164                 Return "Check your Username/Password."
2165             Else
2166                 Return resStatus
2167             End If
2168         End If
2169
2170         Return ""
2171     End Function
2172
2173 #Region "follower取得"
2174     'Delegate Function GetFollowersDelegate(ByVal Query As Integer) As String
2175     'Private semaphore As Threading.Semaphore = Nothing
2176     'Private threadNum As Integer = 0
2177     Private _threadErr As Boolean = False
2178
2179     Private Function GetFollowersMethod() As String
2180         Dim resStatus As String = ""
2181         Dim resMsg As String = ""
2182         Dim lineCount As Integer = 0
2183         Dim page As Long = -1
2184
2185         Do
2186             If _endingFlag Then Exit Do
2187             resMsg = DirectCast(CreateSocket.GetWebResponse("https://" + _hubServer + _GetFollowers + _cursorQry + page.ToString, resStatus, MySocket.REQ_TYPE.ReqGetAPI), String)
2188             If resStatus.StartsWith("OK") = False Then
2189                 _threadErr = True
2190                 Return resStatus
2191             End If
2192             Try
2193                 Using rd As Xml.XmlTextReader = New Xml.XmlTextReader(New System.IO.StringReader(resMsg))
2194                     lineCount = 0
2195                     rd.Read()
2196                     While rd.EOF = False
2197                         If rd.IsStartElement("screen_name") Then
2198                             Dim tmp As String = rd.ReadElementString("screen_name").ToLower()
2199                             SyncLock LockObj
2200                                 If Not tmpFollower.Contains(tmp) Then
2201                                     tmpFollower.Add(tmp)
2202                                 End If
2203                             End SyncLock
2204                             lineCount += 1
2205                         ElseIf rd.IsStartElement("next_cursor") Then
2206                             page = Long.Parse(rd.ReadElementString("next_cursor"))
2207                             If page = 0 Then Exit Do
2208                             Exit While
2209                         Else
2210                             rd.Read()
2211                         End If
2212                     End While
2213                 End Using
2214             Catch ex As Exception
2215                 _threadErr = True
2216                 TraceOut("NG(XmlException)")
2217                 Return "NG(XmlException)"
2218             End Try
2219         Loop While lineCount > 0
2220
2221         Return ""
2222     End Function
2223
2224     'Private Sub GetFollowersCallback(ByVal ar As IAsyncResult)
2225     '    Dim dlgt As GetFollowersDelegate = DirectCast(ar.AsyncState, GetFollowersDelegate)
2226
2227     '    Try
2228     '        Dim ret As String = dlgt.EndInvoke(ar)
2229     '        If Not ret.Equals("") AndAlso Not _threadErr Then
2230     '            TraceOut(ret)
2231     '            _threadErr = True
2232     '        End If
2233     '    Catch ex As Exception
2234     '        _threadErr = True
2235     '        ex.Data("IsTerminatePermission") = False
2236     '        Throw
2237     '    Finally
2238     '        GetTmSemaphore.Release()                     ' セマフォから出る
2239     '        Interlocked.Decrement(threadNum)        ' スレッド数カウンタを-1
2240     '    End Try
2241
2242     'End Sub
2243
2244     ' キャッシュの検証と読み込み -1を渡した場合は読み込みのみ行う(APIエラーでFollowersCountが取得できなかったとき)
2245     Private Function ValidateCache() As Integer
2246
2247         follower.Clear()
2248         Try
2249             Dim setting As SettingFollower = SettingFollower.Load()
2250             follower = setting.Follower
2251             If follower.Count = 0 OrElse Not follower(0).Equals(_uid.ToLower()) Then
2252                 ' 別IDの場合はキャッシュ破棄して読み直し
2253                 Return -1
2254             End If
2255         Catch ex As XmlException
2256             ' 不正なxmlの場合は読み直し
2257             Return -1
2258         Catch ex As InvalidOperationException
2259             'XMLが壊れている場合
2260             Return -1
2261         End Try
2262
2263         'If _FollowersCount = -1 Then Return tmpFollower.Count
2264         Return follower.Count
2265
2266         'If (_FollowersCount + 1) = tmpFollower.Count Then
2267         '    '変動がないので読み込みの必要なし
2268         '    Return 0
2269         'ElseIf (_FollowersCount + 1) < tmpFollower.Count Then
2270         '    '減っている場合はどこが抜けているのかわからないので全部破棄して読み直し
2271         '    tmpFollower.Clear()
2272         '    tmpFollower.Add(_uid.ToLower())
2273         '    Return _FollowersCount
2274         'End If
2275
2276         '' 増えた場合は差分だけ読む
2277
2278         'Return _FollowersCount - tmpFollower.Count
2279
2280     End Function
2281
2282     Private Sub UpdateCache()
2283         Dim setting As New SettingFollower(follower)
2284         setting.Save()
2285     End Sub
2286
2287     Public Function GetFollowers(ByVal CacheInvalidate As Boolean) As String
2288 #If DEBUG Then
2289         Dim sw As New System.Diagnostics.Stopwatch
2290         sw.Start()
2291 #End If
2292
2293         If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
2294
2295         'Dim resStatus As String = ""
2296         'Dim resMsg As String = ""
2297         'Dim i As Integer = 0
2298         'Dim DelegateInstance As GetFollowersDelegate = New GetFollowersDelegate(AddressOf GetFollowersMethod)
2299         'Dim threadMax As Integer = 4            ' 最大スレッド数
2300         'Dim followersCount As Integer = 0
2301
2302         'Interlocked.Exchange(threadNum, 0)      ' スレッド数カウンタ初期化
2303         _threadErr = False
2304         'follower.Clear()
2305         tmpFollower.Clear()
2306         'follower.Add(_uid.ToLower())
2307         tmpFollower.Add(_uid.ToLower())
2308
2309         'resMsg = DirectCast(CreateSocket.GetWebResponse("https://twitter.com/users/show/" + _uid + ".xml", resStatus, MySocket.REQ_TYPE.ReqGetAPI), String)
2310         'If resMsg = "" Then
2311         '    If resStatus.StartsWith("Err: BadRequest") Then
2312         '        Return "Maybe, the requests reached API limit."
2313         '    ElseIf resStatus.StartsWith("Err: Unauthorized") Then
2314         '        Twitter.AccountState = ACCOUNT_STATE.Invalid
2315         '        Return "Check your Username/Password."
2316         '    Else
2317         '        Return resStatus
2318         '    End If
2319         'End If
2320
2321         'Dim xd As XmlDocument = New XmlDocument()
2322         'Try
2323         '    xd.LoadXml(resMsg)
2324         '    followersCount = Integer.Parse(xd.SelectSingleNode("/user/followers_count/text()").Value)
2325         'Catch ex As Exception
2326         '    'If CacheInvalidate OrElse ValidateCache(-1) < 0 Then
2327         '    If ValidateCache(-1) < 0 Then
2328         '        ' FollowersカウントがAPIで取得できず、なおかつキャッシュから読めなかった
2329         '        SyncLock LockObj
2330         '            follower.Clear()
2331         '            follower.Add(_uid.ToLower())
2332         '        End SyncLock
2333         '        Return "Can't get followers_count and invalid cache."
2334         '    Else
2335         '        'キャッシュを読み出せたのでキャッシュを使う
2336         '        SyncLock LockObj
2337         '            follower = tmpFollower
2338         '        End SyncLock
2339         '        Return ""
2340         '    End If
2341         'End Try
2342
2343         'Dim tmp As Integer
2344
2345         ''If CacheInvalidate Then
2346         'tmp = followersCount
2347         ''Else
2348         ''tmp = ValidateCache(followersCount)
2349         ''End If
2350
2351
2352         'If tmp <> 0 Then
2353         '    i = (tmp + 100) \ 100  ' Followersカウント取得しページ単位に切り上げる。1ページ余分に読む
2354         'Else
2355         '    '            ' キャッシュの件数に変化がなかった
2356         '    '#If DEBUG Then
2357         '    '            sw.Stop()
2358         '    '            Console.WriteLine(sw.ElapsedMilliseconds)
2359         '    '#End If
2360         '    '            SyncLock LockObj
2361         '    '                follower = tmpFollower
2362         '    '            End SyncLock
2363         '    'Return ""
2364         '    Return ""   'ユーザー情報のフォロワー数が0
2365         'End If
2366
2367
2368         ''semaphore = New System.Threading.Semaphore(threadMax, threadMax) 'スレッド最大数
2369
2370         'For cnt As Integer = 0 To i
2371         '    If _endingFlag Then Exit For
2372         '    'semaphore.WaitOne()                     'セマフォ取得 threadMax以上ならここでブロックされる
2373         '    GetTmSemaphore.WaitOne()
2374         '    'Interlocked.Increment(threadNum)        'スレッド数カウンタを+1
2375         '    'DelegateInstance.BeginInvoke(cnt + 1, New System.AsyncCallback(AddressOf GetFollowersCallback), DelegateInstance)
2376         '    Dim ret As String = GetFollowersMethod(cnt + 1)
2377         '    'Interlocked.Decrement(threadNum)        'スレッド数カウンタを-1
2378         '    GetTmSemaphore.Release()
2379         '    If _threadErr Then Exit For
2380         'Next
2381
2382         '''全てのスレッドの終了を待つ(スレッド数カウンタが0になるまで待機)
2383         ''Do
2384         ''    Thread.Sleep(50)
2385         ''Loop Until Interlocked.Add(threadNum, 0) = 0
2386
2387         ''semaphore.Close()
2388
2389         Dim ret As String = GetFollowersMethod()
2390         If _endingFlag Then Return ""
2391
2392         If _threadErr Then
2393             If ValidateCache() > 0 Then
2394                 SyncLock LockObj
2395                     For Each name As String In tmpFollower
2396                         If Not follower.Contains(name) Then follower.Add(name)
2397                     Next
2398                 End SyncLock
2399                 If Not _endingFlag AndAlso follower.Count > 1 Then UpdateCache()
2400                 Return "Can't get followers. Use cache."
2401             Else
2402                 ' エラーが発生しているならFollowersリストクリア
2403                 SyncLock LockObj
2404                     follower.Clear()
2405                     follower.Add(_uid.ToLower())
2406                 End SyncLock
2407                 Return "Can't get followers."
2408             End If
2409         End If
2410
2411         SyncLock LockObj
2412             follower = tmpFollower
2413         End SyncLock
2414         If Not _endingFlag AndAlso follower.Count > 1 Then UpdateCache()
2415
2416 #If DEBUG Then
2417         sw.Stop()
2418         'Console.WriteLine(sw.ElapsedMilliseconds)
2419 #End If
2420
2421         Return ""
2422     End Function
2423
2424 #End Region
2425
2426     Public Sub RefreshOwl()
2427         TabInformations.GetInstance.RefreshOwl(follower)
2428     End Sub
2429
2430     Public Property Username() As String
2431         Get
2432             Return _uid
2433         End Get
2434         Set(ByVal value As String)
2435             _uid = value.ToLower
2436             _signed = False
2437         End Set
2438     End Property
2439
2440     Public Property Password() As String
2441         Get
2442             Return _pwd
2443         End Get
2444         Set(ByVal value As String)
2445             _pwd = value
2446             _signed = False
2447         End Set
2448     End Property
2449
2450     Private _accountState As ACCOUNT_STATE = ACCOUNT_STATE.Valid
2451     Public Property AccountState() As ACCOUNT_STATE
2452         Get
2453             Return _accountState
2454         End Get
2455         Set(ByVal value As ACCOUNT_STATE)
2456             _accountState = value
2457         End Set
2458     End Property
2459
2460     Public Property NextThreshold() As Integer
2461         Get
2462             Return _nextThreshold
2463         End Get
2464         Set(ByVal value As Integer)
2465             _nextThreshold = value
2466         End Set
2467     End Property
2468
2469     Public Property NextPages() As Integer
2470         Get
2471             Return _nextPages
2472         End Get
2473         Set(ByVal value As Integer)
2474             _nextPages = value
2475         End Set
2476     End Property
2477
2478     Public ReadOnly Property InfoTwitter() As String
2479         Get
2480             Return _infoTwitter
2481         End Get
2482     End Property
2483
2484     Public Property UseAPI() As Boolean
2485         Get
2486             Return _useAPI
2487         End Get
2488         Set(ByVal value As Boolean)
2489             _useAPI = value
2490         End Set
2491     End Property
2492
2493     Public Property HubServer() As String
2494         Get
2495             Return _hubServer
2496         End Get
2497         Set(ByVal value As String)
2498             _hubServer = value
2499         End Set
2500     End Property
2501
2502     Public Sub GetWedata()
2503         Dim resStatus As String = ""
2504         Dim resMsg As String = ""
2505
2506         resMsg = DirectCast(CreateSocket.GetWebResponse(wedataUrl, resStatus, timeOut:=10 * 1000), String) 'タイムアウト時間を10秒に設定
2507         If resMsg.Length = 0 Then Exit Sub
2508
2509         Dim rs As New System.IO.StringReader(resMsg)
2510
2511         Dim mode As Integer = 0 '0:search name 1:search data 2:read data
2512         Dim name As String = ""
2513
2514         'ストリームの末端まで繰り返す
2515         Dim ln As String
2516         While rs.Peek() > -1
2517             ln = rs.ReadLine
2518
2519             Select Case mode
2520                 Case 0
2521                     If ln.StartsWith("    ""name"": ") Then
2522                         name = ln.Substring(13, ln.Length - 2 - 13)
2523                         mode += 1
2524                     End If
2525                 Case 1
2526                     If ln = "    ""data"": {" Then
2527                         mode += 1
2528                     End If
2529                 Case 2
2530                     If ln = "    }," Then
2531                         mode = 0
2532                     Else
2533                         If ln.EndsWith(",") Then ln = ln.Substring(0, ln.Length - 1)
2534                         Select Case name
2535                             Case "SplitPostReply"
2536                                 If ln.StartsWith("      ""tagfrom"": """) Then
2537                                     _splitPost = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2538                                 End If
2539                             Case "SplitPostRecent"
2540                                 If ln.StartsWith("      ""tagfrom"": """) Then
2541                                     _splitPostRecent = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2542                                 End If
2543                             Case "StatusID"
2544                                 If ln.StartsWith("      ""tagto"": """) Then
2545                                     _statusIdTo = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2546                                 End If
2547                             Case "IsProtect"
2548                                 If ln.StartsWith("      ""tagfrom"": """) Then
2549                                     _isProtect = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2550                                 End If
2551                             Case "IsReply"
2552                                 If ln.StartsWith("      ""tagfrom"": """) Then
2553                                     _isReplyEng = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2554                                 End If
2555                                 If ln.StartsWith("      ""tagfrom2"": """) Then
2556                                     _isReplyJpn = ln.Substring(19, ln.Length - 1 - 19).Replace("\", "")
2557                                 End If
2558                                 If ln.StartsWith("      ""tagto"": """) Then
2559                                     _isReplyTo = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2560                                 End If
2561                                 'Case "GetStar"
2562                                 '    If ln.StartsWith("      ""tagfrom"": """) Then
2563                                 '        _parseStar = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2564                                 '    End If
2565                                 '    If ln.StartsWith("      ""tagfrom2"": """) Then
2566                                 '        _parseStarEmpty = ln.Substring(19, ln.Length - 1 - 19).Replace("\", "")
2567                                 '    End If
2568                                 '    If ln.StartsWith("      ""tagto"": """) Then
2569                                 '        _parseStarTo = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2570                                 '    End If
2571                             Case "Follower"
2572                                 If ln.StartsWith("      ""tagfrom"": """) Then
2573                                     _followerList = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2574                                 End If
2575                                 If ln.StartsWith("      ""tagfrom2"": """) Then
2576                                     _followerMbr1 = ln.Substring(19, ln.Length - 1 - 19).Replace("\", "")
2577                                 End If
2578                                 If ln.StartsWith("      ""tagfrom3"": """) Then
2579                                     _followerMbr2 = ln.Substring(19, ln.Length - 1 - 19).Replace("\", "")
2580                                 End If
2581                                 If ln.StartsWith("      ""tagto"": """) Then
2582                                     _followerMbr3 = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2583                                 End If
2584                             Case "SplitDM"
2585                                 If ln.StartsWith("      ""tagfrom"": """) Then
2586                                     _splitDM = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2587                                 End If
2588                             Case "GetMsgDM"
2589                                 If ln.StartsWith("      ""tagfrom"": """) Then
2590                                     _parseDM1 = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2591                                 End If
2592                                 If ln.StartsWith("      ""tagfrom2"": """) Then
2593                                     _parseDM11 = ln.Substring(19, ln.Length - 1 - 19).Replace("\", "")
2594                                 End If
2595                                 If ln.StartsWith("      ""tagto"": """) Then
2596                                     _parseDM2 = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2597                                 End If
2598                             Case "GetDate"
2599                                 If ln.StartsWith("      ""tagfrom"": """) Then
2600                                     _parseDate = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2601                                 End If
2602                                 If ln.StartsWith("      ""tagto"": """) Then
2603                                     _parseDateTo = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2604                                 End If
2605                             Case "GetMsg"
2606                                 If ln.StartsWith("      ""tagfrom"": """) Then
2607                                     _parseMsg1 = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2608                                 End If
2609                                 If ln.StartsWith("      ""tagto"": """) Then
2610                                     _parseMsg2 = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2611                                 End If
2612                             Case "GetImagePath"
2613                                 If ln.StartsWith("      ""tagfrom"": """) Then
2614                                     _parseImg = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2615                                 End If
2616                                 If ln.StartsWith("      ""tagto"": """) Then
2617                                     _parseImgTo = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2618                                 End If
2619                             Case "GetNick"
2620                                 If ln.StartsWith("      ""tagfrom"": """) Then
2621                                     _parseNick = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2622                                 End If
2623                                 If ln.StartsWith("      ""tagto"": """) Then
2624                                     _parseNickTo = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2625                                 End If
2626                             Case "GetName"
2627                                 If ln.StartsWith("      ""tagfrom"": """) Then
2628                                     _parseName = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2629                                 End If
2630                                 If ln.StartsWith("      ""tagto"": """) Then
2631                                     _parseNameTo = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2632                                 End If
2633                                 'Case "GetSiv"
2634                                 '    If ln.StartsWith("      ""tagfrom"": """) Then
2635                                 '        _getSiv = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2636                                 '    End If
2637                                 '    If ln.StartsWith("      ""tagto"": """) Then
2638                                 '        _getSivTo = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2639                                 '    End If
2640                             Case "AuthKey"
2641                                 If ln.StartsWith("      ""tagfrom"": """) Then
2642                                     _getAuthKey = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2643                                 End If
2644                                 If ln.StartsWith("      ""tagto"": """) Then
2645                                     _getAuthKeyTo = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2646                                 End If
2647                             Case "InfoTwitter"
2648                                 If ln.StartsWith("      ""tagfrom"": """) Then
2649                                     _getInfoTwitter = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2650                                 End If
2651                                 If ln.StartsWith("      ""tagto"": """) Then
2652                                     _getInfoTwitterTo = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2653                                 End If
2654                             Case "GetProtectMsg"
2655                                 If ln.StartsWith("      ""tagfrom"": """) Then
2656                                     _parseProtectMsg1 = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2657                                 End If
2658                                 If ln.StartsWith("      ""tagto"": """) Then
2659                                     _parseProtectMsg2 = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2660                                 End If
2661                             Case "GetDMCount"
2662                                 If ln.StartsWith("      ""tagfrom"": """) Then
2663                                     _parseDMcountFrom = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2664                                 End If
2665                                 If ln.StartsWith("      ""tagto"": """) Then
2666                                     _parseDMcountTo = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2667                                 End If
2668                             Case "GetSource"
2669                                 If ln.StartsWith("      ""tagfrom"": """) Then
2670                                     _parseSourceFrom = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2671                                 End If
2672                                 If ln.StartsWith("      ""tagfrom2"": """) Then
2673                                     _parseSource2 = ln.Substring(19, ln.Length - 1 - 19).Replace("\", "")
2674                                 End If
2675                                 If ln.StartsWith("      ""tagto"": """) Then
2676                                     _parseSource2 = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2677                                 End If
2678                             Case "RemoveClass"
2679                                 If ln.StartsWith("      ""tagfrom"": """) Then
2680                                     _removeClass = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2681                                 End If
2682                         End Select
2683                     End If
2684             End Select
2685         End While
2686
2687         rs.Close()
2688
2689 #If DEBUG Then
2690         GenerateAnalyzeKey()
2691 #End If
2692     End Sub
2693
2694     Public WriteOnly Property GetIcon() As Boolean
2695         Set(ByVal value As Boolean)
2696             _getIcon = value
2697         End Set
2698     End Property
2699
2700     Public WriteOnly Property TinyUrlResolve() As Boolean
2701         Set(ByVal value As Boolean)
2702             _tinyUrlResolve = value
2703         End Set
2704     End Property
2705
2706     Public WriteOnly Property SelectedProxyType() As ProxyType
2707         Set(ByVal value As ProxyType)
2708             _proxyType = value
2709         End Set
2710     End Property
2711
2712     Public WriteOnly Property ProxyAddress() As String
2713         Set(ByVal value As String)
2714             _proxyAddress = value
2715         End Set
2716     End Property
2717
2718     Public WriteOnly Property ProxyPort() As Integer
2719         Set(ByVal value As Integer)
2720             _proxyPort = value
2721         End Set
2722     End Property
2723
2724     Public WriteOnly Property ProxyUser() As String
2725         Set(ByVal value As String)
2726             _proxyUser = value
2727         End Set
2728     End Property
2729
2730     Public WriteOnly Property ProxyPassword() As String
2731         Set(ByVal value As String)
2732             _proxyPassword = value
2733         End Set
2734     End Property
2735
2736     Public WriteOnly Property RestrictFavCheck() As Boolean
2737         Set(ByVal value As Boolean)
2738             _restrictFavCheck = value
2739         End Set
2740     End Property
2741
2742     Public WriteOnly Property IconSize() As Integer
2743         Set(ByVal value As Integer)
2744             _iconSz = value
2745         End Set
2746     End Property
2747
2748     Public Function MakeShortUrl(ByVal ConverterType As UrlConverter, ByVal SrcUrl As String) As String
2749         Dim ret As String = ""
2750         Dim resStatus As String = ""
2751         Dim src As String = urlEncodeMultibyteChar(SrcUrl)
2752
2753         For Each svc As String In _ShortUrlService
2754             If SrcUrl.StartsWith(svc) Then
2755                 Return "Can't convert"
2756             End If
2757         Next
2758
2759         SrcUrl = HttpUtility.UrlEncode(SrcUrl)
2760         Select Case ConverterType
2761             Case UrlConverter.TinyUrl       'tinyurl
2762                 If SrcUrl.StartsWith("http") Then
2763                     If "http://tinyurl.com/xxxxxx".Length > src.Length AndAlso Not src.Contains("?") AndAlso Not src.Contains("#") Then
2764                         ' 明らかに長くなると推測できる場合は圧縮しない
2765                         ret = src
2766                         Exit Select
2767                     End If
2768                     Try
2769                         ret = DirectCast(CreateSocket.GetWebResponse("http://tinyurl.com/api-create.php?url=" + SrcUrl, resStatus, MySocket.REQ_TYPE.ReqPOSTEncode), String)
2770                     Catch ex As Exception
2771                         Return "Can't convert"
2772                     End Try
2773                 End If
2774                 If Not ret.StartsWith("http://tinyurl.com/") Then
2775                     Return "Can't convert"
2776                 End If
2777             Case UrlConverter.Isgd
2778                 If SrcUrl.StartsWith("http") Then
2779                     If "http://is.gd/xxxx".Length > src.Length AndAlso Not src.Contains("?") AndAlso Not src.Contains("#") Then
2780                         ' 明らかに長くなると推測できる場合は圧縮しない
2781                         ret = src
2782                         Exit Select
2783                     End If
2784                     Try
2785                         ret = DirectCast(CreateSocket.GetWebResponse("http://is.gd/api.php?longurl=" + SrcUrl, resStatus, MySocket.REQ_TYPE.ReqPOSTEncode), String)
2786                     Catch ex As Exception
2787                         Return "Can't convert"
2788                     End Try
2789                 End If
2790                 If Not ret.StartsWith("http://is.gd/") Then
2791                     Return "Can't convert"
2792                 End If
2793             Case UrlConverter.Twurl
2794                 If SrcUrl.StartsWith("http") Then
2795                     If "http://twurl.nl/xxxxxx".Length > src.Length AndAlso Not src.Contains("?") AndAlso Not src.Contains("#") Then
2796                         ' 明らかに長くなると推測できる場合は圧縮しない
2797                         ret = src
2798                         Exit Select
2799                     End If
2800                     Try
2801                         ret = DirectCast(CreateSocket.GetWebResponse("http://tweetburner.com/links", resStatus, MySocket.REQ_TYPE.ReqPOSTEncode, "link[url]=" + SrcUrl), String)
2802                     Catch ex As Exception
2803                         Return "Can't convert"
2804                     End Try
2805                 End If
2806                 If Not ret.StartsWith("http://twurl.nl/") Then
2807                     Return "Can't convert"
2808                 End If
2809             Case UrlConverter.Unu
2810                 If SrcUrl.StartsWith("http") Then
2811                     If "http://u.nu/xxxx".Length > src.Length AndAlso Not src.Contains("?") AndAlso Not src.Contains("#") Then
2812                         ' 明らかに長くなると推測できる場合は圧縮しない
2813                         ret = src
2814                         Exit Select
2815                     End If
2816                     Try
2817                         ret = DirectCast(CreateSocket.GetWebResponse("http://u.nu/unu-api-simple?url=" + SrcUrl, resStatus, MySocket.REQ_TYPE.ReqPOSTEncode), String)
2818                     Catch ex As Exception
2819                         Return "Can't convert"
2820                     End Try
2821                 End If
2822                 If Not ret.StartsWith("http://u.nu") Then
2823                     Return "Can't convert"
2824                 End If
2825             Case UrlConverter.Bitly, UrlConverter.Jmp
2826                 Dim BitlyLogin As String = "tweenapi"
2827                 Dim BitlyApiKey As String = "R_c5ee0e30bdfff88723c4457cc331886b"
2828                 If _bitlyId <> "" Then
2829                     BitlyLogin = _bitlyId
2830                     BitlyApiKey = _bitlyKey
2831                 End If
2832                 Const BitlyApiVersion As String = "2.0.1"
2833                 If SrcUrl.StartsWith("http") Then
2834                     If "http://bit.ly/xxxx".Length > src.Length AndAlso Not src.Contains("?") AndAlso Not src.Contains("#") Then
2835                         ' 明らかに長くなると推測できる場合は圧縮しない
2836                         ret = src
2837                         Exit Select
2838                     End If
2839                     Try
2840                         Dim req As String = "http://api.bit.ly/shorten?version=" + BitlyApiVersion + _
2841                             "&login=" + BitlyLogin + _
2842                             "&apiKey=" + BitlyApiKey + _
2843                             "&longUrl=" + SrcUrl
2844                         If BitlyLogin <> "tweenapi" Then req += "&history=1"
2845                         ret = DirectCast(CreateSocket.GetWebResponse(req, resStatus, MySocket.REQ_TYPE.ReqPOSTEncode), String)
2846                         Dim rx As Regex = New Regex("""shortUrl"": ""(?<ShortUrl>.*?)""")
2847                         If rx.Match(ret).Success Then
2848                             ret = rx.Match(ret).Groups("ShortUrl").Value
2849                         End If
2850                     Catch ex As Exception
2851                         Return "Can't convert"
2852                     End Try
2853                 End If
2854                 If Not ret.StartsWith("http://bit.ly") Then
2855                     Return "Can't convert"
2856                 End If
2857                 If ConverterType = UrlConverter.Jmp Then ret = ret.Replace("bit.ly", "j.mp")
2858         End Select
2859         '変換結果から改行を除去
2860         Dim ch As Char() = {ControlChars.Cr, ControlChars.Lf}
2861         ret = ret.TrimEnd(ch)
2862         If src.Length < ret.Length Then ret = src ' 圧縮の結果逆に長くなった場合は圧縮前のURLを返す
2863         Return ret
2864     End Function
2865
2866 #Region "バージョンアップ"
2867     Public Function GetVersionInfo() As String
2868         Dim resStatus As String = ""
2869         Dim ret As String = DirectCast(CreateSocket.GetWebResponse("http://tween.sourceforge.jp/version2.txt?" + Now.ToString("yyMMddHHmmss") + Environment.TickCount.ToString(), resStatus), String)
2870         If ret.Length = 0 Then Throw New Exception("GetVersionInfo: " + resStatus)
2871         Return ret
2872     End Function
2873
2874     Public Function GetTweenBinary(ByVal strVer As String) As String
2875         Dim resStatus As String = ""
2876         Dim ret As String = ""
2877         ret = DirectCast(CreateSocket.GetWebResponse("http://tween.sourceforge.jp/Tween" + strVer + ".gz?" + Now.ToString("yyMMddHHmmss") + Environment.TickCount.ToString(), resStatus, MySocket.REQ_TYPE.ReqGETFile), String)
2878         If ret = "" OrElse resStatus.StartsWith("OK") Then
2879             '取得OKなら、続いてresources.dllダウンロード
2880             ret = GetTweenResourcesDll(strVer)
2881             If ret = "" Then
2882                 Return GetTweenDll(strVer)
2883             Else
2884                 Return ret
2885             End If
2886         Else
2887             Return resStatus
2888         End If
2889     End Function
2890
2891     Public Function GetTweenUpBinary() As String
2892         Dim resStatus As String = ""
2893         Dim ret As String = DirectCast(CreateSocket.GetWebResponse("http://tween.sourceforge.jp/TweenUp.gz?" + Now.ToString("yyMMddHHmmss") + Environment.TickCount.ToString(), resStatus, MySocket.REQ_TYPE.ReqGETFileUp), String)
2894         If ret = "" OrElse resStatus.StartsWith("OK") Then
2895             Return ""
2896         Else
2897             Return resStatus
2898         End If
2899     End Function
2900
2901     Public Function GetTweenResourcesDll(ByVal strver As String) As String
2902         Dim resStatus As String = ""
2903         Dim ret As String = DirectCast(CreateSocket.GetWebResponse("http://tween.sourceforge.jp/TweenRes" + strver + ".gz?" + Now.ToString("yyMMddHHmmss") + Environment.TickCount.ToString(), resStatus, MySocket.REQ_TYPE.ReqGETFileRes), String)
2904         If ret = "" OrElse resStatus.StartsWith("OK") Then
2905             Return ""
2906         Else
2907             Return resStatus
2908         End If
2909     End Function
2910
2911     Public Function GetTweenDll(ByVal strVer As String) As String
2912         Dim resStatus As String = ""
2913         Dim ret As String = ""
2914         ret = DirectCast(CreateSocket.GetWebResponse("http://tween.sourceforge.jp/TweenDll" + strVer + ".gz?" + Now.ToString("yyMMddHHmmss") + Environment.TickCount.ToString(), resStatus, MySocket.REQ_TYPE.ReqGETFileDll), String)
2915         If ret = "" OrElse resStatus.StartsWith("OK") Then
2916             Return ""
2917         Else
2918             Return resStatus
2919         End If
2920     End Function
2921
2922 #End Region
2923
2924     Private Function CreateSocket() As MySocket
2925         Return New MySocket("UTF-8", _uid, _pwd, _proxyType, _proxyAddress, _proxyPort, _proxyUser, _proxyPassword, _defaultTimeOut)
2926     End Function
2927
2928     Public WriteOnly Property ListIcon() As ImageList
2929         Set(ByVal value As ImageList)
2930             _lIcon = value
2931         End Set
2932     End Property
2933
2934     Public WriteOnly Property DetailIcon() As Dictionary(Of String, Image)
2935         Set(ByVal value As Dictionary(Of String, Image))
2936             _dIcon = value
2937         End Set
2938     End Property
2939
2940     Public Property DefaultTimeOut() As Integer
2941         Get
2942             Return _defaultTimeOut
2943         End Get
2944         Set(ByVal value As Integer)
2945             _defaultTimeOut = value
2946         End Set
2947     End Property
2948
2949     Public WriteOnly Property CountApi() As Integer
2950         'API時の取得件数
2951         Set(ByVal value As Integer)
2952             _countApi = value
2953         End Set
2954     End Property
2955
2956     Public WriteOnly Property UsePostMethod() As Boolean
2957         Set(ByVal value As Boolean)
2958             _usePostMethod = False
2959 #If 0 Then
2960             'POSTメソッドが弾かれるためGETに固定(2009/4/9)
2961             If value Then
2962                 _ApiMethod = MySocket.REQ_TYPE.ReqPOSTAPI
2963             Else
2964                 _ApiMethod = MySocket.REQ_TYPE.ReqGetAPI
2965             End If
2966 #Else
2967             _ApiMethod = MySocket.REQ_TYPE.ReqGetAPI
2968 #End If
2969         End Set
2970     End Property
2971
2972     Public Property ReadOwnPost() As Boolean
2973         Get
2974             Return _readOwnPost
2975         End Get
2976         Set(ByVal value As Boolean)
2977             _readOwnPost = value
2978         End Set
2979     End Property
2980
2981     Public ReadOnly Property FollowersCount() As Integer
2982         Get
2983             Return _followersCount
2984         End Get
2985     End Property
2986
2987     Public ReadOnly Property FriendsCount() As Integer
2988         Get
2989             Return _friendsCount
2990         End Get
2991     End Property
2992
2993     Public ReadOnly Property StatusesCount() As Integer
2994         Get
2995             Return _statusesCount
2996         End Get
2997     End Property
2998
2999     Public ReadOnly Property Location() As String
3000         Get
3001             Return _location
3002         End Get
3003     End Property
3004
3005     Public ReadOnly Property Bio() As String
3006         Get
3007             Return _bio
3008         End Get
3009     End Property
3010
3011     Public WriteOnly Property UseSsl() As Boolean
3012         Set(ByVal value As Boolean)
3013             _useSsl = value
3014             If _useSsl Then
3015                 _protocol = "https://"
3016             Else
3017                 _protocol = "http://"
3018             End If
3019         End Set
3020     End Property
3021
3022     Public WriteOnly Property BitlyId() As String
3023         Set(ByVal value As String)
3024             _bitlyId = value
3025         End Set
3026     End Property
3027
3028     Public WriteOnly Property BitlyKey() As String
3029         Set(ByVal value As String)
3030             _bitlyKey = value
3031         End Set
3032     End Property
3033
3034     Public Function GetTimelineApi(ByVal read As Boolean, _
3035                             ByVal gType As WORKERTYPE) As String
3036
3037         If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
3038
3039         If _endingFlag Then Return ""
3040
3041         Dim retMsg As String = ""
3042         Dim resStatus As String = ""
3043         Dim sck As MySocket = CreateSocket()
3044         'スレッド取得は行わず、countで調整
3045         Const COUNT_QUERY As String = "count="
3046         Const FRIEND_PATH As String = "/statuses/home_timeline.xml"
3047         Const REPLY_PATH As String = "/statuses/mentions.xml"
3048
3049         If gType = WORKERTYPE.Timeline Then
3050             retMsg = DirectCast(sck.GetWebResponse(_protocol + _hubServer + FRIEND_PATH + "?" + COUNT_QUERY + _countApi.ToString(), resStatus, _ApiMethod), String)
3051         Else
3052             retMsg = DirectCast(sck.GetWebResponse(_protocol + _hubServer + REPLY_PATH + "?" + COUNT_QUERY + _countApi.ToString(), resStatus, _ApiMethod), String)
3053         End If
3054
3055         If retMsg = "" Then
3056             If resStatus.StartsWith("Err: BadRequest") Then
3057                 Return "Maybe, the requests reached API limit."
3058             ElseIf resStatus.StartsWith("Err: Unauthorized") Then
3059                 Twitter.AccountState = ACCOUNT_STATE.Invalid
3060                 Return "Check your Username/Password."
3061             Else
3062                 Return resStatus
3063             End If
3064         End If
3065
3066         If gType = WORKERTYPE.Timeline Then Debug.WriteLine(retMsg)
3067
3068         Dim arIdx As Integer = -1
3069         Dim dlgt(_countApi) As GetIconImageDelegate    'countQueryに合わせる
3070         Dim ar(_countApi) As IAsyncResult              'countQueryに合わせる
3071         Dim xdoc As New XmlDocument
3072         Try
3073             xdoc.LoadXml(retMsg)
3074         Catch ex As Exception
3075             TraceOut(retMsg)
3076             'MessageBox.Show("不正なXMLです。(TL-LoadXml)")
3077             Return "Invalid XML!"
3078         End Try
3079
3080         For Each xentryNode As XmlNode In xdoc.DocumentElement.SelectNodes("./status")
3081             Dim xentry As XmlElement = CType(xentryNode, XmlElement)
3082             Dim post As New PostClass
3083             Try
3084                 post.Id = Long.Parse(xentry.Item("id").InnerText)
3085                 '二重取得回避
3086                 SyncLock LockObj
3087                     If TabInformations.GetInstance.ContainsKey(post.Id) Then Continue For
3088                 End SyncLock
3089                 'Retweet判定
3090                 Dim xRnode As XmlNode = xentry.SelectSingleNode("./retweeted_status")
3091                 If xRnode IsNot Nothing Then
3092                     Dim xRentry As XmlElement = CType(xRnode, XmlElement)
3093                     post.PDate = DateTime.ParseExact(xRentry.Item("created_at").InnerText, "ddd MMM dd HH:mm:ss zzzz yyyy", System.Globalization.DateTimeFormatInfo.InvariantInfo, System.Globalization.DateTimeStyles.None)
3094                     'Id
3095                     post.RetweetedId = Long.Parse(xRentry.Item("id").InnerText)
3096                     '本文
3097                     post.Data = xRentry.Item("text").InnerText
3098                     'Source取得(htmlの場合は、中身を取り出し)
3099                     post.Source = xRentry.Item("source").InnerText
3100                     'Reply先
3101                     Long.TryParse(xRentry.Item("in_reply_to_status_id").InnerText, post.InReplyToId)
3102                     post.InReplyToUser = xRentry.Item("in_reply_to_screen_name").InnerText
3103                     post.IsFav = TabInformations.GetInstance.GetTabByType(TabUsageType.Favorites).Contains(post.RetweetedId)
3104
3105                     '以下、ユーザー情報
3106                     Dim xRUentry As XmlElement = CType(xRentry.SelectSingleNode("./user"), XmlElement)
3107                     post.Uid = Long.Parse(xRUentry.Item("id").InnerText)
3108                     post.Name = xRUentry.Item("screen_name").InnerText
3109                     post.Nickname = xRUentry.Item("name").InnerText
3110                     post.ImageUrl = xRUentry.Item("profile_image_url").InnerText
3111                     post.IsProtect = Boolean.Parse(xRUentry.Item("protected").InnerText)
3112                     post.IsMe = post.Name.ToLower.Equals(_uid)
3113
3114                     'Retweetした人
3115                     Dim xUentry As XmlElement = CType(xentry.SelectSingleNode("./user"), XmlElement)
3116                     post.RetweetedBy = xUentry.Item("screen_name").InnerText
3117                 Else
3118                     post.PDate = DateTime.ParseExact(xentry.Item("created_at").InnerText, "ddd MMM dd HH:mm:ss zzzz yyyy", System.Globalization.DateTimeFormatInfo.InvariantInfo, System.Globalization.DateTimeStyles.None)
3119                     '本文
3120                     post.Data = xentry.Item("text").InnerText
3121                     'Source取得(htmlの場合は、中身を取り出し)
3122                     post.Source = xentry.Item("source").InnerText
3123                     Long.TryParse(xentry.Item("in_reply_to_status_id").InnerText, post.InReplyToId)
3124                     post.InReplyToUser = xentry.Item("in_reply_to_screen_name").InnerText
3125                     'in_reply_to_user_idを使うか?
3126                     post.IsFav = Boolean.Parse(xentry.Item("favorited").InnerText)
3127
3128                     '以下、ユーザー情報
3129                     Dim xUentry As XmlElement = CType(xentry.SelectSingleNode("./user"), XmlElement)
3130                     post.Uid = Long.Parse(xUentry.Item("id").InnerText)
3131                     post.Name = xUentry.Item("screen_name").InnerText
3132                     post.Nickname = xUentry.Item("name").InnerText
3133                     post.ImageUrl = xUentry.Item("profile_image_url").InnerText
3134                     post.IsProtect = Boolean.Parse(xUentry.Item("protected").InnerText)
3135                     post.IsMe = post.Name.ToLower.Equals(_uid)
3136                 End If
3137                 'HTMLに整形
3138                 post.OriginalData = CreateHtmlAnchor(post.Data, post.ReplyToList)
3139                 post.Data = HttpUtility.HtmlDecode(post.Data)
3140                 post.Data = post.Data.Replace("<3", "♡")
3141                 'Source整形
3142                 If post.Source.StartsWith("<") Then
3143                     Dim rgS As New Regex(">(?<source>.+)<")
3144                     Dim mS As Match = rgS.Match(post.Source)
3145                     If mS.Success Then
3146                         post.Source = mS.Result("${source}")
3147                     End If
3148                 End If
3149
3150                 post.IsRead = read
3151                 If gType = WORKERTYPE.Timeline Then
3152                     post.IsReply = post.ReplyToList.Contains(_uid)
3153                 Else
3154                     post.IsReply = True
3155                 End If
3156
3157                 If post.IsMe Then
3158                     post.IsOwl = False
3159                 Else
3160                     If followerId.Count > 0 Then post.IsOwl = Not followerId.Contains(post.Uid)
3161                 End If
3162                 If post.IsMe AndAlso Not read AndAlso _readOwnPost Then post.IsRead = True
3163
3164                 post.IsDm = False
3165             Catch ex As Exception
3166                 TraceOut(retMsg)
3167                 'MessageBox.Show("不正なXMLです。(TL-Parse)")
3168                 Continue For
3169             End Try
3170
3171             '非同期アイコン取得&StatusDictionaryに追加
3172             arIdx += 1
3173             dlgt(arIdx) = New GetIconImageDelegate(AddressOf GetIconImage)
3174             ar(arIdx) = dlgt(arIdx).BeginInvoke(post, Nothing, Nothing)
3175         Next
3176
3177         'アイコン取得完了待ち
3178         For i As Integer = 0 To arIdx
3179             Try
3180                 dlgt(i).EndInvoke(ar(i))
3181             Catch ex As Exception
3182                 '最後までendinvoke回す(ゾンビ化回避)
3183                 ex.Data("IsTerminatePermission") = False
3184                 Throw
3185             End Try
3186         Next
3187
3188         If _ApiMethod = MySocket.REQ_TYPE.ReqGetAPI Then _remainCountApi = sck.RemainCountApi
3189
3190         Return ""
3191     End Function
3192
3193     Public Function GetSearch(ByVal read As Boolean, _
3194                             ByVal tabName As String) As String
3195
3196         If _endingFlag Then Return ""
3197
3198         Dim retMsg As String = ""
3199         Dim resStatus As String = ""
3200         Dim sck As MySocket = CreateSocket()
3201         Const SEARCH_HOST As String = "search."
3202         Const SEARCH_PATH As String = "/search.atom"
3203
3204         Dim tb As TabClass = TabInformations.GetInstance.Tabs(tabName)
3205         If tb Is Nothing Then Return ""
3206         Dim query As String = tb.SearchQuery
3207         If query = "" Then Return ""
3208
3209         retMsg = DirectCast(sck.GetWebResponse(_protocol + SEARCH_HOST + _hubServer + SEARCH_PATH + "?" + query, resStatus, MySocket.REQ_TYPE.ReqGetAPINoAuth, userAgent:="Tween"), String)
3210
3211         If retMsg = "" Then
3212             If resStatus.StartsWith("Err: BadRequest") Then
3213                 Return "Invalid search query."
3214             ElseIf resStatus.StartsWith("Err: 420") Then    '暫定:2010/1/18よりAPI制限で420返るらしい
3215                 Return "Maybe, the requests reached API limit."
3216             Else
3217                 Return resStatus
3218             End If
3219         End If
3220
3221         Dim arIdx As Integer = -1
3222         Dim dlgt(_countApi) As GetIconImageDelegate    'countQueryに合わせる
3223         Dim ar(_countApi) As IAsyncResult              'countQueryに合わせる
3224         Dim xdoc As New XmlDocument
3225         Try
3226             xdoc.LoadXml(retMsg)
3227         Catch ex As Exception
3228             TraceOut(retMsg)
3229             Return "Invalid ATOM!"
3230         End Try
3231         Dim nsmgr As New XmlNamespaceManager(xdoc.NameTable)
3232         nsmgr.AddNamespace("search", "http://www.w3.org/2005/Atom")
3233         For Each xentryNode As XmlNode In xdoc.DocumentElement.SelectNodes("/search:feed/search:entry", nsmgr)
3234             Dim xentry As XmlElement = CType(xentryNode, XmlElement)
3235             Dim post As New PostClass
3236             Try
3237                 post.Id = Long.Parse(xentry.Item("id").InnerText.Split(":"c)(2))
3238                 post.PDate = DateTime.Parse(xentry.Item("published").InnerText)
3239                 '本文
3240                 post.Data = xentry.Item("title").InnerText
3241                 'Source取得(htmlの場合は、中身を取り出し)
3242                 post.Source = xentry.Item("twitter:source").InnerText
3243                 post.InReplyToId = 0
3244                 post.InReplyToUser = ""
3245                 post.IsFav = False
3246
3247                 '以下、ユーザー情報
3248                 Dim xUentry As XmlElement = CType(xentry.SelectSingleNode("./search:author", nsmgr), XmlElement)
3249                 post.Uid = 0
3250                 post.Name = xUentry.Item("name").InnerText.Split(" "c)(0).Trim
3251                 post.Nickname = xUentry.Item("name").InnerText.Substring(post.Name.Length).Trim
3252                 If post.Nickname.Length > 2 Then
3253                     post.Nickname = post.Nickname.Substring(1, post.Nickname.Length - 2)
3254                 Else
3255                     post.Nickname = post.Name
3256                 End If
3257                 post.ImageUrl = CType(xentry.SelectSingleNode("./search:link[@type='image/png']", nsmgr), XmlElement).GetAttribute("href")
3258                 post.IsProtect = False
3259                 post.IsMe = post.Name.ToLower.Equals(_uid)
3260
3261                 'HTMLに整形
3262                 post.OriginalData = CreateHtmlAnchor(post.Data, post.ReplyToList)
3263                 post.Data = HttpUtility.HtmlDecode(post.Data)
3264                 'Source整形
3265                 If post.Source.StartsWith("<") Then
3266                     Dim rgS As New Regex(">(?<source>.+)<")
3267                     Dim mS As Match = rgS.Match(post.Source)
3268                     If mS.Success Then
3269                         post.Source = mS.Result("${source}")
3270                     End If
3271                 End If
3272
3273                 post.IsRead = read
3274                 post.IsReply = post.ReplyToList.Contains(_uid)
3275
3276                 post.IsOwl = False
3277                 If post.IsMe AndAlso Not read AndAlso _readOwnPost Then post.IsRead = True
3278                 post.IsDm = False
3279                 post.SearchTabName = tabName
3280             Catch ex As Exception
3281                 TraceOut(retMsg)
3282                 Continue For
3283             End Try
3284
3285             '非同期アイコン取得&StatusDictionaryに追加
3286             arIdx += 1
3287             dlgt(arIdx) = New GetIconImageDelegate(AddressOf GetIconImage)
3288             ar(arIdx) = dlgt(arIdx).BeginInvoke(post, Nothing, Nothing)
3289         Next
3290
3291         'アイコン取得完了待ち
3292         For i As Integer = 0 To arIdx
3293             Try
3294                 dlgt(i).EndInvoke(ar(i))
3295             Catch ex As Exception
3296                 '最後までendinvoke回す(ゾンビ化回避)
3297                 ex.Data("IsTerminatePermission") = False
3298                 Throw
3299             End Try
3300         Next
3301
3302         Return ""
3303     End Function
3304
3305     Public Function GetDirectMessageApi(ByVal read As Boolean, _
3306                             ByVal gType As WORKERTYPE) As String
3307         If _endingFlag Then Return ""
3308
3309         If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
3310
3311         Dim retMsg As String = ""
3312         Dim resStatus As String = ""
3313         Dim sck As MySocket = CreateSocket()
3314         'スレッド取得は行わず、countで調整
3315         Const GET_COUNT As Integer = 20
3316         Const RECEIVE_PATH As String = "/direct_messages.xml"
3317         Const SENT_PATH As String = "/direct_messages/sent.xml"
3318
3319         If gType = WORKERTYPE.DirectMessegeRcv Then
3320             retMsg = DirectCast(sck.GetWebResponse(_protocol + _hubServer + RECEIVE_PATH, resStatus, _ApiMethod), String)
3321         Else
3322             retMsg = DirectCast(sck.GetWebResponse(_protocol + _hubServer + SENT_PATH, resStatus, _ApiMethod), String)
3323         End If
3324
3325         If retMsg = "" Then
3326             If resStatus.StartsWith("Err: BadRequest") Then
3327                 Return "Maybe, the requests reached API limit."
3328             ElseIf resStatus.StartsWith("Err: Unauthorized") Then
3329                 Twitter.AccountState = ACCOUNT_STATE.Invalid
3330                 Return "Check your Username/Password."
3331             Else
3332                 Return resStatus
3333             End If
3334         End If
3335
3336         Dim arIdx As Integer = -1
3337         Dim dlgt(GET_COUNT) As GetIconImageDelegate    'countQueryに合わせる
3338         Dim ar(GET_COUNT) As IAsyncResult              'countQueryに合わせる
3339         Dim xdoc As New XmlDocument
3340         Try
3341             xdoc.LoadXml(retMsg)
3342         Catch ex As Exception
3343             TraceOut(retMsg)
3344             'MessageBox.Show("不正なXMLです。(DM-LoadXml)")
3345             Return "Invalid XML!"
3346         End Try
3347
3348         For Each xentryNode As XmlNode In xdoc.DocumentElement.SelectNodes("./direct_message")
3349             Dim xentry As XmlElement = CType(xentryNode, XmlElement)
3350             Dim post As New PostClass
3351             Try
3352                 post.Id = Long.Parse(xentry.Item("id").InnerText)
3353                 '二重取得回避
3354                 SyncLock LockObj
3355                     If TabInformations.GetInstance.ContainsKey(post.Id) Then Continue For
3356                 End SyncLock
3357                 'sender_id
3358                 'recipient_id
3359                 post.PDate = DateTime.ParseExact(xentry.Item("created_at").InnerText, "ddd MMM dd HH:mm:ss zzzz yyyy", System.Globalization.DateTimeFormatInfo.InvariantInfo, System.Globalization.DateTimeStyles.None)
3360                 '本文
3361                 post.Data = xentry.Item("text").InnerText
3362                 'HTMLに整形
3363                 post.OriginalData = CreateHtmlAnchor(post.Data, post.ReplyToList)
3364                 post.Data = HttpUtility.HtmlDecode(post.Data)
3365                 post.Data = post.Data.Replace("<3", "♡")
3366                 post.IsFav = False
3367                 '受信DMかの判定で使用
3368                 If gType = WORKERTYPE.DirectMessegeRcv Then
3369                     post.IsOwl = False
3370                 Else
3371                     post.IsOwl = True
3372                 End If
3373
3374                 '以下、ユーザー情報
3375                 Dim xUentry As XmlElement
3376                 If gType = WORKERTYPE.DirectMessegeRcv Then
3377                     xUentry = CType(xentry.SelectSingleNode("./sender"), XmlElement)
3378                     post.IsMe = False
3379                 Else
3380                     xUentry = CType(xentry.SelectSingleNode("./recipient"), XmlElement)
3381                     post.IsMe = True
3382                 End If
3383                 post.Uid = Long.Parse(xUentry.Item("id").InnerText)
3384                 post.Name = xUentry.Item("screen_name").InnerText
3385                 post.Nickname = xUentry.Item("name").InnerText
3386                 post.ImageUrl = xUentry.Item("profile_image_url").InnerText
3387                 post.IsProtect = Boolean.Parse(xUentry.Item("protected").InnerText)
3388             Catch ex As Exception
3389                 TraceOut(retMsg)
3390                 'MessageBox.Show("不正なXMLです。(DM-Parse)")
3391                 Continue For
3392             End Try
3393
3394             post.IsRead = read
3395             post.IsReply = False
3396             post.IsDm = True
3397
3398             '非同期アイコン取得&StatusDictionaryに追加
3399             arIdx += 1
3400             dlgt(arIdx) = New GetIconImageDelegate(AddressOf GetIconImage)
3401             ar(arIdx) = dlgt(arIdx).BeginInvoke(post, Nothing, Nothing)
3402         Next
3403
3404         'アイコン取得完了待ち
3405         For i As Integer = 0 To arIdx
3406             Try
3407                 dlgt(i).EndInvoke(ar(i))
3408             Catch ex As Exception
3409                 '最後までendinvoke回す(ゾンビ化回避)
3410                 ex.Data("IsTerminatePermission") = False
3411                 Throw
3412             End Try
3413         Next
3414
3415         If _ApiMethod = MySocket.REQ_TYPE.ReqGetAPI Then _remainCountApi = sck.RemainCountApi
3416
3417         Return ""
3418     End Function
3419
3420     Public Function GetFavoritesApi(ByVal read As Boolean, _
3421                         ByVal gType As WORKERTYPE) As String
3422
3423         If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
3424
3425         If _endingFlag Then Return ""
3426
3427         Dim retMsg As String = ""
3428         Dim resStatus As String = ""
3429         Dim sck As MySocket = CreateSocket()
3430         'スレッド取得は行わず、countで調整
3431         Const COUNT_QUERY As String = "count="
3432         Const FAV_PATH As String = "/favorites.xml"
3433
3434         retMsg = DirectCast(sck.GetWebResponse(_protocol + _hubServer + FAV_PATH + "?" + COUNT_QUERY + _countApi.ToString(), resStatus, _ApiMethod), String)
3435
3436         If retMsg = "" Then
3437             If resStatus.StartsWith("Err: BadRequest") Then
3438                 Return "Maybe, the requests reached API limit."
3439             ElseIf resStatus.StartsWith("Err: Unauthorized") Then
3440                 Twitter.AccountState = ACCOUNT_STATE.Invalid
3441                 Return "Check your Username/Password."
3442             Else
3443                 Return resStatus
3444             End If
3445         End If
3446
3447         Dim arIdx As Integer = -1
3448         Dim dlgt(_countApi) As GetIconImageDelegate    'countQueryに合わせる
3449         Dim ar(_countApi) As IAsyncResult              'countQueryに合わせる
3450         Dim xdoc As New XmlDocument
3451         Try
3452             xdoc.LoadXml(retMsg)
3453         Catch ex As Exception
3454             TraceOut(retMsg)
3455             'MessageBox.Show("不正なXMLです。(TL-LoadXml)")
3456             Return "Invalid XML!"
3457         End Try
3458
3459         For Each xentryNode As XmlNode In xdoc.DocumentElement.SelectNodes("./status")
3460             Dim xentry As XmlElement = CType(xentryNode, XmlElement)
3461             Dim post As New PostClass
3462             Try
3463                 post.Id = Long.Parse(xentry.Item("id").InnerText)
3464                 '二重取得回避
3465                 SyncLock LockObj
3466                     If TabInformations.GetInstance.ContainsKey(post.Id) Then Continue For
3467                 End SyncLock
3468                 'Retweet判定
3469                 Dim xRnode As XmlNode = xentry.SelectSingleNode("./retweeted_status")
3470                 If xRnode IsNot Nothing Then
3471                     Dim xRentry As XmlElement = CType(xRnode, XmlElement)
3472                     post.PDate = DateTime.ParseExact(xRentry.Item("created_at").InnerText, "ddd MMM dd HH:mm:ss zzzz yyyy", System.Globalization.DateTimeFormatInfo.InvariantInfo, System.Globalization.DateTimeStyles.None)
3473                     'Id
3474                     post.RetweetedId = Long.Parse(xRentry.Item("id").InnerText)
3475                     '本文
3476                     post.Data = xRentry.Item("text").InnerText
3477                     'Source取得(htmlの場合は、中身を取り出し)
3478                     post.Source = xRentry.Item("source").InnerText
3479                     'Reply先
3480                     Long.TryParse(xRentry.Item("in_reply_to_status_id").InnerText, post.InReplyToId)
3481                     post.InReplyToUser = xRentry.Item("in_reply_to_screen_name").InnerText
3482                     'in_reply_to_user_idを使うか?
3483                     post.IsFav = Boolean.Parse(xRentry.Item("favorited").InnerText)
3484
3485                     '以下、ユーザー情報
3486                     Dim xRUentry As XmlElement = CType(xRentry.SelectSingleNode("./user"), XmlElement)
3487                     post.Uid = Long.Parse(xRUentry.Item("id").InnerText)
3488                     post.Name = xRUentry.Item("screen_name").InnerText
3489                     post.Nickname = xRUentry.Item("name").InnerText
3490                     post.ImageUrl = xRUentry.Item("profile_image_url").InnerText
3491                     post.IsProtect = Boolean.Parse(xRUentry.Item("protected").InnerText)
3492                     post.IsMe = post.Name.ToLower.Equals(_uid)
3493
3494                     'Retweetした人
3495                     Dim xUentry As XmlElement = CType(xentry.SelectSingleNode("./user"), XmlElement)
3496                     post.RetweetedBy = xUentry.Item("screen_name").InnerText
3497                 Else
3498                     post.PDate = DateTime.ParseExact(xentry.Item("created_at").InnerText, "ddd MMM dd HH:mm:ss zzzz yyyy", System.Globalization.DateTimeFormatInfo.InvariantInfo, System.Globalization.DateTimeStyles.None)
3499                     '本文
3500                     post.Data = xentry.Item("text").InnerText
3501                     'Source取得(htmlの場合は、中身を取り出し)
3502                     post.Source = xentry.Item("source").InnerText
3503                     Long.TryParse(xentry.Item("in_reply_to_status_id").InnerText, post.InReplyToId)
3504                     post.InReplyToUser = xentry.Item("in_reply_to_screen_name").InnerText
3505                     'in_reply_to_user_idを使うか?
3506                     post.IsFav = Boolean.Parse(xentry.Item("favorited").InnerText)
3507
3508                     '以下、ユーザー情報
3509                     Dim xUentry As XmlElement = CType(xentry.SelectSingleNode("./user"), XmlElement)
3510                     post.Uid = Long.Parse(xUentry.Item("id").InnerText)
3511                     post.Name = xUentry.Item("screen_name").InnerText
3512                     post.Nickname = xUentry.Item("name").InnerText
3513                     post.ImageUrl = xUentry.Item("profile_image_url").InnerText
3514                     post.IsProtect = Boolean.Parse(xUentry.Item("protected").InnerText)
3515                     post.IsMe = post.Name.ToLower.Equals(_uid)
3516                 End If
3517                 'HTMLに整形
3518                 post.OriginalData = CreateHtmlAnchor(post.Data, post.ReplyToList)
3519                 post.Data = HttpUtility.HtmlDecode(post.Data)
3520                 post.Data = post.Data.Replace("<3", "♡")
3521                 'Source整形
3522                 If post.Source.StartsWith("<") Then
3523                     Dim rgS As New Regex(">(?<source>.+)<")
3524                     Dim mS As Match = rgS.Match(post.Source)
3525                     If mS.Success Then
3526                         post.Source = mS.Result("${source}")
3527                     End If
3528                 End If
3529
3530                 post.IsRead = read
3531                 post.IsReply = post.ReplyToList.Contains(_uid)
3532
3533                 If post.IsMe Then
3534                     post.IsOwl = False
3535                 Else
3536                     If followerId.Count > 0 Then post.IsOwl = Not followerId.Contains(post.Uid)
3537                 End If
3538
3539                 post.IsDm = False
3540             Catch ex As Exception
3541                 TraceOut(retMsg)
3542                 'MessageBox.Show("不正なXMLです。(TL-Parse)")
3543                 Continue For
3544             End Try
3545
3546             '非同期アイコン取得&StatusDictionaryに追加
3547             arIdx += 1
3548             dlgt(arIdx) = New GetIconImageDelegate(AddressOf GetIconImage)
3549             ar(arIdx) = dlgt(arIdx).BeginInvoke(post, Nothing, Nothing)
3550         Next
3551
3552         'アイコン取得完了待ち
3553         For i As Integer = 0 To arIdx
3554             Try
3555                 dlgt(i).EndInvoke(ar(i))
3556             Catch ex As Exception
3557                 '最後までendinvoke回す(ゾンビ化回避)
3558                 ex.Data("IsTerminatePermission") = False
3559                 Throw
3560             End Try
3561         Next
3562
3563         If _ApiMethod = MySocket.REQ_TYPE.ReqGetAPI Then _remainCountApi = sck.RemainCountApi
3564
3565         Return ""
3566     End Function
3567
3568     Public Function GetFollowersApi() As String
3569         If _endingFlag Then Return ""
3570         Dim page As Long = -1
3571
3572         followerId.Clear()
3573
3574         Do
3575             Dim ret As String = FollowerApi(page)
3576             If ret <> "" Then Return ret
3577         Loop While page > 0
3578         Return ""
3579     End Function
3580
3581     Private Function FollowerApi(ByRef page As Long) As String
3582         If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
3583
3584         Dim retMsg As String = ""
3585         Dim resStatus As String = ""
3586         Dim curCount As Integer = followerId.Count
3587
3588         Const FOLLOWER_PATH As String = "/followers/ids.xml"
3589
3590         retMsg = DirectCast(CreateSocket.GetWebResponse(_protocol + _hubServer + FOLLOWER_PATH + _cursorQry + page.ToString(), resStatus, _ApiMethod), String)
3591
3592         If retMsg = "" Then
3593             If resStatus.StartsWith("Err: Unauthorized") Then
3594                 Twitter.AccountState = ACCOUNT_STATE.Invalid
3595                 Return "Check your Username/Password."
3596             Else
3597                 Return resStatus
3598             End If
3599         End If
3600
3601         Dim xdoc As New XmlDocument
3602         Try
3603             xdoc.LoadXml(retMsg)
3604         Catch ex As Exception
3605             TraceOut(retMsg)
3606             MessageBox.Show("The data was broken. Please retry later.(FollowerApi-LoadXml)")
3607             Return "Invalid XML!"
3608         End Try
3609
3610         Try
3611             For Each xentryNode As XmlNode In xdoc.DocumentElement.SelectNodes("/id_list/ids/id")
3612                 followerId.Add(Long.Parse(xentryNode.InnerText))
3613             Next
3614             page = Long.Parse(xdoc.DocumentElement.SelectSingleNode("/id_list/next_cursor").InnerText)
3615         Catch ex As Exception
3616             TraceOut(retMsg)
3617             MessageBox.Show("The data was broken. Please retry later.(FollowerApi-Parse)")
3618             Return "Invalid XML!"
3619         End Try
3620
3621         Return ""
3622
3623     End Function
3624
3625     Private Function CreateHtmlAnchor(ByVal Text As String, ByVal AtList As List(Of String)) As String
3626         Dim retStr As String = HttpUtility.HtmlEncode(Text)     '要検証(デコードされて取得されるので再エンコード)
3627
3628         'uriの正規表現
3629         Dim rgUrl As Regex = New Regex("(?<![0-9A-Za-z])(?:https?|shttp|ftps?)://(?:(?:[-_.!~*'()a-zA-Z0-9;:&=+$,]|%[0-9A-Fa-f" + _
3630                          "][0-9A-Fa-f])*@)?(?:(?:[a-zA-Z0-9](?:[-a-zA-Z0-9]*[a-zA-Z0-9])?\.)" + _
3631                          "*[a-zA-Z](?:[-a-zA-Z0-9]*[a-zA-Z0-9])?\.?|[0-9]+\.[0-9]+\.[0-9]+\." + _
3632                          "[0-9]+)(?::[0-9]*)?(?:/(?:[-_.!~*'()a-zA-Z0-9:@&=+$,]|%[0-9A-Fa-f]" + _
3633                          "[0-9A-Fa-f])*(?:;(?:[-_.!~*'()a-zA-Z0-9:@&=+$,]|%[0-9A-Fa-f][0-9A-" + _
3634                          "Fa-f])*)*(?:/(?:[-_.!~*'()a-zA-Z0-9:@&=+$,]|%[0-9A-Fa-f][0-9A-Fa-f" + _
3635                          "])*(?:;(?:[-_.!~*'()a-zA-Z0-9:@&=+$,]|%[0-9A-Fa-f][0-9A-Fa-f])*)*)" + _
3636                          "*)?(?:\?(?:[-_.!~*'()a-zA-Z0-9;/?:@&=+$,]|%[0-9A-Fa-f][0-9A-Fa-f])" + _
3637                          "*)?(?:#(?:[-_.!~*'()a-zA-Z0-9;/?:@&=+$,]|%[0-9A-Fa-f][0-9A-Fa-f])*)?")
3638         '絶対パス表現のUriをリンクに置換
3639         retStr = rgUrl.Replace(Text, "<a href=""$&"">$&</a>")
3640         '@返信を抽出し、@先リスト作成
3641         'Dim rg As New Regex("(^|[ -/:-@[-^`{-~])@([a-zA-Z0-9_]{1,20}/[a-zA-Z0-9_\-]{1,24}[a-zA-Z0-9_])")
3642         Dim rg As New Regex("(^|[^a-zA-Z0-9_])[@@]([a-zA-Z0-9_]{1,20}/[a-zA-Z0-9_\-]{1,24}[a-zA-Z0-9_])")
3643         Dim m As Match = rg.Match(retStr)
3644         '@先をリンクに置換
3645         retStr = rg.Replace(retStr, "$1@<a href=""/$2"">$2</a>")
3646
3647         'rg = New Regex("(^|[ -/:-@[-^`{-~])@([a-zA-Z0-9_]{1,20})")
3648         rg = New Regex("(^|[^a-zA-Z0-9_])[@@]([a-zA-Z0-9_]{1,20})")
3649         m = rg.Match(retStr)
3650         While m.Success
3651             AtList.Add(m.Result("$2").ToLower)
3652             m = m.NextMatch
3653         End While
3654         '@先をリンクに置換
3655         retStr = rg.Replace(retStr, "$1@<a href=""/$2"">$2</a>")
3656
3657         'ハッシュタグを抽出し、リンクに置換
3658         'Dim rgh As New Regex("(^|[ .!,\-:;<>?])#([^] !""#$%&'()*+,.:;<=>?@\-[\^`{|}~\r\n]+)")
3659         Dim rgh As New Regex("(^|[^a-zA-Z0-9_])[##]([a-zA-Z0-9_]+)")
3660         Dim mh As Match = rgh.Match(retStr)
3661         If mh.Success AndAlso Not IsNumeric(mh.Result("$2")) Then
3662             retStr = rgh.Replace(retStr, "$1<a href=""" + _protocol + "twitter.com/search?q=%23$2"">#$2</a>")
3663         End If
3664
3665
3666         retStr = AdjustHtml(ShortUrlResolve(PreProcessUrl(retStr))) 'IDN置換、短縮Uri解決、@リンクを相対→絶対にしてtarget属性付与
3667         Return retStr
3668     End Function
3669
3670     Public ReadOnly Property RemainCountApi() As Integer
3671         Get
3672             Return _remainCountApi
3673         End Get
3674     End Property
3675
3676     Public Function GetMaxCountApi() As Integer
3677         Dim _maxcnt As Integer = 0
3678         Dim resMsg As String = ""
3679         Dim resStatus As String = ""
3680         resMsg = DirectCast(CreateSocket.GetWebResponse(_protocol + _hubServer + _rateLimitStatus, resStatus, MySocket.REQ_TYPE.ReqGetAPI), String)
3681         Dim xdoc As New XmlDocument
3682         Try
3683             xdoc.LoadXml(resMsg)
3684             _maxcnt = Integer.Parse(xdoc.SelectSingleNode("/hash/hourly-limit").InnerText)
3685         Catch ex As Exception
3686             _maxcnt = 0
3687         End Try
3688         Return _maxcnt
3689     End Function
3690
3691     Public Function GetRemainCountApi() As Integer
3692         Dim _remain As Integer = 0
3693         Dim resMsg As String = ""
3694         Dim resStatus As String = ""
3695         resMsg = DirectCast(CreateSocket.GetWebResponse(_protocol + _hubServer + _rateLimitStatus, resStatus, MySocket.REQ_TYPE.ReqGetAPI), String)
3696         Dim xdoc As New XmlDocument
3697         Try
3698             xdoc.LoadXml(resMsg)
3699             _remain = Integer.Parse(xdoc.SelectSingleNode("/hash/remaining-hits").InnerText)
3700         Catch ex As Exception
3701             _remain = 0
3702         End Try
3703         Return _remain
3704     End Function
3705
3706     Public Function GetResetTimeApi() As DateTime
3707         Dim _tm As DateTime
3708         Dim resMsg As String = ""
3709         Dim resStatus As String = ""
3710         resMsg = DirectCast(CreateSocket.GetWebResponse(_protocol + _hubServer + _rateLimitStatus, resStatus, MySocket.REQ_TYPE.ReqGetAPI), String)
3711         Dim xdoc As New XmlDocument
3712         Try
3713             xdoc.LoadXml(resMsg)
3714             _tm = DateTime.Parse(xdoc.SelectSingleNode("/hash/reset-time").InnerText)
3715         Catch ex As Exception
3716             _tm = Nothing
3717         End Try
3718         Return _tm
3719     End Function
3720
3721     Public Function GetInfoApi(ByRef info As ApiInfo) As Boolean
3722
3723         Dim resMsg As String = ""
3724         Dim resStatus As String = ""
3725         resMsg = DirectCast(CreateSocket.GetWebResponse(_protocol + _hubServer + _rateLimitStatus, resStatus, MySocket.REQ_TYPE.ReqGetAPI), String)
3726         Dim xdoc As New XmlDocument
3727         Try
3728             xdoc.LoadXml(resMsg)
3729             info.MaxCount = Integer.Parse(xdoc.SelectSingleNode("/hash/hourly-limit").InnerText)
3730             info.RemainCount = Integer.Parse(xdoc.SelectSingleNode("/hash/remaining-hits").InnerText)
3731             info.ResetTime = DateTime.Parse(xdoc.SelectSingleNode("/hash/reset-time").InnerText)
3732             info.ResetTimeInSeconds = Integer.Parse(xdoc.SelectSingleNode("/hash/reset-time-in-seconds").InnerText)
3733         Catch ex As Exception
3734             Return False
3735         End Try
3736         Return True
3737     End Function
3738
3739 #Region "デバッグモード解析キー自動生成"
3740 #If DEBUG Then
3741     Public Sub GenerateAnalyzeKey()
3742         '解析キー情報部分のソースをwedataから作成する
3743         '生成したソースはプロジェクトのディレクトリにコピーする
3744         Dim sw As New System.IO.StreamWriter(".\AnalyzeKey.vb", _
3745             False, _
3746             System.Text.Encoding.UTF8)
3747
3748         sw.WriteLine("Public Module AnalyzeKey")
3749         sw.WriteLine("'    このファイルはデバッグビルドのTweenにより自動作成されました   作成日時  " + DateAndTime.Now.ToString())
3750         sw.WriteLine("")
3751
3752         sw.WriteLine("    Public _splitPost As String = " + Chr(34) + _splitPost.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3753         sw.WriteLine("    Public _splitPostRecent As String = " + Chr(34) + _splitPostRecent.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3754         sw.WriteLine("    Public _statusIdTo As String = " + Chr(34) + _statusIdTo.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3755         sw.WriteLine("    Public _splitDM As String = " + Chr(34) + _splitDM.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3756         sw.WriteLine("    Public _parseName As String = " + Chr(34) + _parseName.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3757         sw.WriteLine("    Public _parseNameTo As String = " + Chr(34) + _parseNameTo.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3758         sw.WriteLine("    Public _parseNick As String = " + Chr(34) + _parseNick.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3759         sw.WriteLine("    Public _parseNickTo As String = " + Chr(34) + _parseNickTo.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3760         sw.WriteLine("    Public _parseImg As String = " + Chr(34) + _parseImg.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3761         sw.WriteLine("    Public _parseImgTo As String = " + Chr(34) + _parseImgTo.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3762         sw.WriteLine("    Public _parseMsg1 As String = " + Chr(34) + _parseMsg1.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3763         sw.WriteLine("    Public _parseMsg2 As String = " + Chr(34) + _parseMsg2.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3764         sw.WriteLine("    Public _parseDM1 As String = " + Chr(34) + _parseDM1.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3765         sw.WriteLine("    Public _parseDM11 As String = " + Chr(34) + _parseDM11.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3766         sw.WriteLine("    Public _parseDM2 As String = " + Chr(34) + _parseDM2.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3767         sw.WriteLine("    Public _parseDate As String = " + Chr(34) + _parseDate.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3768         sw.WriteLine("    Public _parseDateTo As String = " + Chr(34) + _parseDateTo.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3769         sw.WriteLine("    Public _getAuthKey As String = " + Chr(34) + _getAuthKey.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3770         sw.WriteLine("    Public _getAuthKeyTo As String = " + Chr(34) + _getAuthKeyTo.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3771         'sw.WriteLine("    Public _parseStar As String = " + Chr(34) + _parseStar.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3772         'sw.WriteLine("    Public _parseStarTo As String = " + Chr(34) + _parseStarTo.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3773         'sw.WriteLine("    Public _parseStarEmpty As String = " + Chr(34) + _parseStarEmpty.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3774         sw.WriteLine("    Public _followerList As String = " + Chr(34) + _followerList.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3775         sw.WriteLine("    Public _followerMbr1 As String = " + Chr(34) + _followerMbr1.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3776         sw.WriteLine("    Public _followerMbr2 As String = " + Chr(34) + _followerMbr2.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3777         sw.WriteLine("    Public _followerMbr3 As String = " + Chr(34) + _followerMbr3.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3778         sw.WriteLine("    Public _getInfoTwitter As String = " + Chr(34) + _getInfoTwitter.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3779         sw.WriteLine("    Public _getInfoTwitterTo As String = " + Chr(34) + _getInfoTwitterTo.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3780         sw.WriteLine("    Public _isProtect As String = " + Chr(34) + _isProtect.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3781         sw.WriteLine("    Public _isReplyEng As String = " + Chr(34) + _isReplyEng.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3782         sw.WriteLine("    Public _isReplyJpn As String = " + Chr(34) + _isReplyJpn.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3783         sw.WriteLine("    Public _isReplyTo As String = " + Chr(34) + _isReplyTo.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3784         sw.WriteLine("    Public _parseProtectMsg1 As String = " + Chr(34) + _parseProtectMsg1.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3785         sw.WriteLine("    Public _parseProtectMsg2 As String = " + Chr(34) + _parseProtectMsg2.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3786         sw.WriteLine("    Public _parseDMcountFrom As String = " + Chr(34) + _parseDMcountFrom.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3787         sw.WriteLine("    Public _parseDMcountTo As String = " + Chr(34) + _parseDMcountTo.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3788         sw.WriteLine("    Public _parseSourceFrom As String = " + Chr(34) + _parseSourceFrom.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3789         sw.WriteLine("    Public _parseSource2 As String = " + Chr(34) + _parseSource2.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3790         sw.WriteLine("    Public _parseSourceTo As String = " + Chr(34) + _parseSourceTo.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3791         sw.WriteLine("    Public _removeClass As String = " + Chr(34) + _removeClass.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3792         sw.WriteLine("End Module")
3793
3794         sw.Close()
3795         'MessageBox.Show("解析キー情報定義ファイル AnalyzeKey.vbを生成しました")
3796
3797     End Sub
3798 #End If
3799 #End Region
3800 End Module