[smuxi] Engine-Twitter: implemented search streams
- From: Mirco M. M. Bauer <mmmbauer src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [smuxi] Engine-Twitter: implemented search streams
- Date: Mon, 29 Dec 2014 19:01:42 +0000 (UTC)
commit 38ab881a6da58187e903b34cd2c5d7b7349acfad
Author: Mirco Bauer <meebey meebey net>
Date: Sun Nov 10 01:33:10 2013 +0100
Engine-Twitter: implemented search streams
lib/Makefile.am | 16 ++-
src/Common-Tests/Common-Tests.csproj | 1 +
src/Common-Tests/RateLimiterTests.cs | 57 +++++++
src/Common/Common.csproj | 1 +
src/Common/Makefile.am | 1 +
src/Common/RateLimiter.cs | 82 ++++++++++
src/Engine-Twitter/Engine-Twitter.csproj | 5 +
src/Engine-Twitter/Makefile.am | 11 +-
.../Protocols/Twitter/TwitterProtocolManager.cs | 22 +++-
.../Protocols/Twitter/TwitterSearchStream.cs | 161 ++++++++++++++++++++
src/smuxi.sln | 14 ++
11 files changed, 365 insertions(+), 6 deletions(-)
---
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 017cfc2..7b95015 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -76,6 +76,14 @@ TWITTERIZER_ASSEMBLY_TARGET = $(OUTPUT_DIR)/$(TWITTERIZER_ASSEMBLY_NAME)
TWITTERIZER_BUILD_FILE = $(TWITTERIZER_SRCDIR)/Twitterizer2.csproj
TWITTERIZER_XBUILD_FLAGS = $(XBUILD_FLAGS) /p:PostBuildEvent=
+TWITTERIZER_STREAMING_SRCDIR = $(srcdir)/$(TWITTERIZER_SUBDIR)/Twitterizer2.Streaming
+TWITTERIZER_STREAMING_SOURCE_FILES = $(foreach pattern, ../*.cs $(SOURCE_PATTERNS), $(wildcard
$(TWITTERIZER_STREAMING_SRCDIR)/$(pattern)))
+TWITTERIZER_STREAMING_EXTRA_FILES = $(TWITTERIZER_STREAMING_BUILD_FILE)
+TWITTERIZER_STREAMING_ASSEMBLY_NAME = Twitterizer2.Streaming.dll
+TWITTERIZER_STREAMING_ASSEMBLY_TARGET = $(OUTPUT_DIR)/$(TWITTERIZER_STREAMING_ASSEMBLY_NAME)
+TWITTERIZER_STREAMING_BUILD_FILE = $(TWITTERIZER_STREAMING_SRCDIR)/Twitterizer2.Streaming.csproj
+TWITTERIZER_STREAMING_XBUILD_FLAGS = $(XBUILD_FLAGS)
+
JABBER_NET_SUBDIR = agsxmpp/agsxmpp
JABBER_NET_SRCDIR = $(srcdir)/$(JABBER_NET_SUBDIR)
JABBER_NET_SOURCE_FILES = $(foreach pattern, $(SOURCE_PATTERNS), $(wildcard $(JABBER_NET_SRCDIR)/$(pattern)))
@@ -161,7 +169,8 @@ if ENABLE_ENGINE_TWITTER
EXTRA_JSON_LIBS = \
$(JSON_ASSEMBLY_TARGET) $(JSON_ASSEMBLY_TARGET).mdb
EXTRA_TWITTER_LIBS = \
- $(TWITTERIZER_ASSEMBLY_TARGET) $(TWITTERIZER_ASSEMBLY_TARGET).mdb
+ $(TWITTERIZER_ASSEMBLY_TARGET) $(TWITTERIZER_ASSEMBLY_TARGET).mdb \
+ $(TWITTERIZER_STREAMING_ASSEMBLY_TARGET) $(TWITTERIZER_STREAMING_ASSEMBLY_TARGET).mdb
endif
if ENABLE_ENGINE_XMPP
EXTRA_XMPP_LIBS = \
@@ -206,6 +215,7 @@ EXTRA_DIST = \
$(SERVICESTACK_COMMON_SRCDIR) $(SERVICESTACK_COMMON_EXTRA_FILES) \
$(JSON_SRCDIR) $(JSON_EXTRA_FILES) \
$(TWITTERIZER_SRCDIR) $(TWITTERIZER_EXTRA_FILES) \
+ $(TWITTERIZER_STREAMING_SRCDIR) $(TWITTERIZER_STREAMING_EXTRA_FILES) \
$(JABBER_NET_SRCDIR) $(JABBER_NET_EXTRA_FILES) \
$(DB4O_SRCDIR) $(DB4O_EXTRA_FILES) \
$(STARKSOFTPROXY_SRCDIR) $(STARKSOFTPROXY_EXTRA_FILES) \
@@ -248,6 +258,9 @@ $(JSON_ASSEMBLY_TARGET) $(JSON_ASSEMBLY_TARGET).mdb: $(JSON_BUILD_FILE) $(JSON_S
$(TWITTERIZER_ASSEMBLY_TARGET) $(TWITTERIZER_ASSEMBLY_TARGET).mdb: $(TWITTERIZER_BUILD_FILE)
$(TWITTERIZER_SOURCE_FILES)
$(XBUILD) $(TWITTERIZER_XBUILD_FLAGS) $(TWITTERIZER_BUILD_FILE)
+$(TWITTERIZER_STREAMING_ASSEMBLY_TARGET) $(TWITTERIZER_STREAMING_ASSEMBLY_TARGET).mdb:
$(TWITTERIZER_STREAMING_BUILD_FILE) $(TWITTERIZER_STREAMING_SOURCE_FILES)
+ $(XBUILD) $(TWITTERIZER_STREAMING_XBUILD_FLAGS) $(TWITTERIZER_STREAMING_BUILD_FILE)
+
$(JABBER_NET_ASSEMBLY_TARGET) $(JABBER_NET_ASSEMBLY_TARGET).mdb: $(JABBER_NET_BUILD_FILE)
$(JABBER_NET_SOURCE_FILES)
$(XBUILD) $(JABBER_NET_XBUILD_FLAGS) $(JABBER_NET_BUILD_FILE)
@@ -283,6 +296,7 @@ endif
if ENABLE_ENGINE_TWITTER
$(XBUILD) $(JSON_XBUILD_FLAGS) /t:Clean $(JSON_BUILD_FILE)
$(XBUILD) $(TWITTERIZER_XBUILD_FLAGS) /t:Clean $(TWITTERIZER_BUILD_FILE)
+ $(XBUILD) $(TWITTERIZER_STREAMING_XBUILD_FLAGS) /t:Clean $(TWITTERIZER_STREAMING_BUILD_FILE)
endif
if ENABLE_ENGINE_XMPP
$(XBUILD) $(JABBER_NET_XBUILD_FLAGS) /t:Clean $(JABBER_NET_BUILD_FILE)
diff --git a/src/Common-Tests/Common-Tests.csproj b/src/Common-Tests/Common-Tests.csproj
index f588a78..447906a 100644
--- a/src/Common-Tests/Common-Tests.csproj
+++ b/src/Common-Tests/Common-Tests.csproj
@@ -36,6 +36,7 @@
<Compile Include="TraceTests.cs" />
<Compile Include="PatternTests.cs" />
<Compile Include="Crc32Tests.cs" />
+ <Compile Include="RateLimiterTests.cs" />
</ItemGroup>
<ItemGroup>
<Reference Include="System" />
diff --git a/src/Common-Tests/RateLimiterTests.cs b/src/Common-Tests/RateLimiterTests.cs
new file mode 100644
index 0000000..4000816
--- /dev/null
+++ b/src/Common-Tests/RateLimiterTests.cs
@@ -0,0 +1,57 @@
+// Smuxi - Smart MUltipleXed Irc
+//
+// Copyright (c) 2014 Mirco Bauer <meebey meebey net>
+//
+// Full GPL License: <http://www.gnu.org/licenses/gpl.txt>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+using System;
+using NUnit.Framework;
+using System.Threading;
+
+namespace Smuxi.Common
+{
+ [TestFixture]
+ public class RateLimiterTests
+ {
+ [Test]
+ public void AboveLimit()
+ {
+ var limiter = new RateLimiter(10, TimeSpan.FromSeconds(10));
+ for (int i = 0; i < 100; i++) {
+ if (limiter.IsRateLimited) {
+ Assert.AreEqual(10, i);
+ break;
+ }
+ limiter++;
+ }
+ }
+
+ [Test]
+ public void BelowLimit()
+ {
+ var limiter = new RateLimiter(10, TimeSpan.FromMilliseconds(10));
+ for (int i = 0; i < 100; i++) {
+ if (limiter.IsRateLimited) {
+ break;
+ }
+ limiter++;
+ }
+ Thread.Sleep(10);
+ Assert.IsFalse(limiter.IsRateLimited);
+ }
+ }
+}
+
diff --git a/src/Common/Common.csproj b/src/Common/Common.csproj
index 220cf30..ce9f98f 100644
--- a/src/Common/Common.csproj
+++ b/src/Common/Common.csproj
@@ -57,6 +57,7 @@
<Compile Include="ThreadPoolQueue.cs" />
<Compile Include="AtomFeed.cs" />
<Compile Include="SpecialFolderPatternConverter.cs" />
+ <Compile Include="RateLimiter.cs" />
</ItemGroup>
<ItemGroup>
<None Include="Defines.cs.in" />
diff --git a/src/Common/Makefile.am b/src/Common/Makefile.am
index 359adfb..045df52 100644
--- a/src/Common/Makefile.am
+++ b/src/Common/Makefile.am
@@ -62,6 +62,7 @@ FILES = \
TaskQueue.cs \
ThreadPoolQueue.cs \
Platform.cs \
+ RateLimiter.cs \
Pattern.cs
DATA_FILES =
diff --git a/src/Common/RateLimiter.cs b/src/Common/RateLimiter.cs
new file mode 100644
index 0000000..6ea8458
--- /dev/null
+++ b/src/Common/RateLimiter.cs
@@ -0,0 +1,82 @@
+// This file is part of Smuxi and is licensed under the terms of MIT/X11
+//
+// Copyright (c) 2014 Mirco Bauer <meebey meebey net>
+// Copyright (c) 2014 Oliver Schneider <smuxi oli-obk de>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+
+namespace Smuxi.Common
+{
+ public class RateLimiter
+ {
+ TimeSpan TimeWindow { get; set; }
+ int CallCounter { get; set; }
+ int CallLimit { get; set; }
+ DateTime FirstCall { get; set; }
+ object SyncRoot { get; set; }
+
+ public bool IsRateLimited {
+ get {
+ return IsAboveLimit && IsInWindow;
+ }
+ }
+
+ bool IsAboveLimit {
+ get {
+ return CallLimit <= CallCounter;
+ }
+ }
+
+ bool IsInWindow {
+ get {
+ return (DateTime.UtcNow - FirstCall) < TimeWindow;
+ }
+ }
+
+ public RateLimiter(int callLimit, TimeSpan timeWindow)
+ {
+ if (callLimit <= 0) {
+ throw new ArgumentException("callLimit must be greater than 0.", "callLimit");
+ }
+
+ CallLimit = callLimit;
+ TimeWindow = timeWindow;
+ SyncRoot = new object();
+ }
+
+ public static RateLimiter operator ++(RateLimiter l)
+ {
+ if (l.IsRateLimited) {
+ throw new InvalidOperationException("IsRateLimited must not be true.");
+ }
+
+ lock (l.SyncRoot) {
+ if (!l.IsInWindow) {
+ l.CallCounter = 0;
+ l.FirstCall = DateTime.UtcNow;
+ }
+
+ l.CallCounter++;
+ }
+ return l;
+ }
+ }
+}
+
diff --git a/src/Engine-Twitter/Engine-Twitter.csproj b/src/Engine-Twitter/Engine-Twitter.csproj
index 6923cd1..28e3605 100644
--- a/src/Engine-Twitter/Engine-Twitter.csproj
+++ b/src/Engine-Twitter/Engine-Twitter.csproj
@@ -35,6 +35,7 @@
<Compile Include="AssemblyInfo.cs" />
<Compile Include="Protocols\Twitter\TwitterProtocolManager.cs" />
<Compile Include="Protocols\Twitter\TwitterMessageBuilder.cs" />
+ <Compile Include="Protocols\Twitter\TwitterSearchStream.cs" />
</ItemGroup>
<ItemGroup>
<Folder Include="Protocols\" />
@@ -61,6 +62,10 @@
<Project>{2FDC3492-6B9E-4771-9755-7892C9CB1E96}</Project>
<Name>Twitterizer2</Name>
</ProjectReference>
+ <ProjectReference Include="..\..\lib\Twitterizer\Twitterizer2.Streaming\Twitterizer2.Streaming.csproj">
+ <Project>{AFDC57ED-C013-4581-9D06-54D8A42D696D}</Project>
+ <Name>Twitterizer2.Streaming</Name>
+ </ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
</Project>
\ No newline at end of file
diff --git a/src/Engine-Twitter/Makefile.am b/src/Engine-Twitter/Makefile.am
index f51ed5b..f476c90 100644
--- a/src/Engine-Twitter/Makefile.am
+++ b/src/Engine-Twitter/Makefile.am
@@ -7,16 +7,19 @@ ASSEMBLY_TARGET = $(TARGET_DIR)/$(ASSEMBLY_FILENAME)
SOURCES = $(top_srcdir)/src/AssemblyVersion.cs \
AssemblyInfo.cs \
Protocols/Twitter/TwitterProtocolManager.cs \
- Protocols/Twitter/TwitterMessageBuilder.cs
+ Protocols/Twitter/TwitterMessageBuilder.cs \
+ Protocols/Twitter/TwitterSearchStream.cs
REFERENCES = $(LOG4NET_LIBS) \
$(SMARTIRC4NET_LIBS) \
System.Web \
System.Core
-DLL_REFERENCES = $(TARGET_DIR)/Twitterizer2.dll \
- $(TARGET_DIR)/smuxi-common.dll \
- $(TARGET_DIR)/smuxi-engine.dll
+DLL_REFERENCES = \
+ $(TARGET_DIR)/Twitterizer2.dll \
+ $(TARGET_DIR)/Twitterizer2.Streaming.dll \
+ $(TARGET_DIR)/smuxi-common.dll \
+ $(TARGET_DIR)/smuxi-engine.dll
SOURCES_BUILD = $(addprefix $(srcdir)/, $(SOURCES))
diff --git a/src/Engine-Twitter/Protocols/Twitter/TwitterProtocolManager.cs
b/src/Engine-Twitter/Protocols/Twitter/TwitterProtocolManager.cs
index f56635e..aa16c73 100644
--- a/src/Engine-Twitter/Protocols/Twitter/TwitterProtocolManager.cs
+++ b/src/Engine-Twitter/Protocols/Twitter/TwitterProtocolManager.cs
@@ -84,6 +84,7 @@ namespace Smuxi.Engine
TwitterStatus[] StatusIndex { get; set; }
int StatusIndexOffset { get; set; }
+ Dictionary<string, TwitterSearchStream> SearchStreams { get; set; }
public override string NetworkID {
get {
@@ -153,6 +154,7 @@ namespace Smuxi.Engine
f_GroupChats.Add(f_DirectMessagesChat);
StatusIndex = new TwitterStatus[99];
+ SearchStreams = new Dictionary<string, TwitterSearchStream>();
}
public override void Connect(FrontendManager fm, ServerModel server)
@@ -206,6 +208,9 @@ namespace Smuxi.Engine
if (!whitelist.Contains("api.twitter.com")) {
whitelist.Add("api.twitter.com");
}
+ if (!whitelist.Contains("stream.twitter.com")) {
+ whitelist.Add("stream.twitter.com");
+ }
}
}
@@ -605,6 +610,15 @@ namespace Smuxi.Engine
}
break;
}
+ } else {
+ // no static/singleton chat, but maybe a search?
+ TwitterSearchStream stream;
+ lock (SearchStreams) {
+ if (SearchStreams.TryGetValue(chat.ID, out stream)) {
+ SearchStreams.Remove(chat.ID);
+ stream.Dispose();
+ }
+ }
}
Session.RemoveChat(chat);
@@ -1102,6 +1116,12 @@ namespace Smuxi.Engine
}
}
Session.SyncChat(chat);
+
+ var stream = new TwitterSearchStream(this, chat, keyword,
+ f_OAuthTokens, f_WebProxy);
+ lock (SearchStreams) {
+ SearchStreams.Add(chat.ID, stream);
+ }
}
public void CommandRetweet(CommandModel cmd)
@@ -1881,7 +1901,7 @@ namespace Smuxi.Engine
return false;
}
- private PersonModel GetPerson(TwitterUser user)
+ internal PersonModel GetPerson(TwitterUser user)
{
if (user == null) {
throw new ArgumentNullException("user");
diff --git a/src/Engine-Twitter/Protocols/Twitter/TwitterSearchStream.cs
b/src/Engine-Twitter/Protocols/Twitter/TwitterSearchStream.cs
new file mode 100644
index 0000000..858ec7d
--- /dev/null
+++ b/src/Engine-Twitter/Protocols/Twitter/TwitterSearchStream.cs
@@ -0,0 +1,161 @@
+// Smuxi - Smart MUltipleXed Irc
+//
+// Copyright (c) 2013-2014 Mirco Bauer <meebey meebey net>
+//
+// Full GPL License: <http://www.gnu.org/licenses/gpl.txt>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+using System;
+using System.Net;
+using Twitterizer;
+using Twitterizer.Streaming;
+using Smuxi.Common;
+
+namespace Smuxi.Engine
+{
+ public class TwitterSearchStream : IDisposable
+ {
+#if LOG4NET
+ static readonly log4net.ILog Logger =
log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
+#endif
+ TwitterProtocolManager ProtocolManager { get; set; }
+ Session Session { get; set; }
+ TwitterStream Stream { get; set; }
+ GroupChatModel Chat { get; set; }
+ RateLimiter MessageRateLimiter { get; set; }
+
+ public TwitterSearchStream(TwitterProtocolManager protocolManager,
+ GroupChatModel chat, string keyword,
+ OAuthTokens tokens, WebProxy proxy)
+ {
+ if (protocolManager == null) {
+ throw new ArgumentNullException("protocolManager");
+ }
+ if (chat == null) {
+ throw new ArgumentNullException("chat");
+ }
+ if (keyword == null) {
+ throw new ArgumentNullException("keyword");
+ }
+ if (tokens == null) {
+ throw new ArgumentNullException("tokens");
+ }
+
+ ProtocolManager = protocolManager;
+ Session = protocolManager.Session;
+ Chat = chat;
+
+ var options = new StreamOptions();
+ options.Track.Add(keyword);
+
+ Stream = new TwitterStream(tokens, null, options);
+ Stream.Proxy = proxy;
+ Stream.StartPublicStream(OnStreamStopped, OnStatusCreated, OnStatusDeleted, OnEvent);
+
+ MessageRateLimiter = new RateLimiter(5, TimeSpan.FromSeconds(5));
+ }
+
+ ~TwitterSearchStream()
+ {
+ Dispose(false);
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ Trace.Call(disposing);
+
+ Stream.EndStream();
+ Stream.Dispose();
+ }
+
+ public void Dispose()
+ {
+ GC.SuppressFinalize(this);
+ Dispose(true);
+ }
+
+ protected TwitterMessageBuilder CreateMessageBuilder()
+ {
+ var builder = new TwitterMessageBuilder();
+ builder.ApplyConfig(Session.UserConfig);
+ return builder;
+ }
+
+ void OnStreamStopped(StopReasons reason)
+ {
+ Trace.Call(reason);
+
+ try {
+ Session.DisableChat(Chat);
+ } catch (Exception ex) {
+#if LOG4NET
+ Logger.Error("OnStreamStopped()", ex);
+#endif
+ }
+ }
+
+ void OnStatusCreated(TwitterStatus status)
+ {
+ Trace.Call(status);
+
+ try {
+ if (MessageRateLimiter.IsRateLimited) {
+ return;
+ }
+ MessageRateLimiter++;
+
+ var sender = ProtocolManager.GetPerson(status.User);
+ var userId = status.User.Id.ToString();
+ lock (Chat.UnsafePersons) {
+ if (!Chat.UnsafePersons.ContainsKey(userId)) {
+ Session.AddPersonToGroupChat(Chat, sender);
+ }
+ }
+ var msg = CreateMessageBuilder().
+ Append(status, sender).
+ ToMessage();
+ Session.AddMessageToChat(Chat, msg);
+ } catch (Exception ex) {
+#if LOG4NET
+ Logger.Error("OnStatusCreated()", ex);
+#endif
+ }
+ }
+
+ void OnStatusDeleted(TwitterStreamDeletedEvent status)
+ {
+ Trace.Call(status);
+
+ try {
+ } catch (Exception ex) {
+#if LOG4NET
+ Logger.Error("OnStatusDeleted()", ex);
+#endif
+ }
+ }
+
+ void OnEvent(TwitterStreamEvent @event)
+ {
+ Trace.Call(@event);
+
+ try {
+ } catch (Exception ex) {
+#if LOG4NET
+ Logger.Error("OnEvent()", ex);
+#endif
+ }
+ }
+ }
+}
diff --git a/src/smuxi.sln b/src/smuxi.sln
index f2a5b29..d8f6fc9 100644
--- a/src/smuxi.sln
+++ b/src/smuxi.sln
@@ -69,6 +69,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Frontend-GNOME-Twitter", "F
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Engine-MessageBuffer",
"Engine-MessageBuffer\Engine-MessageBuffer.csproj", "{7964E3E4-1E98-4AE0-AF1B-1B940CDF0A99}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Twitterizer2.Streaming",
"..\lib\Twitterizer\Twitterizer2.Streaming\Twitterizer2.Streaming.csproj",
"{AFDC57ED-C013-4581-9D06-54D8A42D696D}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Release|Any CPU = Release|Any CPU
@@ -151,6 +153,8 @@ Global
{3F8CF2C1-EA37-444F-8693-A3A00B1131D2}.Release-Win32|x86.Build.0 = Release|Any CPU
{405874F0-A58A-4E79-8766-2150D069F691}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{405874F0-A58A-4E79-8766-2150D069F691}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {405874F0-A58A-4E79-8766-2150D069F691}.Debug-Win32|Any CPU.ActiveCfg = Release|Any CPU
+ {405874F0-A58A-4E79-8766-2150D069F691}.Debug-Win32|Any CPU.Build.0 = Release|Any CPU
{405874F0-A58A-4E79-8766-2150D069F691}.Debug-Win32|x86.ActiveCfg = Debug-Win32|x86
{405874F0-A58A-4E79-8766-2150D069F691}.Debug-Win32|x86.Build.0 = Debug-Win32|x86
{405874F0-A58A-4E79-8766-2150D069F691}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -281,6 +285,16 @@ Global
{AB347741-B8CC-4B6B-BD39-826C77BE0694}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AB347741-B8CC-4B6B-BD39-826C77BE0694}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AB347741-B8CC-4B6B-BD39-826C77BE0694}.Release|Any CPU.Build.0 = Release|Any CPU
+ {AFDC57ED-C013-4581-9D06-54D8A42D696D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {AFDC57ED-C013-4581-9D06-54D8A42D696D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {AFDC57ED-C013-4581-9D06-54D8A42D696D}.Debug-Win32|Any CPU.ActiveCfg = Release|Any CPU
+ {AFDC57ED-C013-4581-9D06-54D8A42D696D}.Debug-Win32|Any CPU.Build.0 = Release|Any CPU
+ {AFDC57ED-C013-4581-9D06-54D8A42D696D}.Debug-Win32|x86.ActiveCfg = Debug|Any CPU
+ {AFDC57ED-C013-4581-9D06-54D8A42D696D}.Debug-Win32|x86.Build.0 = Debug|Any CPU
+ {AFDC57ED-C013-4581-9D06-54D8A42D696D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {AFDC57ED-C013-4581-9D06-54D8A42D696D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {AFDC57ED-C013-4581-9D06-54D8A42D696D}.Release-Win32|x86.ActiveCfg = Release|Any CPU
+ {AFDC57ED-C013-4581-9D06-54D8A42D696D}.Release-Win32|x86.Build.0 = Release|Any CPU
{B68687B3-E45A-410E-BAE6-A7B2590E17B1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B68687B3-E45A-410E-BAE6-A7B2590E17B1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B68687B3-E45A-410E-BAE6-A7B2590E17B1}.Debug-Win32|x86.ActiveCfg = Debug-Win32|x86
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]