<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
  <channel>
    <title>技术尝鲜 - 老赵点滴 - 追求编程之美</title>
    <link>http://blog.zhaojie.me/cutting-edge/</link>
    <description>先做人，再做技术人员，最后做程序员。打造国内最好的.NET技术博客。</description>
    <language>zh-cn</language>
    <managingEditor>jeffz@live.com (老赵)</managingEditor>
    <webMaster>jeffz@live.com (老赵)</webMaster>
    <pubDate>Wed, 31 Aug 2011 16:25:50 GMT</pubDate>
    <lastBuildDate>Wed, 24 Feb 2010 15:45:00 GMT</lastBuildDate>
    <ttl>60</ttl>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/cutting-edge/">技术尝鲜</category>
      <title>HTML Metro开发里的数据绑定（1）：WinJS.Binding.List</title>
      <link>http://blog.zhaojie.me/2012/05/metro-html-binding-1-winjs-binding-list.html</link>
      <guid>http://blog.zhaojie.me/2012/05/metro-html-binding-1-winjs-binding-list.html</guid>
      <description>&lt;p&gt;前段时间接触了一些WPF开发方面内容，了解如何使用MVVM模式将界面与模型几乎彻底分离开来，只通过其强大的绑定功能连接两者，让人叹为观止。Win8的Metro开发支持使用XAML（配合C#，C++等语言）或是HTML（配合JavaScript），前者的控件和数据的绑定已经相当完备，而后者一直没有一个标准的模型。之前我也简单了解过如&lt;a href="http://knockoutjs.com/"&gt;Knockout&lt;/a&gt;这样的绑定支持与MVVM模式实现，理论上说也完全可以在Metro开发里使用，但其实Metro开发本身也已经提供了一些内置的绑定支持，基本对应于XAML/C#开发里涉及到的ObservableCollection与INotifyPropertyChanged。&lt;/p&gt;

&lt;p&gt;ObservableCollection的功能是作为元素的集合，绑定到一个控件上去，当集合发生改变时，将会触发一个CollectionChanged事件，通知控件（或其他监听者）发生了什么样的变化：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;ObservableCollection&lt;/span&gt;&amp;lt;T&amp;gt;
{
    &lt;span style="color: blue"&gt;public event &lt;/span&gt;&lt;span style="color: #2b91af"&gt;NotifyCollectionChangedEventHandler &lt;/span&gt;CollectionChanged;
}

&lt;span style="color: blue"&gt;public delegate void &lt;/span&gt;&lt;span style="color: #2b91af"&gt;NotifyCollectionChangedEventHandler&lt;/span&gt;(&lt;span style="color: blue"&gt;object &lt;/span&gt;sender, &lt;span style="color: #2b91af"&gt;NotifyCollectionChangedEventArgs &lt;/span&gt;e);

&lt;span style="color: blue"&gt;public class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;NotifyCollectionChangedEventArgs &lt;/span&gt;: &lt;span style="color: #2b91af"&gt;EventArgs
&lt;/span&gt;{
    &lt;span style="color: blue"&gt;public &lt;/span&gt;&lt;span style="color: #2b91af"&gt;NotifyCollectionChangedAction &lt;/span&gt;Action { &lt;span style="color: blue"&gt;get&lt;/span&gt;; }
    &lt;span style="color: blue"&gt;public &lt;/span&gt;&lt;span style="color: #2b91af"&gt;IList &lt;/span&gt;NewItems { &lt;span style="color: blue"&gt;get&lt;/span&gt;; }
    &lt;span style="color: blue"&gt;public int &lt;/span&gt;NewStartingIndex { &lt;span style="color: blue"&gt;get&lt;/span&gt;; }
    &lt;span style="color: blue"&gt;public &lt;/span&gt;&lt;span style="color: #2b91af"&gt;IList &lt;/span&gt;OldItems { &lt;span style="color: blue"&gt;get&lt;/span&gt;; }
    &lt;span style="color: blue"&gt;public int &lt;/span&gt;OldStartingIndex { &lt;span style="color: blue"&gt;get&lt;/span&gt;; }
}

&lt;span style="color: blue"&gt;public enum &lt;/span&gt;&lt;span style="color: #2b91af"&gt;NotifyCollectionChangedAction
&lt;/span&gt;{
    Add = 0,
    Remove = 1,
    Replace = 2,
    Move = 3,
    Reset = 4,
}&lt;/pre&gt;

&lt;p&gt;ObservableCollection在Metro开发中的JavaScript对应物为&lt;a href="http://msdn.microsoft.com/en-us/library/windows/apps/hh700774.aspx"&gt;WinJS.Binding.List&lt;/a&gt;类型，它包含许多成员，可惜目前文档奇缺，多亏Visual Studio 2011对JavaScript的强大提示功能，可以让我们了解到该类型有哪些成员，例如：&lt;/p&gt;
&lt;img alt="WinJS.Binding.List事件" src="http://img.zhaojie.me/blog/metro-html-binding/01.png" /&gt; 

&lt;p&gt;这样我们便能知道如何实现一些常见的场景：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;var &lt;/span&gt;list = &lt;span style="color: blue"&gt;new &lt;/span&gt;WinJS.Binding.List();
list.push(&lt;span style="color: maroon"&gt;&amp;quot;Hello&amp;quot;&lt;/span&gt;); &lt;span style="color: green"&gt;// iteminserted
&lt;/span&gt;list.push(&lt;span style="color: maroon"&gt;&amp;quot;World&amp;quot;&lt;/span&gt;); &lt;span style="color: green"&gt;// iteminserted
&lt;/span&gt;list.push(&lt;span style="color: maroon"&gt;&amp;quot;How are you?&amp;quot;&lt;/span&gt;); &lt;span style="color: green"&gt;// iteminserted
&lt;/span&gt;list.setAt(0, &lt;span style="color: maroon"&gt;&amp;quot;Hello World&amp;quot;&lt;/span&gt;); &lt;span style="color: green"&gt;// itemchanged
&lt;/span&gt;list.move(0, 2); &lt;span style="color: green"&gt;// itemmoved
&lt;/span&gt;list.slice(1, 2); &lt;span style="color: green"&gt;// itemremoved
&lt;/span&gt;list.notifyMutated(0); &lt;span style="color: green"&gt;// itemmutated
&lt;/span&gt;list.notifyReload(); &lt;span style="color: green"&gt;// reload&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;与ObservableCollection的集中式CollectionChanged事件相比，WinJS.Binding.List的事件更为分散。此外，还有两个事件是需要外部方法notifyMutated和notifyReload来触发的。其中itemsMutated事件比较特殊，它似乎是在通知集合中某个元素自身状态产生了变化，在XAML开发中这事儿完全不关ObservableCollection管，而是后面要说的，由元素自己实现INotifyPropertyChanged接口来负责。&lt;/p&gt;

&lt;p&gt;WinJS.Binding.List的各种接口和JavaScript数组基本一致，此外它还包括一些有趣的功能，例如它的&lt;a href="http://msdn.microsoft.com/en-us/library/windows/apps/hh700764.aspx"&gt;构造函数&lt;/a&gt;可以传递一个数组以及一个options参数，如果options.proxy为true，则直接将该数组作为内部的存储结构。另外，其实这个集合会为其中每个元素分配一个key，通过&lt;a href="http://msdn.microsoft.com/en-us/library/windows/apps/hh700753.aspx"&gt;getItem(index)&lt;/a&gt;可以得到一个key/value对，通过&lt;a href="http://msdn.microsoft.com/en-us/library/windows/apps/hh700750.aspx"&gt;getItemFromKey&lt;/a&gt;可以通过key得到元素。交换数组中元素的顺序并不会改变key对应的元素，因此这个功能在某些情况下会很有帮助。&lt;/p&gt;

&lt;p&gt;更有特色的可能是&lt;a href="http://msdn.microsoft.com/en-us/library/windows/apps/hh700741.aspx"&gt;createFiltered&lt;/a&gt;，&lt;a href="http://msdn.microsoft.com/en-us/library/windows/apps/hh700742.aspx"&gt;createGrouped&lt;/a&gt;和&lt;a href="http://msdn.microsoft.com/en-us/library/windows/apps/hh700743.aspx"&gt;createSorted&lt;/a&gt;方法，他们都是在原有集合的基础上，返回一个（或一组）新的WinJS.Binding.List对象，每个新集合都和原有集合的内容保持“一致”。例如，基于一个过滤条件由createFiltered方法创建出来的新集合，假如向原集合添加一个满足该过滤条件的元素，则这个元素也会添加到新的容器里，同时触发新容器的iteminserted事件。同样，其他对原集合的修改也会影响新的集合。要实现类似的功能并不困难，只不过比较麻烦，如果您有兴趣，也不妨实验下。&lt;/p&gt;

&lt;h1&gt;相关文章&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;HTML Metro开发里的数据绑定（1）：WinJS.Binding.List &lt;/li&gt;
&lt;/ul&gt;</description>
      <comments>http://blog.zhaojie.me/2012/05/metro-html-binding-1-winjs-binding-list.html#comments</comments>
      <pubDate>Tue, 01 May 2012 14:53:21 GMT</pubDate>
      <lastBuildDate>Tue, 01 May 2012 14:53:21 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/dotnet/">.Net框架</category>
      <category domain="http://blog.zhaojie.me/practice/">实践优化</category>
      <category domain="http://blog.zhaojie.me/cutting-edge/">技术尝鲜</category>
      <title>在.NET平台下使用C#交互式控制台（上）：简介</title>
      <link>http://blog.zhaojie.me/2011/08/port-csharp-repl-from-mono-1-introduction.html</link>
      <guid>http://blog.zhaojie.me/2011/08/port-csharp-repl-from-mono-1-introduction.html</guid>
      <description>&lt;p&gt;上周日在广州的珠三角技术沙龙上，我的演讲题目是“Mono之于.NET程序员”。Mono一直是我十分喜爱的产品，我也一直关注它的发展，总有很多人用各种方式对它进行FUD，甚至是.NET程序员自己。这其实跟程序员使用盗版一样，自掘坟墓，是种无比愚蠢的行为。在演讲中，我提到.NET程序员可以如何从Mono项目中得到帮助，现在便以C#交互式控制台为例，演示下在.NET平台下使用Mono项目的常见方式。&lt;/p&gt;

&lt;p&gt;Mono和.NET都是&lt;a href="http://www.ecma-international.org/publications/standards/Ecma-335.htm"&gt;CLI（ECMA 335）&lt;/a&gt;的实现，包括C#语言编译器，运行时和类库等等。与微软实现的.NET不同，Mono是个开源项目，我们可以在授权允许的范围内任意折腾。例如，微软在Silverlight里提供了一个JSON类库，但我们无法将其用于普通的.NET项目，于是我们就可以&lt;a href="http://blog.zhaojie.me/2010/10/use-silverlight-system-json-in-normal-application.html"&gt;从Mono里剥离相关代码出来&lt;/a&gt;。再比如，Windows Phone的SDK中没有提供像.NET 4.0里面一样的任务并行库，于是也有开发人员&lt;a href="http://www.infoq.com/cn/news/2011/08/Silverlight-TPL"&gt;将Mono里面的实现移植了过来&lt;/a&gt;。社区成员也十分喜欢开源，因此无论是Mono团队还是其他开发人员都会很乐意捣鼓各种东西，并且也搞出许多有意思的东西来。&lt;a href="http://www.mono-project.com/CsharpRepl"&gt;C#交互式控制台&lt;/a&gt;（有时也将其称为&lt;a href="http://en.wikipedia.org/wiki/Read-eval-print_loop"&gt;REPL&lt;/a&gt;，即Read-Eval-Print-Loop）就是其中一个。&lt;/p&gt;

&lt;p&gt;之前Anders Hejlsberg在PDC 2010中提到“C#与Visual Basic的未来”，其中一项功能就是“&lt;a href="http://blog.zhaojie.me/2010/11/pdc2010-the-future-of-csharp-and-vb-by-anders-hejlsberg-3.html"&gt;编译器即服务（Compiler as a Service）&lt;/a&gt;”。这个功能是指，把编译器的功能向普通用户开放出来，这样便可以实现更多的东西，例如代码解释执行，或是把代码变成语法树，让程序理解其语义等等（这便是&lt;a href="http://www.infoq.com/cn/articles/jscex-javascript-asynchronous-programming"&gt;Jscex的根本所在&lt;/a&gt;）。其实几年前就已经在Mono有类似的实现了。Mono的C#编译器mcs本身是由C#实现的，因此它直接就包含了编译器的完整功能，API好用与否暂且不论，但的确提供了这方面的能力，需要的同学完全可以自行获取。&lt;/p&gt;

&lt;p&gt;Mono编译器功能暴露在Mono.CSharp类库中，而C#的交互式控制台便是“编译器即服务”顺理成章的衍生品。我想你一定遇到过这样的情况，例如，知道DateTime类型的ToString在接受某些参数会输出什么样的效果，却有些记不清，查文档自然会有答案但是太麻烦，其实一试便知。还有比如字符串解析，正则表达式匹配，临时计算等等。我见过很多同学在遇到这种情况的时候，都会直接把代码写在程序里，然后设置断点，然后运行程序观察执行效果。经验丰富一点的朋友则会时刻准备着一个控制台项目或是用&lt;a href="http://www.sliver.com/dotnet/SnippetCompiler/"&gt;Snippit Compiler&lt;/a&gt;，写点试验代码运行一下。不过，最理想的方式其实是使用F#，Scala，Ruby，Python等语言中都有的交互式控制台。例如以下便是在VS 2010中自带的F#交互式控制台：&lt;/p&gt;
&lt;img alt="F# REPL" src="http://img.zhaojie.me/blog/csharp-repl/fsharp-repl.png" /&gt; 

&lt;p&gt;我几乎天天都会用到F#交互式控制台，用来验证一些做法和猜想是否正确，确定之后再写成C#代码。我会F#，使用F#交互控制台自然不在话下。如果您懂得Python或Ruby，则使用IronPython或IronRuby的交互式控制台也是个不错的办法。但如果您只会用C#，那似乎就没辙了。幸运的是，Mono为C#程序员打开了这扇窗，我们也完全可以使用C#的交互式控制台来辅助工作，如下图：&lt;/p&gt;
&lt;img alt="C# REPL" src="http://img.zhaojie.me/blog/csharp-repl/csharp-repl-0.png" /&gt; 

&lt;p&gt;在下一篇文章里，我们便来一起看一下，如何让Mono提供的C#交互式控制台运行在Windows和.NET下。这是个不错的例子，略有障碍，也没有过于复杂或取巧的地方，可以作为.NET程序员利用Mono组件的一个典型示例。&lt;/p&gt;

&lt;p&gt;最后再附上上周日的演讲幻灯片，大伙后睹为快：&lt;/p&gt;

&lt;div style="width: 425px" id="__ss_9054321"&gt;&lt;strong style="margin: 12px 0px 4px; display: block"&gt;&lt;a title="Mono for .NET Developers" href="http://www.slideshare.net/jeffz/mono-for-dotnet-developers" target="_blank"&gt;Mono for .NET Developers&lt;/a&gt;&lt;/strong&gt; &lt;iframe height="355" marginheight="0" src="http://www.slideshare.net/slideshow/embed_code/9054321" frameborder="0" width="425" marginwidth="0" scrolling="no"&gt;&lt;/iframe&gt;

  &lt;div style="padding-bottom: 12px; padding-left: 0px; padding-right: 0px; padding-top: 5px"&gt;View more &lt;a href="http://www.slideshare.net/" target="_blank"&gt;presentations&lt;/a&gt; from &lt;a href="http://www.slideshare.net/jeffz" target="_blank"&gt;jeffz&lt;/a&gt; &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;总之一句话：作为.NET程序员，如果您忽视或排斥Mono的话，损失的将会是你自己。&lt;/p&gt;</description>
      <comments>http://blog.zhaojie.me/2011/08/port-csharp-repl-from-mono-1-introduction.html#comments</comments>
      <pubDate>Wed, 31 Aug 2011 16:25:50 GMT</pubDate>
      <lastBuildDate>Thu, 01 Sep 2011 01:25:29 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/discussion/">思考讨论</category>
      <category domain="http://blog.zhaojie.me/cutting-edge/">技术尝鲜</category>
      <title>“花钱”购买App Hub Membership终于成功了</title>
      <link>http://blog.zhaojie.me/2011/01/paid-for-app-hub-membership.html</link>
      <guid>http://blog.zhaojie.me/2011/01/paid-for-app-hub-membership.html</guid>
      <description>&lt;p&gt;作为一个身在天朝的开发人员，要及早使用国外的服务总是一件杯具的事情，注册Windows Phone 7的App Hub Membership也不例外。不幸中的万幸，我工作于&lt;a href="http://blog.zhaojie.me/2010/01/1651772.html"&gt;盛大创新院&lt;/a&gt;，这也是个奇妙的地方，身边的同事就有美国人，在他的帮助下，从提及注册信息到审核成功也只用了6、7个小时。说起来美国人在这方面的确占有十分重大的优势，不光是审核速度快（其他国家用户还需要等待GeoTrust主动联系，并提交更多信息，多花上2、3个工作日十分正常），连价格也便宜（年费只需99美金，前两天让荷兰的朋友帮忙注册需要99欧元），不得不长叹一声。&lt;/p&gt;

&lt;p&gt;由于注册无法重现，我在这里只能简单描述一番。第一个环节是选择国家/地区，以及帐号类型等等，这与接下来的信用卡以及费用有关。接着则是各种信息，姓名电话地址邮编等等，也要和最后那张信用卡相符。之后则是提交信用卡的信息了，自不必说。值得一提的是，在提交信用卡的时候，网站总是说我的信息无法通过认证，几经尝试，最后使用我的美国VPS作代理才注册通过，看来是IP问题。通过之后，邮箱里会收到微软和GeoTrust发来的确认邮件，其中包含一个用于身份认证的链接，点开后则要求输入美国公民的各种信息，例如社会保障号等等。填写必需的字段，提交后便说“请等待处理”了。下午注册，晚上8点就收到邮件说成功了。总体而言，对于国内用户来说，App Hub Membership的“注册代理”比Android Market要宽松一些，后者似乎还要验证邮箱等等。&lt;/p&gt;

&lt;p&gt;App Hub包含了Windows Phone和XBox的开发和发布权限，我虽然也&lt;a href="http://blog.zhaojie.me/2011/01/htc-7-mozart-t8698-windows-phone-7-review-and-xbox-kinect.html"&gt;刚入手了XBox和Kinect&lt;/a&gt;，但我注册个App Hub完全就是为了Windows Phone上面的开发。诚然，如果不需要发布到Marketplace，使用微软提供的免费工具，&lt;a href="http://blog.zhaojie.me/2011/01/htc-7-mozart-t8698-windows-phone-7-review-and-xbox-kinect.html"&gt;再加上ChevronWP7的破解&lt;/a&gt;早已足够了，但我还是选择了购买App Hub。这不到700块钱用于体验时代潮流，仔细想来也并不太多——当然这也涉及到个人的价值观。有些人认为4、500块钱的手机用来打电话发短信也已够用，而另一部分人（包括我）的看法是，几千块钱本身说起来也不能做太多事情，不如用于体会互联网时代的价值，这也是一种进修。所以我会较快购进Windows Phone、Kinect以及MonoTouch等等，即使从某些角度来看Windows Phone并非是一个适合国内用户的产品。&lt;/p&gt;

&lt;p&gt;以前我总是舍不得花钱，和许多朋友一样觉得这也很贵，那也很贵，于是也会用盗版等等。后来我和别人一起创业，虽然并非直接掌管资金，但也对于各种花销建立了一些概念。例如我知道了开一天公司需要多少钱，给员工交工资和福利、网站托管、流量购买需要多少钱，于是我就不会认为一套不到3000的MonoTouch，或是其他某个组件的商业授权有多么昂贵，因为它们的确可以为我省下更多的钱。从那时起，我会适当地选择开发效率更高的.NET平台加上价格便宜（3000左右）工作足够对硬件也十分宽松的Windows Web Server 2008，配合价格便宜选择丰富的*nix作后端存储。&lt;/p&gt;

&lt;p&gt;学会合理花钱的好处其实很多，首先我可以自豪地宣布，我已经不用盗版软件许多年，其次我学会通过花费现在的钱来提高自己或是节省精力，以便赚到更多的钱。我现在越来越喜欢适当使用一些收费的组件，因为我相信他们为了卖更多的授权，会不断提高自己的产品以及服务质量，这让我可以轻松不少。反之如果一切都由自己从头做起，可能大量的时间都耗费在一些无谓的细节上面才能得到与商业产品差不多的质量。时间往往比金钱更有价值。如果纠缠于那些细节无法让人提高，我情愿将时间用在自我学习、娱乐甚至是简单的休息上面。&lt;/p&gt;

&lt;p&gt;说起来购买App Hub Membership也是类似的道理，我不想把大量精力耗费在刷机、破解等方面（虽然我知道许多朋友乐在其中）。非官方的解锁方式总是无法让人安心，可能一次系统升级就让手机重新锁定了，于是又要折腾半天。现在则不然，即便微软接下来会升级Windows Phone，我也可以放心继续使用。因为我已经成为了正式的开发人员，XBox Live的Avatar都可以使用新装备了，哈哈。&lt;/p&gt;

&lt;p&gt;如今是程序员的黄金年代，移动平台和应用市场的兴起让我们可以比以往任何时候都轻松地赚取零花钱，甚至开创一番事业——当然前提是要有创意，这也是我最缺乏的。因此，如果您有什么需求或是点子，也不妨给我一些指点，我也有点实际内容可做。&lt;/p&gt;

&lt;p&gt;最后，依然来推广一下本周六即将举办的“&lt;a href="http://nbazaar.org/"&gt;第三届nBazaar技术交流会&lt;/a&gt;”，欢迎继续报名（近日将发出邀请函）。在今后的交流会上，我也会引入更多有趣的话题，例如移动平台的开发，甚至是与Kinect相关的话题。Kinect的确是神器，在我家已经成为父母每天必修的娱乐活动，可能我还会再买一套送给他们。&lt;/p&gt;</description>
      <comments>http://blog.zhaojie.me/2011/01/paid-for-app-hub-membership.html#comments</comments>
      <pubDate>Mon, 10 Jan 2011 17:45:57 GMT</pubDate>
      <lastBuildDate>Tue, 11 Jan 2011 05:25:36 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/cutting-edge/">技术尝鲜</category>
      <title>HTC 7 Mozart T8698（Windows Phone 7）初体验</title>
      <link>http://blog.zhaojie.me/2011/01/htc-7-mozart-t8698-windows-phone-7-review-and-xbox-kinect.html</link>
      <guid>http://blog.zhaojie.me/2011/01/htc-7-mozart-t8698-windows-phone-7-review-and-xbox-kinect.html</guid>
      <description>&lt;p&gt;上个星期去香港旅游，对于我等IT从业人员来说，数码产品卖场自然是必逛的地方之一。香港的衣食住行都很贵，但是数码产品却十分便宜。看着手中使用了3个月滚珠就已失灵的奥巴马御用机型，决定就在香港采购一台吧。鉴于Android和iPhone 4都已经是烂大街的机器，我打算着重关注一下Windows Phone 7的机器。当时在香港到处可以看到HTC HD 7以及LG Optimus 7 E900，不过都是接近5000港币的价格，再加上实在不是很喜欢它们的外观，于是迟迟不愿下手。后来在百老汇发现新上市的HTC 7 Mozart T8698，据说是加强了多媒体能力的机型，外形和手感都不错，价格也相对较低（4200元港币，约合人民币约3600元），于是遍选中了这台。把玩了几天，记录一下感受。&lt;/p&gt;

&lt;p&gt;对于手机来说，iPhone 4就是iPhone 4，但是说到Android和Windows Phone，不同机器之间的感受还是有很大区别的（尤其是前者）。就拿屏幕来说，Windows Phone的固定配置是480*800的分辨率，于是屏幕越小，画面就显得越精致。例如Mozart是3.7寸屏幕，就比HD 7的4.3寸屏细腻许多。从显示效果上看，Mozart的画面质量远胜iPhone 3GS，从数据上看不如iPhone 4的Retina屏幕（每英寸326像素，Mozart是252像素），不过效果可以说是一个等级的。&lt;/p&gt;

&lt;p&gt;从操作上看，Windows Phone不同于iPhone和Android的图标式布局让人耳目一新，选中某项和程序界面的切换效果也很酷。系统和自带的应用程序使用起来都很流畅，毫无卡顿。系统内置的功能都不错，界面也都很酷。邮箱功能十分令人满意，尤其是对Hotmail和Gmail的支持。令人有些奇怪的是，WP7居然没有自带Live Messenger，不过可以从Marketplace里下载到第三方编写的免费Messenger程序，功能中规中矩。值得一提的是，这个Messenger可以在“退出”之后得到消息推送，让我对系统的“多任务”能力感到很好奇。之前有很多说法认为Windows Phone没有多任务功能，按理来说是无法实现此类功能的。&lt;/p&gt;

&lt;p&gt;其他的例如浏览器，搜索，地图之类的功能就不多说了。游戏方面，Xbox LIVE应该是Windows Phone的特色。Windows Phone的3D功能很强，XNA框架和XBOX游戏开发一脉相承，而且都是使用.NET托管代码（C#）编写，就从极品飞车的效果来看，相信可以让某些认为“托管代码”或是“自动GC”等等“不堪大用”的人更新自己的观念。总体来说，这台HTC 7 Mozart T8698还是让我比较满意的。&lt;/p&gt;

&lt;p&gt;接下来说说它的缺点，当然，这些估计也已经有很多人谈过了，例如暂时还没有复制粘贴等等。对于国内用户来说，最大的缺点莫过于缺少中文输入法的支持。由于微软没有提供相应的API，因此我们无法替换掉系统的输入法，于是如今所有的中文输入功能都是在某个特定程序中实现的，然后“发送”至短信、浏览器地址栏或是邮箱中。这对于一些基础功能来说还算够用，但是限制也很大。例如在联系人列表里（Windows Phone称之为People Hub），我们无法使用中文或是拼音来快速搜索某个联系人，十分不便，这迫使我不得不把联系人的姓名写成英文。现在我都打算开发一个支持中文输入的联系人管理工具了，顺便研究一下怎么开发一个简单的输入法。已有的中文输入法软件，功能可能还不错（如&lt;a href="http://www.cnblogs.com/crazylights"&gt;疯光输入法&lt;/a&gt;），但都很丑，使用也不太方便，我不很喜欢。&lt;/p&gt;

&lt;p&gt;说到软件市场，可以说是Windows Phone软肋了，数量实在太少，更别说面向国内用户的应用程序了。即使是如T-Sina这样的新浪微博客户端，界面也很难看，很没有Windows Phone的样子，这可能也是我打算抽空做的一个功能。考虑到这些，如果您不是手机“玩家”而是普通用户的话，那么Windows Phone的确不太适合您，至少等到今年下半年Windows Phone进入中国市场以后再考虑吧。&lt;/p&gt;

&lt;p&gt;如果您要开发Windows Phone应用程序，可以下载免费的&lt;a href="http://create.msdn.com/en-us/home/getting_started"&gt;Windows Phone Develop Tools&lt;/a&gt;，其中包含Visual Studio 2010 Express Edition和Expression Blend for Windows Phone等工具，应该够用。只可惜这也只能让您在Windows Phone模拟器上运行程序，如果要在真机上调试，还需要购买App Hub会员，这可以让您解锁一定数量的机器，于是可以直接将xap包安装进去。App Hub会员的年费是99美金，但最大的问题其实是无法使用国内的信用卡购买，您可以选择一些代理服务或是请朋友帮忙（希望有条件的朋友也可以来帮我一下，提供一些经验也行）——或者像我一样选择“破解”，俗称“越狱”。&lt;/p&gt;

&lt;p&gt;Windows Phone的破解很容易，应该也是不同机型通用的方式，因为我也是根据HD 7的破解方法来解锁Mozart的：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;准备一台PC，装好Windows Phone Develop Tools和Zune，用数据线将手机和PC连接起来，让Zune和手机处于完全同步的状态（即Sync Relationship不能是Guest）。 &lt;/li&gt;

  &lt;li&gt;下载&lt;a href="http://files.zhaojie.me/ChevronWP7.zip"&gt;ChevronWP7&lt;/a&gt;，将其中的ChevronWP7.cer证书文件传输至手机（可以放在某个站点上用Windows Phone的浏览器下载，或用Email做个中转）并安装。 &lt;/li&gt;

  &lt;li&gt;确保开着Zune，且机器并没有PIN-Locked（即不是黑屏待机或是主画面锁定状态），打开ChevronWP7.exe，选中两个checkbox，再点击Unlock即解锁成功。Unlock之后可以Relock。 &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;经多次试验，发现每次将手机连上机器后（并启动Zune），则会重新变成锁定状态，这时则需要使用ChevronWP7.exe重新解锁。为了避免被重新锁定，您可以在连接之前把手机的飞行模式（airplane mode）打开，连上以后再关闭。解锁后的机器，可以直接使用Application Deployment工具安装xap文件，也可以在VS里选择在Windows Phone 7 Device里调试。在真机上部署和调试都很快，很流畅，让人完全不想用模拟器。我写了点简单的程序（一个&lt;a href="http://instagr.am/"&gt;Instagram&lt;/a&gt;客户端雏形），不得不再次感叹F#写异步程序真的很爽。&lt;/p&gt;

&lt;p&gt;香港之行除了Windows Phone以外，我还带回了一台Xbox 360及Kinect（加起来大约3200人民币）。&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/xbox-kinect.jpg" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/xbox-kinect.jpg" width="450" /&gt;&lt;/a&gt; 

&lt;p&gt;如果您还不知道这是什么的话，那么实在是落伍了。与Wii或PS3的控制杆不同，Kinect识别的是整个人体。因此，以后（其实应该说已经是“现在”了）人们完全是这样玩游戏的：&lt;/p&gt;
&lt;embed src="http://player.youku.com/player.php/sid/XMTgzMzE3MTE2/v.swf" quality="high" width="480" height="400" align="middle" allowScriptAccess="sameDomain" type="application/x-shockwave-flash"&gt;&lt;/embed&gt; 

&lt;p&gt;程序是这样操作的：&lt;/p&gt;
&lt;embed src="http://player.youku.com/player.php/sid/XMjIwMTUxOTMy/v.swf" quality="high" width="480" height="400" align="middle" allowScriptAccess="sameDomain" type="application/x-shockwave-flash"&gt;&lt;/embed&gt; 

&lt;p&gt;而我们也可以写这样的程序：&lt;/p&gt;
&lt;embed src="http://player.youku.com/player.php/sid/XMjMxMjM3NzE2/v.swf" quality="high" width="480" height="400" align="middle" allowScriptAccess="sameDomain" type="application/x-shockwave-flash"&gt;&lt;/embed&gt; 

&lt;p&gt;什么叫革命？什么叫突破？这就叫革命，这就叫突破。&lt;/p&gt;

&lt;p&gt;最后再补充个好消息：&lt;a href="http://monodroid.net/"&gt;MonoDroid&lt;/a&gt;的预览版已经对外公开了，可以自由安装。至此，.NET的“跨平台移动开发”战略又踏出了坚实的一步。此外据Mono老大之前的说法，接下来还会有Nokia……&lt;/p&gt;</description>
      <comments>http://blog.zhaojie.me/2011/01/htc-7-mozart-t8698-windows-phone-7-review-and-xbox-kinect.html#comments</comments>
      <pubDate>Wed, 05 Jan 2011 15:43:33 GMT</pubDate>
      <lastBuildDate>Wed, 05 Jan 2011 17:11:04 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/news/">新闻信息</category>
      <category domain="http://blog.zhaojie.me/dotnet/">.Net框架</category>
      <category domain="http://blog.zhaojie.me/speech/">培训演讲</category>
      <category domain="http://blog.zhaojie.me/practice/">实践优化</category>
      <category domain="http://blog.zhaojie.me/cutting-edge/">技术尝鲜</category>
      <title>第三届nBazaar技术交流会开始报名</title>
      <link>http://blog.zhaojie.me/2010/12/3rd-nbazaar-meeting-sign-up.html</link>
      <guid>http://blog.zhaojie.me/2010/12/3rd-nbazaar-meeting-sign-up.html</guid>
      <description>&lt;p&gt;为了错开年底密集的技术会议，第三届&lt;a href="http://nbazaar.org/"&gt;nBazaar技术交流会&lt;/a&gt;（即前“盛大创新院赞助的.NET技术交流会”）将于2011年1月15日举行。第三届的交流会将继续以往四场高质量的演讲，这也是确定nBazaar名称之后的第一次活动，希望nBazaar能够真正&lt;a href="http://blog.zhaojie.me/2010/10/status-of-iron-languages-and-nbazaar.html"&gt;成为“集市”般热闹的社区活动&lt;/a&gt;。从现在开始，nBazaar技术沙龙的相关信息将逐渐集中至独立域名中，欢迎关注。&lt;/p&gt;

&lt;h1&gt;志愿者招募&lt;/h1&gt;

&lt;p&gt;为了留下每次的活动资料，我们希望为每场演讲进行拍摄。如果您有这方面的志愿请发邮件至&lt;a href="mailto:jeffz@nbazaar.org"&gt;jeffz@nbazaar.org&lt;/a&gt;与我联系。&lt;/p&gt;

&lt;h1&gt;时间及议程安排&lt;/h1&gt;

&lt;p&gt;本次交流会首次向社区征集议题，我们在回复中挑选了三场：面向iPad平台的网站架构、面向企业应用语言ABAP、基于.NET的轻量级分布式框架，以及在创新院内部分享会上倍受好评的“分布式版本管理”话题。四位演讲者都是业界一线技术高手，四场话题都是他们的实战心得，希望能够让您满意。&lt;/p&gt;

&lt;table style="text-align: center" border="1" cellspacing="0" cellpadding="5"&gt;&lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;时间&lt;/th&gt;

      &lt;th&gt;议程&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;&lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;12:30 ~ 13:00&lt;/td&gt;

      &lt;td&gt;签到&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;13:00 ~ 14:00&lt;/td&gt;

      &lt;td&gt;针对iPad平台的高性能网站架构&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;14:00 ~ 14:10&lt;/td&gt;

      &lt;td&gt;短休&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;14:10 ~ 15:10&lt;/td&gt;

      &lt;td&gt;分布式版本管理&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;15:10 ~ 15:40&lt;/td&gt;

      &lt;td&gt;茶歇&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;15:40 ~ 16:40&lt;/td&gt;

      &lt;td&gt;企业开发领域的语言特性&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;16:40 ~ 16:50&lt;/td&gt;

      &lt;td&gt;短休&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;16:50 ~ 17: 50&lt;/td&gt;

      &lt;td&gt;使用.NET构建轻量级分布式框架&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;&lt;/table&gt;

&lt;h1&gt;演讲内容&lt;/h1&gt;

&lt;p&gt;以下为是四场演讲的信息：&lt;/p&gt;
&lt;a href="http://nbazaar.org/_media/%E8%AE%B2%E5%B8%88/mashijie-450x600.jpg" target="_blank"&gt;&lt;img class="floatRight" src="http://nbazaar.org/_media/%E8%AE%B2%E5%B8%88/mashijie-450x600.jpg" height="150" /&gt;&lt;/a&gt; 

&lt;h2&gt;针对iPad平台的高性能网站架构&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;讲师：&lt;/strong&gt;马士杰，EF英孚教育，Tech Leader。关注高性能网站架构和前沿技术在线教育领域的应用创新。曾经重点关注的技术领域包括ORM，AOP和SOA。近期的关注重点是针对移动平台的高性能网站架构。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;简介：&lt;/strong&gt;iPad的横空出世，几乎使得2010年成为全球IT领域的平板电脑之年。摩根士丹利发布的《移动互联网报告》认为移动互联网周期是50年来的第5个新技术周期，以Apple的iPad平板电脑和手机上网为代表的移动互联网的增长势头将超过电脑上网。本演讲的目的是和听众分享本人近一年在针对iPad平台的高性能网站架构方面的一些经验，包括兼容不同平台桌面和移动浏览器的表现层设计模式，针对iPad Mobile Safari浏览器的Web页面性能优化和iPad本地程序和在线网站的无缝整合等。&lt;/p&gt;
&lt;a href="http://nbazaar.org/_media/%E8%AE%B2%E5%B8%88/lijun-400x600.jpg" target="_blank"&gt;&lt;img class="floatRight" src="http://nbazaar.org/_media/%E8%AE%B2%E5%B8%88/lijun-400x600.jpg" height="150" /&gt;&lt;/a&gt; 

&lt;h2&gt;分布式版本管理&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;讲师：&lt;/strong&gt;李骏，中国第一批J2EE开发者，大中华区第一个中间件和SOA领域的Oracle ACE Director。有着10年以上企业级应用系统咨询/设计/实施以及软件公司管理经验的行业老兵，因为喜欢创造能影响人们日常生活的东西，所以来到盛大创新院，梦想能找到“正确的把软件作成业务”的方法。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;演讲：&lt;/strong&gt;源代码和其它软件工程产物的版本管理，是每个开发者每天都会碰到的问题，经过数十年的发展，CVS、SVN等上一代版本管理系统中的一些问题，催生着新的技术及其应用模式。在过去几年中以Git和Mercurial为代表的分布式版本管理工具有了较大的发展，已经基本具备了普及应用的基础。这里将介绍分布式版本管理欲解决的问题及其关键价值，并以Mercurial为例介绍具体使用的方法和流程。&lt;/p&gt;
&lt;a href="http://nbazaar.org/_media/%E8%AE%B2%E5%B8%88/shijianzhuo-576x432.jpg" target="_blank"&gt;&lt;img class="floatRight" src="http://nbazaar.org/_media/%E8%AE%B2%E5%B8%88/shijianzhuo-576x432.jpg" height="150" /&gt;&lt;/a&gt; 

&lt;h2&gt;企业开发领域的语言特性&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;讲师：&lt;/strong&gt;师建茁（Amos Shi），GRC软件工程师，SAP Labs China。中学时代在 286、486 系统上学会了 12个DOS内部命令，若干外部命令；使用QBasic开始程序生涯，半夜起来在图画本上设计流程图。后来跟着谭浩强的C语言课本和Borland的TC 2.0进入 Windows CMD 时代，后来有了 C++、Delphi、Python、.NET、Java，排名不分先后，意识到语言并非那么重要； 直到有一天，遇到了 ABAP，以及 Web Dynpro，意识到，对于优秀的软件，高级语言特性还是有所帮助的。2007年加入SAP Labs China，从事GRC软件产品的研发。日常工作涉及GRC 的多个部分。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;演讲：&lt;/strong&gt;作为一个程序员，在加入SAP之前用过一些各种各样流行的技术来写软件产品，到了Labs之后开始使用一种不广为所知的ABAP语言开发GRC软件产品。在学习和使用ABAP语言的过程中，经常会有类似“啊！对了，以前我就想过应该是这样的”、“是的！就是应该这样集成！”、“本来嘛，已经有足够的信息在那里了，她就是应该自动生成，一行代码都不应该写！”这样的感叹，对很多特性总是有相见恨晚的感觉。回想到以前的产品开发中遇到的种种问题，觉得如果这些特性已经有了的话，可以大大提高效率，降低错误。后来逐渐接触到其后面的NetWeaver平台，和Web Dynpro之后，更觉得这一整套东西为企业应用进行了精心设计。又回想起了“程序员如何在非洲捕捉大象？”这个经典笑话，哈哈哈哈。如果你要开发企业应用的话，确实有很多东西可以从这里借鉴，希望对你能有所裨益。&lt;/p&gt;
&lt;a href="http://nbazaar.org/_media/%E8%AE%B2%E5%B8%88/qiaojie-400x622.jpg" target="_blank"&gt;&lt;img class="floatRight" src="http://nbazaar.org/_media/%E8%AE%B2%E5%B8%88/qiaojie-400x622.jpg" height="150" /&gt;&lt;/a&gt; 

&lt;h2&gt;使用.NET构建轻量级分布式框架&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;讲师：&lt;/strong&gt;乔捷，瓦格纳比罗舞台系统公司，技术主管。热爱技术，对多种技术领域都有涉猎，目前主要从事剧院舞台控制系统和虚拟舞台系统的设计和研发工作，主要涉及到分布式系统、实时控制系统、虚拟现实系统、3D实时/离线渲染等技术领域。主要的编程语言为C++/C#/JavaScript，喜爱.NET技术，最近比较关注分布式计算和并行计算技术，并已在实际的项目应用中取得了初步的成功。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;演讲：&lt;/strong&gt;分布式系统的设计和构建是一项复杂多变而很具有挑战性的任务，设计的目标包括服务的伸缩性、可靠性、安全性、实时性、性能、容错等多个方面，同时还可能需要面对各种异构平台的集成和整合。目前市面上已有的分布式框架包括.NET提供的Remoting和WCF，都不能很好的满足上述所有的这些需求。因此，打造一套轻量级的、高度可定制的、符合自身项目需求的分布式框架变得很有现实意义。本演讲就来讨论如何应用.NET技术构建这样一套轻量级的分布式框架。&lt;/p&gt;

&lt;h1&gt;地点&lt;/h1&gt;

&lt;p&gt;本次交流会举办地为&lt;strong style="color: red"&gt;上海市浦东新区碧波路888号畅星大厦&lt;/strong&gt;（地铁二号线张江高科站下，步行10分钟可达）3楼会议厅，地图如下：&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/snda-dotnet-conf/changxing-map.png"&gt;&lt;img src="http://img.zhaojie.me/blog/snda-dotnet-conf/changxing-map.png" width="400" /&gt;&lt;/a&gt; 

&lt;p&gt;鸟瞰图：&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/snda-dotnet-conf/changxing-hybrid.jpg"&gt;&lt;img src="http://img.zhaojie.me/blog/snda-dotnet-conf/changxing-hybrid.jpg" width="400" /&gt;&lt;/a&gt; 

&lt;p&gt;畅星大厦外观：&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/snda-dotnet-conf/changxing-building.jpg"&gt;&lt;img src="http://img.zhaojie.me/blog/snda-dotnet-conf/changxing-building.jpg" width="400" /&gt;&lt;/a&gt; 

&lt;p&gt;会场实景照片：&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/snda-dotnet-conf/changxing-room.jpg"&gt;&lt;img src="http://img.zhaojie.me/blog/snda-dotnet-conf/changxing-room.jpg" width="400" /&gt;&lt;/a&gt; 

&lt;p&gt;会场容量可以容纳超过200人，希望到时候不会显得太过空旷。:)&lt;/p&gt;

&lt;h1&gt;报名信息&lt;/h1&gt;
&lt;img src="http://img.zhaojie.me/blog/snda-dotnet-conf/sign-up-now.jpg" /&gt; 

&lt;p&gt;本次交流会&lt;a href="http://diaochapai.com/survey518744"&gt;现已开始报名，请填写报名表&lt;/a&gt;。&lt;/p&gt;</description>
      <comments>http://blog.zhaojie.me/2010/12/3rd-nbazaar-meeting-sign-up.html#comments</comments>
      <pubDate>Mon, 20 Dec 2010 16:45:46 GMT</pubDate>
      <lastBuildDate>Mon, 20 Dec 2010 16:45:46 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/front-end/">前端表现</category>
      <category domain="http://blog.zhaojie.me/cutting-edge/">技术尝鲜</category>
      <category domain="http://blog.zhaojie.me/speech/">培训演讲</category>
      <category domain="http://blog.zhaojie.me/parallel/">并行处理</category>
      <category domain="http://blog.zhaojie.me/news/">新闻信息</category>
      <category domain="http://blog.zhaojie.me/language/">语言编程</category>
      <title>关于即将到来的“演出季”以及Jscex类库</title>
      <link>http://blog.zhaojie.me/2010/11/the-coming-talks-and-jscex.html</link>
      <guid>http://blog.zhaojie.me/2010/11/the-coming-talks-and-jscex.html</guid>
      <description>&lt;p&gt;又到了一年一度的“演出季”，接下来将是各式会议扑面而来的一个月。作为“与会爱好者”我自然也进入了繁忙的准备工作。接下来我将在&lt;a href="http://tup.csdn.net/"&gt;TUP&lt;/a&gt;（11月27日）、&lt;a href="http://www.net-china.org/"&gt;2010年第二届.NET技术大会&lt;/a&gt;（12月4~5日）以及&lt;a href="http://sd2china.csdn.net/"&gt;CSDN软件开发2.0大会&lt;/a&gt;（12月9~10日）上与大家分享四场演讲。不过除了一场是关于Windows并发编程的基础以外，其余三场的话题都是围绕“微软在异步编程方面的演变”。在这场演讲中，我还会引入一个与该话题密切相关的JavaScript类库：Jscex。&lt;/p&gt;

&lt;p&gt;并发编程已经成为我们无法回避的一点，但是传统的编程语言在并发、异步等方面的支持非常有限，除了一些面向并发的编程语言（如Erlang），我们只能使用回调的方式，这样代码则被拆得支离破碎。如今的一些新语言，如F#，Scala，Go以及未来的C#都会在这方面有直接的支持。就我个人而言，用过了这些语言之后，就几乎无法回头，因为我实在无法体会到编程的快感。&lt;/p&gt;

&lt;p&gt;如今微软的.NET平台在异步编程领域已经开始发力，从最初十分原始的Begin/End的异步模型和基于事件的异步模型，到后来&lt;a href="http://blog.zhaojie.me/2010/03/async-and-parallel-design-patterns-in-fsharp-1-parallelizing-cpu-and-io-computations.html"&gt;F#中的异步工作流&lt;/a&gt;，.NET 4.0中的&lt;a href="http://blog.zhaojie.me/2010/09/async-programming-and-reactive-framework.html"&gt;Observable及响应式框架&lt;/a&gt;，以及&lt;a href="http://blog.zhaojie.me/2010/10/pdc2010-the-future-of-csharp-and-vb-by-anders-hejlsberg-1.html"&gt;未来C#中将要出现的异步特性&lt;/a&gt;，.NET平台上涌现了各种与并发和异步编程的机制。未来几场演讲的主要话题，便是关于这些异步编程模型的演变。&lt;/p&gt;

&lt;p&gt;只可惜，在某些和异步密切相关的平台上，例如使用JavaScript的浏览器平台，开发人员还是不得不利用最传统的开发模型。响应式框架通过引入一个“推模型”改进了这一点，不过我最欣赏的异步编程支持还是F#上的异步工作流。首先，它是一套“类库”（基于F#中的计算表达式特性）；其次，它让异步编程变得像传统的顺序式开发那样简单。有天我突然意识到，JavaScript其实提供一个很强大的机制：它可以使用toString方法得到一个函数的原始代码，于是我们可以对此解析并生成新的代码，最后使用eval得到新的函数。通过这个手法，JavaScript语言几乎得到了无限的灵活性。&lt;/p&gt;

&lt;p&gt;于是在未来的演讲中，我将会展示一个JavaScript类库的原型：&lt;a href="https://github.com/JeffreyZhao/jscex"&gt;Jscex&lt;/a&gt;（目前还未提交任何代码）。Jscex是&lt;font color="#ff0000"&gt;J&lt;/font&gt;ava&lt;font color="#ff0000"&gt;S&lt;/font&gt;cript &lt;font color="#ff0000"&gt;C&lt;/font&gt;omputation &lt;font color="#ff0000"&gt;Ex&lt;/font&gt;pressions的缩写，即“JavaScript的计算表达式”。计算表达式的原理，便是将一段顺序式的代码，重新编译成另外一个表达式，它便是F#中异步工作流的基础。&lt;/p&gt;

&lt;p&gt;例如，它会将下面这段JavaScript函数：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;function &lt;/span&gt;(urlA, urlB) {
    &lt;span style="color: blue"&gt;var &lt;/span&gt;reqA = &lt;font color="#ff0000"&gt;$await&lt;/font&gt;(Jscex.Async.sendRequest(urlA, &lt;span style="color: maroon"&gt;&amp;quot;GET&amp;quot;&lt;/span&gt;));
    &lt;span style="color: blue"&gt;var &lt;/span&gt;lengthA = reqA.responseText.length;

    &lt;span style="color: blue"&gt;var &lt;/span&gt;reqB = &lt;font color="#ff0000"&gt;$await&lt;/font&gt;(Jscex.Async.sendRequest(urlB, &lt;span style="color: maroon"&gt;&amp;quot;GET&amp;quot;&lt;/span&gt;));
    &lt;span style="color: blue"&gt;var &lt;/span&gt;lengthB = reqB.responseText.length;

    &lt;span style="color: blue"&gt;return &lt;/span&gt;lengthA + lengthB;
}&lt;/pre&gt;

&lt;p&gt;编译成另一段代码：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;function&lt;/span&gt; (urlA, urlB) {
    &lt;span style="color: blue"&gt;return &lt;/span&gt;$async.Delay(&lt;span style="color: blue"&gt;function&lt;/span&gt;() {
        &lt;span style="color: blue"&gt;return &lt;/span&gt;$async.Bind(Jscex.Async.sendRequest(urlA, &lt;span style="color: maroon"&gt;&amp;quot;GET&amp;quot;&lt;/span&gt;), &lt;span style="color: blue"&gt;function&lt;/span&gt;(reqA) {
            &lt;span style="color: blue"&gt;var &lt;/span&gt;lengthA = reqA.responseText.length;
            &lt;span style="color: blue"&gt;return &lt;/span&gt;$async.Bind(Jscex.Async.sendRequest(urlB, &lt;span style="color: maroon"&gt;&amp;quot;GET&amp;quot;&lt;/span&gt;), &lt;span style="color: blue"&gt;function&lt;/span&gt;(reqB) {
                &lt;span style="color: blue"&gt;var &lt;/span&gt;lengthB = reqB.responseText.length;
                &lt;span style="color: blue"&gt;return &lt;/span&gt;$async.Return(lengthA + lengthB);
            });
        });
    });
};&lt;/pre&gt;

&lt;p&gt;对于$async这个构造器来说，$await便是一个bind函数，在此处则会形成一个回调。此外，Jscex也必须能够正确处理循环操作，例如这个&lt;a href="http://files.zhaojie.me/demos/jscex-prototype/clock.html"&gt;时钟示例&lt;/a&gt;（建议使用IE 9，Chrome或Firefox等支持canvas的浏览器观看）其实是这样实现的：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;var &lt;/span&gt;drawClockAsync = eval(Jscex.compile(&lt;span style="color: maroon"&gt;&amp;quot;$async&amp;quot;&lt;/span&gt;, &lt;span style="color: blue"&gt;function &lt;/span&gt;(interval) {
    &lt;span style="color: blue"&gt;while &lt;/span&gt;(&lt;span style="color: blue"&gt;true&lt;/span&gt;) {
        drawClock(&lt;span style="color: blue"&gt;new &lt;/span&gt;Date());
        &lt;font color="#ff0000"&gt;$await&lt;/font&gt;(Jscex.Async.sleep(interval));
    }
}));

Jscex.Async.start(drawClockAsync(1000));&lt;/pre&gt;

&lt;p&gt;对于时钟来说，我们往往会不断使用window.setTimeout来更新界面。不过有了Jscex，一切都变得“顺其自然”。我们只要写一个“死循环”，在需要“等待”的时候，直接$await一个sleep操作即可。这种看似“阻塞”的代码，其实最终会被重新编译成新的函数：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;function&lt;/span&gt;(interval) {
    &lt;span style="color: blue"&gt;return &lt;/span&gt;$async.Delay(&lt;span style="color: blue"&gt;function&lt;/span&gt;() {
        &lt;span style="color: blue"&gt;return &lt;/span&gt;$async.While(
            &lt;span style="color: blue"&gt;function&lt;/span&gt;() { &lt;span style="color: blue"&gt;return true&lt;/span&gt;; },
            $async.Delay(&lt;span style="color: blue"&gt;function&lt;/span&gt;() {
                drawClock(&lt;span style="color: blue"&gt;new &lt;/span&gt;Date);
                &lt;span style="color: blue"&gt;return &lt;/span&gt;$async.Bind(Jscex.Async.sleep(interval), &lt;span style="color: blue"&gt;function&lt;/span&gt;() {
                    &lt;span style="color: blue"&gt;return &lt;/span&gt;$async.Return();
                });
            })
        );
    });
};&lt;/pre&gt;

&lt;p&gt;实际上，它们都是异步的。&lt;/p&gt;

&lt;p&gt;其实在浏览器上有太多的异步场景。例如一个AJAX请求，或者是一段动画效果。这里我还准备了&lt;a href="http://files.zhaojie.me/demos/jscex-prototype/animation.html"&gt;第二个示例&lt;/a&gt;，其中有一段移动元素的方法（将元素e在duration时间内从startPos移动至endPos）是这样编写的：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;var &lt;/span&gt;moveAsync = eval(Jscex.compile(&lt;span style="color: maroon"&gt;&amp;quot;$async&amp;quot;&lt;/span&gt;, &lt;span style="color: blue"&gt;function &lt;/span&gt;(e, startPos, endPos, duration) {
    e.style.left = startPos.x;
    e.style.top = startPos.y;

    &lt;span style="color: blue"&gt;var &lt;/span&gt;time = 0;
    &lt;span style="color: blue"&gt;while &lt;/span&gt;(time &amp;lt; duration) {
        &lt;font color="#ff0000"&gt;$await&lt;/font&gt;(Jscex.Async.sleep(50));
        time = time + 50;
        e.style.left = startPos.x + (endPos.x - startPos.x) * time / duration;
        e.style.top = startPos.y + (endPos.y - startPos.y) * time / duration;
    }
}));

&lt;span style="color: blue"&gt;var &lt;/span&gt;moveBox = document.getElementById(&lt;span style="color: maroon"&gt;&amp;quot;moveBox&amp;quot;&lt;/span&gt;);
Jscex.Async.start(moveAsync(moveBox, { x: 0, y: 0 }, { x: 300, y: 0 }, 1000));&lt;/pre&gt;

&lt;p&gt;没有回调，只有最普通的顺序式编程。甚至我们还可以将moveAsync方法组合到另一个方法中去：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;var &lt;/span&gt;moveSquareAsync = eval(Jscex.compile(&lt;span style="color: maroon"&gt;&amp;quot;$async&amp;quot;&lt;/span&gt;, &lt;span style="color: blue"&gt;function &lt;/span&gt;(e) {
    &lt;font color="#ff0000"&gt;$await&lt;/font&gt;(moveAsync(e, { x: 100, y: 100 }, { x: 400, y: 100 }, 1000));
    &lt;font color="#ff0000"&gt;$await&lt;/font&gt;(moveAsync(e, { x: 400, y: 100 }, { x: 400, y: 400 }, 1000));
    &lt;font color="#ff0000"&gt;$await&lt;/font&gt;(moveAsync(e, { x: 400, y: 400 }, { x: 100, y: 400 }, 1000));
    &lt;font color="#ff0000"&gt;$await&lt;/font&gt;(moveAsync(e, { x: 100, y: 400 }, { x: 100, y: 100 }, 1000));
}));

&lt;span style="color: blue"&gt;var &lt;/span&gt;moveSquareBox = document.getElementById(&lt;span style="color: maroon"&gt;&amp;quot;moveSquareBox&amp;quot;&lt;/span&gt;);
Jscex.Async.start(moveSquareAsync(moveSquareBox));&lt;/pre&gt;

&lt;p&gt;如何让一个元素沿方形移动？“连续执行”四遍moveAsync方法即可。当然，moveSquareAsync方法最终还是由“回调”组成的：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;function &lt;/span&gt;(e) {
    &lt;span style="color: blue"&gt;return &lt;/span&gt;$async.Delay(&lt;span style="color: blue"&gt;function &lt;/span&gt;() {
        &lt;span style="color: blue"&gt;return &lt;/span&gt;$async.Bind(moveAsync(e, {...}, {...}, 1000), &lt;span style="color: blue"&gt;function &lt;/span&gt;() {
            &lt;span style="color: blue"&gt;return &lt;/span&gt;$async.Bind(moveAsync(e, {...}, {...}, 1000), &lt;span style="color: blue"&gt;function &lt;/span&gt;() {
                &lt;span style="color: blue"&gt;return &lt;/span&gt;$async.Bind(moveAsync(e, {...}, {...}, 1000), &lt;span style="color: blue"&gt;function &lt;/span&gt;() {
                    &lt;span style="color: blue"&gt;return &lt;/span&gt;$async.Bind(moveAsync(e, {...}, {...}, 1000), &lt;span style="color: blue"&gt;function &lt;/span&gt;() {
                        &lt;span style="color: blue"&gt;return &lt;/span&gt;$async.Return();
                    });
                });
            });
        });
    });
};&lt;/pre&gt;

&lt;p&gt;我以前在许多地方说过，目前浏览器上的开发效率已经受限于JavaScript的语言特性了。不过，正如我刚才所提到的那样，JavaScript语言的灵活性几乎是无穷的。我认为，Jscex会是一个突破。当然，现在您看到的演示只不过是个原型，如果要提供一个完整的解决方案还有太多的路要走。例如现在的Jscex还不支持for，if，try...catch等常见语言特性，代码也丑陋得很。与此对应的Jscex.Async也只是个初步的模型，且只有寥寥无几的辅助方法。&lt;/p&gt;</description>
      <comments>http://blog.zhaojie.me/2010/11/the-coming-talks-and-jscex.html#comments</comments>
      <pubDate>Mon, 22 Nov 2010 12:30:57 GMT</pubDate>
      <lastBuildDate>Mon, 29 Nov 2010 14:28:28 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/language/">语言编程</category>
      <category domain="http://blog.zhaojie.me/cutting-edge/">技术尝鲜</category>
      <category domain="http://blog.zhaojie.me/front-end/">前端表现</category>
      <title>使用Narcissus解析JavaScript代码</title>
      <link>http://blog.zhaojie.me/2010/11/narcissus-javascript-parser.html</link>
      <guid>http://blog.zhaojie.me/2010/11/narcissus-javascript-parser.html</guid>
      <description>&lt;p&gt;最近在做一个有关JavaScript的实验，需要在客户端将JavaScript代码解析为一棵语法树。换句话说，就是一个用JavaScript实现的JavaScript解析器。这方面的选择有很多，常见的yacc、lex或是bison等等都有JavaScript的版本，使用ANTLR也可以将生成目标设为JavaScript。不过我不想在这方面耗费太多时间，自然想找个现成的工具，于是最终我将目标放在了Narcissus上。&lt;/p&gt;

&lt;p&gt;Narcissus是一个JavaScript引擎，完全使用JavaScript编写，不过利用了&lt;a href="http://en.wikipedia.org/wiki/SpiderMonkey_(JavaScript_engine)"&gt;SpiderMonkey&lt;/a&gt;的一些扩展，因此无法直接在仅仅实现了ECMAScript 3的引擎上执行（例如各浏览器）。从&lt;a href="http://en.wikipedia.org/wiki/Narcissus_%28JavaScript_engine%29"&gt;它的Wikipedia页面上得知&lt;/a&gt;，Narcissus由SpiderMonkey的作者&lt;a href="http://en.wikipedia.org/wiki/Brendan_Eich"&gt;Brendan Eich&lt;/a&gt;开发，名称来源于&lt;a href="http://en.wikipedia.org/wiki/Narcissus_(mythology)"&gt;希腊神话中爱上自己倒影的人物&lt;/a&gt;，和“JavaScript编写的JavaScript引擎”的概念契合（真是太有文化了）。此外，Firefox有一个Zaphod插件，可以将浏览器的JavaScript引擎替换为Narcissus。&lt;/p&gt;

&lt;p&gt;Narcissus是个十分简单的JavaScript引擎，可以用来做一些JavaScript语言新特性的探索工作。它几乎不做任何优化，因此不能与其他引擎比拼性能，但很显然它包含完整的JavaScript分析器，正好为我所用。首先，&lt;a href="https://github.com/mozilla/narcissus"&gt;从Github上下载它的源代码&lt;/a&gt;，其中包括六个文件，而我只需要其中的三个：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;jsdef.js：包含了Narcissus.definitions组件，各种Token定义等等。 &lt;/li&gt;

  &lt;li&gt;jslex.js：包含了Narcissus.lexer组件，分词器。 &lt;/li&gt;

  &lt;li&gt;jsparse.js：包含了Narcissus.parser，分析器。 &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;之前提到过，Narcissus不能直接在浏览器上运行，因此我们还必须对它进行修改。首先，是在jsdefs.js文件中，我们需要将开头的一段利用Object.create方法的定义：&lt;/p&gt;

&lt;pre class="code"&gt;(&lt;span style="color: blue"&gt;function&lt;/span&gt;() {
    &lt;span style="color: blue"&gt;var &lt;/span&gt;builderTypes = Object.create(&lt;span style="color: blue"&gt;null&lt;/span&gt;, {
        ...
    });

    ...

    &lt;span style="color: blue"&gt;var &lt;/span&gt;narcissus = {
        ...&lt;span style="color: blue"&gt;
    &lt;/span&gt;};

    Narcissus = narcissus;
})();&lt;/pre&gt;

&lt;p&gt;替换成直接的声明：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;var &lt;/span&gt;Narcissus = { };&lt;/pre&gt;

&lt;p&gt;其次还是在jsdefs.js中，我们要改变defineProperty和defineGetter的实现：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;function &lt;/span&gt;defineGetter(obj, prop, fn, dontDelete, dontEnum) {
    Object.defineProperty(...);
}

&lt;span style="color: blue"&gt;function &lt;/span&gt;defineProperty(obj, prop, val, dontDelete, readOnly, dontEnum) {
    Object.defineProperty(...);
}&lt;/pre&gt;

&lt;p&gt;Object的defineProperty和defineGetter方法也是SpiderMonkey的扩展，我们要把它们修改为“直接赋值”的版本：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;function &lt;/span&gt;defineGetter(obj, prop, fn, dontDelete, dontEnum) {
    obj[prop] = fn;
}

&lt;span style="color: blue"&gt;function &lt;/span&gt;defineProperty(obj, prop, val, dontDelete, readOnly, dontEnum) {
    obj[prop] = val;
}&lt;/pre&gt;

&lt;p&gt;当然，这么做与之前的效果并不等价，不过并不影响代码的使用。您可以从jsparse.js文件中找到使用了这两个方法的地方。&lt;/p&gt;

&lt;p&gt;现在您就可以在一个页面里引入这三个JavaScript文件，并Narcissus.parser分析JavaScript代码了。Narcissus几乎没有说明文档，不过从代码中找到它的使用方法并不困难。例如：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;function &lt;/span&gt;parseSelf() { 
    &lt;span style="color: blue"&gt;var &lt;/span&gt;builder = &lt;span style="color: blue"&gt;new &lt;/span&gt;Narcissus.parser.DefaultBuilder();
    &lt;span style="color: blue"&gt;return &lt;/span&gt;Narcissus.parser.parse(builder, parseSelf.toString(), &lt;span style="color: maroon"&gt;&amp;quot;temp&amp;quot;&lt;/span&gt;, 1);
}

document.write(&lt;span style="color: maroon"&gt;&amp;quot;&amp;lt;pre&amp;gt;&amp;quot; &lt;/span&gt;+ parseSelf() + &lt;span style="color: maroon"&gt;&amp;quot;&amp;lt;/pre&amp;gt;&amp;quot;&lt;/span&gt;);&lt;/pre&gt;
&lt;textarea id="parseSelf_tree" style="display:none;"&gt;&amp;lt;pre&amp;gt;{
    type: SCRIPT,
    children: {
        type: FUNCTION,
        body: {
            type: SCRIPT,
            children: {
                type: VAR,
                children: {
                    type: IDENTIFIER,
                    children: ,
                    end: 38,
                    initializer: {
                        type: NEW,
                        children: {
                            type: DOT,
                            children: {
                                type: DOT,
                                children: {
                                    type: IDENTIFIER,
                                    children: ,
                                    end: 55,
                                    lineno: 2,
                                    start: 46,
                                    tokenizer: [object Object],
                                    value: Narcissus
                                },{
                                    type: IDENTIFIER,
                                    children: ,
                                    end: 62,
                                    lineno: 2,
                                    start: 56,
                                    tokenizer: [object Object],
                                    value: parser
                                },
                                end: 62,
                                lineno: 2,
                                start: 46,
                                tokenizer: [object Object],
                                value: .
                            },{
                                type: IDENTIFIER,
                                children: ,
                                end: 77,
                                lineno: 2,
                                start: 63,
                                tokenizer: [object Object],
                                value: DefaultBuilder
                            },
                            end: 77,
                            lineno: 2,
                            parenthesized: true,
                            start: 46,
                            tokenizer: [object Object],
                            value: .
                        },
                        end: 77,
                        lineno: 2,
                        start: 41,
                        tokenizer: [object Object],
                        value: new
                    },
                    lineno: 2,
                    name: builder,
                    readOnly: false,
                    start: 31,
                    tokenizer: [object Object],
                    value: builder
                },
                destructurings: ,
                end: 38,
                lineno: 2,
                start: 27,
                tokenizer: [object Object],
                value: var
            },{
                type: RETURN,
                children: ,
                end: 90,
                lineno: 3,
                start: 84,
                tokenizer: [object Object],
                value: {
                    type: CALL,
                    children: {
                        type: DOT,
                        children: {
                            type: DOT,
                            children: {
                                type: IDENTIFIER,
                                children: ,
                                end: 100,
                                lineno: 3,
                                start: 91,
                                tokenizer: [object Object],
                                value: Narcissus
                            },{
                                type: IDENTIFIER,
                                children: ,
                                end: 107,
                                lineno: 3,
                                start: 101,
                                tokenizer: [object Object],
                                value: parser
                            },
                            end: 107,
                            lineno: 3,
                            start: 91,
                            tokenizer: [object Object],
                            value: .
                        },{
                            type: IDENTIFIER,
                            children: ,
                            end: 113,
                            lineno: 3,
                            start: 108,
                            tokenizer: [object Object],
                            value: parse
                        },
                        end: 113,
                        lineno: 3,
                        start: 91,
                        tokenizer: [object Object],
                        value: .
                    },{
                        type: LIST,
                        children: {
                            type: IDENTIFIER,
                            children: ,
                            end: 121,
                            lineno: 3,
                            start: 114,
                            tokenizer: [object Object],
                            value: builder
                        },{
                            type: CALL,
                            children: {
                                type: DOT,
                                children: {
                                    type: IDENTIFIER,
                                    children: ,
                                    end: 132,
                                    lineno: 3,
                                    start: 123,
                                    tokenizer: [object Object],
                                    value: parseSelf
                                },{
                                    type: IDENTIFIER,
                                    children: ,
                                    end: 141,
                                    lineno: 3,
                                    start: 133,
                                    tokenizer: [object Object],
                                    value: toString
                                },
                                end: 141,
                                lineno: 3,
                                start: 123,
                                tokenizer: [object Object],
                                value: .
                            },{
                                type: LIST,
                                children: ,
                                end: 142,
                                lineno: 3,
                                start: 141,
                                tokenizer: [object Object],
                                value: (
                            },
                            end: 142,
                            lineno: 3,
                            start: 123,
                            tokenizer: [object Object],
                            value: (
                        },{
                            type: STRING,
                            children: ,
                            end: 151,
                            lineno: 3,
                            start: 145,
                            tokenizer: [object Object],
                            value: temp
                        },{
                            type: NUMBER,
                            children: ,
                            end: 154,
                            lineno: 3,
                            start: 153,
                            tokenizer: [object Object],
                            value: 1
                        },
                        end: 154,
                        lineno: 3,
                        start: 113,
                        tokenizer: [object Object],
                        value: (
                    },
                    end: 154,
                    lineno: 3,
                    start: 91,
                    tokenizer: [object Object],
                    value: (
                }
            },
            end: 90,
            funDecls: ,
            id: 0,
            lineno: 1,
            start: 21,
            tokenizer: [object Object],
            value: {,
            varDecls: {
                type: IDENTIFIER,
                children: ,
                end: 38,
                initializer: {
                    type: NEW,
                    children: {
                        type: DOT,
                        children: {
                            type: DOT,
                            children: {
                                type: IDENTIFIER,
                                children: ,
                                end: 55,
                                lineno: 2,
                                start: 46,
                                tokenizer: [object Object],
                                value: Narcissus
                            },{
                                type: IDENTIFIER,
                                children: ,
                                end: 62,
                                lineno: 2,
                                start: 56,
                                tokenizer: [object Object],
                                value: parser
                            },
                            end: 62,
                            lineno: 2,
                            start: 46,
                            tokenizer: [object Object],
                            value: .
                        },{
                            type: IDENTIFIER,
                            children: ,
                            end: 77,
                            lineno: 2,
                            start: 63,
                            tokenizer: [object Object],
                            value: DefaultBuilder
                        },
                        end: 77,
                        lineno: 2,
                        parenthesized: true,
                        start: 46,
                        tokenizer: [object Object],
                        value: .
                    },
                    end: 77,
                    lineno: 2,
                    start: 41,
                    tokenizer: [object Object],
                    value: new
                },
                lineno: 2,
                name: builder,
                readOnly: false,
                start: 31,
                tokenizer: [object Object],
                value: builder
            }
        },
        children: ,
        end: 158,
        functionForm: 0,
        lineno: 1,
        name: parseSelf,
        params: ,
        start: 0,
        tokenizer: [object Object],
        value: function
    },
    funDecls: {
        type: FUNCTION,
        body: {
            type: SCRIPT,
            children: {
                type: VAR,
                children: {
                    type: IDENTIFIER,
                    children: ,
                    end: 38,
                    initializer: {
                        type: NEW,
                        children: {
                            type: DOT,
                            children: {
                                type: DOT,
                                children: {
                                    type: IDENTIFIER,
                                    children: ,
                                    end: 55,
                                    lineno: 2,
                                    start: 46,
                                    tokenizer: [object Object],
                                    value: Narcissus
                                },{
                                    type: IDENTIFIER,
                                    children: ,
                                    end: 62,
                                    lineno: 2,
                                    start: 56,
                                    tokenizer: [object Object],
                                    value: parser
                                },
                                end: 62,
                                lineno: 2,
                                start: 46,
                                tokenizer: [object Object],
                                value: .
                            },{
                                type: IDENTIFIER,
                                children: ,
                                end: 77,
                                lineno: 2,
                                start: 63,
                                tokenizer: [object Object],
                                value: DefaultBuilder
                            },
                            end: 77,
                            lineno: 2,
                            parenthesized: true,
                            start: 46,
                            tokenizer: [object Object],
                            value: .
                        },
                        end: 77,
                        lineno: 2,
                        start: 41,
                        tokenizer: [object Object],
                        value: new
                    },
                    lineno: 2,
                    name: builder,
                    readOnly: false,
                    start: 31,
                    tokenizer: [object Object],
                    value: builder
                },
                destructurings: ,
                end: 38,
                lineno: 2,
                start: 27,
                tokenizer: [object Object],
                value: var
            },{
                type: RETURN,
                children: ,
                end: 90,
                lineno: 3,
                start: 84,
                tokenizer: [object Object],
                value: {
                    type: CALL,
                    children: {
                        type: DOT,
                        children: {
                            type: DOT,
                            children: {
                                type: IDENTIFIER,
                                children: ,
                                end: 100,
                                lineno: 3,
                                start: 91,
                                tokenizer: [object Object],
                                value: Narcissus
                            },{
                                type: IDENTIFIER,
                                children: ,
                                end: 107,
                                lineno: 3,
                                start: 101,
                                tokenizer: [object Object],
                                value: parser
                            },
                            end: 107,
                            lineno: 3,
                            start: 91,
                            tokenizer: [object Object],
                            value: .
                        },{
                            type: IDENTIFIER,
                            children: ,
                            end: 113,
                            lineno: 3,
                            start: 108,
                            tokenizer: [object Object],
                            value: parse
                        },
                        end: 113,
                        lineno: 3,
                        start: 91,
                        tokenizer: [object Object],
                        value: .
                    },{
                        type: LIST,
                        children: {
                            type: IDENTIFIER,
                            children: ,
                            end: 121,
                            lineno: 3,
                            start: 114,
                            tokenizer: [object Object],
                            value: builder
                        },{
                            type: CALL,
                            children: {
                                type: DOT,
                                children: {
                                    type: IDENTIFIER,
                                    children: ,
                                    end: 132,
                                    lineno: 3,
                                    start: 123,
                                    tokenizer: [object Object],
                                    value: parseSelf
                                },{
                                    type: IDENTIFIER,
                                    children: ,
                                    end: 141,
                                    lineno: 3,
                                    start: 133,
                                    tokenizer: [object Object],
                                    value: toString
                                },
                                end: 141,
                                lineno: 3,
                                start: 123,
                                tokenizer: [object Object],
                                value: .
                            },{
                                type: LIST,
                                children: ,
                                end: 142,
                                lineno: 3,
                                start: 141,
                                tokenizer: [object Object],
                                value: (
                            },
                            end: 142,
                            lineno: 3,
                            start: 123,
                            tokenizer: [object Object],
                            value: (
                        },{
                            type: STRING,
                            children: ,
                            end: 151,
                            lineno: 3,
                            start: 145,
                            tokenizer: [object Object],
                            value: temp
                        },{
                            type: NUMBER,
                            children: ,
                            end: 154,
                            lineno: 3,
                            start: 153,
                            tokenizer: [object Object],
                            value: 1
                        },
                        end: 154,
                        lineno: 3,
                        start: 113,
                        tokenizer: [object Object],
                        value: (
                    },
                    end: 154,
                    lineno: 3,
                    start: 91,
                    tokenizer: [object Object],
                    value: (
                }
            },
            end: 90,
            funDecls: ,
            id: 0,
            lineno: 1,
            start: 21,
            tokenizer: [object Object],
            value: {,
            varDecls: {
                type: IDENTIFIER,
                children: ,
                end: 38,
                initializer: {
                    type: NEW,
                    children: {
                        type: DOT,
                        children: {
                            type: DOT,
                            children: {
                                type: IDENTIFIER,
                                children: ,
                                end: 55,
                                lineno: 2,
                                start: 46,
                                tokenizer: [object Object],
                                value: Narcissus
                            },{
                                type: IDENTIFIER,
                                children: ,
                                end: 62,
                                lineno: 2,
                                start: 56,
                                tokenizer: [object Object],
                                value: parser
                            },
                            end: 62,
                            lineno: 2,
                            start: 46,
                            tokenizer: [object Object],
                            value: .
                        },{
                            type: IDENTIFIER,
                            children: ,
                            end: 77,
                            lineno: 2,
                            start: 63,
                            tokenizer: [object Object],
                            value: DefaultBuilder
                        },
                        end: 77,
                        lineno: 2,
                        parenthesized: true,
                        start: 46,
                        tokenizer: [object Object],
                        value: .
                    },
                    end: 77,
                    lineno: 2,
                    start: 41,
                    tokenizer: [object Object],
                    value: new
                },
                lineno: 2,
                name: builder,
                readOnly: false,
                start: 31,
                tokenizer: [object Object],
                value: builder
            }
        },
        children: ,
        end: 158,
        functionForm: 0,
        lineno: 1,
        name: parseSelf,
        params: ,
        start: 0,
        tokenizer: [object Object],
        value: function
    },
    id: 0,
    lineno: 1,
    tokenizer: [object Object],
    varDecls: 
}&amp;lt;/pre&amp;gt;&lt;/textarea&gt; 

&lt;p&gt;在JavaScript中调用一个函数的toString方法会得到它的代码，于是执行上面这段代码会打印出&lt;a href="javascript:;" onclick="__showInNewWindow(document.getElementById('parseSelf_tree').value)"&gt;parseSelf方法的语法树&lt;/a&gt;。剩下的我就不多说了，爱玩的同学自然知道可以做什么。&lt;/p&gt;

&lt;p&gt;补：经过实验，Narcissus还是过于依赖SpiderMonkey引擎的特性，如果要在IE上运行还是需要修改更多内容。此外，最新的Narcissus源码还有一些bug，如果您想要使用合适的实现，不妨参考&lt;a href="http://www.neilmix.com/narrativejs/doc/"&gt;NarrativeJS&lt;/a&gt;中旧版的Narcissus代码。&lt;/p&gt;</description>
      <comments>http://blog.zhaojie.me/2010/11/narcissus-javascript-parser.html#comments</comments>
      <pubDate>Wed, 17 Nov 2010 10:08:03 GMT</pubDate>
      <lastBuildDate>Mon, 22 Nov 2010 11:24:36 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/cutting-edge/">技术尝鲜</category>
      <category domain="http://blog.zhaojie.me/speech/">培训演讲</category>
      <category domain="http://blog.zhaojie.me/translation/">翻译引进</category>
      <title>PDC 2010：C#与Visual Basic的未来（下）</title>
      <link>http://blog.zhaojie.me/2010/11/pdc2010-the-future-of-csharp-and-vb-by-anders-hejlsberg-3.html</link>
      <guid>http://blog.zhaojie.me/2010/11/pdc2010-the-future-of-csharp-and-vb-by-anders-hejlsberg-3.html</guid>
      <description>&lt;p&gt;前几天在PDC 2010会议上Anders Hejlsberg发表了一场名为“The Future of C# and Visual Basic”的演说，谈论了未来C#和VB中最为重要的两个特性：“异步（Async）”及“编译器即服务（Compiler as a Service）”。我现在对这场演讲进行总结，但不会像上次《&lt;a href="http://blog.zhaojie.me/2010/04/trends-and-future-directions-in-programming-languages-by-anders-1-history-and-trends.html"&gt;编程语言的发展趋势及未来方向&lt;/a&gt;》那样逐句翻译，而是以Anders的角度使用一种简捷合适的方式表述其完整内容。上一篇Anders对async和await的的实现及效果作更进一步的解释，本篇则是对“编译器即服务”做了些最表面的尝试。&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/36.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/36-s.png" /&gt;&lt;/a&gt; 

&lt;p&gt;你们某些人可能参加了PDC 2008，那时我谈到了“编译器即服务（Compier as a Service）”，也作了点演示。现在我来演示一点这方面的进展。 &lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/37-1.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/37-1-s.png" /&gt;&lt;/a&gt; 

&lt;p&gt;编译器即服务的关键，在于目前的编译器是个黑盒，输入源文件，输出.NET程序集。至于它是如何工作的，你不能参与进去。 &lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/37-2.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/37-2-s.png" /&gt;&lt;/a&gt; 

&lt;p&gt;为了打造更灵活工作过程，我们把编译器展开，把其中的信息展示出来并加以利用，这样就能做到实现元编程、REPL，把C#和VB作为内嵌的DSL，或是根据语言对象模型实现重构，代码生成器等语义相关的工作。 &lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/38.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/38-s.png" /&gt;&lt;/a&gt; 

&lt;p&gt;我最后的示例便是些这方面的展示。（译注：这个示例展示的代码非常复杂，但并不重要，它的主要目的便是根据编译器提供的语言对象模型，判断其中的if/else逻辑，并在Visual Studio中显示出轮廓（就像方法的折叠功能一样）。有趣的是，这个演示失败了……） &lt;/p&gt;

&lt;p&gt;这里的语言对象模型，就是C#和VB编译器内部所使用的，包含了完整的语义，可用于理解代码的工作目的。有了这些数据，我们就能作一些非常有趣的事情了。例如，我们有两个语言，它们的语法非常接近，不是吗？那么我们理解了其中一个语言，把它转化成另外一个应该也不太困难。 &lt;/p&gt;

&lt;p&gt;这里还有一个简单的C#到VB的代码转换器（译注：又一个演示），你可以把C#代码复制到剪贴板里，然后粘贴成VB代码。在实现时，只不过遍历了C#语法树，生成另一个对象模型。当然，这个程序也不是太简单，实际上还是要有几千行代码的，这里只是个最简单的实现。那么我这里来试着把那段没法工作的代码，粘贴到VB文件中……砰，这就出现了功能一致的VB代码（掌声）。这就是利用这种技术可以做到的事情。我们也已经发布了CTP版本的编译器，也包含了这些示例。 &lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/39.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/39-s.png" /&gt;&lt;/a&gt; 

&lt;p&gt;我答应过，这里是Visual Studio Async CTP的下载地址，它基于Visual Studio 2010安装。其中包含了所有我演示过的示例，有C#也有VB。此外还有一些相关的讲座，例如LINQ，我也会参加下午的语言话题讨论。接下来还有点时间，可以回答一两个问题。 &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;提问：&lt;/strong&gt;除了这里您提到的这些，C#和VB还会包含其他功能吗？ &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Anders：&lt;/strong&gt;呃，现在说起C#和VB最终是什么样的为时尚早，不过的确还有些其他的功能。 &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;提问：&lt;/strong&gt;我想知道您对于数据并发和数据共享的看法。 &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Anders：&lt;/strong&gt;并发有许多令人头痛的地方，你说的就是其中之一。我们在内部有些研究是关于不可变性，状态隔离，纯函数式编程，还有其他一些编译器方面的工作。现在还没有准备好公开，不过我们正在取得些不错的进展。我相信接下来的几十年间并发会一直是个课题，这里的异步功能是其中的一小步，我肯定还会有更多进展。 &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;提问：&lt;/strong&gt;从反射的视角来说，异步方法和普通方法有什么区别？ &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Anders：&lt;/strong&gt;对于反射来说，异步方法就是普通的方法，调用方法也一样。不过它会在第一个await的地方返回，等异步任务完成之后，它再继续执行下去。所以它其实和普通方法没有任何区别，但如果你要知道它什么时候结束，那么就必须去关注它返回的Task对象了。你还看到我写过一些void方法，可能你根本不会在乎它什么时候结束，不过原理上它还是一样的。 &lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/40.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/40-s.png" /&gt;&lt;/a&gt; 

&lt;p&gt;就到这里，非常感谢各位参与。&lt;/p&gt;

&lt;h1&gt;相关文章&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="http://blog.zhaojie.me/2010/10/pdc2010-the-future-of-csharp-and-vb-by-anders-hejlsberg-1.html"&gt;PDC 2010：C#与Visual Basic的未来（上）&lt;/a&gt;&lt;/li&gt;

  &lt;li&gt;&lt;a href="http://blog.zhaojie.me/2010/10/pdc2010-the-future-of-csharp-and-vb-by-anders-hejlsberg-2.html"&gt;PDC 2010：C#与Visual Basic的未来（中）&lt;/a&gt;&lt;/li&gt;

  &lt;li&gt;PDC 2010：C#与Visual Basic的未来（下） &lt;/li&gt;
&lt;/ul&gt;</description>
      <comments>http://blog.zhaojie.me/2010/11/pdc2010-the-future-of-csharp-and-vb-by-anders-hejlsberg-3.html#comments</comments>
      <pubDate>Mon, 15 Nov 2010 09:47:47 GMT</pubDate>
      <lastBuildDate>Wed, 17 Nov 2010 12:56:01 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/practice/">实践优化</category>
      <category domain="http://blog.zhaojie.me/cutting-edge/">技术尝鲜</category>
      <category domain="http://blog.zhaojie.me/dotnet/">.Net框架</category>
      <title>服务器端执行JavaScript代码</title>
      <link>http://blog.zhaojie.me/2010/11/execute-javascript-at-server.html</link>
      <guid>http://blog.zhaojie.me/2010/11/execute-javascript-at-server.html</guid>
      <description>&lt;p&gt;话说，如今不在客户端使用JavaScript代码才是稀奇事儿。由于Web应用的体验越来越丰富，客户端用JavaScript实现的逻辑也越来越多，这造成的结果就是某些几乎一致的逻辑需要在客户端和服务器端各实现一遍。这违反了DRY原则，不容易维护。幸运的是，我们可以在服务器端执行JavaScript代码，谁让JavaScript傍上了这无比霸道的浏览器平台呢？&lt;/p&gt;

&lt;p&gt;例如，如今在客户端使用JavaScript进行验证已经是个标准，它可以有效避免用户在正常情况下提交错误的数据，增强用户体验。当然，服务器端的验证是必不可少的，因为这才是“安全性”的体现。有些解决方案，会在服务器端提供有限的验证种类，然后在客户端生成JavaScript代码，并辅以服务器端的验证框架。这种做法可以追溯到ASP.NET 1.x上的Validator控件，但这显然会有扩展性，灵活性上的限制，因此我更倾向于在服务器端执行JavaScript代码。&lt;/p&gt;

&lt;p&gt;例如，要检查用户名是否合法，我们可能会写这样的JavaScript代码：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;var &lt;/span&gt;checkName = &lt;span style="color: blue"&gt;function &lt;/span&gt;(name) { &lt;span style="color: blue"&gt;return &lt;/span&gt;/^\w{3,10}$/.test(name); }&lt;/pre&gt;

&lt;p&gt;这在客户端验证自然没有任何问题，服务器端就要借助一些JavaScript执行引擎了。在.NET平台上有例如比较新的&lt;a href="https://github.com/fholm/IronJS"&gt;IronJS&lt;/a&gt;项目，这是个基于DLR的JavaScript执行引擎，十分重视性能，&lt;a href="http://ironjs.com/blog/"&gt;从作者博客&lt;/a&gt;上的评测结果来看，甚至领先于以速度见长的V8。可惜的是，IronJS还没有完整实现ECMAScript 3.0，还缺少一些重要功能，例如正则表达式。&lt;/p&gt;

&lt;p&gt;&lt;a href="http://jint.codeplex.com/"&gt;Jint&lt;/a&gt;是一个.NET平台上较早的JavaScript执行引擎，因此与DLR关系不大，因此可能不太容易与IronPython，IronRuby等语言进行互操作。用它来执行一些简单的JavaScript脚本不成问题，例如上面的代码： &lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;var &lt;/span&gt;jint = &lt;span style="color: blue"&gt;new&lt;/span&gt; Jint.&lt;span style="color: #2b91af"&gt;JintEngine&lt;/span&gt;();
jint.Run(&lt;span style="color: #a31515"&gt;@&amp;quot;var checkName = function(name) { return /^\w{3,10}$/.test(name); }&amp;quot;&lt;/span&gt;);

&lt;span style="color: #2b91af"&gt;Console&lt;/span&gt;.WriteLine(jint.CallFunction(&lt;span style="color: #a31515"&gt;&amp;quot;checkName&amp;quot;&lt;/span&gt;, &lt;span style="color: #a31515"&gt;&amp;quot;jeffz&amp;quot;&lt;/span&gt;)); &lt;span style="color: green"&gt;// True
&lt;/span&gt;&lt;span style="color: #2b91af"&gt;Console&lt;/span&gt;.WriteLine(jint.CallFunction(&lt;span style="color: #a31515"&gt;&amp;quot;checkName&amp;quot;&lt;/span&gt;, &lt;span style="color: #a31515"&gt;&amp;quot;hello world&amp;quot;&lt;/span&gt;)); &lt;span style="color: green"&gt;// False&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;只可惜，在实际使用中，Jint不支持多线程的环境，即我们无法在多个线程下同时调用jint的CallFunction方法，但是如果每次都重新Run一遍JavaScript代码，也会带来较多的性能开销。其实要解决这个问题也并不困难，构造一个对象池即可，.NET 4中提供了并行容器（如ConcurrentStack，ConcurrentQueue），实现一个简单的对象池可谓不费吹灰之力。&lt;/p&gt;

&lt;p&gt;这方面&lt;a href="http://jurassic.codeplex.com/"&gt;Jurassic&lt;/a&gt;的表现要好的多，这是一个构建于.NET 4.0的JavaScript执行引擎：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;var &lt;/span&gt;engine = &lt;span style="color: blue"&gt;new &lt;/span&gt;Jurassic.&lt;span style="color: #2b91af"&gt;ScriptEngine&lt;/span&gt;();
engine.Evaluate(&lt;span style="color: #a31515"&gt;@&amp;quot;var checkName = function(name) { return /^\w{3,10}$/.test(name); }&amp;quot;&lt;/span&gt;);

&lt;span style="color: #2b91af"&gt;Console&lt;/span&gt;.WriteLine(engine.CallGlobalFunction&amp;lt;&lt;span style="color: blue"&gt;bool&lt;/span&gt;&amp;gt;(&lt;span style="color: #a31515"&gt;&amp;quot;checkName&amp;quot;&lt;/span&gt;, &lt;span style="color: #a31515"&gt;&amp;quot;jeffz&amp;quot;&lt;/span&gt;));
&lt;span style="color: #2b91af"&gt;Console&lt;/span&gt;.WriteLine(engine.CallGlobalFunction&amp;lt;&lt;span style="color: blue"&gt;bool&lt;/span&gt;&amp;gt;(&lt;span style="color: #a31515"&gt;&amp;quot;checkName&amp;quot;&lt;/span&gt;, &lt;span style="color: #a31515"&gt;&amp;quot;hello world&amp;quot;&lt;/span&gt;));&lt;/pre&gt;

&lt;p&gt;此外，&lt;a href="http://jurassic.codeplex.com/wikipage?title=Benchmarks&amp;amp;referringTitle=Home"&gt;从Benchmark上来看&lt;/a&gt;，Jurassic性能也比Jint有所提高，但还是远远落后于V8，甚至IE 8里的JavaScript引擎。而且，它还提供了一个基于Silverlight控制台，您可以在浏览器里把玩一番。&lt;/p&gt;

&lt;p&gt;令人感到意外的是，Jint和Jurassic作为JavaScript执行引擎都有一些严重的问题，那便是不能正确运行&lt;a href="http://attacklab.net/showdown/"&gt;showdown.js&lt;/a&gt;（JavaScript实现的Markdown转化器）——虽然我并没有发现showdown.js中有过于复杂的内容，基本就是些字符串操作吧。原本我还想把它们用在mono中，既然如此也就不做进一步尝试了。不过，经过简单的实验，Jurassic似乎使用了mono 2.8中尚不支持的接口，但也有可能只是Jurassic控制台中的问题。&lt;/p&gt;

&lt;p&gt;有趣的是，.NET平台下最靠谱的JavaScript执行引擎居然是&lt;a href="http://www.mozilla.org/rhino/"&gt;Rhino JavaScript&lt;/a&gt;，最近一次发布是在2009年3月，不过实现的十分完整。要说缺点，可能就是使用起来比较麻烦，还有，这是个Java项目。&lt;/p&gt;

&lt;p&gt;嗯，我没有开玩笑，我们完全可以在.NET平台下使用Rhino JavaScript：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;var &lt;/span&gt;cx = &lt;span style="color: #2b91af"&gt;Context&lt;/span&gt;.enter();
&lt;span style="color: blue"&gt;try
&lt;/span&gt;{
    &lt;span style="color: blue"&gt;var &lt;/span&gt;scope = cx.initStandardObjects();
    cx.evaluateString(scope, &lt;span style="color: #a31515"&gt;@&amp;quot;var checkName = function(name) { return /^\w{3,10}$/.test(name); }&amp;quot;&lt;/span&gt;, &lt;span style="color: #a31515"&gt;&amp;quot;checkName.js&amp;quot;&lt;/span&gt;, 1, &lt;span style="color: blue"&gt;null&lt;/span&gt;);
    &lt;span style="color: blue"&gt;var &lt;/span&gt;func = (&lt;span style="color: #2b91af"&gt;Function&lt;/span&gt;)scope.get(&lt;span style="color: #a31515"&gt;&amp;quot;checkName&amp;quot;&lt;/span&gt;, scope);

    &lt;span style="color: #2b91af"&gt;Console&lt;/span&gt;.WriteLine(&lt;span style="color: #2b91af"&gt;Context&lt;/span&gt;.toString(func.call(cx, scope, scope, &lt;span style="color: #a31515"&gt;&amp;quot;jeffz&amp;quot;&lt;/span&gt;)));
    &lt;span style="color: #2b91af"&gt;Console&lt;/span&gt;.WriteLine(&lt;span style="color: #2b91af"&gt;Context&lt;/span&gt;.toString(func.call(cx, scope, scope, &lt;span style="color: #a31515"&gt;&amp;quot;hello world&amp;quot;&lt;/span&gt;));
}
&lt;span style="color: blue"&gt;finally &lt;/span&gt;
{
    &lt;span style="color: #2b91af"&gt;Context&lt;/span&gt;.exit();
}&lt;/pre&gt;

&lt;p&gt;因为我们有&lt;a href="http://www.ikvm.net/"&gt;IKVM.NET&lt;/a&gt;。mono等.NET开源社区上有大量宝藏，就看您能利用多少了。我用ikvmc把js.jar转化为RhinoJs.dll之后就可以直接使用，效果很好，对调试也有很好的支持（如果JavaScript执行时出现了错误，则VS会直接带您至出错的那行）。性能也是比较令人满意的，在我的Mac OSX上安装的Ubuntu Server 10.10虚拟机，单线程转化并过滤博客上最近的3800条评论，大约耗时20秒。试验时Host上还开着一个Windows 7虚拟机，还有大量浏览器等应用程序，并不十分空闲。&lt;/p&gt;

&lt;p&gt;您可能知道，我的博客目前是基于mono 2.6的，其中比较有特色的地方便是评论功能了，我使用Markdown标记，并提供了实时的预览功能，这自然需要在客户端解释Markdown标记，并进行过滤。目前，我还在服务器使用了C#实现的Markdown转化器及过滤逻辑，但在某些特殊情况下结果会有所不同，且需要维护两套代码。不久以后，我会将把博客升级为ASP.NET 4.0及mono 2.8（C# 4.0的dynamic特性在某些情况下的确比较方便），并且在服务器端使用IKVM.NET + Rhino JavaScript执行相同转化代码。从效果上来看还是十分令人满意的。&lt;/p&gt;

&lt;p&gt;值得一提的是，其实在.NET平台上还有一个基于DLR的JavaScript执行引擎，是为&lt;a href="http://www.remobjects.com/script.aspx"&gt;RemObjects Script for .NET&lt;/a&gt;，据称也支持mono。只可惜它并不是开源产品（不过公开了源代码），且&lt;a href="http://code.remobjects.com/p/roscript/page/License/"&gt;授权协议&lt;/a&gt;要求我们最多在5台机器上安装代码，且只供我们自己使用，于是我就没有对它有关注太多了。&lt;/p&gt;</description>
      <comments>http://blog.zhaojie.me/2010/11/execute-javascript-at-server.html#comments</comments>
      <pubDate>Tue, 09 Nov 2010 10:11:28 GMT</pubDate>
      <lastBuildDate>Tue, 09 Nov 2010 10:11:28 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/cutting-edge/">技术尝鲜</category>
      <category domain="http://blog.zhaojie.me/speech/">培训演讲</category>
      <category domain="http://blog.zhaojie.me/translation/">翻译引进</category>
      <title>PDC 2010：C#与Visual Basic的未来（中）</title>
      <link>http://blog.zhaojie.me/2010/10/pdc2010-the-future-of-csharp-and-vb-by-anders-hejlsberg-2.html</link>
      <guid>http://blog.zhaojie.me/2010/10/pdc2010-the-future-of-csharp-and-vb-by-anders-hejlsberg-2.html</guid>
      <description>&lt;p&gt;前几天在PDC 2010会议上Anders Hejlsberg发表了一场名为“The Future of C# and Visual Basic”的演说，谈论了未来C#和VB中最为重要的两个特性：“异步（Async）”及“编译器即服务（Compiler as a Service）”。我现在对这场演讲进行总结，但不会像上次《&lt;a href="http://blog.zhaojie.me/2010/04/trends-and-future-directions-in-programming-languages-by-anders-1-history-and-trends.html"&gt;编程语言的发展趋势及未来方向&lt;/a&gt;》那样逐句翻译，而是以Anders的角度使用一种简捷合适的方式表述其完整内容。上一篇Anders讲述了async和await的使用方式，而这篇则是对这两个关键字的实现及效果作更进一步的解释。&lt;/p&gt;

&lt;a href="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/11.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/11-s.png" /&gt;&lt;/a&gt; 

&lt;p&gt;异步方法的目标，是为了让代码与同步方法保持一致。微软要让代码充斥着回调函数，混乱不堪，它们完全不是逻辑上你想做的事情。可能您的代码中包含着一个核心模型，你也已经实现了，只是您现在想把它的执行过程变得异步化。您自己就可以享受到这一点。&lt;/p&gt;

&lt;p&gt;与我们之前做的一些扩展一样，工作分为语言和框架两部分。语言的异步功能基于框架中的Task&amp;lt;T&amp;gt;，我们会围绕着Task&amp;lt;T&amp;gt;扩展框架，将它作为异步模型的核心。事实上，从Begin/End，或是基于事件的异步模型进行扩展往往只需要一两行封装的代码，于是您也可以得到自己的Task&amp;lt;T&amp;gt;模型。&lt;/p&gt;

&lt;p&gt;而在语言方面，我们添加了两个新的关键字。一个是async关键字，用于把方法标记为异步。还有一个是await方法，用于等待异步工作完成，或者说是把控制权交换给调用方继续执行其他工作。这两个功能在C#和VB种均有体现。&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/12.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/12-s.png" /&gt;&lt;/a&gt; 

&lt;p&gt;那么什么是Task&amp;lt;T&amp;gt;呢？它表现的是一个“后续会继续进行的操作”，这可以是许多东西，Task&amp;lt;T&amp;gt;并不做任何限制，例如是一个异步I/O，后台工作线程等等，甚至可以是UI上的一个按钮，在用户点击之后任务就结束了。&lt;/p&gt;

&lt;p&gt;Task&amp;lt;T&amp;gt;的优势在于，它使用一个对象封装了整个概念，您可以查询其结果或是状态，或是这个任务所引发的异常。您可以用它来构造一个可组合的异步模型，这正式我们目前的异步编程模型所不足的地方。&lt;/p&gt;

&lt;p&gt;此外，它还提供了一个可组合的回调模型，您可以对一个任务指定说，在它结束之后执行另外一段代码，然后还可以对这个新的任务继续进行设定。这便构造出一个完整的逻辑流，框架会自行帮你完成这些工作。事实上await操作符便会自动把您的逻辑改写成这样的代码，它将您从Lambda表达式及回调函数中的逻辑里解放了出来，一切都交给编译器去做了。您可能会有些疑惑，不过其实这些都是编译器所擅长的事情。&lt;/p&gt;

&lt;p&gt;由于我们统一了异步模型，我们就可以在此之上构建组合工具。例如WhenAll，它接受一系列的Task对象，并在全部结束之后返回所有结果。还有WhenAny，则等待第一个完成的任务，返回其结果。我们还有Delay，可以等待一段时间，但不占用任何资源。&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/13.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/13-s.png" /&gt;&lt;/a&gt; 

&lt;p&gt;沿着这个过程走一遍可能就会清晰一些。这里有个例子，一个异步方法调用另一个异步方法。我们假设这是在UI线程上执行的，消息会一个一个发送至UI线程上。&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/14.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/14-s.png" /&gt;&lt;/a&gt; 

&lt;p&gt;好，有人调用了DoWorkAsync，于是出现了一些任务。&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/15-1.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/15-1-s.png" /&gt;&lt;/a&gt; 

&lt;p&gt;DoWorkAsync的第一件事，是调用了ProcessFeedAsync。&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/15-2.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/15-2-s.png" /&gt;&lt;/a&gt; 

&lt;p&gt;ProcessFeedAsync方法是一个异步方法，所以它做的第一件事是构造一个表示任务的Task对象。&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/16.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/16-s.png" /&gt;&lt;/a&gt; 

&lt;p&gt;然后它调用了DownloadFeedAsync，这会创建另一个Task对象。然后，我们遇上了await操作符，这意味着ProcessFeedAsync后面的部分，将作为DownloadFeedAsync完成后的回调函数/continuation里的工作。&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/17.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/17-s.png" /&gt;&lt;/a&gt; 

&lt;p&gt;于是任务返回至DoWorkAsync，我们得到了t1这个对象。&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/18.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/18-s.png" /&gt;&lt;/a&gt; 

&lt;p&gt;同样的过程会再次出现，是为t2。&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/19.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/19-s.png" /&gt;&lt;/a&gt; 

&lt;p&gt;然后便调用了Task.WhenAll，这会创建一个新任务，表示前两个任务全部完成。于是这里的await操作符表示接下去的代码会在前两个任务完成后再继续下去。此时控制权便还给了DoWorkAsync的调用者，不会对线程造成负担。&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/20.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/20-s.png" /&gt;&lt;/a&gt; 

&lt;p&gt;在未来某一时刻t1和t2会执行完，我们假设t2先结束。此时它会说：我完成了，执行回调函数/continuation吧。&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/21.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/21-s.png" /&gt;&lt;/a&gt; 

&lt;p&gt;于是它会和发起线程的SynchronizationContext交互，给UI线程发一个消息，让后续任务在UI线程上继续执行──您的代码不用关注这些。现在代码运行至SaveDocAsync上了，这是另外一个异步任务。await让代码在这里返回，线程又可以执行目前还未结束的任务了。&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/23.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/23-s.png" /&gt;&lt;/a&gt; 

&lt;p&gt;于是SaveDocAsync任务完成了，UI线程又获得了一个消息执行后续工作。&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/24.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/24-s.png" /&gt;&lt;/a&gt; 

&lt;p&gt;此时任务便到达了ProcessFeedAsync的末尾，于是t2任务结束了。&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/27.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/27-s.png" /&gt;&lt;/a&gt; 

&lt;p&gt;继续等待，上面的过程会再次出现，最终t1也结束了。&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/29.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/29-s.png" /&gt;&lt;/a&gt; 

&lt;p&gt;当t1和t2完成以后，最后DoWorkAsync任务也终于结束了。可以看到，我们逻辑流程，无论是循环还是异常捕获都是同步的，但是其中的执行过程完全是异步的。&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/30.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/30-s.png" /&gt;&lt;/a&gt; 

&lt;p&gt;但是这又是如何实现的？我不会在这里说太细，这又是个完整的话题了。这里有一个例子，是一个异步方法，它会调用并await另一个异步方法。&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/31.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/31-s.png" /&gt;&lt;/a&gt; 

&lt;p&gt;而编译器则最终则生成类似于这样的代码。我只会提几点，首先，这是个状态机，编译器构造的其实就是个状态机，例如迭代器就是个状态机，事实上这里编译器的工作和yield之余迭代器的重写本质上没有太大区别。&lt;/p&gt;

&lt;p&gt;其次就是关于任务的执行和等待，假如在等待时任务已经完成了，那么其实您是在同步地执行后续代码。我们没有必要交还控制，反正已经完成了，我们不妨就直接进行下去了。await有自己的模式，会决定这一任务是同步还是异步地执行。对于同步执行的任务，一切就继续执行下去了，直到某个需要异步执行的地方，便把控制权交还给调用方。&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/32.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/32-s.png" /&gt;&lt;/a&gt; 

&lt;p&gt;那么我们再来看一下异步之于Web服务的意义。这里有个ASP.NET页面，它会向数据库里获取许多RSS地址，然后下载到本地并解析：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;private void &lt;/span&gt;ProcessData()
{
    &lt;span style="color: green"&gt;// ...

    &lt;/span&gt;&lt;span style="color: blue"&gt;var &lt;/span&gt;urls = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: blue"&gt;string&lt;/span&gt;&amp;gt;();
    &lt;span style="color: blue"&gt;using &lt;/span&gt;(&lt;span style="color: blue"&gt;var &lt;/span&gt;conn = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;SqlConnection&lt;/span&gt;(connectionString))
    {
        conn.Open();
        &lt;span style="color: blue"&gt;var &lt;/span&gt;cmd = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;SqlCommand&lt;/span&gt;(&lt;span style="color: #a31515"&gt;&amp;quot;GetUserFeeds&amp;quot;&lt;/span&gt;, conn);
        cmd.CommandType = &lt;span style="color: #2b91af"&gt;CommandType&lt;/span&gt;.StoredProcedure;
        cmd.Parameters.AddWithValue(&lt;span style="color: #a31515"&gt;&amp;quot;@UserID&amp;quot;&lt;/span&gt;, user);
        &lt;span style="color: blue"&gt;using &lt;/span&gt;(&lt;span style="color: blue"&gt;var &lt;/span&gt;reader = cmd.ExecuteReader())
        {
            &lt;span style="color: blue"&gt;while &lt;/span&gt;(reader.Read()) urls.Add(reader[&lt;span style="color: #a31515"&gt;&amp;quot;FeedURL&amp;quot;&lt;/span&gt;].ToString());
        }
    }

    &lt;span style="color: blue"&gt;var &lt;/span&gt;feeds = (&lt;span style="color: blue"&gt;from &lt;/span&gt;url &lt;span style="color: blue"&gt;in &lt;/span&gt;urls &lt;span style="color: blue"&gt;select &lt;/span&gt;CreateWebClient().DownloadString(url)).ToArray();

    &lt;span style="color: green"&gt;// ...
&lt;/span&gt;}&lt;/pre&gt;

&lt;p&gt;这里用到了DownloadString这个同步下载数据的方法。执行下来大约要花费1秒多的时间。这里我不再演示令人痛苦的异步写法了，你必须在Page_Load和Page_PreRender各写一些逻辑，注册一些异步工作，或者就要启用一些后台线程，但这又会影响后台的线程池，对系统的表现会带来影响。&lt;/p&gt;

&lt;p&gt;现在我来演示一些简单的异步化工作：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;private &lt;span style="background-color: #ffff00"&gt;async&lt;/span&gt; void &lt;/span&gt;ProcessData()
{
    &lt;span style="color: green"&gt;// ...

    &lt;/span&gt;&lt;span style="color: blue"&gt;var &lt;/span&gt;urls = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: blue"&gt;string&lt;/span&gt;&amp;gt;();
    &lt;span style="color: blue"&gt;using &lt;/span&gt;(&lt;span style="color: blue"&gt;var &lt;/span&gt;conn = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;SqlConnection&lt;/span&gt;(connectionString))
    {
        conn.Open();
        &lt;span style="color: blue"&gt;var &lt;/span&gt;cmd = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;SqlCommand&lt;/span&gt;(&lt;span style="color: #a31515"&gt;&amp;quot;GetUserFeeds&amp;quot;&lt;/span&gt;, conn);
        cmd.CommandType = &lt;span style="color: #2b91af"&gt;CommandType&lt;/span&gt;.StoredProcedure;
        cmd.Parameters.AddWithValue(&lt;span style="color: #a31515"&gt;&amp;quot;@UserID&amp;quot;&lt;/span&gt;, user);
        &lt;span style="color: blue"&gt;using &lt;/span&gt;(&lt;span style="color: blue"&gt;var &lt;/span&gt;reader = &lt;span style="background-color: #ffff00"&gt;&lt;span style="color: blue"&gt;await &lt;/span&gt;cmd.ExecuteReaderAsync()&lt;/span&gt;)
        {
            &lt;span style="color: blue"&gt;while &lt;/span&gt;(reader.Read()) urls.Add(reader[&lt;span style="color: #a31515"&gt;&amp;quot;FeedURL&amp;quot;&lt;/span&gt;].ToString());
        }
    }

    &lt;span style="color: blue"&gt;var &lt;/span&gt;feeds = &lt;span style="background-color: #ffff00"&gt;&lt;span style="color: blue"&gt;await &lt;/span&gt;&lt;span style="color: #2b91af"&gt;TaskEx&lt;/span&gt;.WhenAll&lt;/span&gt;(
        &lt;span style="color: blue"&gt;from &lt;/span&gt;url &lt;span style="color: blue"&gt;in &lt;/span&gt;urls &lt;span style="color: blue"&gt;select &lt;/span&gt;CreateWebClient().&lt;span style="background-color: #ffff00"&gt;DownloadStringTaskAsync&lt;/span&gt;(url));

    &lt;span style="color: green"&gt;// ...
&lt;/span&gt;}&lt;/pre&gt;

&lt;p&gt;我们将DownloadString修改为DownloadStringTaskAsync，这样LINQ返回的就是一系列表示下载任务的Task对象，然后使用await及WhenAll等待它们全部完成。数据库查询也可以如此。这就是所有我们要做的事情。如今页面的执行效率有了很明显的提高。使用这个做法，我们可以很轻松地提高Web系统的伸缩能力。如今我们需要调用很多互相独立的服务的情况越来越多了，异步方法对此有很大帮助。&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/33.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/33-s.png" /&gt;&lt;/a&gt; 

&lt;p&gt;如今的异步场景有许多种，例如在后台执行一个计算任务，这是基于CPU的异步，还有基于网络或I/O的异步任务。这些都能用Task来表示出来，因为Task表示的就是未来会完成的异步任务。此外，有了async和.NET框架，我们则出现了另外一种任务，既基于某些任务组合而成的异步任务。这也就是async方法所体现出的异步任务，它可以让你使用传统的语句来构造异步执行过程。&lt;/p&gt;

&lt;p&gt;例如有这么一个场景：获取链接，根据链接下载Youtube视频，根据下载到的视频创建mashup并组合起来。在执行这些工作的时候，我们也希望UI可以响应用户操作。&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/34.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/34-s.png" /&gt;&lt;/a&gt; 

&lt;p&gt;而要完成这些工作，代码可能只需要这么简单，完全就像同步代码一样。而这里也体现了多种异步任务：ScrapeYoutubeAsync是网络密集型任务，然后同时下载两个视频并等待它们结束。然后MashupVideosAsync是CPU密集型任务，然后最后则是I/O密集型的的SaveAsync操作。对于异常处理来说，我们可以简捷地使用一个try...catch，就像传统编程那样。&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/35.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/35-s.png" /&gt;&lt;/a&gt; 

&lt;p&gt;总结一下，一个异步方法可以让代码和同步实现一样简单，并统一了计算、网络及I/O的异步化。这可以用来创建高度伸缩的服务器程序，自然还有响应度高的UI程序。&lt;/p&gt;

&lt;p&gt;在演讲的末尾，我会给出Visual Studio Async CTP的下载链接，我很乐于得到大家的反馈。&lt;/p&gt;

&lt;h1&gt;相关文章 &lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="http://blog.zhaojie.me/2010/10/pdc2010-the-future-of-csharp-and-vb-by-anders-hejlsberg-1.html"&gt;PDC 2010：C#与Visual Basic的未来（上）&lt;/a&gt;&lt;/li&gt;

  &lt;li&gt;PDC 2010：C#与Visual Basic的未来（中）&lt;/li&gt;

  &lt;li&gt;&lt;a href="http://blog.zhaojie.me/2010/11/pdc2010-the-future-of-csharp-and-vb-by-anders-hejlsberg-3.html"&gt;PDC 2010：C#与Visual Basic的未来（下）&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <comments>http://blog.zhaojie.me/2010/10/pdc2010-the-future-of-csharp-and-vb-by-anders-hejlsberg-2.html#comments</comments>
      <pubDate>Sun, 31 Oct 2010 13:49:48 GMT</pubDate>
      <lastBuildDate>Wed, 17 Nov 2010 12:55:19 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/cutting-edge/">技术尝鲜</category>
      <category domain="http://blog.zhaojie.me/speech/">培训演讲</category>
      <category domain="http://blog.zhaojie.me/translation/">翻译引进</category>
      <title>PDC 2010：C#与Visual Basic的未来（上）</title>
      <link>http://blog.zhaojie.me/2010/10/pdc2010-the-future-of-csharp-and-vb-by-anders-hejlsberg-1.html</link>
      <guid>http://blog.zhaojie.me/2010/10/pdc2010-the-future-of-csharp-and-vb-by-anders-hejlsberg-1.html</guid>
      <description>&lt;a href="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/01.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/01-s.png" /&gt;&lt;/a&gt; 

&lt;p&gt;PDC不愧为微软最高级的技术人员专业会议，看得我直呼过瘾。前几天在PDC 2010会议上Anders Hejlsberg发表了一场名为“The Future of C# and Visual Basic”的演说，谈论了未来C#和VB中最为重要的两个特性：“异步（Async）”及“编译器即服务（Compiler as a Service）”。我现在对这场演讲进行总结，但不会像上次《&lt;a href="http://blog.zhaojie.me/2010/04/trends-and-future-directions-in-programming-languages-by-anders-1-history-and-trends.html"&gt;编程语言的发展趋势及未来方向&lt;/a&gt;》那样逐句翻译，而是以Anders的角度使用一种简捷合适的方式表述其完整内容。&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/02.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/02-s.png" /&gt;&lt;/a&gt; 

&lt;p&gt;在2000年的PDC上，我们给大家带来了一个全新的平台“.NET”，以及一个语言“C#”。.NET与C#每次发布时都有一个“主题”，一开始是“托管代码”，接着是“泛型”，然后是“LINQ”，直到最近的“动态性”，这就是C#和VB的演变过程。这两种语言面向的用户比较相近，微软也承诺会同时发展两种语言。因此这个演讲虽然以C#作为主题，但其实也会在VB中得以体现。&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/03.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/03-s.png" /&gt;&lt;/a&gt; 

&lt;p&gt;作为语言的设计者，要设法将工业界所重视的内容，使用语言表现出来，因此也有了这样的分类。“声明式”代表了一种编程的趋势，尽可能表现出“做什么”而不是“怎么做”，于是有了函数式编程与DSL等等。然后，目前研究的热门之一则是动态语言，如Python，Ruby，JavaScript等等，以及它们是如何影响静态语言的。还有便是“并发”，这里所指的广义的“并发”，包括单机上多核以及云或是数据中心上分布式系统等等，也就是各种“同时处理”的方式。&lt;/p&gt;

&lt;p&gt;我们可以清楚地看到，C# 3.0和VB 9中的函数式编程，LINQ等特性体现了“声明式”，而C# 4.0和VB 10则出现了动态性，但都没有太多关于“并发”的成分在里面──它都体现在框架中了，例如.NET 4包含了任务并行库（Task Parallel Library），但对于语言来说，除了lock似乎就没有什么这方面的支持了。&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/04.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/04-s.png" /&gt;&lt;/a&gt; 

&lt;p&gt;如今对“并发”的需求已经是毋庸质疑的，很少有一个应用程序或是服务不需要连接外部系统。这种与外部系统，例如互联网进行交互的行为则增加了应用程序的延迟，这可能导致UI在和外部服务交互时长时间失去响应。而对于一个数据中心的服务，您可能就会发现CPU的利用率不高，因为系统都在等待其他服务的回复了。 &lt;/p&gt;

&lt;p&gt;为了解决这个问题，我们往往会使用“异步”的编程方式，它逐渐已经成为“高响应度”，“高伸缩性”的代名词了。此外还有一些API只提供了异步的版本，例如在JavaScript中发起HTTP请求，或是Silverlight的网络交互方面。这种情况以后只会越来越普遍。&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/05.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/05-s.png" /&gt;&lt;/a&gt; 

&lt;p&gt;于是下一版本的C#和VB就会在这里有所行动，目前会展示一下我们的早期工作，希望可以得到一些反馈。&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/06.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/06-s.png" /&gt;&lt;/a&gt; 

&lt;p&gt;说到异步化，您可以简单认为“一起运行”。一个同步方法，好比DownloadString，应用程序会执行这个方法，并等待结果返回，但是你不能把工作的执行过程与结果的送达区分开来。而对于异步编程来说，DownloadStringAsync在调用之后便会立即返回，过了一段时间，结果就会传递过来，于是执行过程和结果的送达便完全是可分离的了。而对于如今典型的异步模型来说，结果通过一个回调函数传递过来。 &lt;/p&gt;

&lt;p&gt;异步化可以的得到高度的响应能力，因为在等待任务的结果时我们可以做其他一些事情。而对于服务器来说，异步可以带来很好的伸缩性，因为线程得到释放了，而不需要等待请求返回结果。&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/07.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/07-s.png" /&gt;&lt;/a&gt; 

&lt;p&gt;通过图示可以更清楚地了解这点。例如有段代码叫做DownloadData，调用以后可以得到一些数据。在执行时，线程会有长时间的终止，它被阻塞了，要等到结果返回之后才能继续处理数据。与此相对的是其异步的版本，我们调用DownloadDataAsync方法之后，它立即将控制权交还给我们，过了一段时间，它会把结果传递给回调函数，让我们继续处理下去。但是在DownloadData和ProcessData之间，我们可以处理其他一些工作。如果这是UI线程，那么就可以用于响应其他用户操作。如果这是个服务器线程，那么在等待结果时这个线程可以用来处理其他请求。&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/08.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/08-s.png" /&gt;&lt;/a&gt; 

&lt;p&gt;那么，如果我们要执行多个请求，例如要调用两遍，对于同步的版本就会获得双倍的阻塞，即便两个请求是完全独立的。而在异步的情况下，我们可以快速地发出两个请求，这样便形成的并发，即便这里并没有使用额外的线程。于是便可以更快地得到结果，也能保证响应能力。&lt;/p&gt;

&lt;p&gt;有人可能会说，我们可以利用后台线程来得到响应。没错，不过就引入了多线程模型，于是就要处理同步等线程安全问题。而且，在开发带有UI的应用程序时，我们不能在后台线程里操作UI，这样又出现了其他的复杂情况。而在服务器应用中，我们又不希望创建更多的线程，因为这会给线程池带来压力，线程之间会有竞争，就会降低请求的处理能力。&lt;/p&gt;

&lt;p&gt;以上便是对异步编程的概述，您可能会问，既然异步有那么多好处，那么为什么不把所有的应用程序都写作异步的呢？那么现在我们就来看一下异步编程大概是什么样子的。&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/09.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/09-s.png" /&gt;&lt;/a&gt; 

&lt;p&gt;这里有个简单的应用程序，输入年份，可以下载到那一年的电影。现在这个程序是同步的写法。在搜索的时候UI会失去响应，这样的结果显然无法令人接受，我们要做的更好。我们可以将其改写为异步的形式。 &lt;/p&gt;

&lt;p&gt;同步的写法是这样的：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;private void &lt;/span&gt;searchButton_Click(&lt;span style="color: blue"&gt;object &lt;/span&gt;sender, &lt;span style="color: #2b91af"&gt;RoutedEventArgs &lt;/span&gt;e)
{
    LoadMovies(&lt;span style="color: #2b91af"&gt;Int32&lt;/span&gt;.Parse(textBox.Text));
}

&lt;span style="color: blue"&gt;void &lt;/span&gt;LoadMovies(&lt;span style="color: blue"&gt;int &lt;/span&gt;year)
{
    resultsPanel.Children.Clear();
    statusText.Text = &lt;span style="color: #a31515"&gt;&amp;quot;&amp;quot;&lt;/span&gt;;
    &lt;span style="color: blue"&gt;var &lt;/span&gt;pageSize = 10;
    &lt;span style="color: blue"&gt;var &lt;/span&gt;imageCount = 0;

    &lt;span style="color: blue"&gt;while &lt;/span&gt;(&lt;span style="color: blue"&gt;true&lt;/span&gt;)
    {
        &lt;span style="color: blue"&gt;var &lt;/span&gt;movies = QueryMovies(year, imageCount, pageSize);
        &lt;span style="color: blue"&gt;if &lt;/span&gt;(movies.Length == 0) &lt;span style="color: blue"&gt;break&lt;/span&gt;;
        DisplayMovies(movies);
        imageCount += movies.Length;
    }

    statusText.Text = &lt;span style="color: #2b91af"&gt;String&lt;/span&gt;.Format(&lt;span style="color: #a31515"&gt;&amp;quot;{0} Titles&amp;quot;&lt;/span&gt;, imageCount);
}

&lt;span style="color: #2b91af"&gt;Movie&lt;/span&gt;[] QueryMovies(&lt;span style="color: blue"&gt;int &lt;/span&gt;year, &lt;span style="color: blue"&gt;int &lt;/span&gt;first, &lt;span style="color: blue"&gt;int &lt;/span&gt;count)
{
    &lt;span style="color: blue"&gt;var &lt;/span&gt;client = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;WebClient&lt;/span&gt;();
    &lt;span style="color: blue"&gt;var &lt;/span&gt;url = &lt;span style="color: #2b91af"&gt;String&lt;/span&gt;.Format(query, year, first, count);
    &lt;span style="color: blue"&gt;var &lt;/span&gt;data = client.DownloadString(&lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Uri&lt;/span&gt;(url));

    &lt;span style="color: blue"&gt;var &lt;/span&gt;movies =
        &lt;span style="color: blue"&gt;from &lt;/span&gt;entry &lt;span style="color: blue"&gt;in &lt;/span&gt;&lt;span style="color: #2b91af"&gt;XDocument&lt;/span&gt;.Parse(data).Desendanies(xs + &lt;span style="color: #a31515"&gt;&amp;quot;entry&amp;quot;&lt;/span&gt;)
        &lt;span style="color: blue"&gt;let &lt;/span&gt;properties = entry.Element(xm + &lt;span style="color: #a31515"&gt;&amp;quot;properties&amp;quot;&lt;/span&gt;)
        &lt;span style="color: blue"&gt;select new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Movie
        &lt;/span&gt;{
            &lt;span style="color: green"&gt;/* ... */
        &lt;/span&gt;};

    &lt;span style="color: blue"&gt;return &lt;/span&gt;movies.ToArray();
}&lt;/pre&gt;

&lt;p&gt;在点击按钮以后会调用LoadMovies方法，它会在一个循环中不断使用QueryMovies方法进行查询，在QueryMovies方法中我们使用WebClient下载一个XML，解析，构造Movie对象并返回，最终呈现在界面上。&lt;/p&gt;

&lt;p&gt;下载时我们使用DownloadString方法，这是个同步方法，我们要把它修改成异步的方式。事实上还真有个异步的方法，叫做DownloadStringAsync，不过这就需要我们修改代码，例如要把QueryMovies中的大部分放入DownloadStringCompleted事件的处理函数中。同时，异步编程的痛苦慢慢体现出现了，我们无法返回数据，而必须传递到某个地方，于是QueryMovies方法则要返回void，并接受一个回调函数。&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;void &lt;/span&gt;QueryMovies(&lt;span style="color: blue"&gt;int &lt;/span&gt;year, &lt;span style="color: blue"&gt;int &lt;/span&gt;first, &lt;span style="color: blue"&gt;int &lt;/span&gt;count, &lt;span style="color: #2b91af"&gt;Action&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;Movie&lt;/span&gt;[]&amp;gt; action)
{
    &lt;span style="color: blue"&gt;var &lt;/span&gt;client = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;WebClient&lt;/span&gt;();
    &lt;span style="color: blue"&gt;var &lt;/span&gt;url = &lt;span style="color: #2b91af"&gt;String&lt;/span&gt;.Format(query, year, first, count);

    client.DownloadStringCompleted += (sender, e) =&amp;gt;
    {
        &lt;span style="color: blue"&gt;var &lt;/span&gt;data = e.Result;
        &lt;span style="color: blue"&gt;var &lt;/span&gt;movies =
            &lt;span style="color: blue"&gt;from &lt;/span&gt;entry &lt;span style="color: blue"&gt;in &lt;/span&gt;&lt;span style="color: #2b91af"&gt;XDocument&lt;/span&gt;.Parse(data).Descendants(xs + &lt;span style="color: #a31515"&gt;&amp;quot;entry&amp;quot;&lt;/span&gt;)
            &lt;span style="color: blue"&gt;let &lt;/span&gt;properties = entry.Element(xm + &lt;span style="color: #a31515"&gt;&amp;quot;properties&amp;quot;&lt;/span&gt;)
            &lt;span style="color: blue"&gt;select new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Movie
            &lt;/span&gt;{
                &lt;span style="color: green"&gt;/* ... */
            &lt;/span&gt;};

        action(movies.ToArray());
    };

    client.DownloadStringAsync(&lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Uri&lt;/span&gt;(url));
}&lt;/pre&gt;

&lt;p&gt;然后我们还需要处理QueryMovies的调用者，这里实在麻烦到家了，因为我们使用了一个while循环来查询电影，那么我们又该如何反复调用一个异步方法？&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;void &lt;/span&gt;LoadMovies(&lt;span style="color: blue"&gt;int &lt;/span&gt;year)
{
    resultsPanel.Children.Clear();
    statusText.Text = &lt;span style="color: #a31515"&gt;&amp;quot;&amp;quot;&lt;/span&gt;;
    &lt;span style="color: blue"&gt;var &lt;/span&gt;pageSize = 10;
    &lt;span style="color: blue"&gt;var &lt;/span&gt;imageCount = 0;

    &lt;span style="color: #2b91af"&gt;Action&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;Movie&lt;/span&gt;[]&amp;gt; action = &lt;span style="color: blue"&gt;null&lt;/span&gt;;
    action = movies =&amp;gt;
    {
        &lt;span style="color: blue"&gt;if &lt;/span&gt;(movie.Length &amp;gt; 0)
        {
            DisplayMovie(movies);
            imageCount += movies.Length;
            QueryMovies(year, imageCount, pageSize, action);
        }
        &lt;span style="color: blue"&gt;else
        &lt;/span&gt;{
            statusText.Text = &lt;span style="color: #2b91af"&gt;String&lt;/span&gt;.Format(&lt;span style="color: #a31515"&gt;&amp;quot;{0} Titles&amp;quot;&lt;/span&gt;, imageCount);
        }
    };

    QueryMovies(year, imageCount, pageSize, action);
}&lt;/pre&gt;

&lt;p&gt;你一定已经发现了，现在的代码已经很难让人保持愉快了。不过它的确是异步的了，运行时界面响应良好。效果是有了，不过这代码变得乱七八糟。想象一下，如果要加上异常处理该怎么做？我们可能要提供两个回调函数，一个处理正常情况，一个处理错误，还到处需要有try...catch，很快麻烦就会接踵而来了。如果不想面对这些麻烦，你可能就要去启用后台线程，这样又有了线程方面的问题。 &lt;/p&gt;

&lt;p&gt;显然我们可以做的更好。首先让我们回到原来的同步代码，然后再用上我们为异步编程设计的新特性。&lt;/p&gt;

&lt;p&gt;如果要把QueryMovies变为异步，则先把它的返回值改为Task&amp;lt;Movie[]&amp;gt;，你如果了解.NET 4则一定已经知道这个类型是任务并行库的一部分。事实上Task类型只是表示一个“开始计算并在未来返回结果”的任务，因此Task&amp;lt;T&amp;gt;表示一个会在将来返回T类型的计算任务，在科学计算领域这通常被称为Future或是Promise。现在方法的返回值是Task&amp;lt;Movie[]&amp;gt;，而最后返回的是Movie[]，这显然不匹配，但我们可以将其标记为一个async方法。对于async方法，编译器会重写整个方法实现来表示一个异步任务，以后我们会来观察它是如何实现这点的。&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;&lt;span style="background-color: #ffff00"&gt;async&lt;/span&gt; &lt;/span&gt;&lt;span style="background-color: #ffff00"&gt;&lt;span style="color: #2b91af"&gt;Task&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;Movie&lt;/span&gt;[]&amp;gt;&lt;/span&gt; QueryMoviesAsync(&lt;span style="color: blue"&gt;int &lt;/span&gt;year, &lt;span style="color: blue"&gt;int &lt;/span&gt;first, &lt;span style="color: blue"&gt;int &lt;/span&gt;count)
{
    &lt;span style="color: blue"&gt;var &lt;/span&gt;client = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;WebClient&lt;/span&gt;();
    &lt;span style="color: blue"&gt;var &lt;/span&gt;url = &lt;span style="color: #2b91af"&gt;String&lt;/span&gt;.Format(query, year, first, count);
    &lt;span style="color: blue"&gt;var &lt;/span&gt;data = client.DownloadString(&lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Uri&lt;/span&gt;(url));

    &lt;span style="color: blue"&gt;var &lt;/span&gt;movies =
        &lt;span style="color: blue"&gt;from &lt;/span&gt;entry &lt;span style="color: blue"&gt;in &lt;/span&gt;&lt;span style="color: #2b91af"&gt;XDocument&lt;/span&gt;.Parse(data).Descendants(xs + &lt;span style="color: #a31515"&gt;&amp;quot;entry&amp;quot;&lt;/span&gt;)
        &lt;span style="color: blue"&gt;let &lt;/span&gt;properties = entry.Element(xm + &lt;span style="color: #a31515"&gt;&amp;quot;properties&amp;quot;&lt;/span&gt;)
        &lt;span style="color: blue"&gt;select new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Movie
        &lt;/span&gt;{
            &lt;span style="color: green"&gt;/* ... */
        &lt;/span&gt;};

    &lt;span style="color: blue"&gt;return &lt;/span&gt;movies.ToArray();
}&lt;/pre&gt;

&lt;p&gt;不过只做到这点还不够，我们的方法还没有异步化，这还是个同步任务。不过，如今在一个async方法中，我们有能力组合调用另一个async方法，并异步地等待。这里使用了一个扩展方法DownloadStringTaskAsync，以后也会包含在框架中。这个方法返回Task&amp;lt;string&amp;gt;类型，表示未来某一时刻将会得到一个string对象。于是在async方法中，我们使用一个新的await操作符来等待其返回。&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;async &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Task&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;Movie&lt;/span&gt;[]&amp;gt; QueryMoviesAsync(&lt;span style="color: blue"&gt;int &lt;/span&gt;year, &lt;span style="color: blue"&gt;int &lt;/span&gt;first, &lt;span style="color: blue"&gt;int &lt;/span&gt;count)
{
    &lt;span style="color: blue"&gt;var &lt;/span&gt;client = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;WebClient&lt;/span&gt;();
    &lt;span style="color: blue"&gt;var &lt;/span&gt;url = &lt;span style="color: #2b91af"&gt;String&lt;/span&gt;.Format(query, year, first, count);
    &lt;span style="color: blue"&gt;var &lt;/span&gt;data = &lt;span style="color: blue"&gt;&lt;span style="background-color: #ffff00"&gt;await&lt;/span&gt; &lt;/span&gt;client.&lt;span style="background-color: #ffff00"&gt;DownloadStringTaskAsync&lt;/span&gt;(&lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Uri&lt;/span&gt;(url));

    &lt;span style="color: blue"&gt;var &lt;/span&gt;movies =
        &lt;span style="color: blue"&gt;from &lt;/span&gt;entry &lt;span style="color: blue"&gt;in &lt;/span&gt;&lt;span style="color: #2b91af"&gt;XDocument&lt;/span&gt;.Parse(data).Descendants(xs + &lt;span style="color: #a31515"&gt;&amp;quot;entry&amp;quot;&lt;/span&gt;)
        &lt;span style="color: blue"&gt;let &lt;/span&gt;properties = entry.Element(xm + &lt;span style="color: #a31515"&gt;&amp;quot;properties&amp;quot;&lt;/span&gt;)
        &lt;span style="color: blue"&gt;select new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Movie
        &lt;/span&gt;{
            &lt;span style="color: green"&gt;/* ... */
        &lt;/span&gt;};

    &lt;span style="color: blue"&gt;return &lt;/span&gt;movies.ToArray();
}&lt;/pre&gt;

&lt;p&gt;在执行时，方法会执行到await操作符这里，并确保接下来的代码是在一个回调函数/continuation中执行的。编译器会在这里重写这个方法，就像为yield重写迭代器那样，于是我们就不需要做其他事情了，任务结束后自然会执行await后面的代码。&lt;/p&gt;

&lt;p&gt;这里的美妙之处在于可以任意组合，对于LoadMovies方法来说，我们也可以将其转化为async方法，并await之前的QueryMoviesAsync方法返回。&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;&lt;span style="background-color: #ffff00"&gt;async&lt;/span&gt; void &lt;/span&gt;LoadMoviesAsync(&lt;span style="color: blue"&gt;int &lt;/span&gt;year)
{
    resultsPanel.Children.Clear();
    statusText.Text = &lt;span style="color: #a31515"&gt;&amp;quot;&amp;quot;&lt;/span&gt;;
    &lt;span style="color: blue"&gt;var &lt;/span&gt;pageSize = 10;
    &lt;span style="color: blue"&gt;var &lt;/span&gt;imageCount = 0;

    &lt;span style="color: blue"&gt;while &lt;/span&gt;(&lt;span style="color: blue"&gt;true&lt;/span&gt;)
    {
        &lt;span style="color: blue"&gt;var &lt;/span&gt;movies = &lt;span style="color: blue"&gt;&lt;span style="background-color: #ffff00"&gt;await&lt;/span&gt; &lt;/span&gt;QueryMoviesAsync(year, imageCount, pageSize);
        &lt;span style="color: blue"&gt;if &lt;/span&gt;(movies.Length == 0) &lt;span style="color: blue"&gt;break&lt;/span&gt;;
        DisplayMovies(movies);
        imageCount += movies.Length;
    }

    statusText.Text = &lt;span style="color: #2b91af"&gt;String&lt;/span&gt;.Format(&lt;span style="color: #a31515"&gt;&amp;quot;{0} Titles&amp;quot;&lt;/span&gt;, imageCount);
}&lt;/pre&gt;

&lt;p&gt;于是异步实现就这么完成了，代码和之前几乎完全一致。您可以看出，这使得我们在执行异步代码时保留原本的逻辑实现。&lt;/p&gt;

&lt;p&gt;那么再为应用程序添加一点功能吧。首先是异常处理：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;async void &lt;/span&gt;LoadMoviesAsync(&lt;span style="color: blue"&gt;int &lt;/span&gt;year)
{
    resultsPanel.Children.Clear();
    statusText.Text = &lt;span style="color: #a31515"&gt;&amp;quot;&amp;quot;&lt;/span&gt;;
    &lt;span style="color: blue"&gt;var &lt;/span&gt;pageSize = 10;
    &lt;span style="color: blue"&gt;var &lt;/span&gt;imageCount = 0;

    &lt;span style="color: blue"&gt;try
    &lt;/span&gt;{
        &lt;span style="color: blue"&gt;while &lt;/span&gt;(&lt;span style="color: blue"&gt;true&lt;/span&gt;)
        {
            &lt;span style="color: blue"&gt;var &lt;/span&gt;movies = &lt;span style="color: blue"&gt;await &lt;/span&gt;QueryMoviesAsync(year, imageCount, pageSize);
            &lt;span style="color: blue"&gt;if &lt;/span&gt;(movies.Length == 0) &lt;span style="color: blue"&gt;break&lt;/span&gt;;
            DisplayMovies(movies);
            imageCount += movies.Length;
        }

        statusText.Text = &lt;span style="color: #2b91af"&gt;String&lt;/span&gt;.Format(&lt;span style="color: #a31515"&gt;&amp;quot;{0} Titles&amp;quot;&lt;/span&gt;, imageCount);
    }
    &lt;span style="color: blue"&gt;catch &lt;/span&gt;(&lt;span style="color: #2b91af"&gt;XmlException&lt;/span&gt;)
    {
        statusText.Text = &lt;span style="color: #a31515"&gt;&amp;quot;Data Error&amp;quot;&lt;/span&gt;;
    }
}&lt;/pre&gt;

&lt;p&gt;我们无需分离代码或是逻辑，这一切都和同步代码完全一致。再来看看“取消（cancellation）”，对于async方法来说，我们可以传递一个CancellationToken，表示任务需要监听这个对象的改变。如QueryMoviesAsync便可以增加一个参数：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;async &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Task&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;Movie&lt;/span&gt;[]&amp;gt; QueryMoviesAsync(&lt;span style="color: blue"&gt;int &lt;/span&gt;year, &lt;span style="color: blue"&gt;int &lt;/span&gt;first, &lt;span style="color: blue"&gt;int &lt;/span&gt;count, &lt;span style="background-color: #ffff00"&gt;&lt;span style="color: #2b91af"&gt;CancellationToken &lt;/span&gt;ct&lt;/span&gt;)
{
    &lt;span style="color: blue"&gt;var &lt;/span&gt;client = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;WebClient&lt;/span&gt;();
    &lt;span style="color: blue"&gt;var &lt;/span&gt;url = &lt;span style="color: #2b91af"&gt;String&lt;/span&gt;.Format(query, year, first, count);
    &lt;span style="color: blue"&gt;var &lt;/span&gt;data = &lt;span style="color: blue"&gt;await &lt;/span&gt;client.DownloadStringTaskAsync(&lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Uri&lt;/span&gt;(url), &lt;span style="background-color: #ffff00"&gt;ct&lt;/span&gt;);

    &lt;span style="color: blue"&gt;var &lt;/span&gt;movies =
        &lt;span style="color: blue"&gt;from &lt;/span&gt;entry &lt;span style="color: blue"&gt;in &lt;/span&gt;&lt;span style="color: #2b91af"&gt;XDocument&lt;/span&gt;.Parse(data).Descendants(xs + &lt;span style="color: #a31515"&gt;&amp;quot;entry&amp;quot;&lt;/span&gt;)
        &lt;span style="color: blue"&gt;let &lt;/span&gt;properties = entry.Element(xm + &lt;span style="color: #a31515"&gt;&amp;quot;properties&amp;quot;&lt;/span&gt;)
        &lt;span style="color: blue"&gt;select new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Movie
        &lt;/span&gt;{
            &lt;span style="color: green"&gt;/* ... */
        &lt;/span&gt;};

    &lt;span style="color: blue"&gt;return &lt;/span&gt;movies.ToArray();
}&lt;/pre&gt;

&lt;p&gt;这样便得到了一个可取消的async方法。对于逻辑流来说，取消操作就相当于一个异常，代码里需要处理一个TaskCanceledException：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="background-color: #ffff00"&gt;&lt;span style="color: #2b91af"&gt;CancellationTokenSource&lt;/span&gt; cts;&lt;/span&gt;

&lt;span style="color: blue"&gt;async &lt;/span&gt;&lt;span style="color: blue"&gt;void &lt;/span&gt;LoadMoviesAsync(&lt;span style="color: blue"&gt;int &lt;/span&gt;year)
{
    resultsPanel.Children.Clear();
    statusText.Text = &lt;span style="color: #a31515"&gt;&amp;quot;&amp;quot;&lt;/span&gt;;
    &lt;span style="color: blue"&gt;var &lt;/span&gt;pageSize = 10;
    &lt;span style="color: blue"&gt;var &lt;/span&gt;imageCount = 0;

    &lt;span style="background-color: #ffff00"&gt;cts = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;CancellationTokenSource&lt;/span&gt;();&lt;/span&gt;
    &lt;span style="color: blue"&gt;try
    &lt;/span&gt;{
        &lt;span style="color: blue"&gt;while &lt;/span&gt;(&lt;span style="color: blue"&gt;true&lt;/span&gt;)
        {
            &lt;span style="color: blue"&gt;var &lt;/span&gt;movies = &lt;span style="color: blue"&gt;await &lt;/span&gt;QueryMoviesAsync(year, imageCount, pageSize, &lt;span style="background-color: #ffff00"&gt;cts.Token&lt;/span&gt;);
            &lt;span style="color: blue"&gt;if &lt;/span&gt;(movies.Length == 0) &lt;span style="color: blue"&gt;break&lt;/span&gt;;
            DisplayMovies(movies);
            imageCount += movies.Length;
        }
        statusText.Text = &lt;span style="color: #2b91af"&gt;String&lt;/span&gt;.Format(&lt;span style="color: #a31515"&gt;&amp;quot;{0} Titles&amp;quot;&lt;/span&gt;, imageCount);
    }
    &lt;span style="color: blue"&gt;catch &lt;/span&gt;(&lt;span style="color: #2b91af"&gt;TaskCanceledException&lt;/span&gt;) { }

    &lt;span style="background-color: #ffff00"&gt;cts = &lt;span style="color: blue"&gt;null&lt;/span&gt;;&lt;/span&gt;
}

&lt;span style="color: blue"&gt;private void &lt;/span&gt;cancelButton_Click(&lt;span style="color: blue"&gt;object &lt;/span&gt;sender, &lt;span style="color: #2b91af"&gt;RoutedEventArgs &lt;/span&gt;e)
{
    &lt;span style="color: blue"&gt;if &lt;/span&gt;(cts != &lt;span style="color: blue"&gt;null&lt;/span&gt;)
    {
        cts.Cancel();
        statusText.Text = &lt;span style="color: #a31515"&gt;&amp;quot;Canceled&amp;quot;&lt;/span&gt;;
    }
}&lt;/pre&gt;

&lt;p&gt;那么超时又怎么说？超时其实就类似一段时间之后的取消。于是我们可以另写一个小方法来处理这个问题：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;async &lt;/span&gt;&lt;span style="color: blue"&gt;void &lt;/span&gt;StartTimeoutAsync()
{
    &lt;span style="color: blue"&gt;await &lt;/span&gt;&lt;span style="color: #2b91af"&gt;TaskEx&lt;/span&gt;.Delay(5000);
    &lt;span style="color: blue"&gt;if &lt;/span&gt;(cts != &lt;span style="color: blue"&gt;null&lt;/span&gt;)
    {
        cts.Cancel();
        statusText.Text = &lt;span style="color: #a31515"&gt;&amp;quot;Timeout&amp;quot;&lt;/span&gt;;
    }
}

&lt;span style="color: blue"&gt;private void &lt;/span&gt;searchButton_Click(&lt;span style="color: blue"&gt;object &lt;/span&gt;sender, &lt;span style="color: #2b91af"&gt;RoutedEventArgs &lt;/span&gt;e)
{
    LoadMoviesAsync(&lt;span style="color: #2b91af"&gt;Int32&lt;/span&gt;.Parse(textBox.Text));
    &lt;span style="background-color: #ffff00"&gt;StartTimeoutAsync();&lt;/span&gt;
}&lt;/pre&gt;

&lt;p&gt;第一步，我们先等待5秒钟，如果任务还在执行，那么我们就取消掉。所以无论是超时，取消还是错误处理，程序的逻辑结构都得以最大限度的保留，就好比编写普通的代码一样。例如上面的Delay，看上去是顺序逻辑流，但实际上是异步的。为了表现出这点，我们可以为程序新加上一个有趣的功能：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;async void &lt;/span&gt;ShowDateTimeAsync()
{
    &lt;span style="color: blue"&gt;while &lt;/span&gt;(&lt;span style="color: blue"&gt;true&lt;/span&gt;)
    {
        Title = &lt;span style="color: #a31515"&gt;&amp;quot;Movie Finder &amp;quot; &lt;/span&gt;+ &lt;span style="color: #2b91af"&gt;DateTime&lt;/span&gt;.Now;
        &lt;span style="color: blue"&gt;await &lt;/span&gt;&lt;span style="color: #2b91af"&gt;TaskEx&lt;/span&gt;.Delay(1000);
    }
}

&lt;span style="color: blue"&gt;public &lt;/span&gt;MainWindow()
{
    InitializeComponent();
    textBox.Focus();
    &lt;span style="background-color: #ffff00"&gt;ShowDateTimeAsync();&lt;/span&gt;
}&lt;/pre&gt;

&lt;p&gt;于是在标题栏上便会每隔一秒刷新显示当前时间，与此同时搜索也好，超时也罢，在程序执行时UI都可以获得响应。&lt;/p&gt;

&lt;p&gt;值得强调的是，上面实现的这些功能都没有启用额外的线程，所有这些都在UI线程上执行。那么什么时候需要额外的线程呢？这便是计算密集型操作。例如这里我要执行五千万次平方根计算，这需要耗费一段时间。不过这样的操作，对于UI线程来说，这也不过是一个异步操作，不是吗？启动操作，然后等待其完成，在它完成之后再对结果做些处理：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;async void &lt;/span&gt;ComputeStuffAsync()
{
    &lt;span style="color: blue"&gt;double &lt;/span&gt;result = 0;
    &lt;span style="color: blue"&gt;await &lt;/span&gt;&lt;span style="color: #2b91af"&gt;TaskEx&lt;/span&gt;.Run(() =&amp;gt;
    {
        &lt;span style="color: blue"&gt;for &lt;/span&gt;(&lt;span style="color: blue"&gt;int &lt;/span&gt;i = 1; i &amp;lt; 500000000; i++)
        {
            result += &lt;span style="color: #2b91af"&gt;Math&lt;/span&gt;.Sqrt(i);
        }
    });

    &lt;span style="color: #2b91af"&gt;MessageBox&lt;/span&gt;.Show(&lt;span style="color: #a31515"&gt;&amp;quot;The result is &amp;quot; &lt;/span&gt;+ result, &lt;span style="color: #a31515"&gt;&amp;quot;Background Task&amp;quot;&lt;/span&gt;,
        &lt;span style="color: #2b91af"&gt;MessageBoxButton&lt;/span&gt;.OK, &lt;span style="color: #2b91af"&gt;MessageBoxImage&lt;/span&gt;.Information);
}

&lt;span style="color: blue"&gt;private void &lt;/span&gt;searchButton_Click(&lt;span style="color: blue"&gt;object &lt;/span&gt;sender, &lt;span style="color: #2b91af"&gt;RoutedEventArgs &lt;/span&gt;e)
{
    LoadMoviesAsync(&lt;span style="color: #2b91af"&gt;Int32&lt;/span&gt;.Parse(textBox.Text));
    StartTimeoutAsync();
    &lt;span style="background-color: #ffff00"&gt;ComputeStuffAsync();&lt;/span&gt;
}&lt;/pre&gt;

&lt;p&gt;TaskEx.Run方法会构造一个后台线程，并返回异步操作，我们使用await等待其返回，这体现了绝佳的组合能力。启动后在任务管理器中便会发现CPU占用率明显上升。&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/10.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/pdc2010-future-of-csharp-vb-anders/10-s.png" /&gt;&lt;/a&gt; 

&lt;p&gt;我在这里宣布，之前演示的技术预览版已经可以下载了。我们已经创建了C#和VB编译器的原型，并提供了一些示例。您可以在开发者中心下载，我在演讲最后会给出URL。&lt;/p&gt;

&lt;h1&gt;相关文章&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;PDC 2010：C#与Visual Basic的未来（上） &lt;/li&gt;

  &lt;li&gt;&lt;a href="http://blog.zhaojie.me/2010/10/pdc2010-the-future-of-csharp-and-vb-by-anders-hejlsberg-2.html"&gt;PDC 2010：C#与Visual Basic的未来（中）&lt;/a&gt;&lt;/li&gt;

  &lt;li&gt;&lt;a href="http://blog.zhaojie.me/2010/11/pdc2010-the-future-of-csharp-and-vb-by-anders-hejlsberg-3.html"&gt;PDC 2010：C#与Visual Basic的未来（下）&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <comments>http://blog.zhaojie.me/2010/10/pdc2010-the-future-of-csharp-and-vb-by-anders-hejlsberg-1.html#comments</comments>
      <pubDate>Sat, 30 Oct 2010 18:43:29 GMT</pubDate>
      <lastBuildDate>Wed, 17 Nov 2010 12:55:05 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/cutting-edge/">技术尝鲜</category>
      <title>在Visual Studio中使用MonoTouch开发iOS应用程序（下）：开发体验</title>
      <link>http://blog.zhaojie.me/2010/09/develop-ios-app-with-monotouch-in-visual-studio-2.html</link>
      <guid>http://blog.zhaojie.me/2010/09/develop-ios-app-with-monotouch-in-visual-studio-2.html</guid>
      <description>&lt;p&gt;对于熟悉.NET程序员来说，编写iOS应用程序的最佳选择自然是MonoTouch。在&lt;a href="http://blog.zhaojie.me/2010/09/develop-ios-app-with-monotouch-in-visual-studio-1.html"&gt;上一篇文章&lt;/a&gt;里，我们已经在Mac OS X上安装了MonoTouch开发环境，并已经能够在Mac OS X和Windows之间共享文件。现在我们就可以来简单体验一下，如何使用Visual Studio，Interface Builder以及少量的MonoDevelop来开发一个最最简单的iOS应用程序。&lt;/p&gt;

&lt;h1&gt;新建项目&lt;/h1&gt;

&lt;p&gt;根据我的个人习惯，我会先创建一个空白的解决方案。首先在Mac OS X中打开MonoDevelop，然后在菜单中选择File - New - Solution，在弹出对话框的Other分类中选择Blank Solution模板，并填写合适的位置和名称：&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/monotouch-with-vs/09.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/monotouch-with-vs/09.png" width="450" /&gt;&lt;/a&gt; 

&lt;p&gt;然后便是创建iPhone应用程序项目。还是刚才的对话框，选择C# - iPhone and iPad分类下的iPhone Window-based Project模板。同样，在对话框下方填写合适的位置和名称，我的习惯是将所有的源代码统一放在src目录下（在解决方案中也会创建一个src目录与之对应）：&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/monotouch-with-vs/10.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/monotouch-with-vs/10.png" width="450" /&gt;&lt;/a&gt; 

&lt;p&gt;点击OK。下一步是额外的项目配置，可以直接点击OK。此时我们就会发现MonoDevelop里展示出的项目文件：&lt;/p&gt;
&lt;img src="http://img.zhaojie.me/blog/monotouch-with-vs/11.png" /&gt; 

&lt;p&gt;其中Main.cs里包含了项目的启动代码及一个AppDelegate类，MainWindow.xib是主窗口的界面文件，而MainWindow.xib.designer.cs文件则是MonoDevelop根据xib文件中的标记所自动创建的C#代码，在绝大部分情况下我们不会去修改它。&lt;/p&gt;

&lt;h1&gt;编辑界面&lt;/h1&gt;

&lt;p&gt;双击MainWindow.xib文件，便会打开Interface Builder。下图左为Library窗口（近似于VS中的Toolbox）；中间上方是可视化的UI编辑器，下方则是对象管理器，显示了界面中定义的对象；右侧便是用来修改属性的Inspector窗口（近似于VS中的Properties窗口）：&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/monotouch-with-vs/12.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/monotouch-with-vs/12-s.png" /&gt;&lt;/a&gt; 

&lt;p&gt;首先，在Library窗口上方选择Objects，并将一个Round Rect Button拖动至UI编辑器，双击，输入Hello World：&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/monotouch-with-vs/13.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/monotouch-with-vs/13.png" width="450" /&gt;&lt;/a&gt; 

&lt;p&gt;然后，在Library窗口上方选择Classes，在上方列表中选择AppDelegate，并在下方下拉框中选取Outlets，并使用下方加号添加一个id，叫做ButtonCounter：&lt;/p&gt;
&lt;img src="http://img.zhaojie.me/blog/monotouch-with-vs/14.png" /&gt; 

&lt;p&gt;接着便是个比较有趣的操作。在对象管理器里选中App Delegate对象，并在Inspector上方选择Connections，再将ButtonCounter右侧的小圆点拖动至按钮，这会将ButtonCounter这个id与按钮关联起来，如下图：&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/monotouch-with-vs/15.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/monotouch-with-vs/15.png" width="450" /&gt;&lt;/a&gt; 

&lt;p&gt;在Interface Builder中保存，回到MonoDevelop，打开MainWindow.xib.designer.cs文件，便可以看到其中在AppDelegate中生成的ButtonCounter属性：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;private &lt;/span&gt;MonoTouch.UIKit.&lt;span style="color: #2b91af"&gt;UIButton &lt;/span&gt;__mt_ButtonCounter;

[MonoTouch.Foundation.&lt;span style="color: #2b91af"&gt;Connect&lt;/span&gt;(&lt;span style="color: #a31515"&gt;&amp;quot;ButtonCounter&amp;quot;&lt;/span&gt;)]
&lt;span style="color: blue"&gt;private &lt;/span&gt;MonoTouch.UIKit.&lt;span style="color: #2b91af"&gt;UIButton &lt;/span&gt;ButtonCounter {
    &lt;span style="color: blue"&gt;get &lt;/span&gt;{
        &lt;span style="color: blue"&gt;this&lt;/span&gt;.__mt_ButtonCounter = ((MonoTouch.UIKit.&lt;span style="color: #2b91af"&gt;UIButton&lt;/span&gt;)(&lt;span style="color: blue"&gt;this&lt;/span&gt;.GetNativeField(&lt;span style="color: #a31515"&gt;&amp;quot;ButtonCounter&amp;quot;&lt;/span&gt;)));
        &lt;span style="color: blue"&gt;return this&lt;/span&gt;.__mt_ButtonCounter;
    }
    &lt;span style="color: blue"&gt;set &lt;/span&gt;{
        &lt;span style="color: blue"&gt;this&lt;/span&gt;.__mt_ButtonCounter = &lt;span style="color: blue"&gt;value&lt;/span&gt;;
        &lt;span style="color: blue"&gt;this&lt;/span&gt;.SetNativeField(&lt;span style="color: #a31515"&gt;&amp;quot;ButtonCounter&amp;quot;&lt;/span&gt;, &lt;span style="color: blue"&gt;value&lt;/span&gt;);
    }
}&lt;/pre&gt;

&lt;p&gt;可见，MonoDevelop根据xib的内容，自动生成了一些C#代码。AppDelegate是个Partial Class，它的另一部分在Main.cs文件中，一会儿我们便会使用这里的ButtonCounter定义。&lt;/p&gt;

&lt;h1&gt;配置Visual Studio&lt;/h1&gt;

&lt;p&gt;虽然MonoDevelop的sln和csproj文件的格式与Visual Studio兼容（包括2005、2008、2010三个版本的VS），但是VS无法识别iPhone应用程序的项目模板，因此如果您直接打开iOS101.sln则会加载失败。因此，我们需要并行地创建一些sln和csproj，其中大部分内容与MonoDevelop创建的内容保持同步。&lt;/p&gt;

&lt;p&gt;例如，我创建了iOS101.VS.sln及iPhoneApp.UI.VS.csproj（一个.NET 2.0的Class Library）两个文件，它们分别与iOS101.sln和iPhoneApp.UI.csproj放在同样的目录下。值得注意的是iPhoneApp.UI.VS.csproj文件，如果您直接在VS里创建这个项目文件，它的默认命名空间里也会包含“VS”，您可能需要手动修改一下。由于要和MonoDevelop中的项目保持一致的“可编译通过性”，我们还需要引用MonoTouch SDK里提供的dll。于是我在iOS101目录中创建了lib/monotouch目录，并使用如下命令复制所有的MonoTouch提供的dll文件：&lt;/p&gt;

&lt;pre class="code"&gt;cp /Developer/MonoTouch/usr/lib/mono/2.1/*.dll ~/Projects/iOS101/lib/monotouch&lt;/pre&gt;

&lt;p&gt;然后，编辑iPhoneApp.UI.VS.csproj的程序集引用和项目文件，最终结果差不多是这样的。请注意MonoTouch中xib文件的类型为Page，而VS中则需要设为None：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color: #a31515"&gt;xml &lt;/span&gt;&lt;span style="color: red"&gt;version&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;1.0&lt;/span&gt;&amp;quot; &lt;span style="color: red"&gt;encoding&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;utf-8&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;?&amp;gt;
&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;Project&lt;/span&gt; ...&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;
  ...
  &lt;span style="color: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;ItemGroup&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
    &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;Reference &lt;/span&gt;&lt;span style="color: red"&gt;Include&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;monotouch&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;&amp;gt;
      &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;HintPath&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;..\..\lib\monotouch\monotouch.dll&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;HintPath&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
    &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;Reference&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
    &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;Reference &lt;/span&gt;&lt;span style="color: red"&gt;Include&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;System&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;&amp;gt;
      &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;HintPath&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;..\..\lib\monotouch\System.dll&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;HintPath&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
    &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;Reference&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
    &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;Reference &lt;/span&gt;&lt;span style="color: red"&gt;Include&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;System.Core&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;&amp;gt;
      &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;HintPath&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;..\..\lib\monotouch\System.Core.dll&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;HintPath&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
    &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;Reference&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
  &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;ItemGroup&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;
  &lt;span style="color: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;ItemGroup&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
    &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;None &lt;/span&gt;&lt;span style="color: red"&gt;Include&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;Info.plist&lt;/span&gt;&amp;quot; &lt;span style="color: blue"&gt;/&amp;gt;
    &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;Compile &lt;/span&gt;&lt;span style="color: red"&gt;Include&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;Main.cs&lt;/span&gt;&amp;quot; &lt;span style="color: blue"&gt;/&amp;gt;
    &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;None &lt;/span&gt;&lt;span style="color: red"&gt;Include&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;MainWindow.xib&lt;/span&gt;&amp;quot; &lt;span style="color: blue"&gt;/&amp;gt;
    &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;Compile &lt;/span&gt;&lt;span style="color: red"&gt;Include&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;MainWindow.xib.designer.cs&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;&amp;gt;
      &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;DependentUpon&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;MainWindow.xib&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;DependentUpon&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
    &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;Compile&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
  &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;ItemGroup&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;
  ...
&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;Project&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;在VS的结果则类似于：&lt;/p&gt;
&lt;img src="http://img.zhaojie.me/blog/monotouch-with-vs/16.png" /&gt; 

&lt;p&gt;试着编译一下，通过则表示配置成功。&lt;/p&gt;

&lt;h1&gt;编写代码&lt;/h1&gt;

&lt;p&gt;这里您是否有些疑惑，为什么上面创建的是一个.NET 2.0项目呢？这样我们还能够使用C# 3.0中的高级特性吗？答案是肯定的，只要我们使用的是Visual Studio 2008或是2010，则即使是针对.NET 2.0所编写的代码，VS也会使用C# 3.0的编译器，因为我们都知道其实C# 3.0只需要一点点框架和类库的支持（扩展方法）。您甚至可以使用C# 4.0的部分特性，例如参数的默认值，命名参数等等。可惜您无法使用C# 4.0的动态性，因为它需要DLR和Microsoft.CSharp.dll，又涉及到大量的动态代码生成，我对此没什么信心和意愿。当然您感兴趣的话也可以尝试一下。我在这里使用.NET 2.0的原因，是希望可以尽可能减少对系统程序集的依赖，而尽量使用MonoTouch所提供的dll。例如现在，除了mscorlib以外，所有的程序集都与Windows上所安装的.NET Framework无关，这保证了我们编写的代码可以在MonoTouch兼容。&lt;/p&gt;

&lt;p&gt;现在就来开始编写代码吧，您可以在VS里打开Main.cs，在AppDelegate的FinishedLaunching方法中添加如下代码，使之成为：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public override bool &lt;/span&gt;FinishedLaunching(&lt;span style="color: #2b91af"&gt;UIApplication &lt;/span&gt;app, &lt;span style="color: #2b91af"&gt;NSDictionary &lt;/span&gt;options)
{
    &lt;span style="color: blue"&gt;int &lt;/span&gt;i = 0;
    &lt;span style="color: blue"&gt;this&lt;/span&gt;.ButtonCounter.TouchDown += &lt;span style="color: blue"&gt;delegate
    &lt;/span&gt;{
        &lt;span style="color: blue"&gt;this&lt;/span&gt;.ButtonCounter.SetTitle((++i).ToString(), &lt;span style="color: #2b91af"&gt;UIControlState&lt;/span&gt;.Normal);
    };

    window.MakeKeyAndVisible();

    &lt;span style="color: blue"&gt;return true&lt;/span&gt;;
}&lt;/pre&gt;

&lt;p&gt;FinishedLaunching方法在程序启动时调用，此时我们为ButtonCounter添加一个TouchDown事件（类似于Click）添加一个处理函数。这里用到了C#中的匿名函数特性，并捕获外部的变量i，每次点击按钮都将i加一，并显示在按钮上。在这里我们使用.NET中比较常用方式添加事件处理，事实上您也可以在Interface Builder中定义一个Action，并把它与Button的TouchDown事件关联起来。这个Action会表现为一个Partial Method，您可以在代码里补全其实现。&lt;/p&gt;

&lt;p&gt;保存代码后您便可以回到MonoDevelop中，为了能够在iPhone模拟器里运行，您还要修改一个参数。对iPhoneApp.UI点击右键，打开Options对话框，在左侧选中Build - iPhone Build类别，并将右侧的SDK version设为4.0，如下：&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/monotouch-with-vs/17.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/monotouch-with-vs/17.png" width="450" /&gt;&lt;/a&gt; 

&lt;p&gt;点击OK保存并关闭对话框。此时可以选择菜单Run - Run，或直接使用快捷键Command（即Win键） + Alt + Enter便会编译项目，并打开模拟器执行程序。在默认情况可能打开的iPad模拟器，您可以在Hardware - Device中选择iPhone或iPhone 4。运行效果如下：&lt;/p&gt;
&lt;img src="http://img.zhaojie.me/blog/monotouch-with-vs/18.png" /&gt; 

&lt;p&gt;试着点击按钮查看效果吧。&lt;/p&gt;

&lt;h1&gt;单元测试及其他&lt;/h1&gt;

&lt;p&gt;如果您想调试代码，只需要在MonoDevelop中设置端点，并选择菜单Run - Debug，或直接使用快捷键Command + Enter便可以对模拟器进行调试。但是如果是要单元测试呢？这问题也不大，MonoDevelop自带NUnit项目，您可以创建这样一个单元测试项目，删除其默认引用，换之为MonoTouch SDK里所提供的程序集，同样您可以在Visual Studio中开发单元测试代码，但是调试执行必须在MonoDevelop里进行，因为MonoTouch提供的程序集都是Mac下的Mono实现，它们在Windows下的作用只是为Visual Studio提供必要的元数据，使我们能够享受到智能提示之类的便利，想要在Windows里运行则是不行的。&lt;/p&gt;

&lt;p&gt;但是，事实上我们也可以将Visual Studio里面的项目定义为.NET Framework 3.5项目，并直接使用.NET提供的程序集，对于MonoTouch里额外的程序集，例如System.Json.dll，则面向.NET 3.5自己重新构建一遍即可（源代码可以使用.NET Reflector获得或是利用Mono上的开源代码）。这么做的优势在于，对于那些与MonoTouch无关的代码，我们都可以在Visual Studio里进行调试与测试了。于是乎，我们可以在代码开发阶段尽可能留在熟悉而强大的环境中，对开发效率有很大帮助。&lt;/p&gt;

&lt;p&gt;这种做法也有缺点，例如，虽然MonoTouch提供的类库与.NET 3.5兼容，但事实上我并不能百分之百保证这点，因此在.NET 3.5里可以编译通过的代码，也有可能无法在MonoTouch里编译执行。此外，这种方法也会让您无法使用Mono程序集中对.NET的扩展（主要是Mono命名空间下的类库）。不过这两个理论上问题到目前为止还没有给我造成什么困扰，我也只有在需要在查看模拟器运行效果时才回到Mac及MonoDevelop中。&lt;/p&gt;

&lt;p&gt;有些朋友看到System.Json可能会有些熟悉，因为它在Silverlight开发中也有出现。您说的没错，事实上MonoTouch里的程序集版本号与Silverlight一样，都是2.0.5.0，甚至连强签名都是一致的。只可惜Silverlight里的类库是.NET 3.5的子集，例如所有同步的IO操作都被去除了，因此我们很难使用Silverlight来开发MonoTouch程序。当然，有了Silverlight，对我们开发MonoTouch也是有所帮助的，这点以后再谈。&lt;/p&gt;

&lt;p&gt;最后，您应该已经意识到，我们需要在VS的项目文件与MonoDevelop的项目文件直接做同步，这个同步包括程序集引用与代码文件两方面。如果您觉得手动编辑比较麻烦的话，就写一个自动同步的小程序咯——不会？那么还是先别搞MonoTouch了，从编程基础学起吧。&lt;/p&gt;

&lt;h1&gt;相关文章&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="http://blog.zhaojie.me/2010/09/develop-ios-app-with-monotouch-in-visual-studio-1.html"&gt;在Visual Studio中使用MonoTouch开发iOS应用程序（上）：环境配置&lt;/a&gt; &lt;/li&gt;

  &lt;li&gt;在Visual Studio中使用MonoTouch开发iOS应用程序（下）：开发体验 &lt;/li&gt;
&lt;/ul&gt;</description>
      <comments>http://blog.zhaojie.me/2010/09/develop-ios-app-with-monotouch-in-visual-studio-2.html#comments</comments>
      <pubDate>Thu, 30 Sep 2010 01:43:53 GMT</pubDate>
      <lastBuildDate>Thu, 30 Sep 2010 01:43:53 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/cutting-edge/">技术尝鲜</category>
      <title>在Visual Studio中使用MonoTouch开发iOS应用程序（上）：环境配置</title>
      <link>http://blog.zhaojie.me/2010/09/develop-ios-app-with-monotouch-in-visual-studio-1.html</link>
      <guid>http://blog.zhaojie.me/2010/09/develop-ios-app-with-monotouch-in-visual-studio-1.html</guid>
      <description>&lt;p&gt;前段时间&lt;a href="http://blog.zhaojie.me/2010/09/how-to-install-mac-os-x-snow-leopard-on-virtualbox.html"&gt;在工作机上装了Mac OS X&lt;/a&gt;，这主要是因为我最近需要开发iPhone应用程序。虽然Xcode，Objective C一定是开发iOS应用程序的主流，但是经过一番考虑，我还是决定尝试一下使用&lt;a href="http://monotouch.net/"&gt;MonoTouch&lt;/a&gt;进行开发。MonoTouch是Novell公司基于开源的&lt;a href="http://www.mono-project.com/Main_Page"&gt;Mono&lt;/a&gt;平台构建的一套iOS开发环境，使用MonoDevelop作为代码编写工具。不过目前的MonoDevelop较之Visual Studio可谓“萤火之光比皓月之明”，甚至还有无法输入中文的低级问题。因此，至今我所有在Mono上运行的代码其实都是用Visual Studio写的，这次自然也不例外。不过，这似乎并不是件非常直接的事情……&lt;/p&gt;

&lt;h1&gt;什么是MonoTouch&lt;/h1&gt;

&lt;p&gt;Mono是由Novell提供的.NET跨平台执行环境，无论别人如何进行FUD，我使用下来对Mono的感觉很不错，自认为也有足够的理由来支持我的观点，如今无论是微软Mix大会还是社区类型的&lt;a href="http://blog.zhaojie.me/2010/07/ndc-2010-videos.html"&gt;NDC 2010&lt;/a&gt;都有Mono的内容（尤其是后者）。在我看来，如果没有尝试过Mono就发表的猜忌就很难令人接受了。&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.mono-project.com/Licensing"&gt;Mono使用的授权方案&lt;/a&gt;允许第三方基于它上构建商业应用程序，MonoTouch便是其中的典型（还有哪些？&lt;a href="http://streaming.ndc2010.no/tcs/?id=95F528ED-572D-41ED-AEFD-C014731A55FE"&gt;自己看吧&lt;/a&gt;）。MonoTouch是Novell公司的产品，可以让开发人员在.NET环境下开发iOS应用程序（包括iPhone 4和iPad），支持最新的iOS SDK 4.1。这样.NET开发人员就可以利用现有的知识来开发iOS应用程序，如.NET 3.5中的绝大部分类库以及C# 3.0。例如，之前有同事抱怨Android里的API没法方便地使用SOAP协议（&lt;a href="http://stackoverflow.com/questions/204465/how-to-access-soap-services-from-iphone"&gt;似乎iOS下也有不便&lt;/a&gt;），但是在MonoTouch中，一切的一切都是最常见的Add Web Services，或是用WCF的&lt;a href="http://msdn.microsoft.com/en-us/library/aa347733.aspx"&gt;svcutil.exe&lt;/a&gt;便可直接生成代理。我们同样可以复用大量.NET平台下的开源类库，只要基于MonoTouch重新编译一遍就可以了。在NDC 2010中“&lt;a href="http://streaming.ndc2010.no/tcs/?id=815EADB7-066D-4516-A70F-31EEFDFB1DE2"&gt;深入MonoTouch&lt;/a&gt;”演讲中便演示了在MonoTouch中使用&lt;a href="http://json.codeplex.com/"&gt;Json.NET&lt;/a&gt;、&lt;a href="http://flickrnet.codeplex.com/"&gt;FlickrNet&lt;/a&gt;及&lt;a href="http://coolstorage.codeplex.com/"&gt;CoolStorage&lt;/a&gt;三套类库的做法。&lt;/p&gt;

&lt;p&gt;除了.NET 3.5中的类库之外，MonoTouch也提供了访问iOS API（即&lt;a href="https://developer.apple.com/technologies/ios/cocoa-touch.html"&gt;Cocoa Touch&lt;/a&gt;）的.NET接口（尤其是在UI方面）。在这方面MonoTouch不是一味地直接暴露出Cocoa Touch的功能，而是在一定程度上将它的API改写为更倾向于.NET程序员的形式。例如UIView的Frame属性为System.Drawing.RectangleF类型，而不是Cocoa Touch中原本使用的CGRect。当然，尤其是UI方面，MonoTouch还是使用了传统iOS应用程序的架构，包括它的MVC驱动方式。因此，即使您使用MonoTouch，最好也要能够看懂简单的Objective C代码，因为SDK提供的文档和大量的示例都是用它来实现的。&lt;/p&gt;

&lt;p&gt;众所周知，Mono使用JIT（Just-in-Time）编译来执行IL代码，JIT代表了在运行时动态生成原生代码，但是iOS不允许这么做。因此，MonoTouch实际上是使用了AOT（Ahead-of-Time）编译方式，真正部署在机器上时已经是原生代码了。此外，MonoTouch还提供了一个Linker，它只会将SDK及我们自己编写的代码中，真正使用到的部分静态链接至应用程序中，这削减了应用程序的体积。从中我们可以看出，使用MonoTouch开发出来的应用程序，其实和普通使用iOS SDK开发出的应用程序并没有什么区别，都是完全独立运行的。当然，这也是因为MonoTouch将一个Runtime塞入应用程序内部的关系，这会给应用程序的体积&lt;a href="http://stackoverflow.com/questions/1444777/how-big-is-an-objective-c-iphone-app-vs-a-monotouch-app"&gt;带来大约5MB的增长&lt;/a&gt;，压缩后（也就是用户真正需要下载的体积）大约是3MB。&lt;/p&gt;

&lt;p&gt;除了MonoTouch以外，用于Android开发的&lt;a href="http://monodroid.net/"&gt;MonoDroid&lt;/a&gt;也已经进入了beta阶段，已经向一些开发人员提供试用版本了。这意味着，在不久的将来，C#及.NET类库将成为Windows Phone，iOS，Android三大移动平台上的跨平台开发工具。关于MonoTouch的更多消息，您可以关注&lt;a href="http://streaming.ndc2010.no/tcs/?id=65BE4F1E-4CA8-44E0-8285-973DDE22AC94"&gt;NDC 2010上的相关演讲&lt;/a&gt;。&lt;/p&gt;

&lt;h1&gt;在Windows和Mac OS X中共享文件&lt;/h1&gt;

&lt;p&gt;MonoTouch的开发工具是MonoDevelop和&lt;a href="http://en.wikipedia.org/wiki/Interface_Builder"&gt;Interface Builder&lt;/a&gt;，后者用于编辑应用程序中的UI文件。不过编写C#代码的神器终归是Visual Studio，即便是最简单的Express版本在代码编写方面也胜出MonoDevelop很多，更别说是&lt;a href="http://www.hanselman.com/blog/TheBestVisualStudio2010ProductivityPowerToolsPowerCommandsAndExtensions.aspx"&gt;经过增强&lt;/a&gt;的高级版本了。因此，我打算使用Visual Studio编写C#代码，而使用Interface Builder开发UI界面。不过我们要做的第一件事情是在Windows和Mac OS X之间共享源文件。这里我继续基于之前&lt;a href="http://blog.zhaojie.me/2010/09/how-to-install-mac-os-x-snow-leopard-on-virtualbox.html"&gt;Win7 + VirtualBox + Snow Leopard&lt;/a&gt;的环境进行配置，您也可以使用相同的方法连接两台独立的机器。&lt;/p&gt;

&lt;p&gt;由于Mac OS X是在虚拟机上，我选择将源文件放在Windows里，并在Mac OS X上访问。首先，我们在Windows上共享一个目录，这里我将整个E盘共享给vbox账号，取名为host-e，并赋予完全控制权限：&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/monotouch-with-vs/01.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/monotouch-with-vs/01.png" width="450" /&gt;&lt;/a&gt; 

&lt;p&gt;然后在Mac OS X中打开Finder，在Go菜单中选择Connect to Server：&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/monotouch-with-vs/02.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/monotouch-with-vs/02.png" width="450" /&gt;&lt;/a&gt; 

&lt;p&gt;在弹出的对话框中输入Windows的IP：&lt;/p&gt;
&lt;img src="http://img.zhaojie.me/blog/monotouch-with-vs/03.png" /&gt; 

&lt;p&gt;点击Connect，并在下一个对话框中输入用户名的密码（注意这里需要包含机器名）：&lt;/p&gt;
&lt;img src="http://img.zhaojie.me/blog/monotouch-with-vs/04.png" /&gt; 

&lt;p&gt;点击Connnet，此时对话框会列出这个账号的共享内容：&lt;/p&gt;
&lt;img src="http://img.zhaojie.me/blog/monotouch-with-vs/05.png" /&gt; 

&lt;p&gt;于是我们选择host-e，并点击OK。此时，您会在Finder的Shared栏目中访问到共享的内容，其中的projects目录是这里的关键：&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/monotouch-with-vs/06.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/monotouch-with-vs/06.png" width="450" /&gt;&lt;/a&gt; 

&lt;p&gt;我将所有的项目都存放在e:\projects目录中，接下来也不例外。为了方便起见，我在Mac OS X的home目录下建立一个软链接，指向共享中的projects目录&lt;/p&gt;

&lt;pre class="code"&gt;ln -s /Volumes/host-e/projects ~/Projects&lt;/pre&gt;

&lt;p&gt;此时我们就能在home目录下看到Projects文件夹了，而在各种应用程序中，我们可以使用~/Projects来访问其中的内容：&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/monotouch-with-vs/07.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/monotouch-with-vs/07.png" width="450" /&gt;&lt;/a&gt; 

&lt;p&gt;自然，其他方式也没有问题，您只要找到适合您自己的最合适的方式即可。例如，我现在提到的共享方式要求两台机器通过网络互连，如果您无法实现这点，也可以借助如&lt;a href="http://www.dropbox.com/"&gt;Dropbox&lt;/a&gt;这样的同步工具，其实也非常方便。&lt;/p&gt;

&lt;h1&gt;安装MonoTouch&lt;/h1&gt;

&lt;p&gt;要安装MonoTouch，首先您必须安装Mono，MonoDevelop，iOS SDK。我的配置是：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Mono 2.6.7 &lt;/li&gt;

  &lt;li&gt;MonoDevelop 2.4 &lt;/li&gt;

  &lt;li&gt;iOS SDK 4.1 &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Mono和iOS SDK的安装过程十分普通，而MonoDevelop的安装方式对于Windows用户可能有些特别。在加载了dmg文件以后，会弹出这样一个界面：&lt;/p&gt;
&lt;img src="http://img.zhaojie.me/blog/monotouch-with-vs/08.png" /&gt; 

&lt;p&gt;根据提示，此时您只需要将MonoDevelop的图标拖至右侧目录中就可以了。&lt;/p&gt;

&lt;p&gt;随后，您便可以安装MonoTouch了。MonoTouch是商业产品，不过您可以免费下载它的试用版，无限期使用。不过试用版只能在模拟器上运行调试，如果需要在真机上运行测试、打包、甚至发布至AppStore，则需要&lt;a href="http://monotouch.net/Store"&gt;购买授权&lt;/a&gt;。企业用户自不必说，MonoTouch针对个人用户的授权费用399美金，如果您真有制作应用程序的好点子，那这点钱实在不算什么了。&lt;/p&gt;

&lt;h1&gt;相关文章&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;在Visual Studio中使用MonoTouch开发iOS应用程序（上）：环境配置 &lt;/li&gt;

  &lt;li&gt;&lt;a href="http://blog.zhaojie.me/2010/09/develop-ios-app-with-monotouch-in-visual-studio-2.html"&gt;在Visual Studio中使用MonoTouch开发iOS应用程序（下）：开发体验&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <comments>http://blog.zhaojie.me/2010/09/develop-ios-app-with-monotouch-in-visual-studio-1.html#comments</comments>
      <pubDate>Tue, 28 Sep 2010 05:52:52 GMT</pubDate>
      <lastBuildDate>Tue, 28 Sep 2010 05:52:52 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/cutting-edge/">技术尝鲜</category>
      <title>Win7 + VirtualBox安装Mac OS X雪豹操作系统图文详解</title>
      <link>http://blog.zhaojie.me/2010/09/how-to-install-mac-os-x-snow-leopard-on-virtualbox.html</link>
      <guid>http://blog.zhaojie.me/2010/09/how-to-install-mac-os-x-snow-leopard-on-virtualbox.html</guid>
      <description>&lt;p&gt;由于工作需要，我需要同时使用Windows和Mac OS X操作系统，虽然公司可以配置两台机器，但是出于发热量，空间占用，操作系统互通等原因，我还是更倾向于在虚拟机环境里工作。由于在大部分工作还是在Windows上完成的，因此我选择Win 7作为Host，而将Mac OS X Snow Leopard作为Guest系统。由于各种原因（如严格和特殊的硬件需求），在虚拟机下安装OS X一直是件无比折腾的事情，留下了无数先驱的身影。但是，我忽然发现，似乎如今新版的VirtualBox对于OS X已经有了非常优秀的支持，尝试之后感觉大好，因此记录下来供需要的朋友参考。&lt;/p&gt;

&lt;h1&gt;准备&lt;/h1&gt;

&lt;p&gt;首先，我建议您准备一台配置充足的机器作为Host。以下是我的机器配置及操作系统：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;CPU：Intel E8400 3.0GHz双核处理器 &lt;/li&gt;

  &lt;li&gt;内存：4.00GB（3.37GB可用） &lt;/li&gt;

  &lt;li&gt;操作系统：Windows 7企业版（32位） &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;我的机器一开始只有2G内存，OS X虚拟机占用了整整1G，于是剩下的1G内存便显得捉襟见肘了。如果您需要打开一些开发工具，或是Visual Studio、Word、Outlook等大型应用程序，会发现内存换页非常频繁，简直难以忍受。不过将内存增加到4G之后，情况便大有好转，与之前相比几乎感觉不到虚拟机所带来的影响。因此，我建议您至少准备3G内存空间，否则接下来的体验会大打折扣。&lt;/p&gt;

&lt;p&gt;在装完Snow Leopard系统之后，便会占用超过9G的硬盘空间。如果您需要在上面做开发，则可能还需要安装&lt;a href="http://developer.apple.com/technologies/xcode.html"&gt;Xcode&lt;/a&gt;及&lt;a href="http://developer.apple.com/devcenter/ios/index.action"&gt;iOS SDK&lt;/a&gt;等工具包，它们都是实打实的大个头，一套下来同样会占用将近10G的硬盘，因此我建议您可以保留30G左右的硬盘空间，以免将来遭遇尴尬的境地。&lt;/p&gt;

&lt;p&gt;在软件部分，新版的&lt;a href="http://www.virtualbox.org/"&gt;VirtualBox&lt;/a&gt;也是必须的，我使用的是最新的3.2.8 r64453，您可以去官网上&lt;a href="http://www.virtualbox.org/wiki/Downloads"&gt;下载最新版本&lt;/a&gt;。自然，您还需要&lt;a href="http://www.apple.com/macosx/"&gt;Mac OS X 10.6 Snow Leopard&lt;/a&gt;的安装DVD或是镜像文件（不要问我哪儿可以搞到）。此外，由于VirtualBox自带的EFI Bootloader只能在OS X作Host时才能正常引导，我们还需要empireEFIv1085.iso，您可以根据自己的CPU下载&lt;a href="http://www.mediafire.com/?thd5nmo2oyn"&gt;32位Intel版本&lt;/a&gt;或是AMD版本，对于64位Intel处理器，可以使用压缩包里的legacyempire_efi1085.iso文件。&lt;/p&gt;

&lt;p&gt;至此，万事俱备。&lt;/p&gt;

&lt;h1&gt;创建虚拟机配置&lt;/h1&gt;

&lt;p&gt;VirtualBox和Snow Leopard的中文翻译都可谓是茶几，因此两者我使用的都是英文版本。&lt;/p&gt;

&lt;p&gt;首先，您需要创建一个虚拟机的配置，设置一个名称（Snow Leopard），并如下图选择合适的操作系统（Mac OS X）及版本（Mac OS X Server）：&lt;/p&gt;

&lt;a href="http://img.zhaojie.me/blog/win7-virtualbox-osx/01.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/win7-virtualbox-osx/01.png" width="450" /&gt;&lt;/a&gt;

&lt;p&gt;选择至少1024 MB内存：&lt;/p&gt;

&lt;a href="http://img.zhaojie.me/blog/win7-virtualbox-osx/02.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/win7-virtualbox-osx/02.png" width="450" /&gt;&lt;/a&gt;

&lt;p&gt;在选择磁盘向导中，创建一个30G大小的虚拟磁盘（如果硬盘空间允许的话，建议创建fixed-size类型的虚拟磁盘，对性能有所帮助。自然，这会在创建虚拟磁盘时消耗一些时间，请耐心等待）：&lt;/p&gt;

&lt;a href="http://img.zhaojie.me/blog/win7-virtualbox-osx/03.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/win7-virtualbox-osx/03.png" width="450" /&gt;&lt;/a&gt;

&lt;p&gt;检查信息，创建虚拟机配置：&lt;/p&gt;

&lt;a href="http://img.zhaojie.me/blog/win7-virtualbox-osx/04.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/win7-virtualbox-osx/04.png" width="450" /&gt;&lt;/a&gt;

&lt;p&gt;右键单击刚创建好的虚拟机，或使用Machine菜单进入Settings面板。首先，选择左侧的System项，调整右侧的启动顺序（先光驱再硬盘），并将默认选中的Enable EFI选项取消（我们将使用刚才下载的empireEFIv1085.iso进行引导）：&lt;/p&gt;

&lt;a href="http://img.zhaojie.me/blog/win7-virtualbox-osx/05.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/win7-virtualbox-osx/05.png" width="450" /&gt;&lt;/a&gt;

&lt;p&gt;然后选中左侧的Display项，将Video Memory调制最大，并启用3D加速：&lt;/p&gt;

&lt;a href="http://img.zhaojie.me/blog/win7-virtualbox-osx/06.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/win7-virtualbox-osx/06.png" width="450" /&gt;&lt;/a&gt;

&lt;p&gt;至此，虚拟机配置完成。&lt;/p&gt;

&lt;h1&gt;安装系统&lt;/h1&gt;

&lt;p&gt;首先，我们使用empireEFIv1085.iso进行引导，还是在刚才的Settings面板中，选择左侧的Storage项，并在右侧选中引导用的镜像：&lt;/p&gt;

&lt;a href="http://img.zhaojie.me/blog/win7-virtualbox-osx/07.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/win7-virtualbox-osx/07.png" width="450" /&gt;&lt;/a&gt;

&lt;p&gt;启动虚拟机，稍等片刻，直至出现如下界面：&lt;/p&gt;

&lt;a href="http://img.zhaojie.me/blog/win7-virtualbox-osx/08.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/win7-virtualbox-osx/08.png" width="450" /&gt;&lt;/a&gt;

&lt;p&gt;根据提示，加载Snow Leopard的安装盘，稍等片刻（让虚拟机识别并加载镜像），点击F5，此时您会发现中央的光盘标志下方显示为Ｍax OS X的安装盘：&lt;/p&gt;

&lt;a href="http://img.zhaojie.me/blog/win7-virtualbox-osx/09.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/win7-virtualbox-osx/09.png" width="450" /&gt;&lt;/a&gt;

&lt;p&gt;此时回车，并根据提示按任意键，稍等片刻便会出现Snow Leopard的安装向导界面：&lt;/p&gt;

&lt;a href="http://img.zhaojie.me/blog/win7-virtualbox-osx/10.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/win7-virtualbox-osx/10-s.png" width="450" /&gt;&lt;/a&gt;

&lt;p&gt;选择一门语言，并根据向导前进，直至安装磁盘选择这一步，此时您会发现可选磁盘列表为空：&lt;/p&gt;

&lt;a href="http://img.zhaojie.me/blog/win7-virtualbox-osx/11.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/win7-virtualbox-osx/11-s.png" width="450" /&gt;&lt;/a&gt;

&lt;p&gt;从上方Utilities菜单中选取Disk Utility，再选中左侧的磁盘，同时进入右侧的Erase栏。然后选择正确的文件系统（Mac OS Extended，Case-sensitive，Journaled）：&lt;/p&gt;

&lt;a href="http://img.zhaojie.me/blog/win7-virtualbox-osx/12.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/win7-virtualbox-osx/12-s.png" width="450" /&gt;&lt;/a&gt;

&lt;p&gt;点击Erase对磁盘进行格式化，关闭Disk Utility，并选择刚才格式化后的磁盘作为安装目标：&lt;/p&gt;

&lt;a href="http://img.zhaojie.me/blog/win7-virtualbox-osx/13.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/win7-virtualbox-osx/13-s.png" width="450" /&gt;&lt;/a&gt;

&lt;p&gt;点击Install按钮开始安装，请耐心等待：&lt;/p&gt;

&lt;a href="http://img.zhaojie.me/blog/win7-virtualbox-osx/14.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/win7-virtualbox-osx/14-s.png" width="450" /&gt;&lt;/a&gt;

&lt;p&gt;最后则会出现安装失败的提示画面：&lt;/p&gt;

&lt;a href="http://img.zhaojie.me/blog/win7-virtualbox-osx/15.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/win7-virtualbox-osx/15-s.png" width="450" /&gt;&lt;/a&gt;

&lt;p&gt;不过别担心，事实上Snow Leopard系统已经安装完成了。此时您可以点击Restart按钮，但系统并不会正常地重新启动，会停留在MACH Reboot字样上。您需要重新加载empireEFIv1085.iso，并手动选择虚拟机控制台中Machine菜单的Reset项强制进行重启（此时虚拟机可能会提示发生严重错误并退出，重新启动即可）：&lt;/p&gt;

&lt;a href="http://img.zhaojie.me/blog/win7-virtualbox-osx/16.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/win7-virtualbox-osx/16.png" width="450" /&gt;&lt;/a&gt;

&lt;p&gt;此时便会重新进入之前出现过的引导界面，不过您会发现其中多了一个启动项，便是刚才装好的操作系统：&lt;/p&gt;

&lt;a href="http://img.zhaojie.me/blog/win7-virtualbox-osx/17.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/win7-virtualbox-osx/17.png" width="450" /&gt;&lt;/a&gt;

&lt;p&gt;按键盘右键切换至新项并回车，根据提示按任意键，稍等片刻，便会进入Snow Leopard第一次启动时的语言选择界面：&lt;/p&gt;

&lt;a href="http://img.zhaojie.me/blog/win7-virtualbox-osx/18.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/win7-virtualbox-osx/18.png" width="450" /&gt;&lt;/a&gt;

&lt;p&gt;我在这里还是选择英文作为操作系统的主要语言。根据向导一步一步前进，在设置了键盘，账号，时区等信息后（您可以跳过设置Apple ID的步骤），最终便可以看到Snow Leopard系统的桌面（可能跳出键盘识别的向导，按提示进行即可）：&lt;/p&gt;

&lt;a href="http://img.zhaojie.me/blog/win7-virtualbox-osx/19.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/win7-virtualbox-osx/19-s.png" width="450" /&gt;&lt;/a&gt;

&lt;p&gt;您现在可以把玩一下Snow Leopard操作系统了。值得一提的是，您很有可能无法使用操作系统的菜单正常关闭和重启操作系统，这时候您只要使用虚拟机的菜单来强制关闭和启动即可。需要注意，在启动时您还是需要empireEFIv1085.iso作为引导。&lt;/p&gt;

&lt;h1&gt;更新系统&lt;/h1&gt;

&lt;p&gt;打开System Profiler，会发现当前操作系统的版本是Mac OS X 10.6.3（当然，如果您使用最新的安装光盘，则下个步骤就可以跳过了）：&lt;/p&gt;

&lt;a href="http://img.zhaojie.me/blog/win7-virtualbox-osx/20.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/win7-virtualbox-osx/20-s.png" width="450" /&gt;&lt;/a&gt;

&lt;p&gt;打开Software Update升级操作系统。经过一段时间的检查，会要求进行操作系统升级，这会下载800多兆的升级文件，这自然需要一个漫长的等待过程。升级完成后重新启动，便会发现操作系统已经更新为Mac OS X 10.6.4（您可能发现截图中升级前后的机器名有所不同，这是我手动修改造成的）：&lt;/p&gt;

&lt;a href="http://img.zhaojie.me/blog/win7-virtualbox-osx/21.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/win7-virtualbox-osx/21-s.png" width="450" /&gt;&lt;/a&gt;

&lt;p&gt;容易理解，您从表面上很难发现升级前后有什么差异。&lt;/p&gt;

&lt;h1&gt;调整分辨率&lt;/h1&gt;

&lt;p&gt;从网上找到的资料来看，调整分辨率的方法有好几种，例如修改com.apple.Boot.plist文件，或是使用VBoxManage.exe修改虚拟机镜像的EfiGopMode参数等等，但我实验下来都没有效果。最终我使用的下面的方法。首先，使用empireEFIv1085.iso引导系统，停留在启动方式选择界面，向右切换至Snow Leopard操作系统，并输入以下命令：&lt;/p&gt;

&lt;pre class="code"&gt;&amp;quot;Graphics Mode&amp;quot;=&amp;quot;1280x1024x32&amp;quot;&lt;/pre&gt;

&lt;p&gt;如下图，请注意图片左下方的命令：&lt;/p&gt;

&lt;a href="http://img.zhaojie.me/blog/win7-virtualbox-osx/22.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/win7-virtualbox-osx/22.png" width="450" /&gt;&lt;/a&gt;

&lt;p&gt;回车，之后Snow Leopard的分辨率便修改成功了。您也可以将1280x1024修改成其他分辨率（并非任意分辨率，系统会自行调整）。我在工作时往往将其设为全屏，并放到扩展桌面上，于是我便可以同时使用两个操作系统了：&lt;/p&gt;

&lt;a href="http://img.zhaojie.me/blog/win7-virtualbox-osx/workspace.jpg" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/win7-virtualbox-osx/workspace.jpg" width="450" /&gt;&lt;/a&gt;

&lt;p&gt;看上去还不错吧？&lt;/p&gt;

&lt;h1&gt;其他&lt;/h1&gt;

&lt;p&gt;至于其他方面，您可以自行摸索了。网络连接方面，我使用默认的NAT工作正常，USB也没有问题，声音方面需要安装一个&lt;a href="http://forums.virtualbox.org/viewtopic.php?f=30&amp;amp;t=33358"&gt;驱动程序&lt;/a&gt;。此外，我在安装的时候也是遵循几篇文章所提供的向导，如果您想摆脱empireEFIv1085.iso启动系统，也可以根据它们的指引进行尝试：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="http://www.sysprobs.com/install-mac-snow-leopard-1063-oracle-virtualbox-32-apple-intel-pc"&gt;How to Install Mac OS X Snow Leopard on VirtualBox 3.2 with Non Apple, Intel PC&lt;/a&gt;&lt;/li&gt;

  &lt;li&gt;&lt;a href="http://www.sysprobs.com/mac-os-guest-virtualbox-326-snow-leopard-1064-windows-7-32-bit"&gt;Mac OS X Guest Snow Leopard 10.6.4 on PC with VirtualBox 3.2.6 – on Windows 7 32 Bit&lt;/a&gt;&lt;/li&gt;

  &lt;li&gt;&lt;a href="http://www.sysprobs.com/increase-mac-os-virtual-machine-screen-resolution-virtualbox-vmware-player"&gt;How to Increase Mac OS X Snow Leopard Virtual Machine Screen Resolution on VirtualBox and VMware&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;总结&lt;/h1&gt;

&lt;p&gt;您现在便可以尝试Mac OS X Snow Leopard操作系统及软件了。当然，这并不能给您带来完整的苹果机的体验，使用苹果机一体化的硬件配合它的操作系统，可以给您带来一些额外的感受，例如苹果笔记本带多点触摸的触摸板，它的使用体验和操作方式都给我留下了非常深刻的印象。&lt;/p&gt;</description>
      <comments>http://blog.zhaojie.me/2010/09/how-to-install-mac-os-x-snow-leopard-on-virtualbox.html#comments</comments>
      <pubDate>Sun, 26 Sep 2010 02:50:04 GMT</pubDate>
      <lastBuildDate>Sun, 26 Sep 2010 02:50:04 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/front-end/">前端表现</category>
      <category domain="http://blog.zhaojie.me/practice/">实践优化</category>
      <category domain="http://blog.zhaojie.me/parallel/">并行处理</category>
      <category domain="http://blog.zhaojie.me/cutting-edge/">技术尝鲜</category>
      <category domain="http://blog.zhaojie.me/speech/">培训演讲</category>
      <title>盛大创新院赞助第二届.NET技术交流会 - 演讲录像及下载</title>
      <link>http://blog.zhaojie.me/2010/09/2nd-snda-dotnet-conference-videos.html</link>
      <guid>http://blog.zhaojie.me/2010/09/2nd-snda-dotnet-conference-videos.html</guid>
      <description>&lt;p&gt;经过一个多星期的努力，我们在此为大家奉上&lt;a href="http://blog.zhaojie.me/2010/01/1651772.html"&gt;盛大创新院&lt;/a&gt;赞助&lt;a href="http://blog.zhaojie.me/2010/08/2nd-snda-dotnet-conference-sign-up.html"&gt;第二届.NET技术交流会&lt;/a&gt;的演讲录像。由于录像过程中的一些失误，我们在在讲师录像方面存在着很大问题，经过补救，也只能得到后两场演讲中使用手持设备拍摄下来的录像。在此向大家表示深深的歉意，有了这次的教训，我们以后会更加重视每一个环节的预防及补救措施，尽力避免如现在这样无可挽回的结果。&lt;/p&gt;

&lt;h1&gt;响应式编程与响应式框架&lt;/h1&gt;

&lt;a href="http://img.zhaojie.me/blog/snda-dotnet-conf/zhaojie.jpg" target="_blank"&gt;&lt;img class="floatRight" src="http://img.zhaojie.me/blog/snda-dotnet-conf/zhaojie.jpg" height="150" /&gt;&lt;/a&gt; 

&lt;p&gt;讲师：赵劼，盛大创新院，研究员。关注前沿技术，并致力于开源社区与微软平台的组合优化。对函数式编程，并行程序开发，代码之美以及程序员能力与修养等相关问题也有着浓厚的兴趣，同时非常希望能够写程序到60岁。最近致力于F#，Scala语言及mono平台在社区中的推广。&lt;/p&gt;

&lt;p&gt;简介：异步编程改变了我们的编程方式，也为我们带来的许多挑战，同时让一些编程模型重新焕发了生机。与传统的“拉”模型不同，响应式编程将异步事件流视为可观察的集合，这是一种“推”模型。微软为了提高云时代的编程体验而设计了响应式框架，其目的是为了简化复杂事件处理之间混合操作。从中我们了解到一些异步编程的模式与LINQ使用技巧，并可以将这种编程模型普及到JavaScript等其他平台上去。&lt;/p&gt;
&lt;embed src="http://player.youku.com/player.php/sid/XMjA3OTIzNzI0/v.swf" quality="high" width="480" height="400" align="middle" allowScriptAccess="sameDomain" type="application/x-shockwave-flash"&gt;&lt;/embed&gt; 

&lt;p&gt;&lt;a href="http://dlc2.sdo.com/FTP/cop/20100928/1/rx.mov"&gt;高清格式下载&lt;/a&gt;（mov格式，1280 * 720，265M）&lt;/p&gt;

&lt;h1&gt;大话程序员可用的算法&lt;/h1&gt;
&lt;a href="http://img.zhaojie.me/blog/snda-dotnet-conf/chengshaofei.jpg" target="_blank"&gt;&lt;img class="floatRight" src="http://img.zhaojie.me/blog/snda-dotnet-conf/chengshaofei.jpg" height="150" /&gt;&lt;/a&gt; 

&lt;p&gt;讲师：程劭非，盛大创新院，研究员。网名winter，无忧脚本版主。Web前端技术的积极倡导者。学生时代曾经热衷于参加ACM/ICPC。目前工作在Bambook电子书项目，主要负责文字排版和浏览器引擎WebKit相关。之前曾负责在Windows CE系统上的IE开发。&lt;/p&gt;

&lt;p&gt;简介：俗话说“数据结构+算法=程序”，算法是什么？算法书里满篇是看不懂的形式化推导，网上一些&amp;quot;高人&amp;quot;写的关于算法文章高深莫测，大公司面 试最让人讨厌的就是考算法题，“我做了这么多年，跟本在实际开发中就没用过算法！”，算法真的是距离我们如此遥远的东西吗？且听这回演讲， 算法究竟如何影响我们的开发。&lt;/p&gt;
&lt;embed src="http://player.youku.com/player.php/sid/XMjA3OTI3MjAw/v.swf" quality="high" width="480" height="400" align="middle" allowScriptAccess="sameDomain" type="application/x-shockwave-flash"&gt;&lt;/embed&gt; 

&lt;p&gt;&lt;a href="http://dlc2.sdo.com/FTP/cop/20100928/1/algorithms.mov"&gt;高清格式下载&lt;/a&gt;（mov格式，1280 * 720，128M）&lt;/p&gt;

&lt;h1&gt;Windows内核技术介绍&lt;/h1&gt;
&lt;a href="http://img.zhaojie.me/blog/snda-dotnet-conf/panaimin.jpg" target="_blank"&gt;&lt;img class="floatRight" src="http://img.zhaojie.me/blog/snda-dotnet-conf/panaimin.jpg" height="150" /&gt;&lt;/a&gt; 

&lt;p&gt;讲师：潘爱民，盛大创新院专家，微软学者，集团COO专家顾问。长期从事软件和系统技术的研究和开发工作，撰写了大量软件技术文章，并著译了多部经典计算机图书。在MSR/清华等从事多年科研工作，在北大和清华多年执教经验。数学学士学位和计算机科学博士，主要研究领域包括软件设计、信息安全、操作系统和Internet技术。&lt;/p&gt;

&lt;p&gt;简介：Windows操作系统经过二十年的发展，已臻成熟。Microsoft在推动Windows内核方面做了大量工作，譬如于2006年夏季向教育界开放了当时最为先进的内核源代码（Windows Research Kernel）。主讲者在这次讲座中，结合这些可利用的资源，分享对Windows内核研究的体会，尤其将重点讨论Windows中的I/O模型和环境子系统。&lt;/p&gt;
&lt;embed src="http://player.youku.com/player.php/sid/XMjEyOTkyMzgw/v.swf" quality="high" width="480" height="400" align="middle" allowScriptAccess="sameDomain" type="application/x-shockwave-flash"&gt;&lt;/embed&gt; 

&lt;p&gt;&lt;a href="http://dlc2.sdo.com/FTP/cop/20100928/1/win-kernal.mov"&gt;高清格式下载&lt;/a&gt;（mov格式，1280 * 720，480M）&lt;/p&gt;

&lt;h1&gt;面向对象与生活&lt;/h1&gt;
&lt;a href="http://img.zhaojie.me/blog/snda-dotnet-conf/gaoxiang.jpg" target="_blank"&gt;&lt;img class="floatRight" src="http://img.zhaojie.me/blog/snda-dotnet-conf/gaoxiang.jpg" height="150" /&gt;&lt;/a&gt; 

&lt;p&gt;讲师：高翔，5173.com&amp;#160; 项目经理。关注前沿技术和技术人员的非技术生活。对面向对象、模式和建模技术有浓厚兴趣，并对游戏设计和图形学方面也比较感兴趣。最近在学习F#，Lua以及关注一些关于职业生涯规划方面的话题。&lt;/p&gt;

&lt;p&gt;简介：面向对象这个话题虽然很热，但与哲学一样，很难给其一个很准确的定义。也因为如此，每个人对它都有自己的理解。本次演讲将从一个实际的例子出发，逐步引入面向对象的三个特征，结合对象的生命周期，以及基于事件的对象扩展方式等方面，探讨其与设计模式，与生活之间的联系。&lt;/p&gt;
&lt;embed src="http://player.youku.com/player.php/sid/XMjA2NjIxMzky/v.swf" quality="high" width="480" height="400" align="middle" allowScriptAccess="sameDomain" type="application/x-shockwave-flash"&gt;&lt;/embed&gt; 

&lt;p&gt;&lt;a href="http://dlc2.sdo.com/FTP/cop/20100928/1/ooad.mov"&gt;高清格式下载&lt;/a&gt;（mov格式，1280 * 720，320M）&lt;/p&gt;

&lt;h1&gt;相关文章&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="http://blog.zhaojie.me/2010/08/2nd-snda-dotnet-conference-sign-up.html"&gt;盛大创新院赞助第二届.NET技术交流会开始报名了！&lt;/a&gt; &lt;/li&gt;

  &lt;li&gt;&lt;a href="http://blog.zhaojie.me/2010/09/2nd-snda-dotnet-conference-is-coming.html"&gt;盛大创新院赞助第二届.NET技术交流会即将召开&lt;/a&gt; &lt;/li&gt;

  &lt;li&gt;&lt;a href="http://blog.zhaojie.me/2010/09/2nd-snda-dotnet-conference-all-slides.html"&gt;盛大创新院赞助第二届.NET技术交流会 - 各场演讲幻灯片&lt;/a&gt; &lt;/li&gt;

  &lt;li&gt;盛大创新院赞助第二届.NET技术交流会 - 演讲录像及下载 &lt;/li&gt;

  &lt;li&gt;盛大创新院赞助首届.NET技术交流会：&lt;a href="http://blog.zhaojie.me/2010/05/first-snda-dotnet-conference-sign-up.html"&gt;报名&lt;/a&gt;、&lt;a href="http://blog.zhaojie.me/2010/06/first-snda-dotnet-conference-is-coming.html"&gt;预告&lt;/a&gt;、&lt;a href="http://blog.zhaojie.me/2010/06/first-snda-dotnet-conference-all-slides.html"&gt;幻灯片&lt;/a&gt;、&lt;a href="http://blog.zhaojie.me/2010/06/first-snda-dotnet-conference-videos.html"&gt;演讲录象及下载&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;</description>
      <comments>http://blog.zhaojie.me/2010/09/2nd-snda-dotnet-conference-videos.html#comments</comments>
      <pubDate>Tue, 21 Sep 2010 03:27:11 GMT</pubDate>
      <lastBuildDate>Tue, 21 Sep 2010 03:27:11 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/language/">语言编程</category>
      <category domain="http://blog.zhaojie.me/front-end/">前端表现</category>
      <category domain="http://blog.zhaojie.me/cutting-edge/">技术尝鲜</category>
      <title>异步编程与响应式框架</title>
      <link>http://blog.zhaojie.me/2010/09/async-programming-and-reactive-framework.html</link>
      <guid>http://blog.zhaojie.me/2010/09/async-programming-and-reactive-framework.html</guid>
      <description>&lt;p&gt;本文原发表于《程序员》杂志9月刊，现将全文公开至此。前几天的技术交流会上我也讲了这部分内容，配合着看会有更好效果。&lt;/p&gt;

&lt;p&gt;此外我想再多几句。《程序员》杂志在某些方面必须尽快做出调整。就拿我这篇文章来说，代码除了被三栏的版式搞得支离破碎以外，其中必要的空格也莫名奇妙地少了许多。我认为《程序员》如今在内容方面已经有了显著提高，但是在这种“表面”工夫上也得抓紧才好，这也是国内同类杂志中“最专业者”所应有的风范。&lt;/p&gt;

&lt;h1&gt;前言&lt;/h1&gt;

&lt;p&gt;异步操作是强大的，它是许多高伸缩性架构的基石。异步操作在许多情况下是必须的，例如在客户端保持用户界面的响应能力，以及在日益兴起的云计算场景中。但是，异步编程又是十分困难的，它让这让许多程序员敬而远之。因此，越来越多的编程语言都对异步编程提供了相当程度的支持，其中的典型代表便是F#中的异步工作流以及Scala的Actor模型。不过目前的一些主流编程语言，如C#或是JavaScript，它们在设计之时并没有在异步编程上考虑太多，我们便会根据它们的语言特性，提供合适的异步编程模型及其实现。而本文介绍的便是其中一例：响应式编程（Reactive Programming）模型及响应式框架（Reactive Framework，简称Rx）。&lt;/p&gt;

&lt;h1&gt;异步编程的难点&lt;/h1&gt;

&lt;p&gt;异步编程之所以困难，主要有三大难点。&lt;/p&gt;  &lt;p&gt;首先是对于状态的维护。在普通编程中，我们已经习惯了根据各种状态采取不同做法的编程方式。在异步编程中，状态对于操作的影响则往往更为复杂。例如，我们在编写一个鼠标“拖动及绘图”的行为时，一般会采用这样的逻辑：&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;在MouseDown事件中将isDragging标记设为true，表示“拖动开始”，并记录当前鼠标位置prevPos。 &lt;/li&gt;    &lt;li&gt;在MouseUp事件中将isDragging标记设为false，表示“拖动结束”。 &lt;/li&gt;    &lt;li&gt;在MouseMove事件中检查isDragging标记，如果为true，根据鼠标当前位置currPos和之前记录的prevPos进行绘图，并将currPos的值写入prevPos。 &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;仅在这样一个最基本的场景中，我们便需要编写三个事件处理器（Event Handler），控制isDragging，prevPos等外部状态，并根据这些状态决定事件触发时的效果。这样的例子数不胜数，尤其是在各式拖放操作中，几乎都会涉及大量状态的控制（例如，判断物体是否进入某个特定区域）。&lt;/p&gt;  &lt;p&gt;异步编程的另一个难点，在于异步操作之间的组合及交互。例如在如上的简单拖放操作中，我们便涉及到了MouseDown，MouseUp及MouseMove三个事件。从某些角度来说，客户端的UI事件还是比较容易处理的，因为它们往往都是在单一线程上依次执行。但是在另外一些场景中，如云计算时，我们往往会同时发起多个异步操作，并根据这些操作的结果进行后续处理，甚至还会有一个额外的超时监控，这样便很有可能会出现并发操作的竞争（Race）情况，这将会成为程序复杂度的灾难。&lt;/p&gt;  &lt;p&gt;此外，异步操作还会破坏“代码局部性（Code Locality）”，这可能也是异步操作中最为常见的阻碍。程序员早已习惯了“线性”地表达逻辑，但即便是多个顺序执行的异步操作，也会因为大量的回调函数而将算法拆得支离破碎，更何况还会出现各种循环及条件判断。同时，在线性的代码中，我们可以使用“局部变量”保存状态，而在编写异步代码时则需要手动地在多个函数中传递状态。此外，由于逻辑被拆分至多个方法，因此我们也无法使用传统的try/catch进行统一异常处理。&lt;/p&gt;

&lt;h1&gt;推模型与拉模型&lt;/h1&gt;

&lt;p&gt;平时我们使用最多的便是“交互式（Interactive）”的编程方式，采用的是组件之间的相互调用来表现逻辑。例如，对象A向对象B请求数据并等待返回，待对象B完成并返还数据之后A才继续进行后面的操作。交互式编程的一个典型应用便是GoF23中的迭代器（Iterator）模式，它在.NET中的实现为IEnumerable及IEnumerator接口，例如：&lt;/p&gt;  &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;void &lt;/span&gt;Traverse(&lt;span style="color: #2b91af"&gt;IEnumerable&lt;/span&gt;&amp;lt;&lt;span style="color: blue"&gt;int&lt;/span&gt;&amp;gt; source)
{
    &lt;span style="color: blue"&gt;var &lt;/span&gt;etor = source.GetEnumerator();
    &lt;span style="color: blue"&gt;while &lt;/span&gt;(etor.MoveNext())
    {
        &lt;span style="color: #2b91af"&gt;Console&lt;/span&gt;.WriteLine(etor.Current);
    }
}&lt;/pre&gt;

&lt;p&gt;为了更好地说明问题，这里我们将标准的foreach操作展开为传统的迭代器使用形式，并省略了using语句。在使用时，我们先调用一个IEnumerable对象的GetEnumerator方法，获得一个迭代器，再根据MoveNext及Current进行遍历。在调用MoveNext时，迭代器会去“准备”下一个元素，并根据存在与否返回true或者false。试想，如果其中某个MoveNext的“准备”工作涉及到一个耗时较长的操作，则迭代器的使用者也必须眼巴巴地等待其返回。&lt;/p&gt;

&lt;p&gt;这是一种“拉（Pull）”模型，数据由消费者（Consumer）从生产者（Producer）那里主动“拉”来。这是一种同步的交互方式，数据消费者会依赖于数据生产者的表现。这就好比我们去食堂吃饭时必须主动去取餐，此时则必须从队伍的最后排起，我们什么时候能结束等待并进行下一步操作（即“吃饭”），则要看食堂的生产速度如何。很显然，有些时候这种交互方式是不可接受的，例如我们在实现一个搜索引擎的“关键字提示”功能时，不可能让用户在输入一个字符后，必须等待远程的提示请求返回才能继续输入下一个字符。&lt;/p&gt;

&lt;p&gt;而与交互式编程对应的便是“响应式（Reactive）”编程。响应式编程是一种基于“改变”的编程方式。例如在交互式编程中，A = B + C这样的表达式意味着将B与C之和赋给A，而此后B与C的改变都与A无关。而在响应式编程中，A会去“响应”B或C的变化，即一旦B或C改变之后，A的值也会随之变化。响应式编程的一个典型应用便是GoF23中的观察者（Observer）模式。与迭代器的IEnumerable/IEnumerator不同，在之前的.NET框架中并没有对这样一种编程模型指定“标准化（Formallized）”接口，不过在.NET 4.0的基础类库中增加了IObservable及IObserver接口，签名如下：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public interface &lt;/span&gt;&lt;span style="color: #2b91af"&gt;IObservable&lt;/span&gt;&amp;lt;&lt;span style="color: blue"&gt;out &lt;/span&gt;T&amp;gt;
{
    &lt;span style="color: #2b91af"&gt;IDisposable &lt;/span&gt;Subscribe(&lt;span style="color: #2b91af"&gt;IObserver&lt;/span&gt;&amp;lt;T&amp;gt; observer);
}

&lt;span style="color: blue"&gt;public interface &lt;/span&gt;&lt;span style="color: #2b91af"&gt;IObserver&lt;/span&gt;&amp;lt;&lt;span style="color: blue"&gt;in &lt;/span&gt;T&amp;gt;
{
    &lt;span style="color: blue"&gt;void &lt;/span&gt;OnCompleted();
    &lt;span style="color: blue"&gt;void &lt;/span&gt;OnError(&lt;span style="color: #2b91af"&gt;Exception &lt;/span&gt;error);
    &lt;span style="color: blue"&gt;void &lt;/span&gt;OnNext(T value);
}&lt;/pre&gt;

&lt;p&gt;如果我们仔细比较“迭代器”与“观察者”的标准化接口，则会发现它们是完全“对偶（dual）”的：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;IEnumerable.GetEnumerator方法“输出”一个IEnumerater对象；IObservable.Subscribe方法“输入”一个IObserver对象。 &lt;/li&gt;

  &lt;li&gt;在遍历元素用尽时，IEnumerator.MoveNext方法返回false；在响应内容用尽时，IObserver.OnCompleted方法被调用。 &lt;/li&gt;

  &lt;li&gt;在有新元素需要遍历时，IEnumerator.MoveNext方法返回true，并通过Current属性“输出”；在有新元素需要响应时，IObserver.OnNext方法被调用，并通过参数“输入”。 &lt;/li&gt;

  &lt;li&gt;在出现错误时，IEnumerator.MoveNext方法会“抛出”一个异常；在出现错误时，IObserver.OnError方法会被调用，并通过参数“接受”异常信息。 &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;至于IObservable.Subscribe方法返回的IDisposable对象，则用于“退定”操作，即让输入的IObserver对象再也不需要继续响应IObservable对象的新元素了。&lt;/p&gt;

&lt;p&gt;从比较中可以看出，如果说IEnumerator对象是由数据消费者使用的话，那么IObserver对象则是由数据的生产者，即IObservable对象使用的。换句话说，数据是由数据的生产者“推”给数据消费者的，是一种“推（Push）”模型。在这种异步的交互方式中，数据消费者不必依赖于数据生产者的表现。这就好比我们去饭店吃饭，点菜后便可坐下和同伴聊聊天或是用手机上上网，而作为菜品的生产者，饭店，则会在产出之后主动端上桌来。这么做无疑解放了数据的消费者，例如用户可以在文本框里不断地输入字符，而只需等远程服务器将提示结果“推”给客户端后再显示即可。&lt;/p&gt;

&lt;p&gt;许多模型都可以统一至标准的生产者接口IObservable上，如MouseMove事件便可以认做是“永不停止的MouseEventArgs对象的生产者”。而另一方面，单个异步操作则可以被视为“只产出单个数据便结束的生产者”。&lt;/p&gt;

&lt;h1&gt;LINQ to Observable&lt;/h1&gt;

&lt;p&gt;在许多人眼中，C# 3.0中新增的LINQ特性只是一种用于操作数据的DSL，它的主要作用也仅仅是针对IEnumerable或是IQueryable的数据操作。事实上，LINQ本身的能力远不止此。LINQ是一种非常简单的语言特性，编译器只是将LINQ查询语句转化为“字面等价”的“LINQ标准方法”调用（如Where，Select等等）和“和Lambda表达式”参数（如x =&amp;gt; x &amp;gt; 0）而已。但是这里的关键便是“字面等价”四个字，LINQ本身并不规定“LINQ标准方法”是对象的实例方法还是扩展方法，“Lambda表达式”是构造出一个匿名函数还是表达式树，这一切都是由利用LINQ的类库来决定的。因此，微软能够基于LINQ实现了PLINQ这样的并行类库。直到最近的访谈中，LINQ的设计者Erik Meijer依旧认为LINQ还是被低估了，他们自己也还在继续挖掘LINQ的更多能力。&lt;/p&gt;

&lt;p&gt;虽然LINQ本身在语法上只是一些方法调用，但是它在语义上是针对数据流的一系列操作，因此LINQ to Object，LINQ to SQL以及PLINQ可以认为是最自然，最符合LINQ语义的应用。如今，微软的“云编程能力团队（Cloud Programmability Team）”在其“响应式框架（Reactive Framework，简称Rx）”提供了LINQ to Observable，这又是另一个LINQ的经典使用案例。IObservable本身可以被认为是一股“推送数据”的数据流，因此也可以对其进行“过滤”或是“投影”等操作，这便是LINQ的应用场景，LINQ to Observable是对IObservable接口实现的一系列LINQ标准方法。因此，我们可以认为，LINQ to Observable是一套与LINQ to Object对偶的类库，事实上在响应式框架中，还有一套与LINQ to Queryable对偶的LINQ to Qbservable，请注意第一个字母是Q，我们可以把它看作是LINQ to Observable的“远程查询”版本。&lt;/p&gt;

&lt;p&gt;利用LINQ to Object可以编写出声明式（表示“做什么”）的代码，其可读性往往远高于等价的命令式（表示“怎么做”）代码。LINQ to Observable也有类似的效果。假设现在有一个需求：利用ADWS键控制小球的位置。传统的写法可能是这样的：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;void &lt;/span&gt;OnKeyPress(&lt;span style="color: blue"&gt;object &lt;/span&gt;sender, &lt;span style="color: #2b91af"&gt;KeyPressEventArgs &lt;/span&gt;e)
{
    // 如果游戏已经开始
    &lt;span style="color: blue"&gt;if &lt;/span&gt;(isPlaying) &lt;span style="color: green"&gt;&lt;/span&gt;
    {
        &lt;span style="color: green"&gt;// 向左且小球没有超出边界&lt;/span&gt;
        &lt;span style="color: blue"&gt;if &lt;/span&gt;(e.KeyChar == &lt;span style="color: #a31515"&gt;'a'&lt;/span&gt; &amp;amp;&amp;amp; ball.Left &amp;gt; 0)
        {
            ball.Left -= 5;
        }
        &lt;span style="color: green"&gt;// 向上且小球没有超出边界&lt;/span&gt;
        &lt;span style="color: blue"&gt;else if &lt;/span&gt;(e.KeyChar == &lt;span style="color: #a31515"&gt;'w'&lt;/span&gt; &amp;amp;&amp;amp; ball.Top &amp;gt; 0)
        {
            ball.Top -= 5;
        }
        &lt;span style="color: blue"&gt;else &lt;/span&gt;... &lt;span style="color: green"&gt;&lt;/span&gt;
    }
    &lt;span style="color: blue"&gt;else &lt;/span&gt;...
}&lt;/pre&gt;

&lt;p&gt;由于KeyPress事件总是不断触发，因此我们只能它的事件处理器中进行判断各种状态，采取不同措施。而如果我们利用LINQ to Observable，则几乎是另外一种思维方式：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: green"&gt;// 过滤出isPlaying时的keyPress事件
&lt;/span&gt;&lt;span style="color: blue"&gt;var &lt;/span&gt;keyPress = GetKeyPress().Where(_ =&amp;gt; isPlaying);

&lt;span style="color: green"&gt;// 过滤出向左移动的事件
&lt;/span&gt;&lt;span style="color: blue"&gt;var &lt;/span&gt;moveLeft = &lt;span style="color: blue"&gt;from &lt;/span&gt;ev &lt;span style="color: blue"&gt;in &lt;/span&gt;keyPress
               &lt;span style="color: blue"&gt;where &lt;/span&gt;ev.EventArgs.KeyChar == &lt;span style="color: #a31515"&gt;'a'
               &lt;/span&gt;&lt;span style="color: blue"&gt;where &lt;/span&gt;ball.Left &amp;gt; 0
               &lt;span style="color: blue"&gt;select &lt;/span&gt;ev;
moveLeft.Subscribe(_ =&amp;gt; ball.Left -= 5);

&lt;span style="color: green"&gt;// 过滤出向上移动的事件
&lt;/span&gt;&lt;span style="color: blue"&gt;var &lt;/span&gt;moveTop = &lt;span style="color: blue"&gt;from &lt;/span&gt;ev &lt;span style="color: blue"&gt;in &lt;/span&gt;keyPress
              &lt;span style="color: blue"&gt;where &lt;/span&gt;ev.EventArgs.KeyChar == &lt;span style="color: #a31515"&gt;'w'
              &lt;/span&gt;&lt;span style="color: blue"&gt;where &lt;/span&gt;ball.Top &amp;gt; 0
              &lt;span style="color: blue"&gt;select &lt;/span&gt;ev;
moveTop.Subscribe(_ =&amp;gt; ball.Top -= 5);&lt;/pre&gt;

&lt;p&gt;我们可以将“KeyPress事件”视为“推送KeyPressEventArgs对象”这一数据流的数据源（由GetKeyPress方法返回），那么如今的代码便是使用LINQ过滤出“需要”的数据，并针对真正需要的那部分进行响应。这么做，便将“条件”与“操作”解耦，显著增强了代码的语义表达能力。事实上，只要补充一些辅助方法，可以利用LINQ表示更为完整复杂的逻辑。例如，微软咨询师Matthew Podwysocki便&lt;a href="http://codebetter.com/blogs/matthew.podwysocki/archive/2009/11/18/introduction-to-the-reactive-framework-part-v.aspx"&gt;在博客中展示过一段代码&lt;/a&gt;，基于LINQ to Observable实现了创建一个WebRequest对象，设置属性，异步发送及下载数据的一系列操作。&lt;/p&gt;

&lt;h1&gt;更多扩展&lt;/h1&gt;

&lt;p&gt;.NET基础类库针对IEnumerable定义了大量的函数式的辅助方法，开发人员可以直接将它们组合运用在项目中。除了标准的LINQ操作方法之外，响应式框架中同样定义了大量辅助方法，可以配合LINQ to Observable组合使用。例如本文开头所设想的鼠标“拖动及绘图”功能，便可以使用如下代码完成：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;var &lt;/span&gt;mouseMove = GetMouseMove();
&lt;span style="color: blue"&gt;var &lt;/span&gt;mouseDiff = mouseMove.Zip(mouseMove.Skip(1), (prev, curr) =&amp;gt;
    &lt;span style="color: blue"&gt;new
    &lt;/span&gt;{
        PrevPos = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Point&lt;/span&gt;(prev.EventArgs.X, prev.EventArgs.Y),
        CurrPos = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Point&lt;/span&gt;(curr.EventArgs.X, curr.EventArgs.Y)
    });

&lt;span style="color: blue"&gt;var &lt;/span&gt;mouseDrag = &lt;span style="color: blue"&gt;from &lt;/span&gt;_ &lt;span style="color: blue"&gt;in &lt;/span&gt;GetMouseDown()
                &lt;span style="color: blue"&gt;from &lt;/span&gt;diff &lt;span style="color: blue"&gt;in &lt;/span&gt;mouseDiff.TakeUntil(GetMouseUp())
                &lt;span style="color: blue"&gt;select &lt;/span&gt;diff;
mouseDrag.Subscribe(diff =&amp;gt; DrawLine(diff.PrevPos, diff.CurrPos));&lt;/pre&gt;

&lt;p&gt;在这段代码中，我们首先将mouseMove事件使用Skip跳开一项，再与自身通过Zip方法组合成mouseDiff，这是一个输出相邻两次MouseMove事件坐标的数据源；接着，我们利用LINQ从触发MouseDown事件开始，向mouseDiff数据源获取每一项diff，直至（TakeUntil）触发MouseUp事件，以此生成最终的mouseDrag；最后再将绘图功能订阅至这个数据源上。您会发现此时我们已经无须手动维护操作过程中的各种状态了，从事件的“开始”到“结束”均使用响应式框架的辅助方法“声明”而来。&lt;/p&gt;

&lt;p&gt;以上便是一个利用了Skip，Zip，TakeUntil等辅助方法的例子。当然，这些辅助方法在IEnumerable上都有语义相同的对应操作，而在响应式框架中还有更多辅助方法是针对特性异步场景的。假设我们现在要编写一个即时翻译功能，同时发起三个请求，将中文分别翻译至英语、法语及西班牙语，并显示最先返回的两个结果（真是个奇怪的需求）。此外，我们不会在用户输入每个字符的时候便发起一个远程请求，而是在用户停止输入0.5秒之后才根据当前的输入框中的文字进行提示。于是我们可以编写这样的代码：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;var &lt;/span&gt;limit = &lt;span style="color: #2b91af"&gt;TimeSpan&lt;/span&gt;.FromSeconds(0.5);
&lt;span style="color: blue"&gt;var &lt;/span&gt;translate =
    &lt;span style="color: blue"&gt;from &lt;/span&gt;_ &lt;span style="color: blue"&gt;in &lt;/span&gt;GetKeyPress().Throttle(limit)
    &lt;span style="color: blue"&gt;let &lt;/span&gt;text = &lt;span style="color: blue"&gt;this&lt;/span&gt;.txtInput.Text
    &lt;span style="color: blue"&gt;where &lt;/span&gt;text.Length &amp;gt; 0
    &lt;span style="color: blue"&gt;let &lt;/span&gt;english = &lt;span style="color: #2b91af"&gt;Bing&lt;/span&gt;.Translate(text, &lt;span style="color: #a31515"&gt;&amp;quot;en&amp;quot;&lt;/span&gt;)
    &lt;span style="color: blue"&gt;let &lt;/span&gt;french = &lt;span style="color: #2b91af"&gt;Bing&lt;/span&gt;.Translate(text, &lt;span style="color: #a31515"&gt;&amp;quot;fr&amp;quot;&lt;/span&gt;)
    &lt;span style="color: blue"&gt;let &lt;/span&gt;spanish = &lt;span style="color: #2b91af"&gt;Bing&lt;/span&gt;.Translate(text, &lt;span style="color: #a31515"&gt;&amp;quot;es&amp;quot;&lt;/span&gt;)
    &lt;span style="color: blue"&gt;from &lt;/span&gt;result &lt;span style="color: blue"&gt;in &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Observable&lt;/span&gt;.Join(
       english.And(french).Then((en, fr) =&amp;gt;
           &lt;span style="color: blue"&gt;new &lt;/span&gt;{ English = en, French = fr, Spanish = &lt;span style="color: #a31515"&gt;&amp;quot;&amp;quot;&lt;/span&gt; }),
       english.And(spanish).Then((en, es) =&amp;gt;
           &lt;span style="color: blue"&gt;new &lt;/span&gt;{ English = en, French = &lt;span style="color: #a31515"&gt;&amp;quot;&amp;quot;&lt;/span&gt;, Spanish = es }),
       french.And(spanish).Then((fr, es) =&amp;gt;
           &lt;span style="color: blue"&gt;new &lt;/span&gt;{ English = &lt;span style="color: #a31515"&gt;&amp;quot;&amp;quot;&lt;/span&gt;, French = fr, Spanish = es }))
    &lt;span style="color: blue"&gt;select &lt;/span&gt;result;

translate.Subscribe(...);&lt;/pre&gt;

&lt;p&gt;这里用到了Throottle方法，它会过滤某个数据源的输出，确保在该数据源“静默”特定时间之后，才将最近的一条数据推送至外部。此外，这里还使用了Observable.Join方法控制多个数据源，根据返回结果的先后获得合适的结果。响应式框架提供了大量针对某种异步场景的辅助方法，例如用于定期推送数据的Interval方法，从一个数据源根据特定条件进行采样的Sample方法，合并多个数据源的ForkJoin方法，以及表示流程控制的For，While，If等等。这些方法内部会维护各种所需要的状态，为我们打理各种复杂的竞争情况，以此节省了开发人员的精力。&lt;/p&gt;

&lt;p&gt;如果这些还不能满足我们的要求，我们也可以根据自己的需要开发特定的辅助方法，就像我们在使用LINQ to Object时为IEnumerable所作的各种扩展那样。响应式框架也提供了一系列Subject类型，简化了IObservable自定义扩展的开发过程。由于响应式框架尚未正式发布，微软目前建立了&lt;a href="http://rxwiki.wikidot.com/"&gt;一个Wiki&lt;/a&gt;，用于展示关于各辅助方法及Subject类的使用示例及其他相关信息。&lt;/p&gt;

&lt;h1&gt;响应式框架的JavaScript版本&lt;/h1&gt;

&lt;p&gt;响应式编程的重要使用场景之一便是与用户交互的GUI界面。例如，Silverlight禁止任何阻塞的IO操作，换言之Silverlight中的所有网络操作都是异步的，微软也正是出于简化异步开发的目的才设计了响应式框架（事实上响应式框架已经集成到Silverlight Toolkit中）。不过与Silverlight相比，基于浏览器的原生JavaScript应用程序无疑使用地更为广泛。对于这样的应用程序来说，动画是异步的，AJAX请求也是异步的，我们几乎可以断言，如果有一套面向JavaScirpt应用程序的响应式框架，一定会比面向Silverlight的框架更有意义得多。&lt;/p&gt;

&lt;p&gt;微软也想到了这一点。之前我们讨论的“响应式框架”，其实只是响应式编程模型的一种实现。更确切地说，我们只是讨论了这套框架的.NET版本，微软还提供了JavaScript版本的响应式框架。JavaScript版本的API与.NET版本几乎完全一致，例如我们之前讨论的拖放操作，使用JavaScript即可写作：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;var &lt;/span&gt;target = $(&lt;span style="color: maroon"&gt;&amp;quot;#dragTarget&amp;quot;&lt;/span&gt;);
&lt;span style="color: blue"&gt;var &lt;/span&gt;mouseMove = target.toObservable(&lt;span style="color: maroon"&gt;&amp;quot;mousemove&amp;quot;&lt;/span&gt;);
&lt;span style="color: blue"&gt;var &lt;/span&gt;mouseDiff = mouseMove.Zip(mouseMove.Skip(1), 
    &lt;span style="color: blue"&gt;function&lt;/span&gt;(prev, curr) {
        &lt;span style="color: blue"&gt;return &lt;/span&gt;{
            PrevPos: { x: prev.clientX, y: prev.clientY },
            CurrPos: { x: curr.clientX, y: curr.clientY }
        };
    });

&lt;span style="color: blue"&gt;var &lt;/span&gt;mouseDown = target.toObservable(&lt;span style="color: maroon"&gt;&amp;quot;mousedown&amp;quot;&lt;/span&gt;);
&lt;span style="color: blue"&gt;var &lt;/span&gt;mouseUp = target.toObservable(&lt;span style="color: maroon"&gt;&amp;quot;mouseup&amp;quot;&lt;/span&gt;);
&lt;span style="color: blue"&gt;var &lt;/span&gt;mouseDrag = mouseDown.SelectMany(&lt;span style="color: blue"&gt;function&lt;/span&gt;() {
    mouseDiff.TakeUntil(mouseUp);
});

mouseDrag.Subscribe(...);&lt;/pre&gt;

&lt;p&gt;由于没有C#中的LINQ查询语言，我们只能直接使用展开后的方法，如SelectMany来编写逻辑。JavaScript版本的响应式框架还提供了一系列的“胶合”层，能够与jQuery，Dojo，MooTools，Prototype等流行框架同时使用。例如，上一段代码中的toObservable便是在jQuery根对象上扩展的方法。&lt;/p&gt;

&lt;h1&gt;总结&lt;/h1&gt;

&lt;p&gt;异步编程在用户交互式界面及一些云计算场景中尤其重要。微软的云编程能力团队针对.NET平台和JavaScirpt分别提供了一套响应式框架，希望以此简化异步程序的开发。不过，这套响应式框架所表现出的理念是通用的。而且，事实上只要是拥有匿名函数及闭包的语言，例如Scala，Python，Ruby等等，实现这样一套框架其实都不是十分困难的事情。&lt;/p&gt;
</description>
      <comments>http://blog.zhaojie.me/2010/09/async-programming-and-reactive-framework.html#comments</comments>
      <pubDate>Tue, 14 Sep 2010 12:14:28 GMT</pubDate>
      <lastBuildDate>Tue, 14 Sep 2010 12:14:28 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/front-end/">前端表现</category>
      <category domain="http://blog.zhaojie.me/practice/">实践优化</category>
      <category domain="http://blog.zhaojie.me/parallel/">并行处理</category>
      <category domain="http://blog.zhaojie.me/cutting-edge/">技术尝鲜</category>
      <category domain="http://blog.zhaojie.me/speech/">培训演讲</category>
      <title>盛大创新院赞助第二届.NET技术交流会 - 各场演讲幻灯片</title>
      <link>http://blog.zhaojie.me/2010/09/2nd-snda-dotnet-conference-all-slides.html</link>
      <guid>http://blog.zhaojie.me/2010/09/2nd-snda-dotnet-conference-all-slides.html</guid>
      <description>&lt;p&gt;昨天有160多位朋友参加了&lt;a href="http://blog.zhaojie.me/2010/01/1651772.html"&gt;盛大创新院&lt;/a&gt;赞助的&lt;a href="http://blog.zhaojie.me/2010/08/2nd-snda-dotnet-conference-sign-up.html"&gt;第二届.NET技术交流会&lt;/a&gt;，再次感谢各位对我们的支持。比较遗憾的是，这次的讲师录像方面有着很大问题，我们正在想办法进行修补，希望可以有“差强人意”的结果。现在，大家请在第一时间浏览本次活动新鲜出炉的幻灯片。&lt;/p&gt;

&lt;h1&gt;响应式编程与响应式框架&lt;/h1&gt;
&lt;a href="http://img.zhaojie.me/blog/snda-dotnet-conf/zhaojie.jpg" target="_blank"&gt;&lt;img class="floatRight" src="http://img.zhaojie.me/blog/snda-dotnet-conf/zhaojie.jpg" height="150" /&gt;&lt;/a&gt; 

&lt;p&gt;讲师：赵劼，盛大创新院，研究员。关注前沿技术，并致力于开源社区与微软平台的组合优化。对函数式编程，并行程序开发，代码之美以及程序员能力与修养等相关问题也有着浓厚的兴趣，同时非常希望能够写程序到60岁。最近致力于F#，Scala语言及mono平台在社区中的推广。&lt;/p&gt;

&lt;p&gt;简介：异步编程改变了我们的编程方式，也为我们带来的许多挑战，同时让一些编程模型重新焕发了生机。与传统的“拉”模型不同，响应式编程将异步事件流视为可观察的集合，这是一种“推”模型。微软为了提高云时代的编程体验而设计了响应式框架，其目的是为了简化复杂事件处理之间混合操作。从中我们了解到一些异步编程的模式与LINQ使用技巧，并可以将这种编程模型普及到JavaScript等其他平台上去。&lt;/p&gt;

&lt;div style="width: 425px" id="__ss_5183111"&gt;&lt;strong style="margin: 12px 0px 4px; display: block"&gt;&lt;a title="响应式编程及框架" href="http://www.slideshare.net/jeffz/reactive-programming-and-framework"&gt;响应式编程及框架&lt;/a&gt;&lt;/strong&gt;&lt;object id="__sse5183111" width="425" height="355"&gt;&lt;param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=rx-100912025913-phpapp01&amp;stripped_title=reactive-programming-and-framework" /&gt;&lt;param name="allowFullScreen" value="true"/&gt;&lt;param name="allowScriptAccess" value="always"/&gt;&lt;embed name="__sse5183111" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=rx-100912025913-phpapp01&amp;stripped_title=reactive-programming-and-framework" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"&gt;&lt;/embed&gt;&lt;/object&gt;

  &lt;div style="padding-bottom: 12px; padding-left: 0px; padding-right: 0px; padding-top: 5px"&gt;View more &lt;a href="http://www.slideshare.net/"&gt;presentations&lt;/a&gt; from &lt;a href="http://www.slideshare.net/jeffz"&gt;jeffz&lt;/a&gt;.&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;相关下载：&lt;a href="http://files.zhaojie.me/slides/snda-dotnet-conf/20100911/rx-zhaojie.pdf"&gt;幻灯片&lt;/a&gt;、&lt;a href="http://files.zhaojie.me/slides/snda-dotnet-conf/20100911/rx-demo-zhaojie.zip"&gt;示例程序&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;大话程序员可用的算法&lt;/h1&gt;
&lt;a href="http://img.zhaojie.me/blog/snda-dotnet-conf/chengshaofei.jpg" target="_blank"&gt;&lt;img class="floatRight" src="http://img.zhaojie.me/blog/snda-dotnet-conf/chengshaofei.jpg" height="150" /&gt;&lt;/a&gt; 

&lt;p&gt;讲师：程劭非，盛大创新院，研究员。网名winter，无忧脚本版主。Web前端技术的积极倡导者。学生时代曾经热衷于参加ACM/ICPC。目前工作在Bambook电子书项目，主要负责文字排版和浏览器引擎WebKit相关。之前曾负责在Windows CE系统上的IE开发。&lt;/p&gt;

&lt;p&gt;简介：俗话说“数据结构+算法=程序”，算法是什么？算法书里满篇是看不懂的形式化推导，网上一些&amp;quot;高人&amp;quot;写的关于算法文章高深莫测，大公司面 试最让人讨厌的就是考算法题，“我做了这么多年，跟本在实际开发中就没用过算法！”，算法真的是距离我们如此遥远的东西吗？且听这回演讲， 算法究竟如何影响我们的开发。&lt;/p&gt;

&lt;div style="width: 425px" id="__ss_5183325"&gt;&lt;strong style="margin: 12px 0px 4px; display: block"&gt;&lt;a title="大话程序员可用的算法" href="http://www.slideshare.net/jeffz/programmers-and-algorithms"&gt;大话程序员可用的算法&lt;/a&gt;&lt;/strong&gt;&lt;object id="__sse5183325" width="425" height="355"&gt;&lt;param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=random-100912045100-phpapp01&amp;stripped_title=programmers-and-algorithms" /&gt;&lt;param name="allowFullScreen" value="true"/&gt;&lt;param name="allowScriptAccess" value="always"/&gt;&lt;embed name="__sse5183325" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=random-100912045100-phpapp01&amp;stripped_title=programmers-and-algorithms" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"&gt;&lt;/embed&gt;&lt;/object&gt;

  &lt;div style="padding-bottom: 12px; padding-left: 0px; padding-right: 0px; padding-top: 5px"&gt;View more &lt;a href="http://www.slideshare.net/"&gt;presentations&lt;/a&gt; from &lt;a href="http://www.slideshare.net/jeffz"&gt;jeffz&lt;/a&gt;.&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;相关下载：&lt;a href="http://files.zhaojie.me/slides/snda-dotnet-conf/20100911/algorithms-chengshaofei.pdf"&gt;幻灯片&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;Windows内核技术介绍&lt;/h1&gt;
&lt;a href="http://img.zhaojie.me/blog/snda-dotnet-conf/panaimin.jpg" target="_blank"&gt;&lt;img class="floatRight" src="http://img.zhaojie.me/blog/snda-dotnet-conf/panaimin.jpg" height="150" /&gt;&lt;/a&gt; 

&lt;p&gt;讲师：潘爱民，盛大创新院专家，微软学者，集团COO专家顾问。长期从事软件和系统技术的研究和开发工作，撰写了大量软件技术文章，并著译了多部经典计算机图书。在MSR/清华等从事多年科研工作，在北大和清华多年执教经验。数学学士学位和计算机科学博士，主要研究领域包括软件设计、信息安全、操作系统和Internet技术。&lt;/p&gt;

&lt;p&gt;简介：Windows操作系统经过二十年的发展，已臻成熟。Microsoft在推动Windows内核方面做了大量工作，譬如于2006年夏季向教育界开放了当时最为先进的内核源代码（Windows Research Kernel）。主讲者在这次讲座中，结合这些可利用的资源，分享对Windows内核研究的体会，尤其将重点讨论Windows中的I/O模型和环境子系统。&lt;/p&gt;

&lt;div style="width:425px" id="__ss_5183269"&gt;&lt;strong style="display:block;margin:12px 0 4px"&gt;&lt;a href="http://www.slideshare.net/jeffz/win-os-kernel-tech" title="Windows内核技术介绍"&gt;Windows内核技术介绍&lt;/a&gt;&lt;/strong&gt;&lt;object id="__sse5183269" width="425" height="355"&gt;&lt;param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=winos-kernel-techforsnda2010-9-100912042602-phpapp01&amp;stripped_title=win-os-kernel-tech&amp;userName=jeffz" /&gt;&lt;param name="allowFullScreen" value="true"/&gt;&lt;param name="allowScriptAccess" value="always"/&gt;&lt;embed name="__sse5183269" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=winos-kernel-techforsnda2010-9-100912042602-phpapp01&amp;stripped_title=win-os-kernel-tech&amp;userName=jeffz" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;div style="padding:5px 0 12px"&gt;View more &lt;a href="http://www.slideshare.net/"&gt;presentations&lt;/a&gt; from &lt;a href="http://www.slideshare.net/jeffz"&gt;jeffz&lt;/a&gt;.&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;相关下载：&lt;a href="http://files.zhaojie.me/slides/snda-dotnet-conf/20100911/win-kernel-panaimin.pdf"&gt;幻灯片&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;面向对象与生活&lt;/h1&gt;
&lt;a href="http://img.zhaojie.me/blog/snda-dotnet-conf/gaoxiang.jpg" target="_blank"&gt;&lt;img class="floatRight" src="http://img.zhaojie.me/blog/snda-dotnet-conf/gaoxiang.jpg" height="150" /&gt;&lt;/a&gt; 

&lt;p&gt;讲师：高翔，5173.com&amp;#160; 项目经理。关注前沿技术和技术人员的非技术生活。对面向对象、模式和建模技术有浓厚兴趣，并对游戏设计和图形学方面也比较感兴趣。最近在学习F#，Lua以及关注一些关于职业生涯规划方面的话题。&lt;/p&gt;

&lt;p&gt;简介：面向对象这个话题虽然很热，但与哲学一样，很难给其一个很准确的定义。也因为如此，每个人对它都有自己的理解。本次演讲将从一个实际的例子出发，逐步引入面向对象的三个特征，结合对象的生命周期，以及基于事件的对象扩展方式等方面，探讨其与设计模式，与生活之间的联系。&lt;/p&gt;

&lt;div style="width: 425px" id="__ss_5183310"&gt;&lt;strong style="margin: 12px 0px 4px; display: block"&gt;&lt;a title="面向对象与生活" href="http://www.slideshare.net/jeffz/object-orientation-and-life"&gt;面向对象与生活&lt;/a&gt;&lt;/strong&gt;&lt;object id="__sse5183310" width="425" height="355"&gt;&lt;param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=random-100912044502-phpapp01&amp;stripped_title=object-orientation-and-life" /&gt;&lt;param name="allowFullScreen" value="true"/&gt;&lt;param name="allowScriptAccess" value="always"/&gt;&lt;embed name="__sse5183310" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=random-100912044502-phpapp01&amp;stripped_title=object-orientation-and-life" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"&gt;&lt;/embed&gt;&lt;/object&gt;

  &lt;div style="padding-bottom: 12px; padding-left: 0px; padding-right: 0px; padding-top: 5px"&gt;View more &lt;a href="http://www.slideshare.net/"&gt;presentations&lt;/a&gt; from &lt;a href="http://www.slideshare.net/jeffz"&gt;jeffz&lt;/a&gt;.&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;相关下载：&lt;a href="http://files.zhaojie.me/slides/snda-dotnet-conf/20100911/ooad-gaoxiang.pdf"&gt;幻灯片&lt;/a&gt;、附加资料“&lt;a href="http://files.zhaojie.me/slides/snda-dotnet-conf/20100911/%e4%b8%96%e7%95%8c%e7%9a%84%e5%ae%8f%e8%a7%82%e5%92%8c%e5%be%ae%e8%a7%82.pptx"&gt;世界的宏观和微观&lt;/a&gt;”&lt;/p&gt;

&lt;h1&gt;相关文章&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="http://blog.zhaojie.me/2010/08/2nd-snda-dotnet-conference-sign-up.html"&gt;盛大创新院赞助第二届.NET技术交流会开始报名了！&lt;/a&gt; &lt;/li&gt;

  &lt;li&gt;&lt;a href="http://blog.zhaojie.me/2010/09/2nd-snda-dotnet-conference-is-coming.html"&gt;盛大创新院赞助第二届.NET技术交流会即将召开&lt;/a&gt; &lt;/li&gt;

  &lt;li&gt;盛大创新院赞助第二届.NET技术交流会 - 各场演讲幻灯片 &lt;/li&gt;

  &lt;li&gt;&lt;a href="http://blog.zhaojie.me/2010/09/2nd-snda-dotnet-conference-videos.html"&gt;盛大创新院赞助第二届.NET技术交流会 - 演讲录像及下载&lt;/a&gt; &lt;/li&gt;

  &lt;li&gt;盛大创新院赞助首届.NET技术交流会：&lt;a href="http://blog.zhaojie.me/2010/05/first-snda-dotnet-conference-sign-up.html"&gt;报名&lt;/a&gt;、&lt;a href="http://blog.zhaojie.me/2010/06/first-snda-dotnet-conference-is-coming.html"&gt;预告&lt;/a&gt;、&lt;a href="http://blog.zhaojie.me/2010/06/first-snda-dotnet-conference-all-slides.html"&gt;幻灯片&lt;/a&gt;、&lt;a href="http://blog.zhaojie.me/2010/06/first-snda-dotnet-conference-videos.html"&gt;演讲录象及下载&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;</description>
      <comments>http://blog.zhaojie.me/2010/09/2nd-snda-dotnet-conference-all-slides.html#comments</comments>
      <pubDate>Sun, 12 Sep 2010 14:32:31 GMT</pubDate>
      <lastBuildDate>Sun, 19 Dec 2010 17:32:00 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/front-end/">前端表现</category>
      <category domain="http://blog.zhaojie.me/practice/">实践优化</category>
      <category domain="http://blog.zhaojie.me/parallel/">并行处理</category>
      <category domain="http://blog.zhaojie.me/cutting-edge/">技术尝鲜</category>
      <category domain="http://blog.zhaojie.me/speech/">培训演讲</category>
      <title>盛大创新院赞助第二届.NET技术交流会即将召开</title>
      <link>http://blog.zhaojie.me/2010/09/2nd-snda-dotnet-conference-is-coming.html</link>
      <guid>http://blog.zhaojie.me/2010/09/2nd-snda-dotnet-conference-is-coming.html</guid>
      <description>&lt;p&gt;由&lt;a href="http://blog.zhaojie.me/2010/01/1651772.html"&gt;盛大创新院&lt;/a&gt;赞助的第二届.NET技术大会将于9月11号下午1点召开，本次交流会请到了四位讲师，议题覆盖了响应式编程、算法、面向对象设计及Windows内核等多个方面，其中最为突出的莫过于由潘爱民老师为大家带来的Windows内核方面的话题。我已经看过了各场演讲的幻灯片终稿，也很期待各位讲师在正式演讲中的表现。&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/snda-dotnet-conf/conf-2-600x850.jpg" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/snda-dotnet-conf/conf-2-600x850.jpg" width="300" /&gt;&lt;/a&gt; 

&lt;p&gt;本次大会中，我们还获得了人民邮电出版社&lt;a href="http://www.turingbook.com/Homepage/Default.aspx"&gt;图灵教育&lt;/a&gt;赠送的15册图书、数枚书签、几件T恤，再加上由会务经费购买的两本潘老师的著作，将会作为各场次的奖品，赠送给在交流会中表现积极的听众。&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/snda-dotnet-conf/turingbook.jpg" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/snda-dotnet-conf/turingbook.jpg" width="300" /&gt;&lt;/a&gt; 

&lt;p&gt;同样，我们还请到了&lt;a href="http://www.ku6.com/"&gt;酷六网&lt;/a&gt;的专业摄影师对演讲过程进行全程拍摄，并配合各位讲师自身的屏幕录像，将在后期合成为适合独立观看的演讲视频（&lt;a href="http://blog.zhaojie.me/2010/06/first-snda-dotnet-conference-videos.html"&gt;效果&lt;/a&gt;），让不能到场的朋友在线或是下载后观看。&lt;/p&gt;
&lt;img src="http://img.zhaojie.me/blog/snda-dotnet-conf/ku6-logo.jpg" /&gt; 

&lt;p&gt;最后，本次活动中我们还邀请了&lt;a href="http://renjian.com/"&gt;人间网&lt;/a&gt;为我们进行线上直播，我们会有专人负责直播信息的管理和发布。您也可以在活动现场，甚至在场外通过会场的无线网络或者短信发布消息。这些信息都会显示在会场的大屏幕上。&lt;/p&gt;
&lt;img src="http://img.zhaojie.me/blog/snda-dotnet-conf/renjian-logo.jpg" /&gt; 

&lt;p&gt;以下是直播效果：&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/snda-dotnet-conf/renjian-live-demo.jpg" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/snda-dotnet-conf/renjian-live-demo.jpg" width="300" /&gt;&lt;/a&gt; 

&lt;p&gt;本次会议的邀请函已经发给各位报名者，请携带邀请函至会议现场签到，没有报名的朋友可以在现场直接报名。&lt;a href="http://blog.zhaojie.me/2010/08/2nd-snda-dotnet-conference-sign-up.html"&gt;关于会议的时间、地点、交通、议程等更多信息，请关注会议的报名信息&lt;/a&gt;。&lt;/p&gt;

&lt;h1&gt;相关文章&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="http://blog.zhaojie.me/2010/08/2nd-snda-dotnet-conference-sign-up.html"&gt;盛大创新院赞助第二届.NET技术交流会开始报名了！&lt;/a&gt;&lt;/li&gt;

  &lt;li&gt;盛大创新院赞助第二届.NET技术交流会即将召开&lt;/li&gt;

  &lt;li&gt;&lt;a href="http://blog.zhaojie.me/2010/09/2nd-snda-dotnet-conference-all-slides.html"&gt;盛大创新院赞助第二届.NET技术交流会 - 各场演讲幻灯片&lt;/a&gt;&lt;/li&gt;

  &lt;li&gt;&lt;a href="http://blog.zhaojie.me/2010/09/2nd-snda-dotnet-conference-videos.html"&gt;盛大创新院赞助第二届.NET技术交流会 - 演讲录像及下载&lt;/a&gt; &lt;/li&gt;

  &lt;li&gt;盛大创新院赞助首届.NET技术交流会：&lt;a href="http://blog.zhaojie.me/2010/05/first-snda-dotnet-conference-sign-up.html"&gt;报名&lt;/a&gt;、&lt;a href="http://blog.zhaojie.me/2010/06/first-snda-dotnet-conference-is-coming.html"&gt;预告&lt;/a&gt;、&lt;a href="http://blog.zhaojie.me/2010/06/first-snda-dotnet-conference-all-slides.html"&gt;幻灯片&lt;/a&gt;、&lt;a href="http://blog.zhaojie.me/2010/06/first-snda-dotnet-conference-videos.html"&gt;演讲录象及下载&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <comments>http://blog.zhaojie.me/2010/09/2nd-snda-dotnet-conference-is-coming.html#comments</comments>
      <pubDate>Thu, 09 Sep 2010 03:14:43 GMT</pubDate>
      <lastBuildDate>Thu, 09 Sep 2010 03:14:43 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/front-end/">前端表现</category>
      <category domain="http://blog.zhaojie.me/practice/">实践优化</category>
      <category domain="http://blog.zhaojie.me/parallel/">并行处理</category>
      <category domain="http://blog.zhaojie.me/cutting-edge/">技术尝鲜</category>
      <category domain="http://blog.zhaojie.me/speech/">培训演讲</category>
      <title>盛大创新院赞助第二届.NET技术交流会开始报名了！</title>
      <link>http://blog.zhaojie.me/2010/08/2nd-snda-dotnet-conference-sign-up.html</link>
      <guid>http://blog.zhaojie.me/2010/08/2nd-snda-dotnet-conference-sign-up.html</guid>
      <description>&lt;img class="floatRight" src="http://img.zhaojie.me/blog/snda-in.png" /&gt; 

&lt;p&gt;自上次&lt;a href="http://blog.zhaojie.me/2010/05/first-snda-dotnet-conference-sign-up.html"&gt;盛大创新院&lt;/a&gt;赞助的&lt;a href="http://blog.zhaojie.me/2010/06/first-snda-dotnet-conference-videos.html"&gt;首届.NET技术交流会&lt;/a&gt;到现在已经有两个月，这意味着按照原来的“一季一次”的计划也已经离第二次的活动不远了，考虑到9月份的中秋和国庆假期将工作日和休息日搞的支离破碎，于是交流会的时间会略微有些提前。第二届交流会的形式与上次相同，将为您献上四场高质量的技术演讲。当然这次在内容上有了新的尝试，除了引入了算法及面向对象设计的内容之外，这次更是请到了“传说中的大侠”为大家带来有关Windows内核的深度内容。&lt;font color="#ff0000"&gt;人数暂定为200人，事不宜迟，赶快报名吧&lt;/font&gt;。除了.NET社区的群众以外，也欢迎其他技术社区的朋友前来参与交流。事实上，我组织技术交流会的目的之一便是希望能够促进.NET社区与其他技术社区的交流及相互学习。&lt;/p&gt;

&lt;h1&gt;时间及议程安排&lt;/h1&gt;

&lt;p&gt;第二次交流会定于&lt;strong style="color: red"&gt;2010年9月11日&lt;/strong&gt;（周六）举行，具体时间及议程安排如下。本次依然安排了四场演讲，不过在内容上有了新的尝试：在与一些朋友和同事进行沟通之后，我决定在第二次交流会上引入与算法相关的议题，由创新院内部的ACM/ICPC达人来谈一下日常工作中的算法，如果您对于算法在工作的处境所有疑惑的话，这也是个共同探讨的好机会；此外，我也邀请了&lt;a href="http://www.5173.com/"&gt;5173.com&lt;/a&gt;的技术专家来讨论面向对象设计方面的问题，我看过他过去在内部演讲时使用的PPT，内容很充实；而这次的“重头戏”，便是请到了传说中的&lt;font color="#ff0000"&gt;潘爱民&lt;/font&gt;老师为大家演讲Windows内核方面的问题。潘老师是业界著名技术专家，不久前加入了盛大创新院，可谓“镇院之宝”。事实上，在9月初潘老师便会回到北京工作，而这次他也是为了交流会专门出差至上海，您怎能错过这次机会？&lt;/p&gt;

&lt;table style="text-align: center" border="1" cellspacing="0" cellpadding="5"&gt;&lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;时间&lt;/th&gt;

      &lt;th&gt;议程&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;&lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;12:30 ~ 13:00&lt;/td&gt;

      &lt;td&gt;签到&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;13:00 ~ 14:00&lt;/td&gt;

      &lt;td&gt;响应式编程与响应式框架&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;14:00 ~ 14:10&lt;/td&gt;

      &lt;td&gt;短休&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;14:10 ~ 15:10&lt;/td&gt;

      &lt;td&gt;大话程序员可用的算法&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;15:10 ~ 15:40&lt;/td&gt;

      &lt;td&gt;茶歇&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;15:40 ~ 16:40&lt;/td&gt;

      &lt;td&gt;面向对象与生活&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;16:40 ~ 16:50&lt;/td&gt;

      &lt;td&gt;短休&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;16:50 ~ 17: 50&lt;/td&gt;

      &lt;td&gt;Windows内核技术介绍&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;&lt;/table&gt;

&lt;h1&gt;演讲内容&lt;/h1&gt;

&lt;p&gt;以下是关于四场演讲的详细描述。&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/snda-dotnet-conf/zhaojie.jpg" target="_blank"&gt;&lt;img class="floatRight" src="http://img.zhaojie.me/blog/snda-dotnet-conf/zhaojie.jpg" height="150" /&gt;&lt;/a&gt; 

&lt;h2&gt;响应式编程与响应式框架&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;讲师：&lt;/strong&gt;赵劼，盛大创新院，研究员。关注前沿技术，并致力于开源社区与微软平台的组合优化。对函数式编程，并行程序开发，代码之美以及程序员能力与修养等相关问题也有着浓厚的兴趣，同时非常希望能够写程序到60岁。最近致力于F#，Scala语言及mono平台在社区中的推广。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;简介：&lt;/strong&gt;异步编程改变了我们的编程方式，也为我们带来的许多挑战，同时让一些编程模型重新焕发了生机。与传统的“拉”模型不同，响应式编程将异步事件流视为可观察的集合，这是一种“推”模型。微软为了提高云时代的编程体验而设计了响应式框架，其目的是为了简化复杂事件处理之间混合操作。从中我们了解到一些异步编程的模式与LINQ使用技巧，并可以将这种编程模型普及到JavaScript等其他平台上去。&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/snda-dotnet-conf/chengshaofei.jpg" target="_blank"&gt;&lt;img class="floatRight" src="http://img.zhaojie.me/blog/snda-dotnet-conf/chengshaofei.jpg" height="150" /&gt;&lt;/a&gt; 

&lt;h2&gt;大话程序员可用的算法&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;讲师：&lt;/strong&gt;程劭非，盛大创新院，研究员。网名winter，无忧脚本版主。Web前端技术的积极倡导者。学生时代曾经热衷于参加ACM/ICPC。目前工作在Bambook电子书项目，主要负责文字排版和浏览器引擎WebKit相关。之前曾负责在Windows CE系统上的IE开发。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;简介：&lt;/strong&gt;俗话说“数据结构+算法=程序”，算法是什么？算法书里满篇是看不懂的形式化推导，网上一些&amp;quot;高人&amp;quot;写的关于算法文章高深莫测，大公司面 试最让人讨厌的就是考算法题，“我做了这么多年，跟本在实际开发中就没用过算法！”，算法真的是距离我们如此遥远的东西吗？且听这回演讲， 算法究竟如何影响我们的开发。&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/snda-dotnet-conf/gaoxiang.jpg" target="_blank"&gt;&lt;img class="floatRight" src="http://img.zhaojie.me/blog/snda-dotnet-conf/gaoxiang.jpg" height="150" /&gt;&lt;/a&gt; 

&lt;h2&gt;面向对象与生活&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;讲师：&lt;/strong&gt;高翔，5173.com&amp;#160; 项目经理。关注前沿技术和技术人员的非技术生活。对面向对象、模式和建模技术有浓厚兴趣，并对游戏设计和图形学方面也比较感兴趣。最近在学习F#，Lua以及关注一些关于职业生涯规划方面的话题。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;简介：&lt;/strong&gt;面向对象这个话题虽然很热，但与哲学一样，很难给其一个很准确的定义。也因为如此，每个人对它都有自己的理解。本次演讲将从一个实际的例子出发，逐步引入面向对象的三个特征，结合对象的生命周期，以及基于事件的对象扩展方式等方面，探讨其与设计模式，与生活之间的联系。&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/snda-dotnet-conf/panaimin.jpg" target="_blank"&gt;&lt;img class="floatRight" src="http://img.zhaojie.me/blog/snda-dotnet-conf/panaimin.jpg" height="150" /&gt;&lt;/a&gt; 

&lt;h2&gt;Windows内核技术介绍&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;讲师：&lt;/strong&gt;潘爱民，盛大创新院专家，微软学者，集团COO专家顾问。长期从事软件和系统技术的研究和开发工作，撰写了大量软件技术文章，并著译了多部经典计算机图书。在MSR/清华等从事多年科研工作，在北大和清华多年执教经验。数学学士学位和计算机科学博士，主要研究领域包括软件设计、信息安全、操作系统和Internet技术。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;简介：&lt;/strong&gt;Windows操作系统经过二十年的发展，已臻成熟。Microsoft在推动Windows内核方面做了大量工作，譬如于2006年夏季向教育界开放了当时最为先进的内核源代码（Windows Research Kernel）。主讲者在这次讲座中，结合这些可利用的资源，分享对Windows内核研究的体会，尤其将重点讨论Windows中的I/O模型和环境子系统。&lt;/p&gt;

&lt;h1&gt;地点&lt;/h1&gt;

&lt;p&gt;本次交流会举办地为&lt;strong style="color: red"&gt;上海市浦东新区碧波路888号畅星大厦&lt;/strong&gt;（地铁二号线张江高科站下，步行10分钟可达）3楼会议厅，地图如下：&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/snda-dotnet-conf/changxing-map.png"&gt;&lt;img src="http://img.zhaojie.me/blog/snda-dotnet-conf/changxing-map.png" width="400" /&gt;&lt;/a&gt; 

&lt;p&gt;鸟瞰图：&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/snda-dotnet-conf/changxing-hybrid.jpg"&gt;&lt;img src="http://img.zhaojie.me/blog/snda-dotnet-conf/changxing-hybrid.jpg" width="400" /&gt;&lt;/a&gt; 

&lt;p&gt;畅星大厦外观：&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/snda-dotnet-conf/changxing-building.jpg"&gt;&lt;img src="http://img.zhaojie.me/blog/snda-dotnet-conf/changxing-building.jpg" width="400" /&gt;&lt;/a&gt; 

&lt;p&gt;会场实景照片：&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/snda-dotnet-conf/changxing-room.jpg"&gt;&lt;img src="http://img.zhaojie.me/blog/snda-dotnet-conf/changxing-room.jpg" width="400" /&gt;&lt;/a&gt; 

&lt;p&gt;会场容量可以容纳超过200人，希望到时候不会显得太过空旷。:)&lt;/p&gt;

&lt;h1&gt;报名信息&lt;/h1&gt;
&lt;img src="http://img.zhaojie.me/blog/snda-dotnet-conf/sign-up-now.jpg" /&gt; 

&lt;p&gt;本次交流会&lt;a href="http://www.diaochapai.com/survey504720"&gt;现已开始报名，请填写报名表&lt;/a&gt;，&lt;strike&gt;报名截止日期为2010年9月5日&lt;/strike&gt;人数已满，多谢大家支持。&lt;/p&gt;

&lt;h1&gt;相关文章&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;盛大创新院赞助第二届.NET技术交流会开始报名了！ &lt;/li&gt;

  &lt;li&gt;&lt;a href="http://blog.zhaojie.me/2010/09/2nd-snda-dotnet-conference-is-coming.html"&gt;盛大创新院赞助第二届.NET技术交流会即将召开&lt;/a&gt;&lt;/li&gt;

  &lt;li&gt;&lt;a href="http://blog.zhaojie.me/2010/09/2nd-snda-dotnet-conference-all-slides.html"&gt;盛大创新院赞助第二届.NET技术交流会 - 各场演讲幻灯片&lt;/a&gt;&lt;/li&gt;

  &lt;li&gt;&lt;a href="http://blog.zhaojie.me/2010/09/2nd-snda-dotnet-conference-videos.html"&gt;盛大创新院赞助第二届.NET技术交流会 - 演讲录像及下载&lt;/a&gt; &lt;/li&gt;

  &lt;li&gt;盛大创新院赞助首届.NET技术交流会：&lt;a href="http://blog.zhaojie.me/2010/05/first-snda-dotnet-conference-sign-up.html"&gt;报名&lt;/a&gt;、&lt;a href="http://blog.zhaojie.me/2010/06/first-snda-dotnet-conference-is-coming.html"&gt;预告&lt;/a&gt;、&lt;a href="http://blog.zhaojie.me/2010/06/first-snda-dotnet-conference-all-slides.html"&gt;幻灯片&lt;/a&gt;、&lt;a href="http://blog.zhaojie.me/2010/06/first-snda-dotnet-conference-videos.html"&gt;演讲录象及下载&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <comments>http://blog.zhaojie.me/2010/08/2nd-snda-dotnet-conference-sign-up.html#comments</comments>
      <pubDate>Mon, 16 Aug 2010 03:02:30 GMT</pubDate>
      <lastBuildDate>Mon, 16 Aug 2010 03:02:30 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/dotnet/">.Net框架</category>
      <category domain="http://blog.zhaojie.me/language/">语言编程</category>
      <category domain="http://blog.zhaojie.me/cutting-edge/">技术尝鲜</category>
      <category domain="http://blog.zhaojie.me/speech/">培训演讲</category>
      <title>NDC 2010视频下载：看看其他微软平台程序员们都在做什么</title>
      <link>http://blog.zhaojie.me/2010/07/ndc-2010-videos.html</link>
      <guid>http://blog.zhaojie.me/2010/07/ndc-2010-videos.html</guid>
      <description>&lt;p&gt;&lt;a href="http://www.ndc2010.no/"&gt;NDC&lt;/a&gt;（Norwegian Developers Conference，挪威开发者大会）是一年一度的挪威最大的微软平台开发者大会，&lt;a href="http://www.ndc2010.no/agenda.aspx?cat=1071"&gt;内容丰富&lt;/a&gt;，&lt;a href="http://www.ndc2010.no/index.aspx?cat=1070"&gt;讲师阵容强大&lt;/a&gt;。NDC与&lt;a href="http://blog.zhaojie.me/2009/11/videos-of-pdc09-algorithms-data-structure-visual-studio-documentary.html"&gt;PDC&lt;/a&gt;同为高端技术会议，但NDC与PDC的不同之处在于，PDC是微软官方会议，主要是面向微软资深产品的深入探讨。而NDC涉及的内容则广泛的多，包括了我所感兴趣的Java、Mono、IronRuby/Ruby on Rails、NoSQL方面的内容。这也就像我一直强调的那样，微软技术社区非常开放，微软平台上的太多程序员都能够非常热情地拥抱其他平台的技术。那些认为微软技术社区是井底之蛙的兄弟，殊不知&lt;a href="http://blog.zhaojie.me/2010/03/microsoft-technology-and-the-attitude.html"&gt;你们的嘲笑只能体现出自身的狭隘&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;总而言之，NDC是我理想中的微软平台技术大会。&lt;/p&gt;

&lt;p&gt;如今&lt;a href="http://streaming.ndc2010.no/tcs/"&gt;NDC 2010的视频已经全部公开&lt;/a&gt;，可以在线观看（使用Silverlight），也可以下载。为了便于大家浏览和下载，我写了一段小程序整理出了所有的视频简介以及下载链接，共计123条，&lt;a onclick="$(&amp;#39;#ndc-video-list&amp;#39;).show(); return false;" href="#"&gt;请点击这里&lt;/a&gt;。&lt;/p&gt;

&lt;table style="display:none;" id="ndc-video-list" border="1" cellspacing="0" cellpadding="5"&gt;&lt;tbody&gt;
    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/919676F9-9BEB-4370-B9CA-F7EADB515143/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=919676F9-9BEB-4370-B9CA-F7EADB515143" target="_blank"&gt;Fubu MVC 18 Jun 10 4:20 PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;FubuMVC is an open source framework for web development using the ModelView Controller (MVC) pattern. FubuMVC is built in C# and depends on theSystem.Web.Routing subsystem of the base CLR, but has no dependency on the ASP.Net MVC framework. In this talk I will highlight the architectural design of FubuMVC, how it works and more importantly the reasoning behind it. I will not make this into a comparison match with ASP.NET MVC, but there are so many interesting patterns being used in the FubuMVC code base that in its self should make this a very interesting talk. The FubuMVC code base has been an example for many others even in different areas outside of web development.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/0F6607A2-4202-451C-95C6-51A3BC10D907"&gt;iPod Video 320x240 (71 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/32DA3486-A0A7-4561-9CC7-2D624E325E51"&gt;MPEG-4 for QuickTime Medium 1280x480 (330.7 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/A065D732-92B5-4965-A8E8-B91491B0D796/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=A065D732-92B5-4965-A8E8-B91491B0D796" target="_blank"&gt;Leading a Self-Organizing Team 18 Jun 10 3:20 PM&lt;/a&gt;&lt;/p&gt;

        

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/D348B96D-330E-4453-B6B2-81EA2873C22E"&gt;iPod Video 320x240 (147.7 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/88A55AE0-6276-4980-8780-E2B38B78C5D6"&gt;MPEG-4 for QuickTime Medium 1280x480 (395.2 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/42B4E3B9-C0D3-4C34-AA29-115C5D322CF9/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=42B4E3B9-C0D3-4C34-AA29-115C5D322CF9" target="_blank"&gt;State vs. Interaction Testing 18 Jun 10 3:19 PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;Mocking frameworks allow you to stub out behaviour in order to perform tests of individual peices of functionality in isolation. However, there are times when performing certain actions and assert a result is not sufficient. In this session we will drill deep into unit testing and explain the differences between state and interaction-based testing. We will examine the role of stubs versus mocks and how to correctly write unit tests that are not fragile or counter-productive.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/09EA0A40-8964-4677-83F2-F315E7DF73FC"&gt;iPod Video 320x240 (94.8 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/7579BDFE-7278-44D3-A4DB-598770BDCCDB"&gt;MPEG-4 for QuickTime Medium 1280x480 (349.5 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/575B06E8-755D-41B6-BC8A-22908491B66D/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=575B06E8-755D-41B6-BC8A-22908491B66D" target="_blank"&gt;Bridging code between Java &amp;amp; .NET 18 Jun 10 3:18 PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;Frustrated .NET developer forced to work with old, boring java? Or are you a java developer having to work with the incompatible and evil .NET technology? With IVKM.NET you can compile your java byte code to the .NET IL and run your favorite java code on .NET and maybe even your Java applications will run faster under IVKM.NET than under SUNs JVM? We take a look at IKVM.NET and how it can be used to bridge your java libraries to your .NET application and the other way around, reusing .NET APIs in your java code. We also show how to use IVKM.NET for creating java-stubs from already existing .NET libraries in order to access your .NET code in java.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/ECD741DD-BD17-4960-A3BA-957E788AA8A8"&gt;iPod Video 320x240 (120.1 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/EC41B80B-D810-40E8-8B18-03EEA09A369B"&gt;MPEG-4 for QuickTime Medium 1280x480 (410.8 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/A4176987-8DF0-491F-B25E-951925F755C3/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=A4176987-8DF0-491F-B25E-951925F755C3" target="_blank"&gt;Rough Cuts in Legacy Code 18 Jun 10 3:17 PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;Getting legacy code under test is hard, particularly when it is deeply intertwined. In some of the worst code bases, there are no real components, the code is just one large soup.In this session, Michael Feathers will describe a series of strategies and techniques that you can use to separate clusters of classes from your application, characterize them and write tests for them to enable deterministic change.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/732E92BE-DE16-4516-8EF9-2F2FE0852B58"&gt;iPod Video 320x240 (57 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/1D23F326-1241-4350-B873-74F799AA53F3"&gt;MPEG-4 for QuickTime Medium 1280x480 (223.6 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/6118D38B-9A20-4601-A470-1752FFE1BF30/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=6118D38B-9A20-4601-A470-1752FFE1BF30" target="_blank"&gt;The SharePoint 2010 Business Intelligence Soup 18 Jun 10 4:17 PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;SharePoint 2010 has rich BI capabilities, much more enhanced than what SharePoint 2007 provided. Did you try using SharePoint 2007 as a BI delivery mechanism? How was the experience? Was it too difficult to setup? Did you feel you were limited on the lines of performance, capabilities, diagnosis ability? Did you think the featureset was great, and made for good demos ?C but delivering real solutions was a whole another story? Well is SharePoint 2010 any better? Come over and let??s talk about it. In this session, Sahil will talk about the various BI specific improvements in SharePoint 2010, with specific emphasis on what is new compared to SharePoint 2007.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/1CBBCF81-6F06-410A-AA7A-53C8609D1A01"&gt;iPod Video 320x240 (131.3 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/C5CBFADF-B8BA-4616-881C-141F39440053"&gt;MPEG-4 for QuickTime Medium 1280x480 (606.5 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/DDE1EF15-1290-4AD8-B8F5-E7B3EBF6B61B/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=DDE1EF15-1290-4AD8-B8F5-E7B3EBF6B61B" target="_blank"&gt;LINQ - Beyond Queries18 Jun 10 4:14 PM&lt;/a&gt;&lt;/p&gt;

        

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/FB02936E-A742-42FB-9510-4BBA680C3B5D"&gt;iPod Video 320x240 (115.2 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/B6530547-1CFB-4D80-AF39-F01FFCB5A0F8"&gt;MPEG-4 for QuickTime Medium 1280x480 (523.6 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/66BF46DF-0BB6-4A52-831C-28165F048D6E/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=66BF46DF-0BB6-4A52-831C-28165F048D6E" target="_blank"&gt;Scaling Agile to Work with a Distributed Team 18 Jun 10 2:00 PM&lt;/a&gt;&lt;/p&gt;

        

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/F8E1F30D-6377-447A-BB02-6E1CE27D377C"&gt;iPod Video 320x240 (145.2 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/0299E29A-0D32-42D1-B5BE-491F0C358D2F"&gt;MPEG-4 for QuickTime Medium 1280x480 (398.5 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/C95AB956-D65D-4F80-A75D-84E48767D061/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=C95AB956-D65D-4F80-A75D-84E48767D061" target="_blank"&gt;Get Your Business Out of My Face: Legacy Refactorings for Testable User Interface Code 18 Jun 10 1:58 PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;Traditional acceptance testing works at the front-end of a fully-integrated system. There is a need for this kind of testing, however the need accounts for a comparatively small amount of the overall checking you should do on your system. Unfortunately, effectively checking your system requires some basic design principles, which are typically not applied.This session will give you an idea of the kinds of design changes you?ll need to make to improve the testability of your system through a demonstration of legacy refactoring techniques targeted at getting business logic out of UI code.This session will be code-driven. I?ll begin with some example code, displayed for the audience. We will begin by writing automated tests to verify some of the business logic leaving the code as is.After writing a few tests, we will review the pros and cons of the testing approach.I will then provide a few basic design principles that apply to the particular situation: dependency inversion principle, single responsibility principle, not mixing enabling code with business logic.We will then make some ?obvious? legacy refactorings, done badly. Review the results. This first round will be an application of the Single Responsibility Principle. Then we will discuss the Dependency Inversion Principle and do the refactoring more effectively.We will continue with a comparison of the first tests with their final form and the first version of the business logic with the refactored version. We will review&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/E3458620-1B2B-422A-87D6-93D58736580D"&gt;iPod Video 320x240 (92.8 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/7D609906-A58D-4543-BFFF-11C0223E1723"&gt;MPEG-4 for QuickTime Medium 1280x480 (396.8 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/94B33824-779E-44D9-803B-BE462815A5D5/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=94B33824-779E-44D9-803B-BE462815A5D5" target="_blank"&gt;No Source Code, No Problem - Reverse Code Engineering in Product Development 18 Jun 10 2:58 PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;Reverse Code Engineering (RCE) is commonly applied to solve security-related challenges. It is all about understanding the behavior of software without access to its source code. This often means studying low-level machine code generated from a higher level language like C or C++. Such translation is lossy and highly architecture and compiler dependent, which makes going in the reverse direction quite challenging.In this talk I'm going to discuss RCE from a product development perspective, where interoperability with platform-specific undocumented APIs could be a necessity. First some background including practical examples of key challenges solved by RCE from my own experience, followed by a live demonstration of some tools and techniques.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/8E8FAC98-DC07-4CF3-955C-8003D05E35EE"&gt;iPod Video 320x240 (182.2 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/DD5BD460-8404-4535-B640-28797F6257C9"&gt;MPEG-4 for QuickTime Medium 1280x480 (735.8 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/C44B65E2-980B-4406-B2AB-3E079E5CA804/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=C44B65E2-980B-4406-B2AB-3E079E5CA804" target="_blank"&gt;Collaboration in ABB - from drawing board to real-life solution using SharePoint 2010 18 Jun 10 2:57 PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;ABB is a global leader in power and automation technologies, operates in around 100 countries and employs about 117,000 people. ABB's global intranet is a complex and highly tailored solution containing several hundred thousand pages in more than fifty country sites. The intranet was named one of "The Ten Best Intranets of the Year" by Nielsen Norman Group in 2002, but the general concept of the intranet has not evolved substantially since then. For several years ABB worked on new concepts for making the intranet more valuable to users, by increasing findability, quality of content and opportunities for collaboration. Late last year, SharePoint 2010 was selected as the technical platform to achieve these goals. This talk will outline the collaboration concept that ABB envisioned, and what happened when the concept from the drawing board met the real-life platform SharePoint 2010. The talk will focus on the "social" aspects of the solution such as profiles, networking with colleagues, sharing of information through status updates, activity feeds, social tagging and commenting. It will describe, feature by feature, which parts of SharePoint were used as they are, and which were tailored to achieve a more interactive and collaborative intranet for ABB. The talk will focus both on functionality and on hands-on technical implementation.The speakers will share their experiences of what worked well and what not in terms of conceptual design, development of improved or new social fea&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/6AC313B1-389D-4BB2-80E1-7D682CF30D1B"&gt;iPod Video 320x240 (131.9 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/480C2CC2-DDBF-4198-8924-37573ED287AA"&gt;MPEG-4 for QuickTime Medium 1280x480 (614.5 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/6F6790C2-BB0F-46C8-8373-E00341777A59/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=6F6790C2-BB0F-46C8-8373-E00341777A59" target="_blank"&gt;Creating Web Sites with Open Rasta 18 Jun 10 2:57 PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;OpenRasta is a framework built from the ground?Cup to unleash the power of HTTP. Be it web sites, forms or web services, OpenRasta lets you build your application quickly and efficiently, without the hassle of complicated APIs and god objects.
          &lt;br&gt;Come and discover why OpenRasta is the most talked about ReST framework on .net, and how it can help you deliver better, more http?Cfriendly systems.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/BE49FF2E-99C2-4BFC-9EDF-60AF8991AC65"&gt;iPod Video 320x240 (137 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/2B25C121-C445-432A-9742-CE0AA63CE664"&gt;MPEG-4 for QuickTime Medium 1280x480 (679.4 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/002F9CBC-CBED-4D71-83A5-08C0EBED02BC/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=002F9CBC-CBED-4D71-83A5-08C0EBED02BC" target="_blank"&gt;Product Development in TANDBERG 18 Jun 10 1:57 PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;TANDBERG has never cared much about documentation, procedures, methodologies and risk reduction. However, we do care very much about our culture and our principles. This has enabled us to outperform all competition in the video conferencing and telepresence market during the last decade.In retrospect, we realize that TANDBERG has for 10-15 years built a culture that is quite compatible with Agile and Lean ideas.This talk will give a glimpse into how we do product development in TANDBERG R&amp;amp;D at Lysaker. I will show an example of how we developed a particular product with emphasis on software development, before I dive into the principles that we follow.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/E1EDF859-7EFB-43CC-829A-C75532A0AD85"&gt;iPod Video 320x240 (112.7 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/8C9D31C1-411E-4E03-8F27-470D592ABDCB"&gt;MPEG-4 for QuickTime Medium 1280x480 (320.4 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/4AC3CE10-48E7-476B-9238-D7FC946DB8E3/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=4AC3CE10-48E7-476B-9238-D7FC946DB8E3" target="_blank"&gt;Clean Code III: Functions 18 Jun 10 1:51 PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;Get ready for a challenge as Robert Martin dives deep into the topic of clean Java code by examining what makes a good function. In this talk you will look at a lot of code; some good and some bad. You will experience how such code is analyzed, critiqued, and eventually refactored. You will understand the decisions made by an expert in the field as bad code is gradually transformed into good code. How big should a function be? How should it be named? How should it be documented. How many indent levels should it have? How should it deal with exceptions, arguments, and return values. This talk is all about code at the lowest level. And yet the principles and techniques presented have far reaching implications.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/E2EEF5A5-8421-4818-9CA1-7A3F15484378"&gt;iPod Video 320x240 (149 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/AF569962-C936-4542-9461-B51C4F6CAF86"&gt;MPEG-4 for QuickTime Medium 1280x480 (449.2 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/6EB9A2DD-E1F2-4E90-9DAE-E4BDA2FF7A8D/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=6EB9A2DD-E1F2-4E90-9DAE-E4BDA2FF7A8D" target="_blank"&gt;Advanced Topics in Agile Planning 18 Jun 10 12:40 PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;Velocity is perhaps the most useful metric available to agile teams. In this session we will look at advanced uses of velocity for planning under special but common circumstances. We will see how to forecast velocity in the complete absence of any historical data. We will look at how a new team can forecast velocity by looking at other teams. We will see how to predict the velocity of a team that will grow or shrink in size. Most importantly we will look at the use of confidence intervals to create plans we can be 90% confident in, even on fixed-price or fixed-date contracts.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/E449FDDF-8954-4445-8539-9882B3D6276B"&gt;iPod Video 320x240 (143.8 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/721E1266-5F00-489A-B262-1BFEA4605EC5"&gt;MPEG-4 for QuickTime Medium 1280x480 (396.1 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/9147ECD9-4F4B-48B2-95E6-B2602BDA37B0/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=9147ECD9-4F4B-48B2-95E6-B2602BDA37B0" target="_blank"&gt;SharePoint 2010 - Is it Scalable or not? 18 Jun 10 12:38 PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;If there is any topic that has generated more debate, it is the scalability of SharePoint lists and document libraries. In this session, Sahil will talk about the new and improved details around the scalability, and performance aspects of SharePoint 2010. Topics covered will include List management infrastructure, content database schema improvements, and RBS capabilities, with practical gotchas and things to watch out for.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/FA1C656E-F92E-48D3-8CF9-52B8A970CDFC"&gt;iPod Video 320x240 (98 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/E09DE432-8F2D-447D-BE34-046D99A5C4DE"&gt;MPEG-4 for QuickTime Medium 640x480 (186 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/2E806A0F-059E-4D8C-B47C-F2D30B1FAFB4/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=2E806A0F-059E-4D8C-B47C-F2D30B1FAFB4" target="_blank"&gt;Aspect Oriented Programming: Learning by Re-Invention 18 Jun 10 1:38 PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;This talk aims to provide an in-depth understanding of the concept of Aspect Oriented Programming and how an AOP framework does what it does, by taking the audience through the implementation of (a simple) one from scratch.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/B38D034D-864A-4D51-8021-9DA3875EEC83"&gt;iPod Video 320x240 (154.3 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/BDA7204A-2953-42D7-A096-785D4A693CC4"&gt;MPEG-4 for QuickTime Medium 1280x480 (616.3 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/9FC4E2E6-9A9F-49C0-803B-A91E6AF41312/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=9FC4E2E6-9A9F-49C0-803B-A91E6AF41312" target="_blank"&gt;Agile Release Strategy 18 Jun 10 12:37 PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;Releasing often is probably the most important practice in agile development. In many projects it can also be the hardest practice. This talk will give you hands on advice on how to reliably reduce your release cycle.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/3992E103-507B-4D1D-A391-9689F886B062"&gt;iPod Video 320x240 (62.9 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/9B396E05-C208-4E56-9351-95480160831F"&gt;MPEG-4 for QuickTime Medium 1280x480 (244.9 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/C6611670-4B70-42B3-9C2B-86D576338350/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=C6611670-4B70-42B3-9C2B-86D576338350" target="_blank"&gt;Testing C# and ASP.NET Applications with Ruby 18 Jun 10 1:37 PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;With the reach and diversity of different programming languages andparadigms at the moment, it's possible to use the appropriate languagefor the appropriate task. In my case, I develop applications using C# but test the code using Ruby. The Ruby community has always understood the importance of testing. They strive to make applications more testable while improving the approaches and tools they use. As aresult, they have created some amazing frameworks and a series of best practices to support testing. While this is great for Ruby developers, C# and ASP.net developers can take full advantage for their own applications. This session provides an insight into the Ruby world and how you can take advantage to create readable, maintainable and valuable tests for ASP.net based web applications, from the business logic up to the user interface. Taken from my own experiences of using this approach, the session will demonstrate how to integrate Ruby frameworks such as RSpec and Cucumber into your application development cycle, and how different frameworks combined with Ruby can solve a number of problems traditionally faced when using C#. There will also be discussionaround IronRuby and JRuby and their implications for the future andthe future of Testing ASP.net applications in general.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/E6ED8E7D-AC7B-41EE-A43E-AC43DA25AAE7"&gt;iPod Video 320x240 (98.4 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/C547E00D-FB1A-4E07-AD76-AF4EEE00FEE3"&gt;MPEG-4 for QuickTime Medium 1280x480 (523.3 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/8FFAC6DC-C74E-4001-9908-9B3188A4569D/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=8FFAC6DC-C74E-4001-9908-9B3188A4569D" target="_blank"&gt;The Art of the Method 18 Jun 10 12:35 PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;Have you ever looked at a method or function in someone else's code and felt that you've seen it before? Methods don't come in infinite varieties. There are some very common structural and semantic patterns which recur in code. Some of them occur because teams have adopted good coding and design conventions. others occur because methods tend to fall apart and degrade in similar ways.In this session, Michael Feathers will name and describe various types of methods seen in the field and talk about how a nomenclature for these methods can simplify and focus design.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/4C88314B-CE08-4159-81D5-B67E15A7482A"&gt;iPod Video 320x240 (75.8 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/90C5D5F4-746A-4ADF-AD7B-A68739368E7D"&gt;MPEG-4 for QuickTime Medium 1280x480 (285.2 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/44950364-77F8-49AA-91D7-13441F398DD0/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=44950364-77F8-49AA-91D7-13441F398DD0" target="_blank"&gt;ASP.NET MVC vs Ruby on Rails - The .NET Rocks Smackdown 18 Jun 10 1:18 PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;Shay Friedman's comparison of ASP.NET MVC and Ruby on Rails gets redesigned for an NDC 2010 exclusive.
          &lt;br&gt;Carl Franklin and Richard Campbell joins in and moderates a smackdown between the two leading web frameworks featuring Rob Conery, Chris Hardy, Hadi Hariri, Scott Bellware and of course Shay Friedman.

          &lt;br&gt;This is you're chance to be part of a lively discussion which will be broadcasted on the leading .NET talkshow .NET Rocks this summer.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/66253B2B-7E0B-4986-8751-6EAA21110681"&gt;iPod Video 320x240 (286.4 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/D470DFFF-AB8F-4409-BE2A-389107460641"&gt;MPEG-4 for QuickTime Medium 320x240 (209 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/A8883298-AAF9-4E5A-91B1-2F7A31241F34/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=A8883298-AAF9-4E5A-91B1-2F7A31241F34" target="_blank"&gt;Spark Deep Dive 18 Jun 10 11:40 AM&lt;/a&gt;&lt;/p&gt;

        

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/7CFA11A7-6E2B-40C7-BC36-5E9F46D4EE04"&gt;iPod Video 320x240 (173.2 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/A899D0DA-E3C0-4885-9312-1D71C8AD8E08"&gt;MPEG-4 for QuickTime Medium 1280x480 (619.7 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/4DE02ACE-8B75-4807-B135-5B0E260FEEDC/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=4DE02ACE-8B75-4807-B135-5B0E260FEEDC" target="_blank"&gt;SharePoint 2010 - Business Connectivity Services 18 Jun 10 10:39 AM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;Business connectivity services, now enables you to bring external data into SharePoint and office with full CRUD (Create/Retrieve/Update/Delete) capabilities. This talk explains BCS in SharePoint 2010 in an end-to-end fashion, covering from the browser, through SPD, to the Visual Studio 2010 story&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/A3C836AF-7328-41BB-80AE-420F7D70858D"&gt;iPod Video 320x240 (95.2 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/065C76BD-1683-49B1-93A3-5E28FB50C9CE"&gt;MPEG-4 for QuickTime Medium 1280x480 (442.5 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/222F58E0-D553-456A-B76F-BA566D351145/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=222F58E0-D553-456A-B76F-BA566D351145" target="_blank"&gt;Agile Estimating 18 Jun 10 10:38 AM&lt;/a&gt;&lt;/p&gt;

        

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/71E23FCC-FDDC-4ED6-8546-FC2E85273F16"&gt;iPod Video 320x240 (126.5 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/32B1EDB6-92AF-432C-9EA1-E92CF0B9F518"&gt;MPEG-4 for QuickTime Medium 1280x480 (247.6 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/A8B70AC9-947E-49B1-AC5C-53F63CFD89BB/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=A8B70AC9-947E-49B1-AC5C-53F63CFD89BB" target="_blank"&gt;Using ReST to design a better OData 18 Jun 10 11:40 AM&lt;/a&gt;&lt;/p&gt;

        

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/E68630A5-D7F6-4FF9-8DEC-1D260FBBB520"&gt;iPod Video 320x240 (162.9 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/57133307-C4DA-4CF0-A548-28ED270F03FE"&gt;MPEG-4 for QuickTime Medium 1280x480 (777.7 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/DCFE1E9A-6DFA-4AFD-BA77-42C534E3894E/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=DCFE1E9A-6DFA-4AFD-BA77-42C534E3894E" target="_blank"&gt;Code Contracts 18 Jun 10 11:36 AM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;Code Contracts are a new feature of .NET 4 and present themselves as a way of greatly simplifying our code by using the concepts of Design by contract. In this talk we will cover the basics of Code Contracts and see how they can be used in real-world applications, how they can be tested, and see if they are all they are cut out to be.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/DCA3C0F8-139F-4E98-AFBD-AB98491FAFB8"&gt;iPod Video 320x240 (139.5 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/EBD4AE5C-F5F7-4281-B8CE-5D34098C9E69"&gt;MPEG-4 for QuickTime Medium 1280x480 (633 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/AD824D8A-F579-4CF1-9A7D-B167CC11076A/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=AD824D8A-F579-4CF1-9A7D-B167CC11076A" target="_blank"&gt;Clean Code I: Arguments 18 Jun 10 10:35 AM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;Keeping code clean is a simple matter of professional ethics. In this talk Robert Martin shows how a Java module can start clean, grow to become messy, and then be refactored back to cleanliness. Be forewarned: his tutorial is about CODE. We will put code on the screen and we will read and critique it. And then, one tiny step at a time, we will clean it. In this tutorial you will participate in the step by step improvement of a module. You will see the techniques of the Prime Directive (Never Be Blocked), and Agile Design Principles brought into play. You will witness the decision making process that Agile Developers employ to write code that is expressive, flexible, and clean. Finally, you learn an attitude of professional ethics that defines the software developer??s craft.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/3D8BC681-77E2-4581-B7C5-CFE60A0FE4B9"&gt;iPod Video 320x240 (111.8 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/89664554-99D7-44E5-A2B6-CDA9396C9411"&gt;MPEG-4 for QuickTime Medium 1280x480 (309.4 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/E524650B-F5BD-4450-8B39-502AAD7FC053/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=E524650B-F5BD-4450-8B39-502AAD7FC053" target="_blank"&gt;The Deep Synergy Between Testability and Good Design 18 Jun 10 10:34 AM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;Many people moan about it the fact that their code is hard to test. They hack their code to make it testable and then they moan some more about how unit testing is an irritant, it makes code ugly. The fact of the matter is, it isn't true. There's a deep synergy between testability and good design. All of the pain that we feel when writing unit tests points at underlying design problems. In this session, Michael Feathers will, through a series of examples, show how you can use testability challenges to reconsider and improve your design.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/FAB20016-6162-4712-9868-41656B8976B2"&gt;iPod Video 320x240 (79.4 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/C1FD8E8B-5010-4F4E-A8B9-556BF8293189"&gt;MPEG-4 for QuickTime Medium 1280x480 (283.1 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/9DE90613-B2A2-4C0C-ADCC-DFC72E45D087/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=9DE90613-B2A2-4C0C-ADCC-DFC72E45D087" target="_blank"&gt;User Stories for Agile Requirements 18 Jun 10 9:20 AM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;The technique of expressing requirements as user stories is one of the most broadly applicable techniques introduced by the agile processes. User stories are an effective approach on all time constrained projects and are a great way to begin introducing a bit of agility to your projects. In this session, we will look at how to identify and write good user stories. The class will describe the six attributes that good stories should exhibit and present thirteen guidelines for writing better stories. We will explore how user role modeling can help when gathering a project??s initial stories. Because requirements touch all job functions on a development project, this tutorial will be equally suited for analysts, customers, testers, programmers, managers, or anyone involved in a software development project. By the end of this tutorial, you will leave knowing the six attributes of a good story, learn a good format for writing most user stories, learn practical techniques for gathering user stories, know how much work to do up-front and how much to do just-in-time.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/B70ECBFF-9581-4A1E-B56B-F8BB02428B8F"&gt;iPod Video 320x240 (132.4 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/DC45E89C-7FF6-4BE2-B7D3-20D1B0322C83"&gt;MPEG-4 for QuickTime Medium 1280x480 (340.9 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/E241ACE5-D26B-41FA-8FA1-FBB3AD8DF5B3/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=E241ACE5-D26B-41FA-8FA1-FBB3AD8DF5B3" target="_blank"&gt;The Solid Principles of OO &amp;amp; Agile Design 18 Jun 10 9:19 AM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;What happens to software? Why does is rot over time? How does an Agile development team prevent this rot, and prevent good designs from becoming legacy code? How can we be sure our designs are good in the first place? This class presents the agile S.O.L.I.D. principles for designing object oriented class structures. These principles govern the structure and interdependencies between classes in large object oriented systems. The principles include: The Open Closed Principle, The Liskov Substitution Principle, and the Dependency Inversion Principle, among others.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/07841105-200B-4F85-BCAD-FFFF1F82D407"&gt;iPod Video 320x240 (140 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/3F8944E1-F57B-46AA-83CD-37E5297245A8"&gt;MPEG-4 for QuickTime Medium 1280x480 (579.1 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/FEAA8270-AA9A-49CC-8CEA-ECB47B238F13/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=FEAA8270-AA9A-49CC-8CEA-ECB47B238F13" target="_blank"&gt;Being an effective team leader 18 Jun 10 9:18 AM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;In this talk we'll review practices and principles that make good team leaders into great ones. from basic communication and influencing skills to essential day to day practices and things to look out for - this is a session every team lead should be interested in.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/5919CA3D-88CB-47FD-A289-3BAF710976C7"&gt;iPod Video 320x240 (108.8 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/896ED493-B83B-452E-8FCA-1FF2A066CB64"&gt;MPEG-4 for QuickTime Medium 1280x480 (509.1 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/4087616A-3B88-4DA5-9B9E-CE2FE2887F09/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=4087616A-3B88-4DA5-9B9E-CE2FE2887F09" target="_blank"&gt;The Dependency Inversion Principle Applied 18 Jun 10 10:17 AM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;This is a talk which aims to explain the Dependency Inversion Principle in practice. It is not a one hour theoretical explanation of what the principle states, but rather a real life demonstration of how it becomes a natural pattern to apply in the pursuit of a clean, maintainable design within the boundaries of a statically typed language. This is a ??code and commentary?? talk, with virtually no slides. Though the code demonstrated is C#, this is not a technology-specific talk.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/A6038941-AC88-4CA4-B61A-2101789D0805"&gt;iPod Video 320x240 (154.6 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/C1070B19-4AFE-433E-A326-54ADEDE09AE4"&gt;MPEG-4 for QuickTime Medium 1280x480 (637 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/D8EC7885-B8D2-447B-AE10-DF5FAE0F626D/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=D8EC7885-B8D2-447B-AE10-DF5FAE0F626D" target="_blank"&gt;Testable C# 18 Jun 10 9:16 AM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;Unit testing is valuable, but it's hard to go very far with it without realizing that sometimes languages make it easy and sometimes they make it hard. In this code rich presentation, Michael Feathers will present a series of testability traps in the C# language: features and ways of using them which make unit testing impossible without specialized tooling. He will also present a simple rule along with supporting concepts that you can use to sidestep all of them and produce C# code which is always easily testable.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/56B0175F-14F2-43D6-93C5-3703F4641F8C"&gt;iPod Video 320x240 (22.8 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/59C524C6-4073-482D-8196-C980B1DD2574"&gt;MPEG-4 for QuickTime Medium 1280x480 (234.8 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/74F9C23C-BCF0-4863-9968-BB53C3C677D5/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=74F9C23C-BCF0-4863-9968-BB53C3C677D5" target="_blank"&gt;Developing Testable Web Parts for SharePoint 18 Jun 10 10:15 AM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;The development of components for use in SharePoint is a complex process, and often seems to fly in the face of what is considered good development practice in a Test Driven Development world.In this session I will show how using some good design practices and tools such as Typemock Isolator you can develop testable components for SharePoint (2007 &amp;amp; 2010); often without even having to have SharePoint on your development PC.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/5EA24C36-8D98-4AEA-9278-6954AD28850A"&gt;iPod Video 320x240 (145.2 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/72B7DC54-080D-4A61-85F4-48BE0C7ABD9A"&gt;MPEG-4 for QuickTime Medium 1280x480 (702.8 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/22ECAB7E-431D-4CAF-813D-DC3B36BFA601/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=22ECAB7E-431D-4CAF-813D-DC3B36BFA601" target="_blank"&gt;Introducing Spark View Engine 18 Jun 10 10:08 AM&lt;/a&gt;&lt;/p&gt;

        

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/6AB73F67-5C72-402F-BBC5-BEDA93CB6DB2"&gt;iPod Video 320x240 (134.8 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/8B98994B-2226-4774-86DA-3585F6C72EC3"&gt;MPEG-4 for QuickTime Medium 1280x480 (481.9 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/62309161-262E-44BA-BDA0-B5653698089B/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=62309161-262E-44BA-BDA0-B5653698089B" target="_blank"&gt;Getting Agile with Scrum 18 Jun 10 8:00 AM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;Scrum is one of the leading agile software development processes. Over 12,000 project managers have become certified to run Scrum projects . Since its origin on Japanese new product development projects in the 1980s, Scrum has become recognized as one of the best project management frameworks for handling rapidly changing or evolving projects. Especially useful on projects with lots of technology or requirements uncertainty, Scrum is a proven, scalable agile process for managing software projects.Through lecture, discussion and exercises, this fast-paced tutorial covers the basics of what you need to know to get started with Scrum. You will learn about all key aspects of Scrum including product and sprint backlog, the sprint planning meeting, the sprint review, conducting a sprint retrospective, activities that occur during sprints, measuring and monitoring progress, and scaling Scrum to work with large and distributed teams. Also covered are the roles and responsibilities of the ScrumMaster, the product owner, and the Scrum team.This session will be equally suited for managers, programmers, testers, product managers and anyone else interested in improving product delivery.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/73B922DE-AF72-4B27-8CFF-B49766D74A08"&gt;iPod Video 320x240 (108.3 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/A476A315-A6AB-40D1-9CBA-1DA278999726"&gt;MPEG-4 for QuickTime Medium 1280x480 (330.5 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/373CB716-5F6B-4233-A5C0-7E91CB5FB89F/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=373CB716-5F6B-4233-A5C0-7E91CB5FB89F" target="_blank"&gt;Introduction to GIT 18 Jun 10 9:00 AM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;An introduction to distributed version control using Git, and how your VCS should work with you and not against you. How DVCS can completely alter your development process, streamline it, and help you produce better software, faster. Covering how local repositories speed up your development, multiple authoritative sources, distributed teams, multiple workflows, and some of the more distinct features of Git. With experiences from an OSS team on how the migration from SVN to Git has helped the project and changed how the team works (Fluent NHibernate).&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/AAF63449-316A-45CB-A97A-7C6D8877B655"&gt;iPod Video 320x240 (152.8 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/C6F26DA8-6A6A-44AF-A59F-FFD2197BD557"&gt;MPEG-4 for QuickTime Medium 1280x480 (717.4 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/B6E99D3E-FA79-4915-B5E2-CBF1A4E0D5C2/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=B6E99D3E-FA79-4915-B5E2-CBF1A4E0D5C2" target="_blank"&gt;Riding IronRuby on Rails 18 Jun 10 9:00 AM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;The most famous Ruby?Cdriven framework is, by far, Ruby on Rails. With IronRuby, .NET developers can now take advantage of this incredible web framework without leaving their comfort zone. In this session, Shay Friedman will build an entire Web 2.0 site from scratch while using and explaining the key features of Ruby on Rails.
          &lt;br&gt;Come and see what Ruby on Rails is all about and what's made it the success it is today.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/92483947-503D-4840-8634-7DA959B54272"&gt;iPod Video 320x240 (108.3 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/00079578-7C66-4D7D-9C78-9547E4571317"&gt;MPEG-4 for QuickTime Medium 1280x480 (468.2 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/3DEF9777-6E67-4DF5-A0B6-BD274A17B610/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=3DEF9777-6E67-4DF5-A0B6-BD274A17B610" target="_blank"&gt;Developing for SharePoint 2010 18 Jun 10 8:57 AM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;Sure you're a .NET developer. Maybe you are even a SharePoint developer. But have you seen development for SharePoint 2010? It comes with full tooling support in VS2010, and massive improvements in the platform itself. Developing for SharePoint is finally manageable, but is it easy to be a SharePoint developer? Come and find out!&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/030F0119-18CA-40DD-8BBC-DBA2D0C229A3"&gt;iPod Video 320x240 (154.3 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/3657FB2E-DE46-4EE6-A261-1B4EDB3985E1"&gt;MPEG-4 for QuickTime Medium 1280x480 (794.5 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/67F7C9FF-0F0D-4F2E-91C0-49C84FF19109/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=67F7C9FF-0F0D-4F2E-91C0-49C84FF19109" target="_blank"&gt;The Three Laws of TDD 18 Jun 10 9:00 AM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;The jury is in, the case is closed. TDD works, and works well. In this talk Uncle Bob makes the point that TDD is not a testing technique at all. Rather, TDD is a way to ensure good architecture, good design, good documentation, and that the software works as the programmer intended. TDD is a necessary discipline for those developers seeking to become professionals. This talk is half lecture and half demonstration. Examples are in Java and Junit.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/6B224D9C-5AC2-47A5-A6FF-04FC6F17E235"&gt;iPod Video 320x240 (186.8 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/DEE43269-466E-495F-90BF-C018F4A9435E"&gt;MPEG-4 for QuickTime Medium 1280x480 (622.3 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/D75877EB-3F20-4A9A-8B39-B016EE0419D5/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=D75877EB-3F20-4A9A-8B39-B016EE0419D5" target="_blank"&gt;The Next Big Thing Or Cool-Kid Koolaid? Slicing Through The Rhetoric of MVC vs. WebForms 18 Jun 10 9:00 AM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;In this presentation Rob Conery dissects the arguments that are polluting the blogosphere, surrounding the discussion of whether ASP.NET MVC is "right" for you and your team. Passion, misinformation, assumptions and fear have pushed people into entrenched positions, leaving little room for intelligent thought. The goal of this presentation is to "shake loose" the rhetoric and give you some concrete ideas to think about if you're considering a move to ASP.NET MVC. In addition, Rob will try to offer an answer to the question: "Is WebForms Dead?"&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/A9076CC9-36AB-4268-95CA-61093899D2FF"&gt;iPod Video 320x240 (104.7 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/4B633AE1-54CF-4EDF-A790-F3B9B7EBFEFB"&gt;MPEG-4 for QuickTime Medium 1280x480 (592.8 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/29649A14-2F1B-428E-BB12-9A43A1676221/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=29649A14-2F1B-428E-BB12-9A43A1676221" target="_blank"&gt;C# Quo Vadis? 17 Jun 10 4:40 PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;What??s next for C#? This session will not answer that question! Mads will open with about 10 minutes about the challenges and constraints of language design, followed by an open discussion on where to take C# involving fellow C# designers Eric Lippert and Neal Gafter, C# author and luminary Jon Skeet as well as you in a lively free-form discussion that can take us anywhere and will be absolutely once-in-a-lifetime.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/8519E157-0163-4764-B005-19E00AEBD895"&gt;iPod Video 320x240 (75.5 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/7CCBD189-9996-46CA-AFAA-045482B11CC7"&gt;MPEG-4 for QuickTime Medium 1280x480 (256.5 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/D57D0BF0-E555-44CA-B9B5-DA42B211836D/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=D57D0BF0-E555-44CA-B9B5-DA42B211836D" target="_blank"&gt;ASP.NET performance for free using caching 17 Jun 10 5:39 PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;Is your ASP.NET application not performing like you wished it would? Performance not what it has to be? Have you considered caching? While many developers know the basics of caching in ASP.NET, there's actually a lot more possible than initially thought. Also, not every technique is good to solve every problem. In this session, we'll do an overview of all the options ASP.NET has to offer for caching and state management, helping you to get a better performing application.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/5508E549-95EE-4279-8DEB-FB75E41A2BCC"&gt;iPod Video 320x240 (156.6 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/58481C42-44C0-4A13-9FA8-156AE1EB123A"&gt;MPEG-4 for QuickTime Medium 1280x480 (637.1 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/921B0A59-558B-411E-B77B-E384F4162661/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=921B0A59-558B-411E-B77B-E384F4162661" target="_blank"&gt;jQuery: Write less, do more 17 Jun 10 4:40 PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;jQuery is a JavaScript library which allows you to develop solutions with less code, in less time. You can build interactive prototypes for your prospective clients, or take an existing solution and add new dynamic behaviour with little effort.We will see how jQuery can be used to quickly and concisely apply JavaScript behaviour to your web app. It will cover selectors, Ajax, DOM manipulation and more. The aim: to produce lean unobtrusive JavaScript with jQuery&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/6DF9A5DF-0AC2-4894-875E-89DF042143E4"&gt;iPod Video 320x240 (73.8 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/41FBB71C-159A-4F82-9F4D-F545354E805A"&gt;MPEG-4 for QuickTime Medium 1280x480 (273.3 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/43BE894B-DB27-4B0C-897F-D75ED6FDCFFA/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=43BE894B-DB27-4B0C-897F-D75ED6FDCFFA" target="_blank"&gt;Beautiful Teams &amp;amp; Leaders 17 Jun 10 4:38 PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;A look at what makes teams productive, and what makes team leaders effective. from team practices such as automation and communication, to team leads that grow and coach their people, confront problems and finds ways to make people better. this is an overview session. specific issues are elaborated in other sessions.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/2F1C583E-947D-40D6-BCE7-672CAA5FB42D"&gt;iPod Video 320x240 (107 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/9D2AF5FD-6B26-415F-9979-9153A71FFB78"&gt;MPEG-4 for QuickTime Medium 1280x480 (516.5 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/F552E0B6-C036-4A8D-BEEA-64E4B1B005CE/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=F552E0B6-C036-4A8D-BEEA-64E4B1B005CE" target="_blank"&gt;5 reasons why projects using DDD fail 17 Jun 10 4:40 PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;Many people try applying Domain Driven Design and #fail miserably.This presentation looks at five top reasons for failure and discusses how to avoid them.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/2A7C85FA-CEC9-4253-AD88-EFD57FE69A6A"&gt;iPod Video 320x240 (140.3 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/4F985E73-D2EC-49ED-B2CE-47ED4C17DDE2"&gt;MPEG-4 for QuickTime Medium 1280x480 (459.6 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/FF182A3A-3793-488C-BCEC-5F644640DF19/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=FF182A3A-3793-488C-BCEC-5F644640DF19" target="_blank"&gt;Introducing the .NET Service Bus 17 Jun 10 5:37 PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;The .NET services bus is part of the new Microsoft Cloud Computing Windows Azure initiative, and arguably, it is the most accessible, ready to use, powerful, and needed piece. The service bus allows clients to connects to services across any machine, network, firewall, NAT, routers, load balancers, virtualization, IP and DNS as if they were part of the same local network, and doing all that without compromising on the programming model or security. The service bus also supports callbacks, event publishing, authentication and authorization and doing all that in a WCF-friendly manner. This session will present the service bus programming model, how to configure and administer service bus solutions, working with the dedicated relay bindings including the available communication modes, relying on authentication in the cloud for local services and the various authentication options, and how to provide for end-to-end security through the relay service. You will also see some advanced WCF programming techniques, original helper classes, productivity-enhancing utilities and tools, as well as discussion of design best practices and pitfalls.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/EEEC5FCF-389A-4C1D-A003-3D9D69A03CE0"&gt;iPod Video 320x240 (146.4 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/C53E66C4-A805-40DB-9002-7CF7F0037E4A"&gt;MPEG-4 for QuickTime Medium 1280x480 (674.7 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/7CE9268F-045F-4AC1-AA46-6362276862BE/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=7CE9268F-045F-4AC1-AA46-6362276862BE" target="_blank"&gt;Architecting for the .NET Event Model 17 Jun 10 5:25 PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;You may have a basic understanding of .NET's event model, but how can you best architect your applications to take advantage of .NET events? This session spends a few minutes on the basics, then provides real-world examples showing how you can design your applications to take advantage of the .NET event model for things such as:* Custom data binding in Windows Forms and Web Forms* Establishing relationships between business components* Creating world-class, end-user-configurable security* Localizing the user interface dynamically at run time&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/306C679F-CE26-4B71-8CE1-E3254AA2EF04"&gt;iPod Video 320x240 (123.2 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/4BC61FCB-3C07-4199-B87B-B4EFAB733A70"&gt;MPEG-4 for QuickTime Medium 1280x480 (660.1 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/DF0361BF-1AE6-42CE-AAB3-963E424A1BBD/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=DF0361BF-1AE6-42CE-AAB3-963E424A1BBD" target="_blank"&gt;The Purpose of Leadership and Governance 17 Jun 10 4:21 PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;There are three types of organizations: ordered, chaotic, and complex organizations. The best management approach depends on the type of organization, and the amount of rule?Cmaking a development manager?team leader should concern himself with. However, this distinction is a false (but useful) metaphor. In reality, development teams are complex _adaptive_ systems, meaning that they should be doing their own rule?Cmaking, as self?Corganizing systems.
          &lt;br&gt;However, self?Corganization alone is not enough. Management is needed for imposing boundaries and constraints. There's a great checklist available to managers and team leaders for defining boundaries to authority in self?Corganizing teams.

          &lt;br&gt;There are two kinds of purpose: archeo?Cpurpose and neo?Cpurpose. Both the team itself and the manager can assign a neo?Cpurpose to a team. This neo?Cpurpose is not the same as the goal of the project they are working on, or the goals of any of the stakeholders. One thing a manager?leader can do is to assign purpose to a self?Corganizing team. We will discuss how to do that.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/949994EB-AD53-4896-8F32-14E0CEE6C120"&gt;iPod Video 320x240 (129.8 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/0F9AFB61-056F-4DE1-B24A-AD3AFAA831FC"&gt;MPEG-4 for QuickTime Medium 1280x480 (733.6 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/8114E030-D145-4C7E-B34C-B92312BFC87B/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=8114E030-D145-4C7E-B34C-B92312BFC87B" target="_blank"&gt;Building Applications with Silverlight 4 17 Jun 10 3:20 PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;Now that Silverlight 4 is released, find out what is new?changed and how to write great data-driven applications with Silverlight 4. Learn about how you can leverage Silverlight 4 for rich desktop applications using the new ??trusted application?? model and how to best take advantage of these features. Accessing data using RIA Services makes data-driven applications easier and can support a ViewModel development pattern approach. This session will be faced pace in overview, but deep in code. Few slides, mostly code.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/AAC3D1FC-8980-4790-9245-80D3D5A9A923"&gt;iPod Video 320x240 (131.8 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/EFC36FEC-ADD3-42FD-A098-CCF2FF86E279"&gt;MPEG-4 for QuickTime Medium 1280x480 (323.4 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/D4CE2890-99BC-49C5-A668-485D952A894D/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=D4CE2890-99BC-49C5-A668-485D952A894D" target="_blank"&gt;From one web server to two: Making the leap to web farms 17 Jun 10 4:20 PM&lt;/a&gt;&lt;/p&gt;

        

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/887B2602-DD14-412A-86E6-4DC9E7D63786"&gt;iPod Video 320x240 (143.2 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/C3FF5782-F356-4D9B-BE63-B3A4AC8EFF37"&gt;MPEG-4 for QuickTime Medium 1280x480 (709.9 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/F87D064C-09C8-4380-B1FE-17E526199C0C/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=F87D064C-09C8-4380-B1FE-17E526199C0C" target="_blank"&gt;Code Excavations, Wishful Invocations, and Domain Specific Unit Test Frameworks 17 Jun 10 3:20 PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;In this talk I'll describe a technique for unit-testing code embedded in an impenetrable framework (such as Sharepoint, Silverlight, and BizTalk) that make such code inaccessible. We know we should write code that is easy to test because it has clean boundaries, but sometimes the vendors we work with make that kind of modularity just too hard. I will talk about how we can test such plug-in code by faking its environment in memory, simulating the underlying engines. As an example, I'll be showing SilverUnit, a framework to test code written for the Silverlight framework without driving through the browser. I'll talk about how the need for this sort of testing arose during silverlight development and how it allowed me to make sure my silverlight code worked as expected. even the UI logic.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/90A3BEBE-7A7B-4939-8285-4BF359DD4CA5"&gt;iPod Video 320x240 (102.3 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/4223DA88-7FB5-40C4-996E-2D143531A276"&gt;MPEG-4 for QuickTime Medium 1280x480 (475.7 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/AFDB4098-C5C8-49DF-8C2A-7E317F63E72D/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=AFDB4098-C5C8-49DF-8C2A-7E317F63E72D" target="_blank"&gt;If I Ruled the World - C# 5.0 According to Jon 17 Jun 10 3:20 PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;Now that C# 4 is out, thoughts are naturally turning towards what C# 5 might hold. Speaking from a position of breathtaking ignorance of what the team is actually planning, and without the safety net of a working implementation, I will outline a few ideas about what could be in C# 5. Some will be wacky, some mundane and perhaps even obvious. One thing's almost certain: this won't be the feature set of the real C# 5. Even so, it will provide some food for thought.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/7B88225D-8837-4650-8451-2488B664F828"&gt;iPod Video 320x240 (126.4 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/55B05224-8CE6-479C-8AC3-89675931E559"&gt;MPEG-4 for QuickTime Medium 1280x480 (529.2 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/0C981B83-1787-4D62-B395-4016989F52C3/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=0C981B83-1787-4D62-B395-4016989F52C3" target="_blank"&gt;Domain Driven Entity Framework 17 Jun 10 3:20 PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;If you think of your database as an "implementation detail", it is likely that you are not interested in building your all important domain classes based on a database or being bound by the limitations of a modeling tool. In the U.S., Telemark skiers cry "Free the Heel". In this session we'll make that a call to "Free the Domain Classes". We'll take a look at the different mechanisms that do not involve reverse engineering a database. In VS2010, EF's Model-First support and in the Entity Framework Feature CTP, the completely model-less Code Only support. We'll finish with a quick look at SQL Server Modeling's M language, which provides yet another option for defining entity classes without the EDM designer .&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/772818E8-B827-403F-ACF5-4121883C7241"&gt;iPod Video 320x240 (121.8 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/6FC4CB4C-8D8B-4921-9854-077420D0311A"&gt;MPEG-4 for QuickTime Medium 1280x480 (422 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/434A8AAD-2209-48A9-A2A5-9E135FBD9648/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=434A8AAD-2209-48A9-A2A5-9E135FBD9648" target="_blank"&gt;Top Security Scenarios for WCF Services: On Premise &amp;amp; In The Cloud 17 Jun 10 4:20 PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;Today you will be hard-pressed to find an enterprise application that does not rely on distributed messaging and service-orientation. Client applications such as rich clients, Rich Internet Applications (RIAs) built with Silverlight or some flavor or AJAX, and those targeting mobile devices all access resources via services exposed to the intranet or Internet. Oftentimes the middle tier also includes layers of services living in the DMZ or behind it. There are many possible security models available for scenarios involving the various client technologies and service tiers - and Windows Communication Foundation (WCF) supplies the tools necessary to implement each and every possibility. In this session, you will learn the most common and practical security scenarios that involve WCF services within the intranet or exposed to the Intranet including classic Windows security, username and password, certificates, federated identity, REST-based and securing calls between tiers. The session will also discuss scenarios that can benefit from aspects of Windows Azure platform including AppFabric Service Bus and Access Control - such as for securing services behind the DMZ and enabling federation for REST-based services. All examples will cover requirements for the client and service, give you a formula to achieve each scenario, and show you custom components that simplify implementation. You??ll leave this session with a recipe for the most common security scenarios including sample code&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/007682F1-899E-4F92-A036-1E0DFB338C24"&gt;iPod Video 320x240 (152.7 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/FABD9586-E4EC-4890-A59A-A2C24089F4C0"&gt;MPEG-4 for QuickTime Medium 1280x480 (727.6 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/815EADB7-066D-4516-A70F-31EEFDFB1DE2/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=815EADB7-066D-4516-A70F-31EEFDFB1DE2" target="_blank"&gt;MonoTouch Deep Dive 17 Jun 10 2:00 PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;A deep dive into developing applications with MonoTouch. Learn about the different UI components available on the iPhone and iPad and how to use these with MonoTouch as well as how you can create interoperability with your .Net libraries within MonoTouch.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/025D02B1-ECF6-45EE-A5DC-13C25A210FD4"&gt;iPod Video 320x240 (108.2 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/2DB58A2E-126D-468B-A53B-8DB6E03194AB"&gt;MPEG-4 for QuickTime Medium 1280x480 (294.4 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/29F8ADBD-2479-4DC1-A2D2-B4D6BFF13C31/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=29F8ADBD-2479-4DC1-A2D2-B4D6BFF13C31" target="_blank"&gt;What I've learned About DDD Since the Book 17 Jun 10 2:00 PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;In the 5 years since the book was published, I've practiced DDD on various client projects, and I've continued to learn about what works, what doesn't work, and how to conceptualize and describe it all. Also, I've gained perspective and learned a great deal from the increasing number of expert practitioners of DDD who have emerged.The fundamentals have held up well, as well as most patterns, but there are differences in how I do things and look at things now. I will try to describe them, very informally, in this talk.Over this time, I have folded in a couple of additional patterns, and essentially come to ignore a few, but the biggest change has been a subtle shift of emphasis. Ubiquitous Language and Context Mapping and Core Domain are at the center, with aggregates in close orbit. Why, I ask myself, did I put context mapping in Chapter 14? Core domain in Chapter 15?! Before the book, it seemed self-evident to me that SOA fit well with DDD, but five years of questions on that topic have made it clear that my early explanations were inadequate and helped me clarify how it fits. Increased emphasis on events and distributed processing have crystallized the significance of aggregates and refined the building blocks.The talk cannot go into depth on all these topics, but the goal will be to give a quick look at where my view of DDD has been heading.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/1D0BC65F-5272-4EC2-889F-84AB41CAB3A6"&gt;iPod Video 320x240 (117.1 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/2318F2BA-25D5-4739-A29A-FED9715814C7"&gt;MPEG-4 for QuickTime Medium 1280x480 (448.6 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/6750B4DA-632C-4888-B9BD-2F1D44D4C930/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=6750B4DA-632C-4888-B9BD-2F1D44D4C930" target="_blank"&gt;Advanced Tips &amp;amp; Tricks for ASP.NET MVC 2 17 Jun 10 1:57 PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;In this session we??ll not only look at improving the maintainability and performance of an MVC application, but also how to increase your productivity. Topics include model binding, meta-data providers, and T4 Templates.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/1FF232FC-BA01-45D8-9398-59587B1AEF84"&gt;iPod Video 320x240 (111.5 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/B9D2CB7C-FF4D-4C5C-9C16-011EA9AE3DBE"&gt;MPEG-4 for QuickTime Medium 1280x480 (416 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/1D104BB5-4312-4ABE-A6B1-23AF9FB02D39/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=1D104BB5-4312-4ABE-A6B1-23AF9FB02D39" target="_blank"&gt;C# in the Big World 17 Jun 10 1:57 PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;C# 4.0 focuses on being a good citizen in a big world. In this talk we look at named and optional arguments, as well as the much improved COM interaction. We pay special attention to the new dynamic feature and the Dynamic Language Runtime (DLR) that it builds on: How do they work, how can you use them and why did we design them this way. We??ll also interoperate with COM and the HTML DOM, and build our own dynamic objects.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/E2BAD064-94AB-4EE0-B3FC-5A8D5C9E7817"&gt;iPod Video 320x240 (110.7 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/A5BD7F69-EFC7-4D81-BA75-CE26620E2961"&gt;MPEG-4 for QuickTime Medium 1280x480 (365.5 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/0054B7C0-A854-485D-8BE2-0E2DC7D3D738/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=0054B7C0-A854-485D-8BE2-0E2DC7D3D738" target="_blank"&gt;Tasks &amp;amp; Threading in .NET 4.0 17 Jun 10 3:00 PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;Writing multi-threaded applications is hard - making them work is even harder. Scaling applications to the current and future multiple-core machines can really be a daunting task --- but it doesn't have to be! In this session, Ingo Rammer shows you the new task-based API and how it simplifies the creation of multi-core supporting applications. You will learn how you can take advantage of the fine-grained parallelism and control which is offered by this new .NET feature. Ingo will also show you how to extend your in-memory LINQ query to run in parallel, and how the new Visual Studio 10 debugging tools will make troubleshooting this kind of applications a lot easier.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/2BD48D9B-02EF-477C-8CF5-251777A751FB"&gt;iPod Video 320x240 (158.9 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/2BFDE6B9-30AA-437F-BE2B-FE99B0D14C7A"&gt;MPEG-4 for QuickTime Medium 1280x480 (579.7 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/54B70126-AF2C-4627-B47B-CDBE2BDEC8B1/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=54B70126-AF2C-4627-B47B-CDBE2BDEC8B1" target="_blank"&gt;Making Manual Testing a Part of Your Development Process 17 Jun 10 3:00 PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;Software has always needed to be tested manually, automation can help, but it is never going to replace the need for manual testing totally. How a team manages this requirement for manual testing can be key to a projects success or failure.In the 2010 release of Visual Studio, Microsoft have provided a whole new set of tools to aid in this process - Microsoft Test Manager. In this session I will show how MTM can be used to assist a tester in creating detailed, accurate and repeatable testing that are a joy to use (well might be stretching a point there!). Also I will show how the tooling can allow these manual tests can become the basis for automated tests and Coded UI tests, and how the advanced logging features of the tools allow bugs to be accurately passed back to developers for speed the production of fixes.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/E162C105-0D34-4DB1-BCD9-47F94256CB3B"&gt;iPod Video 320x240 (137.6 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/0B0342C0-CA91-4332-A319-C5D7C0FD871B"&gt;MPEG-4 for QuickTime Medium 1280x480 (644.4 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/2E7AD1AC-9998-47B7-95FB-8DE7B6E1041B/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=2E7AD1AC-9998-47B7-95FB-8DE7B6E1041B" target="_blank"&gt;Windows Identity Foundation and Windows Azure 17 Jun 10 3:00 PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;Claims-based identity provides an open and interoperable approach to identity and access control that can be consistently applied both on-premises and in the cloud. Come to this session to learn about how Windows Identity Foundation can be used to secure your Web Roles hosted in Windows Azure, how you can take advantage of existing on-premises identities and how to make the best of features in our cloud offering, such as certificate management and staged environments.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/2CF8F8D0-4F6B-4E19-8C05-57D11CAD970C"&gt;iPod Video 320x240 (110.5 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/3D2CE3C3-DC4C-40B6-8A49-7FB0A670EEB1"&gt;MPEG-4 for QuickTime Medium 1280x480 (572.5 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/CB98EEE9-56A1-44BB-834B-6F8806A79B55/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=CB98EEE9-56A1-44BB-834B-6F8806A79B55" target="_blank"&gt;Software Is Not Manufacturing 17 Jun 10 12:45 PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;While we assert that software development is not manufacturing, we often slip into manufacturing metaphors and analogies and then fail to extricate our explorations of how software development unfolds from manufacturing. Some of these analogies are so deeply-rooted into our customs that we readily contradict our own assertions. This presentation looks at just how handicapped your software development becomes at the hand of these engrained manufacturing perspectives. It looks at product development theory as a better analogy to software development and a more practicable body of knowledge for software development. And it looks at how even product development theory fails to illuminate software development when we backslide into manufacturing-specific product development. Lean and Agile methods are framed in terms of product development and software development productivity problems are laid open under the surgical precision of product development analogies to building software machines.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/4CFECB5D-59FA-42F0-9FB6-D8966060FEA3"&gt;iPod Video 320x240 (62.1 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/6D1E1D79-E553-467C-8E56-3D069878C8E9"&gt;MPEG-4 for QuickTime Medium 1280x480 (255.1 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/65BE4F1E-4CA8-44E0-8285-973DDE22AC94/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=65BE4F1E-4CA8-44E0-8285-973DDE22AC94" target="_blank"&gt;Introduction to MonoTouch 17 Jun 10 12:39 PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;An overview of what's possible using Monotouch, Novell's tool to enable C# and .Net based applications for the iPhone, iPod touch and iPad. Find out what you need to start using Monotouch and how to create a sample application. If you have any questions on why you'd use this, what are the benefits and downsides of using Monotouch then this is your place!&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/56695511-6E17-4709-AD44-AEDF8FAF7093"&gt;iPod Video 320x240 (90.9 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/ECAC6BFF-B513-48B7-900B-B90E5502A650"&gt;MPEG-4 for QuickTime Medium 1280x480 (251.7 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/327039DB-BFD5-4465-BE31-A13BE5EAAF47/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=327039DB-BFD5-4465-BE31-A13BE5EAAF47" target="_blank"&gt;Technology Supported Requirement Handling and Estimation 17 Jun 10 1:40 PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;Lindorff Group is a leading outsourced receivables management company in Europe, and one of the leading on a global basis. For the past three-four years, they have increasingly adopted agile practices, especially in a large scale project converting and improving an old system written in Powerhouse to new .Net-technology.The results from adopting agile practices have been mostly positive, however, there were challenging issues related to requirement handling and estimation that needed attention. In 2008, Lindorff joined a project with Symphonical funded by Innovation Norway. The purpose of the project was to develop software for requirements handling, estimation and knowledge management for the Symphonical platform. Symphonical is a flexible web-based collaboration platform, where users can brainstorm, plan, organize and coordinate any process.This talk presents results from a case study detailing the challenges faced by Lindorff as they simultaneously adopted agile practices and introduced a new system for requirement handling and estimation. According to the respondents of the case study, Lindorff appears to have improved on two of the main points of concern presented in the 2007 study: requirement handling and estimation. Many users report that the introduction of agile methods and the platform Symphonical has improved the quality of important work processes. Furthermore, they report that the introduction of Symphonical has provided a framework for structured discussions re&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/03FEC611-7B4D-411F-A308-5DC675381D84"&gt;iPod Video 320x240 (124.2 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/190BED7E-FF81-4AEB-8C50-30B9BF466EA4"&gt;MPEG-4 for QuickTime Medium 1280x480 (594.5 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/316D856E-9734-473E-BD75-D6A675BDAEB7/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=316D856E-9734-473E-BD75-D6A675BDAEB7" target="_blank"&gt;Rocking AppFabric Access Control: Practical Scenarios, Killer Code and Wicked Tools 17 Jun 10 12:38 PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;AppFabric Access Control is a feature of the Windows Azure platform that makes it easy to secure web resources such as REST-based services using a simple set of standard protocols. In fact, AppFabric Access Control uniquely facilitates several scenarios not previously possible including a standards-based mechanism for securing web resources, identity federation for REST, and secure calls from Silverlight and AJAX clients to web resources including REST-based WCF services or REST-based MVC implementations. In this session you will get a tour of the AppFabric Access Control feature set and learn how to implement these key security scenarios with the help of some custom tools that encapsulate common functionality exposing a simple object model for working with the protocols underlying Access Control. In addition, you will learn how to integrate typical Windows Identity Foundation (WIF) authorization techniques such as ClaimsPrincipal to decouple the authentication and authorization mechanism from the business logic.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/D10B3B51-9157-4FD3-822B-449AA11EBEA7"&gt;iPod Video 320x240 (138.5 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/48237FF8-8CCF-43D4-B3C5-6B6335AFE57E"&gt;MPEG-4 for QuickTime Medium 1280x480 (570.6 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/06AF739D-271D-4D24-9058-1935D9E304F9/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=06AF739D-271D-4D24-9058-1935D9E304F9" target="_blank"&gt;Unleash Your Domain 17 Jun 10 12:40 PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;Our application runs over 10,000 sustained transactions per second with a rich model. The key? Modeling state transitions explicitly.In today's world many systems have non-functional requirements that prevent them from being single database centric. This presentation looks at how Domain Driven Design can fit into such environments including extremely large scale web sites, batch processing, and even using highly scalable backing stores such as CouchDb or HyperTable.Event streams, a different way of storing the current state of an object, open many doors in this session not only in how we scale and store our domain but also in how we rationalize about it.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/2DDA5370-3246-4442-802D-D131512D696A"&gt;iPod Video 320x240 (112.6 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/72B5743C-570D-4A93-B315-A78A859F67CC"&gt;MPEG-4 for QuickTime Medium 1280x480 (410 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/BB983DB3-FBB5-4898-848E-40CBB8794169/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=BB983DB3-FBB5-4898-848E-40CBB8794169" target="_blank"&gt;Testers Are Not Your Enemy 17 Jun 10 1:40 PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;Manual testing has been marginalized in agile development. Usdevelopers seems to think that manual testing is outdated and shouldnow be replaced by automatic test scripts. I think that manual testingshould still be a part of the development process, and in this talk,you will learn why that is and how we can integrate manual testers onagile teams.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/DAE1B9CB-6ABC-4DF7-849E-2DBD1FE2669A"&gt;iPod Video 320x240 (66.3 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/0F857841-5D33-49FA-9A35-E2FCB80607F8"&gt;MPEG-4 for QuickTime Medium 1280x480 (330.1 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/6660D5A9-C231-4EE3-8F9A-D359F15CCABB/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=6660D5A9-C231-4EE3-8F9A-D359F15CCABB" target="_blank"&gt;Improving Your ASP.NET Application Performance with Asynchcronous Pages and Parallel Extensions 17 Jun 10 1:40 PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;Asynchronous pages and handlers can be used in ASP.NET to improve the performance of the application, especially the throughput, but wrongly used can lead to unexpected behavior, including a degraded performance. One of the key technologies that are part of the Visual Studio 2010 is Parallel Extensions. So come to this interactive session to see how you can benefit from those new technologies and how they can help you to mitigate some of the problems.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/AC43AF8E-6F1F-4E12-AE44-574740C6601E"&gt;iPod Video 320x240 (141.8 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/03F4B3EA-4E22-45E7-989D-8FF1A67BF475"&gt;MPEG-4 for QuickTime Medium 1280x480 (674.5 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/B663FE0E-7F19-482E-95BF-D7AB9A4C9CBE/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=B663FE0E-7F19-482E-95BF-D7AB9A4C9CBE" target="_blank"&gt;Fluent Nhibernate 17 Jun 10 11:40 AM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;(misses 4 minutes in the start)An introduction and overview to object?relational mapping using Fluent NHibernate. See how Fluent NHibernate can help you map your domain with the least amount of effort, how you can remain flexible with your database, and how to drive your design through convention?Cover?Cconfiguration; all without writing a single line of XML.
          &lt;br&gt;The talk is an introduction to Fluent NHibernate for those that aren't familiar with it, and assumes some NHibernate experience and is for .Net developers primarily. The goal is to show people how low?Cimpact NHibernate can be with Fluent NHibernate, and how it can actually speed up development in rapid?Cchange environments.

          &lt;br&gt;I'll cover an overview of what Fluent NHibernate is, the various parts of it (the fluent interface, the conventions, and the auto?Cmappings, and the configuration aspect), then expand on how these features can be utilised to improve your NHibernate experience and simplify your development process.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/715B25D0-4BA3-496D-996B-2328D03F336F"&gt;iPod Video 320x240 (94.8 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/A0DE0481-5A63-4046-9442-35F20D826175"&gt;MPEG-4 for QuickTime Medium 1280x480 (512.5 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/C567290C-750D-4597-96F2-44699BD20F35/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=C567290C-750D-4597-96F2-44699BD20F35" target="_blank"&gt;Folding Design to Agile 17 Jun 10 10:40 AM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;After a decade of heavy process, the Agile revolution of the late '90s threw off the dead hand of big upfront design. The bloody purge that followed was needed!There were unintended consequences. Too many teams interpret "Agile" as a permit to not think about design. But if they have ambitious goals, Agile teams need more than standup meetings and iterations. Many teams get off to a quick start, building lots of features in early iterations, but end up with a "Big Ball of Mud". Without clear and well-structured code, they cannot sustain their pace and also put themselves at risk of, one day, encountering a critical feature they simply cannot deliver. Without the common understanding between developers and stakeholders that is forged in domain analysis, one of the greatest benefits of iteration, the deepening communication about what the software should do and how it should do it, is never realized.We must not return to the "Analysis Paralysis" that we used to endure (and that many teams still do), but interpreting "Do the Simplest Thing" as "Do the Easiest Thing" doesn't work either.This talk will consider ways of incorporating modeling and design into the iterative process in a lightweight way that increases communication with stakeholders and decreases the likelihood of painting ourselves into corners, without returning to the dead-hand of the analysis phase. As a concrete example of how such techniques can be incorporated into the Agile framework, we'll have an overview of&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/E45EE484-17D1-457C-8E6E-9FE0A4009D56"&gt;iPod Video 320x240 (88.4 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/7157FD1C-F6FA-49D5-A89A-D51EFF373CC6"&gt;MPEG-4 for QuickTime Medium 1280x480 (234.3 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/9569A807-9FF8-45F7-B076-566EB839EDE5/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=9569A807-9FF8-45F7-B076-566EB839EDE5" target="_blank"&gt;Silverlight data access and services not for the faint of heart 17 Jun 10 10:40 AM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;For data needs, Silverlight can talk to services like WCF or REST enabled services. These service types are sufficient for most scenarios. But what if it isn't? Most examples that can be found out there cover the basics, but in the real world, that's sometimes not enough. In this session, we'll explore the dark corners of Silverlight??s service access. Among others, we??ll cover duplex communication, debugging services, the HttpWebRequest, TCP communication and securing service communication from Silverlight.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/E128F1C5-4334-4A85-972E-054F356D8944"&gt;iPod Video 320x240 (126.8 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/8E5C9B51-C6FA-48F9-B71D-0924A7150390"&gt;MPEG-4 for QuickTime Medium 1280x480 (414.6 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/3F9663A1-95AD-49D4-BF60-B248EB7B7824/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=3F9663A1-95AD-49D4-BF60-B248EB7B7824" target="_blank"&gt;Zen of Architecture 17 Jun 10 10:37 AM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;Wonder about architecture best practices, guidelines and pitfalls? Wonder how to design world?Cclass systems? You understand the concepts but not how to apply them? In the first half of this high pace session, Juval will explain his original approach to large system analysis design. Then, he will discuss logical tiers, security, interoperability, scalability, transactions, and other aspects of a modern application. You will see how to approach rarely discussed topics such as allocation of services to assemblies, allocation of services to processes, transaction boundaries, identity management, authorization and authentication boundaries and more.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/23E152C9-A082-47A7-9752-CF4E6E763CB4"&gt;iPod Video 320x240 (101.8 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/6DE2F70E-E9EA-467F-987B-CA60D0832EC6"&gt;MPEG-4 for QuickTime Medium 1280x480 (393.9 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/D55B1D6D-1B66-4AE3-90C0-4A299CFDD207/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=D55B1D6D-1B66-4AE3-90C0-4A299CFDD207" target="_blank"&gt;Modularization, Testing &amp;amp; Technical Debt in a Large Agile Project 17 Jun 10 10:40 AM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;This experience reports focuses on the major scrum?Crelated technical challenges that arose during a 120 000 hour scrum controlled project. For each of them, we try to identify the cause and the consequence, and then follow up with any solutions we tried. Finally we sum up and assess whether the problem was successfully solved or not.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/4ECFFFF5-F771-4AFF-BF19-E9EC4CD36913"&gt;iPod Video 320x240 (66 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/4B65502D-0303-4A4C-9649-76FAC5D4BAC6"&gt;MPEG-4 for QuickTime Medium 1280x480 (294.1 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/7CA2DE20-2C1E-4E15-B962-5A61426B2218/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=7CA2DE20-2C1E-4E15-B962-5A61426B2218" target="_blank"&gt;Hardcore .NET Production Debugging 17 Jun 10 11:40 AM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;But ... it used to work yesterday! In this newest version of his classic session, Ingo Rammer will introduce the hardcore and low-level tools used for production debugging of .NET applications. You'll learn how to attack the nastiest bugs in your applications, how to look at what's causing that grinding halt of your ASP.NET application and how to find the cause of that horrible memory leak in your Windows Forms application. Knowledge of these production debugging tools like WinDbg and SOS is not only important for cases when you really don't have access to Visual Studio and your source code, but these tools also reveal a lot more information than just the regular managed code debuggers.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/02A5543D-E2A8-49F9-813B-86629B1505A7"&gt;iPod Video 320x240 (165.9 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/7D7AC028-F469-441A-B9F6-3694E2259AAF"&gt;MPEG-4 for QuickTime Medium 1280x480 (697 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/B28EBB6E-460F-4951-90A8-C4F10E3E368A/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=B28EBB6E-460F-4951-90A8-C4F10E3E368A" target="_blank"&gt;Solid C++ code by example 17 Jun 10 11:36 AM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;Sometimes you see code that is perfectly OK according to the definition of the language, but which is flawed because it breaks too many established idioms and conventions. On the other hand, a solid piece of code is something that looks like it is written by an experienced person who cares about professionalism in programming.
          &lt;br&gt;This will be an interactive discussion about good vs bad C++ code. We will discuss simple C++ idioms and coding conventions, but we will also touch upon best practices when working with C++ in large codebases with lots of developers with mixed skills.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/5B9E29D6-C172-49A7-B59C-8E5C0678DA3D"&gt;iPod Video 320x240 (98.9 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/AD7A5C8E-F267-466B-AAC4-DE2A9C925EFB"&gt;MPEG-4 for QuickTime Medium 1280x480 (337.1 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/33E5A226-B72F-425A-AFE1-A0F10324EF5E/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=33E5A226-B72F-425A-AFE1-A0F10324EF5E" target="_blank"&gt;Silverlight Applications for Windows Phone 7 17 Jun 10 9:20 AM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;Windows Phone 7 is brand new, totally fresh operating system that will appear in phones before Christmas. The new platform is a complete rewrite and offers lots of interesting opportunities to third party developers. The development platform for Windows Phone 7 is all based around managed code and the tools and frameworks you already know and love. This presentation you will give you an overview of the Windows Phone 7 development platform, and how you can leverage your existing Silverlight skills to build great applications for the Windows Phone 7 marketplace. The session assumes some prior knowledge of Silverlight, as the focus of this presentation will be features that are specific to the phone. It will not only cover the basics of the Windows Phone 7 platform, but also how you can re-use many of the same patterns, frameworks, techniques and practices that you use when building regular Silverlight applications.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/DB82EF1C-7FE5-4149-AF3D-8A9C5E769E9B"&gt;iPod Video 320x240 (115.6 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/E358E185-84EA-486D-9797-34EA9DC733F5"&gt;MPEG-4 for QuickTime Medium 1280x480 (366.1 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/BCEF7A82-56FF-45FE-9580-2DED9406FB9A/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=BCEF7A82-56FF-45FE-9580-2DED9406FB9A" target="_blank"&gt;Entity Framework Persistance Ignorance 17 Jun 10 9:20 AM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;Entity Framework in .NET 4 has finally embraced agile development. Thanks to it's new POCO support, you can now build completely persistent ignorant entity classes. In this session, we'll look at building an intelligent repository from entity classes and mocking up some extra classes in order to build unit tests against methods that have some dependency on the Entity Framework without touching the EF APIs. A prior understanding of the PI and Unit Testing should keep your head from spinning too much.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/340C88A5-8F8C-460A-ABD2-A1A92315FDBC"&gt;iPod Video 320x240 (115.2 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/47A57CCD-C1B6-4230-B677-A2995D00773F"&gt;MPEG-4 for QuickTime Medium 1280x480 (425.7 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/EE42F3A4-4B04-43A1-962E-22870D7C1877/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=EE42F3A4-4B04-43A1-962E-22870D7C1877" target="_blank"&gt;Service Oriented Development Process 17 Jun 10 9:20 AM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;When you develop a service-oriented application, it would be naive of you to expect that the only things you will do differently will be limited to design and technology. The development process itself needs to be service-oriented. You cannot "stare into the fire" of WCF without a mature service-oriented development process supporting your effort. This talk presents you with a service-oriented development process that you can apply to your WCF-based products to achieve robust applications, manage requirements and ensure faster time to market.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/5AC07B0F-EFE3-4871-ABCF-B36B87842B06"&gt;iPod Video 320x240 (90.7 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/97F3A10F-0EE7-49BF-B738-031C8D4F51EA"&gt;MPEG-4 for QuickTime Medium 1280x480 (324.9 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/7A0F3A2B-AD46-47E8-8748-5BAF9611B4E3/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=7A0F3A2B-AD46-47E8-8748-5BAF9611B4E3" target="_blank"&gt;IronRuby - A Brave New World for .NET 17 Jun 10 10:18 AM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;.NET developers are about to enter a brave new world. With Microsoft'sDynamic Language Runtime (DLR) developers can start taking advantageof dynamic languages, such as IronRuby and IronPython, on top of the.Net platform and integrating the language into their existing .netbased applications. However, why is this important?In this session, Ben will provide an insight into the deep darksecrets of why he loves the Ruby language and how it can result in amore effective solution when compared to C#. After demonstrating thepowerful capabilities, Ben will explain how the DLR with IronRubyallows you to take full advantage of Ruby from C# applications,resulting in you choosing the appropriate language (C# or Ruby) forthe appropriate feature. The combination results in a powerfultool-set and opens some amazing possibilities for both C# and Rubydevelopers. With C# 4.0, these capabilities are taken a step further.But the advantage is not just one way, there are also advantages forRuby developers by allowing them to develop against the .Netframework.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/D2A3C378-E023-4234-916D-B0EADEC66892"&gt;iPod Video 320x240 (119.8 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/56485999-04EC-43C1-95AC-BA04E3F56C25"&gt;MPEG-4 for QuickTime Medium 1280x480 (570.1 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/7CB648EE-545B-4184-9DFF-2FA37DBD7943/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=7CB648EE-545B-4184-9DFF-2FA37DBD7943" target="_blank"&gt;jQuery for ASP.NET developers 17 Jun 10 9:20 AM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;This session is a practical tour of the ??write less, do more?? JavaScript library - jQuery. In this session we will build an application using ASP.NET and jQuery while learning about CSS selectors, DOM manipulation, and asynchronous communications using the jQuery library. We??ll also look at the jQuery plug-in model, examine common jQuery programming paradigms, and see how to invoke WCF web services using jQuery.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/552627F4-8EC0-4CD9-B9CC-794EEB8879EA"&gt;iPod Video 320x240 (97.3 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/5F2A05DA-A1D1-49E3-A40B-B2117B726B00"&gt;MPEG-4 for QuickTime Medium 640x480 (190.4 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/B25D60E8-48C1-4514-9276-608859B4CC72/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=B25D60E8-48C1-4514-9276-608859B4CC72" target="_blank"&gt;Advanced Debugging with Visual Studio 17 Jun 10 10:17 AM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;Basically every .NET developer knows the Visual Studio debugger, but only few know its little secrets. In this session, Ingo shows you what you can achieve with this tool beyond the setting of simple breakpoints. You will learn how advanced breakpoints, debugger macros and visualizers, interactive breakpoints, tracepoints and interactive object instantiation at development time can support your hunt for bugs in your applications. Ingo will also show you the new crash-dump debugging features of Visual Studio 2010 which allow you to get closer to your problem even if you don't have access to Visual Studio on the machine which exhibits the unexpected behavior.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/507CBC74-B2A6-46DD-852D-69F83FFE9C1A"&gt;iPod Video 320x240 (177.7 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/0F217368-0162-4866-B63A-E9AB0D1C43FE"&gt;MPEG-4 for QuickTime Medium 640x480 (176.5 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/4DEB5112-B18A-44A8-AA01-56EDD95EB0EF/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=4DEB5112-B18A-44A8-AA01-56EDD95EB0EF" target="_blank"&gt;Unit Testing Best Practices &amp;amp; Test Reviews 17 Jun 10 10:20 AM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;In this session we look at existing .NET code form open source projects and discuss anti patterns worst practices when doing unit testing in the wild. From abuse of mock objects, unmaintainable tests and unreadable tests to checking interactions vs. state - this talk will take you deep into the real ugly world of unit testing.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/E2232282-BD09-4B7B-9ADF-81206FEDF545"&gt;iPod Video 320x240 (134.8 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/B78EE753-34E3-476D-A9D1-97A00381D43E"&gt;MPEG-4 for QuickTime Medium 1280x480 (664.2 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/874B6020-4A57-472A-807C-1B6E66FB308D/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=874B6020-4A57-472A-807C-1B6E66FB308D" target="_blank"&gt;Ruby for .NET developers 17 Jun 10 9:00 AM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;After having spent many years coding in C#, and after having spent equally as much time in the C# language culture, Ruby seemed like a lot of bad ideas and heresy. In fact, much of Ruby is heretical to a C# or VB.NET mono-culture, but the productivity gains demonstrated by Ruby on Rails teams remains an unavoidable elephant in the room. This presentation looks at C# code examples side by side with some equivalent Ruby code and shines a little light on what it means to have either "ceremony" and "essence". It challenges the claims of static typing's effect on tooling to deliver "developer productivity". And finally, some examples of Ruby meta programming are given to demonstrate direct solutions to programming problems that would require much ado with restrictions in C# that don't end up doing much more than reducing the efficiency of software development efforts.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/646691C3-E4FB-4F22-BBC0-2A0977273BF9"&gt;iPod Video 320x240 (2.3 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/CFEFCB53-4D3D-4F80-B650-A13426355759"&gt;iPod Video 320x240 (22.5 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/D9ADEB9E-8C47-49E1-A138-CE4E227A2E12"&gt;iPod Video 320x240 (98 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/94C4A832-6CCC-4494-9F6F-BE516C1DD556"&gt;MPEG-4 for QuickTime Medium 1280x480 (384.6 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/DEC10BA7-5065-4A8E-8508-B2778EDE04E5/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=DEC10BA7-5065-4A8E-8508-B2778EDE04E5" target="_blank"&gt;Silverlight for Windows Phone 17 Jun 10 9:00 AM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;Windows Phone 7 Series is coming??and if you are a Silverlight developer there is good news: Silverlight *is* the development platform for Windows Phone applications. This session will provide an overview of the tools, the emulator, and the core APIs for Silverlight for Windows Phone development. Find out what is (and is not) possible in creating and porting your Silverlight applications ready for Windows Phone 7.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/44C70EDA-7DDE-481D-9AAD-11BD2AEEF246"&gt;iPod Video 320x240 (130.3 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/86E4E98C-245F-447C-A136-AD595F0A16A3"&gt;MPEG-4 for QuickTime Medium 1280x480 (316 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/FE7C8B56-42E7-4F99-9C1C-F2BB0980F520/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=FE7C8B56-42E7-4F99-9C1C-F2BB0980F520" target="_blank"&gt;Putting Some Testing Into Your TFS Build 17 Jun 10 9:00 AM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;Continuous Integration and scheduled builds are an important part of any development process. To get the best out of these tools, as much testing as possible should be wired into the post build process. With the 2010 release of Visual Studio we get the Lab Manager product that allows us to deploy our automated build to a virtualised test environment for either manual and?or automated testing. In this session I will show by doing an end to end demo, showing how an application can be build, deployed and tested with the Lab Manager environment.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/551EBB80-E427-4ED1-9E55-77180F1C8985"&gt;iPod Video 320x240 (132.8 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/11636CFA-4AEF-4F0E-9715-05DD4052A7E1"&gt;MPEG-4 for QuickTime Medium 1280x480 (578.1 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/522865A3-FB1B-44F2-8528-214D8D73B333/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=522865A3-FB1B-44F2-8528-214D8D73B333" target="_blank"&gt;Big-Ass View on Competency 17 Jun 10 9:00 AM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;Agile team members create their own rules, based on constraints imposed by the environment. But something else is needed for good results: some call it discipline, craftsmanship, or competence. Traffic management teaches us that there are 7 approaches to achieving competence in a self-organizing system. We are going to look at all of them.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/932D6A04-9721-43B3-A2C5-DD07C0C4DBF3"&gt;iPod Video 320x240 (129.4 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/C0CB578F-0F6D-47E3-BE6B-FE566624D872"&gt;MPEG-4 for QuickTime Medium 1280x480 (699.8 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/F931D805-3B03-432A-A0FE-26F7E9CAF721/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=F931D805-3B03-432A-A0FE-26F7E9CAF721" target="_blank"&gt;Strategic Design 17 Jun 10 9:00 AM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;As software development leaders, we need to think more strategically. Some design decisions affect the trajectory of the whole project or even the organization. These decisions arise in early chartering and throughout development, and they are about much more than architecture. This talk will examine these issues through the lens of the Strategic Design principles of domain-driven design, which systematize a few critical practices some successful teams do intuitively.It is common for skilled teams to deliver software they are not proud of, due to compromises with legacy designs. Others toil for years, producing a platform that is never used to good advantage. These are strategic failures. On the other hand, there are projects with a direct explanation of how the software contributes to business goals. There are projects where designers work with a realistic view of the context of their development within the larger system, allowing them to maintain design clarity and integrity. These are strategic successes. Winning strategy starts with the domain.Two domain-driven design principles, "Context Mapping" and "Distilling the Core Domain", help you see your strategic situation more clearly and approach strategic design decisions more systematically. These techniques require extensive interaction with domain experts as well as the leaders of the organization, in discussions broader than functional requirements. They sometimes lead to priorities quite different from our most comfort&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/EEC4043E-D680-4686-A431-B0FCA258A408"&gt;iPod Video 320x240 (130.2 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/A3A05BA3-0B0C-4ED9-80D1-D9D705C0F1CA"&gt;MPEG-4 for QuickTime Medium 1280x480 (603.5 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/F36BD4C5-4FB7-4C1B-A0E1-990DA59308F5/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=F36BD4C5-4FB7-4C1B-A0E1-990DA59308F5" target="_blank"&gt;Co- and contra-variance in C# 17 Jun 10 7:57 AM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;What's the difference between a bunch of bananas and a fruit bowl? Why can't I order a collection of circles by area? Why is the Hokey Cokey invariant? These questions (and some rather more sensible ones) will be answered in this session on variance. C# has supported variance to different degrees over different versions; C# 4 introduces covariance and contravariance to generic delegates and interfaces. Many developers may well use these features without even being aware of them - but as ever, it's useful to know what's going on for the times where things go wrong. Pre-requisites: a strong cup of coffee for when we discuss higher order functions, and a reasonable grasp of generics. Understanding Func, Action, IEnumerable and IComparer would be a good start.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/6E75B535-23C7-46FC-A163-B14216AAAEF7"&gt;iPod Video 320x240 (132.2 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/9B1AEFFD-C380-43D3-B458-4022FDEB7D42"&gt;MPEG-4 for QuickTime Medium 640x480 (139.9 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/72AF92FC-C72C-4CFF-A9F3-2F51DDC5B08C/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=72AF92FC-C72C-4CFF-A9F3-2F51DDC5B08C" target="_blank"&gt;Windows Identity Foundation Overview 17 Jun 10 8:51 AM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;Hear how Windows Identity Foundation makes advanced identity capabilities and open standards first class citizens in the Microsoft .NET Framework. Learn how the Claims Based access model integrates seamlessly with the traditional .NET identity object model while also giving developers complete control over every aspect of authentication, authorization, and identity-driven application behavior. See examples of the point and click tooling with tight Microsoft Visual Studio integration, advanced STS capabilities, and much more that Windows Identity Foundation consistently provides across on-premise, service-based, ASP.NET and Windows Communication Foundation (WCF) applications.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/23C83C49-DD49-41D5-9CB9-4B91DBC82906"&gt;iPod Video 320x240 (119.8 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/C191BAF1-5EFD-4306-AB9B-0ECD8E14E513"&gt;MPEG-4 for QuickTime Medium 1280x480 (608.3 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/163E9CCC-7317-41A5-B772-81595467BBAF/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=163E9CCC-7317-41A5-B772-81595467BBAF" target="_blank"&gt;Browsers with Wings: HTML5 APIs for webapp developers 16 Jun 10 4:40 PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;HTML5 is all the rage with the cool kids, and although there's a lot of focus on the new language, there's plenty for web app developers with new JavaScript APIs both in the HTML5 spec and separated out as their own W3C specifications. This session will take you through demos and code and show off some of the outright crazy bleeding edge demos that are being produced today using the new JavaScript APIs. But it's not all pie in the sky - plenty is useful today, some even in Internet Explorer!Specifically we'll be looking at scripting the video media element, 2D canvas and some of the mashups we can achieve. How to take our web apps completely offline, going beyond the cookie and HTML5's answer to threading: web workers.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/6C10CEF6-5D4D-474A-B3D1-7E8F3B70D81F"&gt;iPod Video 320x240 (95.3 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/0A7C3DCF-8883-4C17-98C0-24E9DC6F512D"&gt;MPEG-4 for QuickTime Medium 1280x480 (370.2 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/30DC4F1D-3867-41FD-944E-167872AE4EF2/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=30DC4F1D-3867-41FD-944E-167872AE4EF2" target="_blank"&gt;Test-Driven JavaScript 16 Jun 10 4:40 PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;Javascript becomes much more important to interactive website development then before (ok it has been for a while already) but the notion of testing that logic seems even further fetched then testing the code written in C#, Java. And this is something that is wrong as well. How do you test drive your javascript development, what do you need to think about to make it testable? How can you deal with timers, async calls and the dom. Demonstrate all these things including how easy it is to make your own fakes for testing. Demonstrate the refactoring and changing behaviour becomes so much easier.And not to forget that the design of the code is much better as well. Basically that you gain all the benefits that TDD gives you in other languages also when doing TDD for javascript development.Building a feature without ever loading up a web-page to physically look at it and when you finally do it does exactly what you intended it to do, that is magic :-)&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/5749CE3E-EBE0-4A72-9FBE-BB56FDFCDD9B"&gt;iPod Video 320x240 (123.8 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/844C4775-CC44-418A-81F7-FC3FFF16CB45"&gt;MPEG-4 for QuickTime Medium 1280x480 (326.5 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/0CB02DD9-8B8E-43CF-BA75-5C3FEA3BDCEF/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=0CB02DD9-8B8E-43CF-BA75-5C3FEA3BDCEF" target="_blank"&gt;Windows Azure AppFabric 16 Jun 10 4:40 PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;As one of the key platform providers for enterprise solutions today, Microsoft realizes that there are very many assets in corporate datacenters that are not easily moved to the cloud. A lot of data is subject to government or corporate regulation about data protection that does not allow for the data to be hosted off-site and over the past decade, companies have made enormous investments in streamlining and integrating their applications in ways that make it not particularly attractive to break out parts of that integration chain and move them off into the cloud as insular solutions. The Windows Azure AppFabric??s Service Bus and Access Control services which Clemens will introduce in this session are about bridging these gaps and to provide application-to-application connectivity and access control federation across network and trust scopes.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/9A5D8386-E0F0-4431-9742-5FF75638EDEA"&gt;iPod Video 320x240 (120.7 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/FE8D7A25-2ACB-4A45-AFB7-90515A70C7E5"&gt;MPEG-4 for QuickTime Medium 1280x480 (379.1 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/F6DB36EA-62CE-466E-9E8F-778261513777/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=F6DB36EA-62CE-466E-9E8F-778261513777" target="_blank"&gt;The Parallel Task Library in .NET 4.0 16 Jun 10 5:b40PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;Introduced with .Net 4.0, the Parallel Task Library gives a new approach to task-parallel programming. In this session we dive into the details of the library, looking at the various ways that it can be utilised. We will cover a number of areas, including:? Data Parallelism, using Parallel.For and Parallel.ForEach? Task Parallelism, using Parallel.Invoke and the Task class? Exception Handling? Cancellation? Asynchronous continuation patterns? PLinq The session is aimed at the intermediate developer - a good understanding of basic threading principles is a requirement.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/768EFCE0-884D-4CA1-8D73-A53554862A6F"&gt;iPod Video 320x240 (153.5 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/F9F4FFFE-C760-4DD0-A127-494D0BD94F0B"&gt;MPEG-4 for QuickTime Medium 1280x480 (651.2 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/EC40F1C9-6A3D-4920-B57C-42316D7B5875/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=EC40F1C9-6A3D-4920-B57C-42316D7B5875" target="_blank"&gt;The Whole Team Approach to Testing 16 Jun 10 5:40 PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;Many test teams find themselves ??squeezed to the end??, with code delivered too late to complete all the testing before the release deadline. They can??t get traction on critical activities such as test automation, and find themselves falling further and further behind. The software development organization is weighed down by increasing technical debt. Customers aren??t getting the software they wanted. Serious bugs get out to production, slowing the team down more as fixing one bug might cause two more. It can seem impossible to break out of this downward spiral.One way to turn this trend around is to get the whole team involved in building quality into the application, and solving testing problems together. In this session, Lisa Crispin will explain how to make quality a team responsibility, and testing a team??s problem to solve. She??ll explain how the ??whole team?? approach, leveraging multiple skill sets and planning in time for testing activities, leads to more testable code, better testing solutions. Participants will leave with some practical ideas to try right away.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/C52CE5CD-5DE1-4ECA-B797-09FB737ACE4F"&gt;iPod Video 320x240 (101.6 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/BB31F99E-1E3D-4D27-AF4F-EEB02030306D"&gt;MPEG-4 for QuickTime Medium 1280x480 (422.1 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/302740C4-D6FD-40D1-BF97-A0D21392EEFD/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=302740C4-D6FD-40D1-BF97-A0D21392EEFD" target="_blank"&gt;Real-World Design with the Visual Studio 2010 Modelling Tools 16 Jun 10 3:21 PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;Visual Studio 2010 introduces new Layer, Class, Activity, Use Case, Sequence, and Component diagrams. This session provides an overview of each of these diagrams and demonstrates practical examples of when they are useful, and when they are not! You will see how VS 2010 allows you to reverse-engineer your existing .NET code and generate sequence diagrams that graphically depict the object interaction in your applications. You??ll also get a tour of the new Architecture Explorer, and learn how you can best fit these design tools into your software development processes - including agile software processes.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/0FC91B77-AB31-49A9-AFD9-030364B418B4"&gt;iPod Video 320x240 (103.9 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/9EF81C68-C1B9-4A45-80AF-F997FA49EF38"&gt;MPEG-4 for QuickTime Medium 1280x480 (299.5 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/903C3339-7F84-4626-B30D-476E74517929/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=903C3339-7F84-4626-B30D-476E74517929" target="_blank"&gt;Building a Real-World, E-Commerce, Data-Driven Web Site 16 Jun 10 3:20 PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;In this session, I'll take you on a tour of what it took to go from an empty space in my ISPs web farm and turn it into a functional ecommerce web site. We'll include a discussion of how the domain was attached, how the site was built in ASP.NET, where the graphics and layout came from, how the products and site settings were managed in SQL Server, how the site was published, how shipping, taxes and handling are calculated, how money is collected and how the site is maintained. If you've ever wanted to see what it takes to start from scratch and build a real-world ecommerce web site, this is the place for you.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/95BED923-EE0E-475B-BB86-0F59EC1AC206"&gt;iPod Video 320x240 (103.7 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/1412E8B9-3876-45AD-83FA-FC43356886BD"&gt;MPEG-4 for QuickTime Medium 1280x480 (325.9 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/5E52750E-D4FC-41AA-9164-427A00BBC49D/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=5E52750E-D4FC-41AA-9164-427A00BBC49D" target="_blank"&gt;Distributed Computing 2.0 16 Jun 10 4:19 PM&lt;/a&gt;&lt;/p&gt;

        

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/7188E52A-58A4-40AA-A1C3-03186BD0E40C"&gt;iPod Video 320x240 (164.5 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/AFAE6D66-4F22-4C3C-940F-C706DE5CB28A"&gt;MPEG-4 for QuickTime Medium 1280x480 (864.3 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/80B9DFA5-672A-4773-BDA2-72B2B9ED3B68/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=80B9DFA5-672A-4773-BDA2-72B2B9ED3B68" target="_blank"&gt;Windows Azure Platform Compute &amp;amp; Storage 16 Jun 10 3:20 PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;At the heart of Windows Azure are its compute and management capabilities, which are foundational not only for ISV and enterprise solutions, but also for the Windows Azure platform components themselves. In this session Clemens will introduce Windows Azure??s notion of service and configuration models, the deployment and upgrade mechanisms, and introduce the diagnostics and management capabilities. You will furthermore learn about the various storage capabilities including the relational SQL Azure database service. Clemens will also show how Windows Azure??s different roles provide an architectural guidance framework for building scalable apps.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/14DF94D5-04AD-4513-BEAA-9FE7C50C2666"&gt;iPod Video 320x240 (147.7 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/AC095D5A-B799-4FEA-8CE1-2CFBA2952047"&gt;MPEG-4 for QuickTime Medium 1280x480 (40.5 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/7F971DA3-985E-48B0-A31E-3A3E50B2DF61"&gt;MPEG-4 for QuickTime Medium 1280x480 (690.6 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/84E5914B-BC2F-44B7-8276-C19C65833313/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=84E5914B-BC2F-44B7-8276-C19C65833313" target="_blank"&gt;Noda time: An Alternative Date &amp;amp; Time Framework 16 Jun 10 3:20 PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;The date and time API within the .NET framework has certainly improved over time, but it's still not as rich as it might be. Noda Time is an open source project porting the popular "Joda Time" framework from Java to .NET, and improving it along the way. I'll explain why DateTime and DateTimeOffset aren't always enough, the main concepts in Noda Time, and some lessons we've learned about .NET, porting in general, and running an open source project.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/8B620277-9794-4EB9-B903-67D889CA9F66"&gt;iPod Video 320x240 (140 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/3683519C-A600-4FCB-9DC3-4875371D74A7"&gt;MPEG-4 for QuickTime Medium 1280x480 (611.2 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/7242BEA2-BE20-4A74-B47C-33DF1C20F4F5/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=7242BEA2-BE20-4A74-B47C-33DF1C20F4F5" target="_blank"&gt;Does Self-Organization Actually Work &amp;amp; Are Agile Teams Actually Motivated By It? 16 Jun 10 4:20 PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;Self-organising teams are a key component of all of the agile methodologies, but do teams and organisations know what they are actually letting themselves in for when signing up for things like Scrum? In my experience the definition of "self-organisation" is widely different from organisation to organisation, team to team and even individual to individual within a team. This leads to fear, sub-optimisation and in a lot of cases subversion of the principle such that teams are being directed to work in sprints or iterations. In this session, Geoff will share his experiences of self-organisation, the common characteristics that are required for self-organisation to work and how commonly these characteristics are found in organisations that say that are "doing agile".&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/18AC3332-46AA-4F9C-BEFB-E12B9C4244ED"&gt;iPod Video 320x240 (103.2 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/E951C1EA-774E-4DFA-AE5B-5B74B712EA87"&gt;MPEG-4 for QuickTime Medium 1280x480 (439.4 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/E0F27D82-039B-4CE8-839C-DD69D641CB58/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=E0F27D82-039B-4CE8-839C-DD69D641CB58" target="_blank"&gt;Mono - A Great Platform for .NET in the Cloud 16 Jun 10 2:00 PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;ASP.NET WebForms and MVC apps run out-of-the-box on Mono on a variety of platforms. With so many options for hosting Linux servers on services such as EC2 and Linode, Mono has become an attractive platform for cloud deployment. This presentation will walk through several approaches to developing, debugging, and deploying .NET applications to the cloud with Mono.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/FA27ACC7-3833-43A0-AA41-361861EFD3F4"&gt;iPod Video 320x240 (92.9 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/604C5AAA-F90B-4B4C-BA1C-74DDD385800A"&gt;MPEG-4 for QuickTime Medium 1280x480 (294.8 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/D034F11E-646B-4A8A-94F7-64231F2C882D/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=D034F11E-646B-4A8A-94F7-64231F2C882D" target="_blank"&gt;I Can't Hear You - There's an ORM In My Ear: Effective Use of NoSQL In an ASP.NET MVC Web Application 16 Jun 10 2:00 PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;The NoSQL movement is gaining momentum (to many people's annoyance) and gaining many fans. For developers who haven't used a NoSQL solution (Object Database, Document Database, etc) it's a bit awkward to conceive of how you might do common tasks - like querying or generating application reports. In this talk Rob Conery shows how you can build an effective data access strategy using both NoSQL and traditional Relational Databases, focusing on using each system for its strengths rather than compensating for its weaknesses.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/CD9C9B96-6AD6-4682-901F-DECFC8963A2B"&gt;iPod Video 320x240 (364.2 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/30B6030D-0B5A-4EAE-BA35-730484A52D45"&gt;MPEG-4 for QuickTime Medium 320x240 (230.8 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/10ED66AB-C227-41DF-9943-03DF3F34686A/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=10ED66AB-C227-41DF-9943-03DF3F34686A" target="_blank"&gt;Lean Quality Assurance 16 Jun 10 3:00 PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;Quality Assurance (QA) in software worldwide has in fact degenerated into testing alone. Software?IT management has ignorantly allowed this to happen.Of course many parts of the industry have been well-aware of more cost-effective ways of delivering required quality in practice, but this has in fact been largely ignored; while granting very large resources to testing alone.It is time for a wakeup call!This manifesto is here to tell the industry that;testing alone is 10x more costly than doing Real QA. testing alone is not good enough, this can and need not go on. We know how to do real QA much much better than testing alone, using smarter upstream engineering practices, based on design, prevention and upstream inspections.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/9108952D-9CB6-4E5E-A227-95735D90C744"&gt;iPod Video 320x240 (145 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/FACABF23-1BF7-4CFB-B631-BB0E6D8DA904"&gt;MPEG-4 for QuickTime Medium 1280x480 (399.2 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/EEF24F50-5532-4F29-8313-3E5A87166282"&gt;MPEG-4 for QuickTime Medium 1280x480 (689.7 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/376DFD42-5231-48E0-AC24-0FB883A2166A/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=376DFD42-5231-48E0-AC24-0FB883A2166A" target="_blank"&gt;Design, Don't Decorate 16 Jun 10 3:00 PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;Putting the advanced capabilities of WPF and Silverlight to full use requires collaboration, experimentation, and iterative prototyping. In this session, you??ll see all five sequential prototypes for the acclaimed StaffLynx application (as seen on .NET Rocks TV), and discuss practices that worked and didn't work in real-world advanced UI development. We'll also discuss the role of visual and interactive designers in creating new era user interfaces, give some tips on how to think about using WPF and Silverlight capabilities to make interfaces feel natural and less stressful to users, and cover the most valuable lessons learned from a real-world project using advanced, next generation user interface technology.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/11B44CD9-7A55-4FDE-BA57-AEACA6F3F1E7"&gt;iPod Video 320x240 (109.3 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/CD0B714C-FC9B-49C6-9E7A-63BACAF1A4BD"&gt;MPEG-4 for QuickTime Medium 1280x480 (457.9 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/317A8278-F06C-4D24-AB31-330565EC0AE3/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=317A8278-F06C-4D24-AB31-330565EC0AE3" target="_blank"&gt;Inside modern JavaScript 16 Jun 10 2:00 PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;JavaScript is a dynamic, functional, ubiquitous language that has many hidden secrets. In this session we will take a deep look at the core JavaScript features that many contemporary libraries leverage, including constructor functions, prototypical inheritance, closures, hash parameters, method chaining, and more. Having a solid grasp of these features will not only help you write more maintainable JavaScript code, but also allow you to take greater advantage of today??s JavaScript libraries.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/6B6DBBAE-B439-4845-97B0-61962D8A2D20"&gt;iPod Video 320x240 (94.6 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/774FBBD6-2282-4E7A-9071-7B01CB835FE9"&gt;MPEG-4 for QuickTime Medium 1280x480 (390.6 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/2377CA9F-F9F8-418F-879A-17BCE95ED916/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=2377CA9F-F9F8-418F-879A-17BCE95ED916" target="_blank"&gt;CHESS - Finding &amp;amp; Reproducing Heisenbugs in Concurrent Programs 16 Jun 10 2:55 PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;CHESS is a tool from Microsoft Research that aims to find and reproduce hard to locate concurrency bugs. It does so by repeatedly running tests, systematically enumerating how the various threads are interleaved on each run. When (if) errors occur, CHESS can also then re--?]run the specific interleaving that resulted in the error, massively simplifying the debugging effort.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/1F52A581-6AF6-42BD-9CA3-CAD83E92CC42"&gt;iPod Video 320x240 (155.2 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/0B9F8812-C9A7-45FC-8E0B-FB90219E646A"&gt;MPEG-4 for QuickTime Medium 1280x480 (663.1 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/806323A0-D35F-4F60-A71B-37347C89176D/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=806323A0-D35F-4F60-A71B-37347C89176D" target="_blank"&gt;Windows Azure Overview 16 Jun 10 1:54 PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;HASH(0x1060cd48)&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/95568687-743E-4041-9FCB-ED4E5D92F335"&gt;iPod Video 320x240 (149.6 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/EA907797-D580-4234-98E5-0546C7F1022F"&gt;MPEG-4 for QuickTime Medium 1280x480 (709.7 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/95F528ED-572D-41ED-AEFD-C014731A55FE/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=95F528ED-572D-41ED-AEFD-C014731A55FE" target="_blank"&gt;What has Mono done for .NET developers Lately? 16 Jun 10 12:40 PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;Mono is an open-source, cross-platform implementation of the .NET framework based on the ECMA standards for C# and the Common Language Infrastructure. With Mono, users can run .NET applications written and compiled in Visual Studio on Windows, Linux, and Mac OS X. This session will provide an introduction to cross-platform development and deployment with Mono. Participants will see how they can leverage their existing skills and tools to write .NET applications that will run on multiple platforms and architectures with Mono. The presentation will also include a discussion of cross-platform considerations for leveraging Mono, and demonstrate how to use MoMA, the Mono Migration Analyzer, to determine how ready anapplication is for cross-platform deployment. Additional demonstrations will examine how best to leverage Visual Studio to develop and deploy to Linux and OS X, and take a peek at the current state of Moonlight 3 and 4.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/186869AD-5769-470B-8BEE-9A81A9874E72"&gt;iPod Video 320x240 (78.5 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/2ECAEE91-16B8-47E3-9E6D-9BC940047FD4"&gt;MPEG-4 for QuickTime Medium 1280x480 (245.7 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/D191A552-A38A-4870-8AB8-DE96203A581B/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=D191A552-A38A-4870-8AB8-DE96203A581B" target="_blank"&gt;Patterns for Parallel Programming 16 Jun 10 1:40 PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;Every five to ten years the world of computer programming is facing now a new paradigm shift, like GUI, object orientation, or generics. Right now we are facing a new paradigm shift, the multi-core one. Successful research in this area has been done for the past 30 years, but we are still not using the results efficiently. A pattern is a working solution to a recurring problem, and parallel?multi-core programming has its own problems which led to a set of patterns. Come and see in this session about which patterns exists in the area of parallel?multi-core programming and how they can be used with Visual Studio 2010.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/C58B6D44-2803-4907-BA44-72A1B06768B5"&gt;iPod Video 320x240 (176.3 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/965B1D6A-C262-41C0-941B-FF2750620274"&gt;MPEG-4 for QuickTime Medium 1280x480 (936.6 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/464F8EB9-9399-432A-A0B7-BCB17757BE46/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=464F8EB9-9399-432A-A0B7-BCB17757BE46" target="_blank"&gt;Programming with GUTs on 16 Jun 10 1:38 PM&lt;/a&gt;&lt;/p&gt;

        

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/CE3C1B66-A831-4FFD-8AFF-D877781A30B6"&gt;iPod Video 320x240 (112.4 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/F7B14893-DF7E-43FB-8ABD-44F11A648009"&gt;MPEG-4 for QuickTime Medium 1280x480 (483 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/91A8D9BC-4D17-4DB0-85DF-D8E573C0461D/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=91A8D9BC-4D17-4DB0-85DF-D8E573C0461D" target="_blank"&gt;CouchDB for .NET Developers 16 Jun 10 1:37 PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;RDBMS has been the standard for many years, when it has come to data storage. However, recently there has been an increase in document databases. In this talk we are going to cover the basics of CouchDB and how to consume this kind of database from .NET applications.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/4DFFDE4B-FBA8-43E9-9BEB-672B9BE36807"&gt;iPod Video 320x240 (132.8 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/DACDB1ED-CEF6-47EB-9180-6458BD4EA1C0"&gt;MPEG-4 for QuickTime Medium 1280x480 (684.6 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/F8D7D4BC-686F-4865-A4B2-C3211D246C8E/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=F8D7D4BC-686F-4865-A4B2-C3211D246C8E" target="_blank"&gt;How to Get the Best ROI From a Scrum Team as a Product Owner 16 Jun 10 12:37 PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;The Product Owner is probably the role that has received the least attention and help of all the three Scrum roles but it is paramount to an organisation's success with Scrum. While most projects benefit immediately from switching or adopting Scrum, to get the best out of the project a Product Owner really needs to understand both the team and the Scrum framework. In this tutorial Geoff will share his views and experiences of working with Scrum teams to provide you with a number of tips to improve your ROI.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/B8080CFA-585F-459D-8779-4A200D49FFF5"&gt;iPod Video 320x240 (205.3 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/AADA154E-622A-4EB1-BB0A-167A0D32794F"&gt;MPEG-4 for QuickTime Medium 1280x480 (516.8 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/1C166DD2-560F-4CE2-97CB-608C4F78866C/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=1C166DD2-560F-4CE2-97CB-608C4F78866C" target="_blank"&gt;.NET Design Patterns for Agile Software Processes 16 Jun 10 12:40 PM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;In the world of agile programming techniques, one of your best tools is design patterns. This session provides practical examples and implementation of design patterns in .NET. Familiarizing yourself with patterns such as Model-View-Controller, Observer, Abstract and Concrete Factories, and concepts such as programming to an interface rather than an implementation will help you build applications quickly that can easily adapt to your customer??s changing needs.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/52A75902-5E75-4D24-9C1D-59D5F09B2629"&gt;iPod Video 320x240 (131 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/29C798E1-AD5B-4275-A746-F64A3098BD72"&gt;MPEG-4 for QuickTime Medium 1280x480 (578 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/E915B78B-D9B7-4CE9-96DA-2B794391AD2F/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=E915B78B-D9B7-4CE9-96DA-2B794391AD2F" target="_blank"&gt;C# Puzzlers 16 Jun 10 12:32 PM&lt;/a&gt;&lt;/p&gt;

        

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/CD2DBF38-EECD-4B27-829E-4CEB2C10B189"&gt;iPod Video 320x240 (105.8 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/9908F342-50FD-4606-8AB2-59A5EFD97AC1"&gt;MPEG-4 for QuickTime Medium 1280x480 (505.3 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/5C145BA1-0861-478D-A467-AFF3A5089E03/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=5C145BA1-0861-478D-A467-AFF3A5089E03" target="_blank"&gt;Architecture of the Client Tier for WPF &amp;amp; Silverlight 16 Jun 10 10:40 AM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;Stateful client-based technologies for user interfaces, such as WPF and Silverlight, require more sophisticated design and architecture for the client tier than typical web applications. This session discusses the construction of a client-based navigation shell that replaces server-based navigation for a cleaner, more responsive user experience in multi-page applications. Implementation of capabilities such as data validation, temporary caching of unsaved data to allow for network downtime, and graceful shutdown will all be discussed. The session features a working model that attendees can use as a starting point for their own projects.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/E0A937F9-4078-44AD-B59C-E84FA66EEE76"&gt;iPod Video 320x240 (118.4 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/B5F1412F-0761-4935-8023-4824F42A6A21"&gt;MPEG-4 for QuickTime Medium 1280x480 (340.6 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/1272299E-1DD1-4C11-B7A3-EBDE5B11A5B7/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=1272299E-1DD1-4C11-B7A3-EBDE5B11A5B7" target="_blank"&gt;Individuals &amp;amp; Interaction Over Processes and Tools 16 Jun 10 10:40 AM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;Although it is a simple value, the idea that individuals and interactions are more significant than processes and tools is overlooked perhaps more often than it is valued. Of course, processes and tools make a difference -- sometimes a very big difference -- but what determines whether a process or tool is effective is related to the individuals and interactions. To best achieve agility you need to start with the current context and understand how people actually behave in response to their environment, their beliefs and one another. What actually motivates and demotivates people, developers in particular? What actually makes their work easier or harder? Does making "business value" the centrepiece of what they do actually motivate the people who ultimately produce such business value? Or is it more about the individuals and interactions?&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/20B40A5F-AF56-4849-81A7-A7A0735C1CE5"&gt;iPod Video 320x240 (119.2 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/60AC1636-0002-45EB-B6BA-C299B106EFE5"&gt;MPEG-4 for QuickTime Medium 1280x480 (385.3 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/2C3F6822-1694-48A6-9C49-8B3E3D4C6CE5/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=2C3F6822-1694-48A6-9C49-8B3E3D4C6CE5" target="_blank"&gt;Reactive Extensions (Rx) 16 Jun 10 10:37 AM&lt;/a&gt;&lt;/p&gt;

        

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/E91A35E6-2221-41A1-B88D-37AA6C35A79C"&gt;iPod Video 320x240 (123.3 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/8AFD1B19-6EED-45CF-B34D-CC3046ABB684"&gt;MPEG-4 for QuickTime Medium 1280x480 (534.9 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/38AD648E-835D-4FD4-91E8-B34E1D437D89/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=38AD648E-835D-4FD4-91E8-B34E1D437D89" target="_blank"&gt;Practical IronRuby 16 Jun 10 9:21 AM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;Ruby has been a home for some great innovative frameworks like Ruby on Rails, Cucumber and Rake. IronRuby version 1.0 will soon be released, unleashing the power of Ruby to the .NET world. 
          &lt;br&gt;In this session you will get familiar with the Ruby language and its amazing ecosystem and you will learn to take advantage of it in your everyday development tasks. Come and see how this great new addition to the .NET family makes your development process faster, clearer and happier!&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/445362FF-8CA1-494C-976F-06864CABA19D"&gt;iPod Video 320x240 (90.8 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/09B77798-02C0-4A6C-A167-9B1CC0765A62"&gt;MPEG-4 for QuickTime Medium 1280x480 (308.2 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/4E353FF7-ACDA-428B-99C9-9EACBC7C471C/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=4E353FF7-ACDA-428B-99C9-9EACBC7C471C" target="_blank"&gt;Strategies Against Architecture 16 Jun 10 9:18 AM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;Good architecture requires good vision and good people, but there are times when actions and decisions taken with the best of intent begin to work against an architecture. Instead of helping a system achieve a long life, speculation about reuse, flexibility and generality can bring a system to an early grave, weighing the codebase down with accidental complexity that invites workarounds and, ultimately, a new ad hoc architectural style. Documentation intended to be helpful becomes shelfware, ignored equally by its authors and its prospective readership. Dysfunctional memes in code and tests go unchecked because the detail of code is not considered a part of the architecture. Instead of stability and responsiveness, an architecture achieves stasis and loses reflex.This session looks at the reality of how development process and practices interact with the grander vision of architecture, the pitfalls of "architect as cop" and how to employ speculation and uncertainty to a system's advantage.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/AB9B343F-8332-4028-A7B5-CABE45BB2053"&gt;iPod Video 320x240 (113.6 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/B28AFB59-FDCD-4F26-AC2D-3C33C0508BAE"&gt;MPEG-4 for QuickTime Medium 1280x480 (36 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/9F36B1C3-E917-41BC-AF9F-2E8E0FB4D3E4"&gt;MPEG-4 for QuickTime Medium 1280x480 (376.8 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/C21C13ED-8657-4D10-9A21-213BA1031F90/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=C21C13ED-8657-4D10-9A21-213BA1031F90" target="_blank"&gt;A Style of Programming 16 Jun 10 9:17 AM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;This talk describes a set of coding principles that constitutes a style of programming that focuses on ease of coding, ease of changing the code, and ease of testing the code. The presentation aims at helping programmers understand how the principles relate to actual code. Every principle is made concrete through examples. This style of programming is influenced by leading object oriented and agile developers, and it is perfect for applying on object oriented languages such as C#.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/63D6EAB4-1ABD-4D6D-9D1D-84513B4BF893"&gt;iPod Video 320x240 (154.5 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/82055901-F9EF-4181-8A10-6CA548166E95"&gt;MPEG-4 for QuickTime Medium 1280x480 (753.5 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/0F97309E-B237-4CEF-A4D9-9E4DCD790F4B/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=0F97309E-B237-4CEF-A4D9-9E4DCD790F4B" target="_blank"&gt;Multicore - The Future of Computing 16 Jun 10 10:16 AM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;Since hitting both the memory and power wall about 3-5 years ago, all cpu vendors have been forced to turn from making the fastest possible single-thread cpu to instead putting several (sometimes simpler) cores on a single chip.Reducing the clock frequency by 50% can reduce power usage by 80%, so actual throughput per watt can improve a lot, as long as the code can be parallelized.Existing GPUs from Nvidia and AMD, Cell processors as used in the PS3 and Intel's announced Larrabee architecture can all supply an order of magnitude more fp processing power per watt than what is currently available from normal cpus.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/2785FDD1-BC5B-4754-856D-E26C1CCCA73F"&gt;iPod Video 320x240 (116.6 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/385CAC19-A22D-4C8C-A599-D3D468D9018F"&gt;MPEG-4 for QuickTime Medium 1280x480 (571.8 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr style="vertical-align: top"&gt;
      &lt;td&gt;&lt;img src="http://streaming.ndc2010.no/tcs/slides/DD7F9AD4-50AF-4B66-8A05-A9465C4F19BF/thumbnails/thumbnail.jpg"&gt;&lt;/td&gt;

      &lt;td&gt;
        &lt;p&gt;&lt;a href="http://streaming.ndc2010.no/tcs/?id=DD7F9AD4-50AF-4B66-8A05-A9465C4F19BF" target="_blank"&gt;Seven Key Factors for Agile Testing Success 16 Jun 10 10:13 AM&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;Agile development approaches present unique challenges for testers and test teams. Working in short iterations, often with limited written requirements, agile development teams can leave traditional testers behind. Common testing-related activities such as user acceptance testing, testing inter-product relationships, and installation testing need different approaches to fit into agile projects. Lisa Crispin explains seven key factors for testing success within agile projects that you can also apply to more traditional methodologies. Using a whole team approach and adopting an agile testing mindset are among the important components of a successful agile testing strategy. Learn how to overcome cultural and organizational obstacles and barriers to success in areas such as test automation. Discover the seven critical factors that provide a foundation for building your team's focus on quality and that deliver maximum value to your business.&lt;/p&gt;

        

        &lt;ul&gt;
          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/415AABE2-F055-406F-94F5-2B5C25A63FA4"&gt;iPod Video 320x240 (126 MB)&lt;/a&gt;&lt;/li&gt;

          &lt;li&gt;&lt;a href="http://streaming.ndc2010.no/tcs/download/D5225EC6-A679-4F7B-B4F8-9A27B3B9EAB2"&gt;MPEG-4 for QuickTime Medium 1280x480 (661.3 MB)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;

        
      &lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;&lt;/table&gt;</description>
      <comments>http://blog.zhaojie.me/2010/07/ndc-2010-videos.html#comments</comments>
      <pubDate>Tue, 13 Jul 2010 07:13:12 GMT</pubDate>
      <lastBuildDate>Tue, 13 Jul 2010 07:13:12 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/language/">语言编程</category>
      <category domain="http://blog.zhaojie.me/practice/">实践优化</category>
      <category domain="http://blog.zhaojie.me/parallel/">并行处理</category>
      <category domain="http://blog.zhaojie.me/cutting-edge/">技术尝鲜</category>
      <category domain="http://blog.zhaojie.me/speech/">培训演讲</category>
      <title>盛大创新院赞助首届.NET技术交流会 - 演讲录像及下载</title>
      <link>http://blog.zhaojie.me/2010/06/first-snda-dotnet-conference-videos.html</link>
      <guid>http://blog.zhaojie.me/2010/06/first-snda-dotnet-conference-videos.html</guid>
      <description>&lt;p&gt;经过几天的努力，终于将&lt;a href="http://blog.zhaojie.me/2010/01/1651772.html"&gt;盛大创新院&lt;/a&gt;赞助的&lt;a href="http://blog.zhaojie.me/2010/05/first-snda-dotnet-conference-sign-up.html"&gt;首届.NET技术交流会&lt;/a&gt;的演讲录像制作完成了。本来在现在的高清视频以外，我还想像Channel 9一样提供一些低码率的格式下载，但多次尝试都以失败告终，各中滋味难以言喻。因此目前只能给大家提供mov格式的高清视频下载，对于Windows下各类强大的播放器都不成问题。您也可以在线观看这些视频，不过上传至优酷后，发现除了清晰度较低外，甚至还有音画不同步的问题。我正在联系&lt;a href="http://www.ku6.com/"&gt;酷六网&lt;/a&gt;，会尽快用上质量更好的视频。&lt;/p&gt;

&lt;h1&gt;F#语言对异步程序设计的支持&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;讲师：&lt;/strong&gt;赵劼，盛大创新院，研究员&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;简介：&lt;/strong&gt;如今的Web应用、 Silverlight以及各种分布式系统让异步解决方案有了更进一步的需求。F#是微软.NET平台上的函数式编程语言，并添加了不少让并行及异步编程变得有趣且轻松的特性。本次演讲将讨论F#的核心概念，并探讨F#中的不可变性、函数式设计、异步工作流、代理等特性是如何应对真实应用中的异步挑战的。&lt;/p&gt;
&lt;embed src="http://player.youku.com/player.php/sid/XMjEzMDM1MDgw/v.swf" quality="high" width="480" height="400" align="middle" allowScriptAccess="sameDomain" type="application/x-shockwave-flash"&gt;&lt;/embed&gt; 

&lt;p&gt;&lt;a href="http://dlc2.sdo.com/FTP/cop/20100624/1/fsharp-async-20100619-high.mov"&gt;高清视频下载&lt;/a&gt;（mov格式，1280 * 720，495M）&lt;/p&gt;

&lt;h1&gt;Rails: Better Framework, Better Life&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;讲师：&lt;/strong&gt;吕国宁，Intridea.com，高级工程师&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;简介：&lt;/strong&gt;RoR是Ruby on Rails的缩写，是一个用于编写Web应用的框架。它基于Ruby语言，给开发人员提供了强大便利的框架支持。Ruby有很多优点，但是一直以来其流行范围仅局限于日本。2004年，当Rails框架横空出世，让人们认识到了一个更符合实际需要并且高效的web框架，在其出现不久就受到了业内的广泛关注。吕国宁将结合自己三年的Rails开发经验，给大家介绍一些Rails的优点，背后的设计文化，以及Rails的前景发展等内容。&lt;/p&gt;
&lt;embed src="http://player.youku.com/player.php/sid/XMTg0MTI0NjU2/v.swf" quality="high" width="480" height="400" align="middle" allowScriptAccess="sameDomain" type="application/x-shockwave-flash"&gt;&lt;/embed&gt; 

&lt;p&gt;&lt;a href="http://dlc2.sdo.com/FTP/cop/20100624/1/ror-20100619-high.mov"&gt;高清视频下载&lt;/a&gt;（mov格式，1280 * 720，432M）&lt;/p&gt;

&lt;h1&gt;大众点评网的技术变迁之路&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;讲师：&lt;/strong&gt;王宏，大众点评网，架构师&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;简介：&lt;/strong&gt;大众点评网从2003年创建以来，已经经历了7个年头，在技术方面从最初构建时期的简单的、低成本的方案，到发展阶段不断“痛苦”的转型演变，到目前比较复杂的技术架构，大众点评网的技术团队一直在关注业界新技术，力求提高可用性、降低成本、优化用户体验，并针对“点评”这一第三方参与的特点，摸索出一些特有的解决方案，借此机会希望能够分享给大家。&lt;/p&gt;
&lt;embed src="http://player.youku.com/player.php/sid/XMTg0MTA5MTY0/v.swf" quality="high" width="480" height="400" align="middle" allowScriptAccess="sameDomain" type="application/x-shockwave-flash"&gt;&lt;/embed&gt; 

&lt;p&gt;&lt;a href="http://dlc2.sdo.com/FTP/cop/20100624/1/dianping-20100619-high.mov"&gt;高清视频下载&lt;/a&gt;（mov格式，1280 * 720，486M）&lt;/p&gt;

&lt;h1&gt;Q &amp;amp; A&lt;/h1&gt;

&lt;p&gt;按照计划，原本还会有一场关于C#的演讲，但该场的讲师由于突然有急事只得作罢。于是我在最后增加了“演讲嘉宾问答”的环节，您可以在&lt;a href="http://www.ku6.com/"&gt;酷六网&lt;/a&gt;上进行在线观看。&lt;/p&gt;

&lt;p&gt;第1段：&lt;/p&gt;
&lt;embed src="http://player.ku6.com/refer/QFX3kb6ZJ8Wqge-w/v.swf" quality="high" width="480" height="400" align="middle" allowScriptAccess="always" allowfullscreen="true" type="application/x-shockwave-flash"&gt;&lt;/embed&gt; 

&lt;p&gt;第2段：&lt;/p&gt;
&lt;embed src="http://player.ku6.com/refer/wmD_kenujbB6gxnM/v.swf" quality="high" width="480" height="400" align="middle" allowScriptAccess="always" allowfullscreen="true" type="application/x-shockwave-flash"&gt;&lt;/embed&gt; 

&lt;h1&gt;相关文章&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="http://blog.zhaojie.me/2010/05/first-snda-dotnet-conference-sign-up.html"&gt;盛大创新院赞助首届.NET技术交流会开始报名了！&lt;/a&gt; &lt;/li&gt;

  &lt;li&gt;&lt;a href="http://blog.zhaojie.me/2010/06/first-snda-dotnet-conference-is-coming.html"&gt;盛大创新院赞助首届.NET技术交流会即将召开&lt;/a&gt; &lt;/li&gt;

  &lt;li&gt;&lt;a href="http://blog.zhaojie.me/2010/06/first-snda-dotnet-conference-all-slides.html"&gt;盛大创新院赞助首届.NET技术交流会 - 各场演讲幻灯片&lt;/a&gt; &lt;/li&gt;

  &lt;li&gt;盛大创新院赞助首届.NET技术交流会 - 演讲录像及下载 &lt;/li&gt;
&lt;/ul&gt;</description>
      <comments>http://blog.zhaojie.me/2010/06/first-snda-dotnet-conference-videos.html#comments</comments>
      <pubDate>Thu, 24 Jun 2010 06:40:51 GMT</pubDate>
      <lastBuildDate>Thu, 24 Jun 2010 06:40:51 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/language/">语言编程</category>
      <category domain="http://blog.zhaojie.me/practice/">实践优化</category>
      <category domain="http://blog.zhaojie.me/parallel/">并行处理</category>
      <category domain="http://blog.zhaojie.me/cutting-edge/">技术尝鲜</category>
      <category domain="http://blog.zhaojie.me/speech/">培训演讲</category>
      <title>盛大创新院赞助首届.NET技术交流会 - 各场演讲幻灯片</title>
      <link>http://blog.zhaojie.me/2010/06/first-snda-dotnet-conference-all-slides.html</link>
      <guid>http://blog.zhaojie.me/2010/06/first-snda-dotnet-conference-all-slides.html</guid>
      <description>&lt;p&gt;今天是近期最热的一天，气温高达35度，异常闷热，但是依然有160多位朋友冒着酷暑参加了&lt;a href="http://blog.zhaojie.me/2010/01/1651772.html"&gt;盛大创新院&lt;/a&gt;赞助的&lt;a href="http://blog.zhaojie.me/2010/05/first-snda-dotnet-conference-sign-up.html"&gt;首届.NET技术交流会&lt;/a&gt;，这让我感到很欣慰，因此这里首先要感谢大家的支持。我刚才浏览了一下三场演讲的桌面录像，可谓异常完美，现在只等酷六网的摄影师的讲师录像到手，便可以合成为最终的演讲视频了，希望能够尽快展示给大家。不过现在，大家可以在第一时间浏览本次活动新鲜出炉的幻灯片。&lt;/p&gt;

&lt;h1&gt;F#语言对异步程序设计的支持&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;讲师：&lt;/strong&gt;赵劼，盛大创新院，研究员 &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;简介：&lt;/strong&gt;如今的Web应用、 Silverlight以及各种分布式系统让异步解决方案有了更进一步的需求。F#是微软.NET平台上的函数式编程语言，并添加了不少让并行及异步编程变得有趣且轻松的特性。本次演讲将讨论F#的核心概念，并探讨F#中的不可变性、函数式设计、异步工作流、代理等特性是如何应对真实应用中的异步挑战的。&lt;/p&gt;

&lt;div style="width: 425px" id="__ss_4546454"&gt;&lt;strong style="margin: 12px 0px 4px; display: block"&gt;&lt;a title="F#语言对异步程序设计的支持" href="http://www.slideshare.net/jeffz/f-4546454"&gt;F#语言对异步程序设计的支持&lt;/a&gt;&lt;/strong&gt;&lt;object id="__sse4546454" width="425" height="355"&gt;&lt;param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=f-100619111719-phpapp01&amp;stripped_title=f-4546454" /&gt;&lt;param name="allowFullScreen" value="true"/&gt;&lt;param name="allowScriptAccess" value="always"/&gt;&lt;embed name="__sse4546454" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=f-100619111719-phpapp01&amp;stripped_title=f-4546454" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"&gt;&lt;/embed&gt;&lt;/object&gt;

  &lt;div style="padding-bottom: 12px; padding-left: 0px; padding-right: 0px; padding-top: 5px"&gt;View more &lt;a href="http://www.slideshare.net/"&gt;presentations&lt;/a&gt; from &lt;a href="http://www.slideshare.net/jeffz"&gt;jeffz&lt;/a&gt;.&lt;/div&gt;
&lt;/div&gt;

&lt;h1&gt;Rails: Better Framework, Better Life&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;讲师：&lt;/strong&gt;吕国宁，Intridea.com，高级工程师 &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;简介：&lt;/strong&gt;RoR是Ruby on Rails的缩写，是一个用于编写Web应用的框架。它基于Ruby语言，给开发人员提供了强大便利的框架支持。Ruby有很多优点，但是一直以来其流行范围仅局限于日本。2004年，当Rails框架横空出世，让人们认识到了一个更符合实际需要并且高效的web框架，在其出现不久就受到了业内的广泛关注。吕国宁将结合自己三年的Rails开发经验，给大家介绍一些Rails的优点，背后的设计文化，以及Rails的前景发展等内容。&lt;/p&gt;

&lt;div style="width: 425px" id="__ss_4545483"&gt;&lt;strong style="margin: 12px 0px 4px; display: block"&gt;&lt;a title="Better Framework Better Life" href="http://www.slideshare.net/jeffz/better-framework-better-life"&gt;Better Framework Better Life&lt;/a&gt;&lt;/strong&gt;&lt;object id="__sse4545483" width="425" height="355"&gt;&lt;param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=better-framework-better-life-100619101625-phpapp01&amp;stripped_title=better-framework-better-life" /&gt;&lt;param name="allowFullScreen" value="true"/&gt;&lt;param name="allowScriptAccess" value="always"/&gt;&lt;embed name="__sse4545483" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=better-framework-better-life-100619101625-phpapp01&amp;stripped_title=better-framework-better-life" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"&gt;&lt;/embed&gt;&lt;/object&gt;

  &lt;div style="padding-bottom: 12px; padding-left: 0px; padding-right: 0px; padding-top: 5px"&gt;View more &lt;a href="http://www.slideshare.net/"&gt;presentations&lt;/a&gt; from &lt;a href="http://www.slideshare.net/jeffz"&gt;jeffz&lt;/a&gt;.&lt;/div&gt;
&lt;/div&gt;

&lt;h1&gt;大众点评网的技术变迁之路&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;讲师：&lt;/strong&gt;王宏，大众点评网，架构师 &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;简介：&lt;/strong&gt;大众点评网从2003年创建以来，已经经历了7个年头，在技术方面从最初构建时期的简单的、低成本的方案，到发展阶段不断“痛苦”的转型演变，到目前比较复杂的技术架构，大众点评网的技术团队一直在关注业界新技术，力求提高可用性、降低成本、优化用户体验，并针对“点评”这一第三方参与的特点，摸索出一些特有的解决方案，借此机会希望能够分享给大家。&lt;/p&gt;

&lt;div style="width: 425px" id="__ss_4545503"&gt;&lt;strong style="margin: 12px 0px 4px; display: block"&gt;&lt;a title="大众点评网的技术变迁之路" href="http://www.slideshare.net/jeffz/ss-4545503"&gt;大众点评网的技术变迁之路&lt;/a&gt;&lt;/strong&gt;&lt;object id="__sse4545503" width="425" height="355"&gt;&lt;param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=random-100619101718-phpapp02&amp;stripped_title=ss-4545503" /&gt;&lt;param name="allowFullScreen" value="true"/&gt;&lt;param name="allowScriptAccess" value="always"/&gt;&lt;embed name="__sse4545503" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=random-100619101718-phpapp02&amp;stripped_title=ss-4545503" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"&gt;&lt;/embed&gt;&lt;/object&gt;

  &lt;div style="padding-bottom: 12px; padding-left: 0px; padding-right: 0px; padding-top: 5px"&gt;View more &lt;a href="http://www.slideshare.net/"&gt;presentations&lt;/a&gt; from &lt;a href="http://www.slideshare.net/jeffz"&gt;jeffz&lt;/a&gt;.&lt;/div&gt;

&lt;/div&gt;&lt;h1&gt;相关文章&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="http://blog.zhaojie.me/2010/05/first-snda-dotnet-conference-sign-up.html"&gt;盛大创新院赞助首届.NET技术交流会开始报名了！&lt;/a&gt; &lt;/li&gt;

  &lt;li&gt;&lt;a href="http://blog.zhaojie.me/2010/06/first-snda-dotnet-conference-is-coming.html"&gt;盛大创新院赞助首届.NET技术交流会即将召开&lt;/a&gt; &lt;/li&gt;

  &lt;li&gt;盛大创新院赞助首届.NET技术交流会 - 各场演讲幻灯片 &lt;/li&gt;

  &lt;li&gt;&lt;a href="http://blog.zhaojie.me/2010/06/first-snda-dotnet-conference-videos.html"&gt;盛大创新院赞助首届.NET技术交流会 - 演讲录像及下载&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;</description>
      <comments>http://blog.zhaojie.me/2010/06/first-snda-dotnet-conference-all-slides.html#comments</comments>
      <pubDate>Sat, 19 Jun 2010 15:48:23 GMT</pubDate>
      <lastBuildDate>Sat, 19 Jun 2010 15:48:23 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/language/">语言编程</category>
      <category domain="http://blog.zhaojie.me/practice/">实践优化</category>
      <category domain="http://blog.zhaojie.me/parallel/">并行处理</category>
      <category domain="http://blog.zhaojie.me/cutting-edge/">技术尝鲜</category>
      <category domain="http://blog.zhaojie.me/speech/">培训演讲</category>
      <title>盛大创新院赞助首届.NET技术交流会即将召开</title>
      <link>http://blog.zhaojie.me/2010/06/first-snda-dotnet-conference-is-coming.html</link>
      <guid>http://blog.zhaojie.me/2010/06/first-snda-dotnet-conference-is-coming.html</guid>
      <description>&lt;p&gt;由&lt;a href="http://blog.zhaojie.me/2010/01/1651772.html"&gt;盛大创新院&lt;/a&gt;赞助的首届.NET技术大会将于6月19号下午1点召开，本次交流会请到了四位讲师，议题覆盖了F#、C#、Rails及架构等多个方面。我已经看过了各场演讲的幻灯片草稿，也很期待各位讲师在正式演讲中的表现。&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/snda-dotnet-conf/conf-1-600x850.jpg" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/snda-dotnet-conf/conf-1-600x850.jpg" width="300" /&gt;&lt;/a&gt; 

&lt;p&gt;本次大会中，我们还获得了人民邮电出版社&lt;a href="http://www.turingbook.com/Homepage/Default.aspx"&gt;图灵教育&lt;/a&gt;赠送的20册图书，将会作为奖品赠送给在交流会中表现积极的听众。&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/snda-dotnet-conf/turingbook.jpg" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/snda-dotnet-conf/turingbook.jpg" width="300" /&gt;&lt;/a&gt; 

&lt;p&gt;此外，我们还请到了&lt;a href="http://www.ku6.com/"&gt;酷六网&lt;/a&gt;的专业摄影师对演讲过程进行全程拍摄，并配合各位讲师自身的屏幕录像，将在后期合成为适合独立观看的演讲视频，让不能到场的朋友在线或是下载后观看。&lt;/p&gt;

&lt;img src="http://img.zhaojie.me/blog/snda-dotnet-conf/ku6-logo.jpg" /&gt; 

&lt;p&gt;本次会议的邀请函已经发给各位报名者，请携带邀请函至会议现场签到，&lt;span style="color:red;"&gt;没有报名的朋友可以在现场直接报名&lt;/span&gt;。&lt;a href="http://blog.zhaojie.me/2010/05/first-snda-dotnet-conference-sign-up.html"&gt;关于会议的时间、地点、交通、议程等更多信息，请关注会议的报名信息&lt;/a&gt;。&lt;/p&gt;

&lt;h1&gt;相关文章&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="http://blog.zhaojie.me/2010/05/first-snda-dotnet-conference-sign-up.html"&gt;盛大创新院赞助首届.NET技术交流会开始报名了！&lt;/a&gt; &lt;/li&gt;

  &lt;li&gt;盛大创新院赞助首届.NET技术交流会即将召开 &lt;/li&gt;

  &lt;li&gt;&lt;a href="http://blog.zhaojie.me/2010/06/first-snda-dotnet-conference-all-slides.html"&gt;盛大创新院赞助首届.NET技术交流会 - 各场演讲幻灯片&lt;/a&gt; &lt;/li&gt;

  &lt;li&gt;&lt;a href="http://blog.zhaojie.me/2010/06/first-snda-dotnet-conference-videos.html"&gt;盛大创新院赞助首届.NET技术交流会 - 演讲录像及下载&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;</description>
      <comments>http://blog.zhaojie.me/2010/06/first-snda-dotnet-conference-is-coming.html#comments</comments>
      <pubDate>Thu, 17 Jun 2010 03:45:06 GMT</pubDate>
      <lastBuildDate>Thu, 17 Jun 2010 03:45:06 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/cutting-edge/">技术尝鲜</category>
      <category domain="http://blog.zhaojie.me/practice/">实践优化</category>
      <title>使用OpenOffice.org将各类文档转为PDF</title>
      <link>http://blog.zhaojie.me/2010/05/convert-document-to-pdf-via-openoffice.html</link>
      <guid>http://blog.zhaojie.me/2010/05/convert-document-to-pdf-via-openoffice.html</guid>
      <description>&lt;p&gt;最近在项目中遇到一个需求，是要将各类文档转换为PDF。这应该是个很常见的工作，而且我也只需要支持MS Word，Excel，PowerPoint等常见的文档格式就行了。于是有朋友就建议了，可以使用MS Office转嘛。当然也可以使用其他方法，例如装一些PDF打印机，把文档打印成pdf文件。不过这些做法在“授权”方面似乎都有些问题。当然，我也找了一些商业解决方案（如&lt;a href="http://www.aspose.com/"&gt;Aspose&lt;/a&gt;）保底，咋看之下它的授权方式也并不算贵。不过现在看来，&lt;a href="http://www.openoffice.org/"&gt;OpenOffice.org&lt;/a&gt;已经能够满足我的需求了。如果您有更好的做法也请告诉我。&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.openoffice.org/"&gt;OpenOffice.org&lt;/a&gt;是个开源的办公套件，提供了与MS Word，Excel，PowerPoint等对应的多个软件，在很多时候倒也足够使用。更重要的是，它支持包括MS Office 2007在内的多种格式，并且能够将其导出为PDF文件，再加上它的授权方式是&lt;a href="http://www.openoffice.org/licenses/lgpl_license.html"&gt;LGPL&lt;/a&gt;，在生产环境里使用自然也不会有什么明显的限制了。此外，&lt;a href="http://developer.openoffice.org/"&gt;OOo本身也有相当多的开发文档&lt;/a&gt;，我对完成这个工作还是很有信心的——但我没想到的是，这过程还真不如想象中那么顺利。&lt;/p&gt;

&lt;h1&gt;编译通过也不容易&lt;/h1&gt;

&lt;p&gt;首先，我安装了&lt;a href="http://download.openoffice.org/"&gt;OpenOffice.org主程序&lt;/a&gt;以及&lt;a href="http://download.openoffice.org/sdk/"&gt;SDK&lt;/a&gt;。SDK随带一些示例代码，其中&lt;a href="http://wiki.services.openoffice.org/wiki/API/Samples/Java/Office/DocumentHandling"&gt;DocumentHandling部分&lt;/a&gt;正好包含一个我需要的DocumentConverter功能。于是我打开Eclipse，倒入这个文件，很显然会出现无数错误提示：还没有引入合适的类库嘛。那么我该引用哪些jar包呢？根据其他一些搜索到的零碎的资料提示，我该引入的是一些放在~\Basis\program\classes下的几个jar包，比如unoil.jar、juh.jar……等等，这个包在什么地方？事实上，我在这么目录下唯独只找到unoil.jar这个独苗。莫名之余，我一股脑的将目录中的30多个jar包全部引入，可是错误依旧。&lt;/p&gt;

&lt;p&gt;我就蒙了，在搜索引擎里不断地用juh.jar相关的关键字进行查询，希望可以找到一些提示，一无所获。然后我动用了系统中的文件搜索，在~/Basis目录中查找*.jar，还是没有发现juh.jar的踪影。于是我很沮丧，怎么第一步也这么不顺利。直到大约过了一个小时后，我才无意间在~\URE\java目录下发现了那几个关键的jar包。引入后我长吁一口气：示例代码终于编译通过了。概括来说，如果需要让DocumentConverter.java编译通过，需要引入一下三个jar包：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;~\URE\java\juh.jar &lt;/li&gt;

  &lt;li&gt;~\URE\java\jurt.jar &lt;/li&gt;

  &lt;li&gt;~\Basis\program\classes\unoil.jar &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;真是痛恨文档和实际现象不符的情况，消耗时间不说，心情也变糟糕了。&lt;/p&gt;

&lt;h1&gt;整理示例代码&lt;/h1&gt;

&lt;p&gt;不得不说，DocumentConverter.java真不能算是段优秀的示例代码。首先，它并没有很好地起到示范的作用。我理想中的示例代码应该能够清晰地说明工作的方式和步骤，而不会添加太多额外的内容。这段示例代码的效果是“转化指定目录中的所有文件”，还用到了递归。再加上它没有import任何类型，每个类型在使用时都拖着长长的“com.sun.star”，这让原本就十分冗余的Java代码变得更为难以理解。更别说注释与代码本身的冲突，还有多余的类型强制转换等问题。为此，我根据&lt;a href="http://wiki.services.openoffice.org/wiki/API/Samples/Java/Office/DocumentHandling"&gt;文档说明&lt;/a&gt;，重新改写了一下示例代码，将整个过程拆分为多个步骤。&lt;/p&gt;

&lt;p&gt;首先，我们打开并连接一个OOo程序，这需要创建一个XComponentContext对象：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;private static&lt;/span&gt; &lt;span style="color: #2b91af"&gt;XComponentContext&lt;/span&gt; createContext() &lt;span style="color: blue"&gt;throws&lt;/span&gt; &lt;span style="color: #2b91af"&gt;Exception&lt;/span&gt; {
    &lt;span style="color: green"&gt;// get the remote office component context&lt;/span&gt;
    &lt;span style="color: blue"&gt;return&lt;/span&gt; &lt;span style="color: #2b91af"&gt;Bootstrap&lt;/span&gt;.bootstrap();
}&lt;/pre&gt;

&lt;p&gt;然后创建一个XComponentLoader对象：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;private static&lt;/span&gt; &lt;span style="color: #2b91af"&gt;XComponentLoader&lt;/span&gt; createLoader(&lt;span style="color: #2b91af"&gt;XComponentContext&lt;/span&gt; context) &lt;span style="color: blue"&gt;throws&lt;/span&gt; &lt;span style="color: #2b91af"&gt;Exception&lt;/span&gt; {
    &lt;span style="color: green"&gt;// get the remote office service manager&lt;/span&gt;
    &lt;span style="color: #2b91af"&gt;XMultiComponentFactory&lt;/span&gt; mcf = context.getServiceManager();
    &lt;span style="color: #2b91af"&gt;Object&lt;/span&gt; desktop = mcf.createInstanceWithContext(&lt;span style="color: #a31515"&gt;&amp;quot;com.sun.star.frame.Desktop&amp;quot;&lt;/span&gt;, context);
    &lt;span style="color: blue"&gt;return&lt;/span&gt; &lt;span style="color: #2b91af"&gt;UnoRuntime&lt;/span&gt;.queryInterface(&lt;span style="color: #2b91af"&gt;XComponentLoader&lt;/span&gt;.&lt;span style="color: blue"&gt;class&lt;/span&gt;, desktop);
}&lt;/pre&gt;

&lt;p&gt;从Loader对象可以加载一篇文档：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;private static&lt;/span&gt; &lt;span style="color: #2b91af"&gt;Object&lt;/span&gt; loadDocument(&lt;span style="color: #2b91af"&gt;XComponentLoader&lt;/span&gt; loader, &lt;span style="color: #2b91af"&gt;String&lt;/span&gt; inputFilePath) &lt;span style="color: blue"&gt;throws&lt;/span&gt; &lt;span style="color: #2b91af"&gt;Exception&lt;/span&gt; {
    &lt;span style="color: green"&gt;// Preparing properties for loading the document&lt;/span&gt;
    &lt;span style="color: #2b91af"&gt;PropertyValue&lt;/span&gt;[] propertyValues = &lt;span style="color: blue"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af"&gt;PropertyValue&lt;/span&gt;[1];
    propertyValues[0] = &lt;span style="color: blue"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af"&gt;PropertyValue&lt;/span&gt;();
    propertyValues[0].Name = &lt;span style="color: #a31515"&gt;&amp;quot;Hidden&amp;quot;&lt;/span&gt;;
    propertyValues[0].Value = &lt;span style="color: blue"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af"&gt;Boolean&lt;/span&gt;(true);
    
    &lt;span style="color: green"&gt;// Composing the URL by replacing all backslashs&lt;/span&gt;
    &lt;span style="color: #2b91af"&gt;File&lt;/span&gt; inputFile = new &lt;span style="color: #2b91af"&gt;File&lt;/span&gt;(inputFilePath);
    &lt;span style="color: #2b91af"&gt;String&lt;/span&gt; inputUrl = &lt;span style="color: #a31515"&gt;&amp;quot;file:///&amp;quot;&lt;/span&gt; + inputFile.getAbsolutePath().replace(&lt;span style="color: #a31515"&gt;'\\'&lt;/span&gt;, &lt;span style="color: #a31515"&gt;'/'&lt;/span&gt;);

    &lt;span style="color: blue"&gt;return&lt;/span&gt; loader.loadComponentFromURL(inputUrl, &lt;span style="color: #a31515"&gt;&amp;quot;_blank&amp;quot;&lt;/span&gt;, 0, propertyValues);
}&lt;/pre&gt;

&lt;p&gt;接着自然就是文档转换了：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;private static void&lt;/span&gt; convertDocument(&lt;span style="color: #2b91af"&gt;Object&lt;/span&gt; doc, &lt;span style="color: #2b91af"&gt;String&lt;/span&gt; outputFilePath, &lt;span style="color: #2b91af"&gt;String&lt;/span&gt; convertType) &lt;span style="color: blue"&gt;throws&lt;/span&gt; &lt;span style="color: #2b91af"&gt;Exception&lt;/span&gt; {
    &lt;span style="color: green"&gt;// Preparing properties for converting the document&lt;/span&gt;
    &lt;span style="color: #2b91af"&gt;PropertyValue&lt;/span&gt;[] propertyValues = &lt;span style="color: blue"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af"&gt;PropertyValue&lt;/span&gt;[2];
    &lt;span style="color: green"&gt;// Setting the flag for overwriting&lt;/span&gt;
    propertyValues[0] = &lt;span style="color: blue"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af"&gt;PropertyValue&lt;/span&gt;();
    propertyValues[0].Name = &lt;span style="color: #a31515"&gt;&amp;quot;Overwrite&amp;quot;&lt;/span&gt;;
    propertyValues[0].Value = &lt;span style="color: blue"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af"&gt;Boolean&lt;/span&gt;(true);
    &lt;span style="color: green"&gt;// Setting the filter name&lt;/span&gt;
    propertyValues[1] = &lt;span style="color: blue"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af"&gt;PropertyValue&lt;/span&gt;();
    propertyValues[1].Name = &lt;span style="color: #a31515"&gt;&amp;quot;FilterName&amp;quot;&lt;/span&gt;;
    propertyValues[1].Value = convertType;
    
    &lt;span style="color: green"&gt;// Composing the URL by replacing all backslashs&lt;/span&gt;
    &lt;span style="color: #2b91af"&gt;File&lt;/span&gt; outputFile = &lt;span style="color: blue"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af"&gt;File&lt;/span&gt;(outputFilePath);
    &lt;span style="color: #2b91af"&gt;String&lt;/span&gt; outputUrl = &lt;span style="color: #a31515"&gt;&amp;quot;file:///&amp;quot;&lt;/span&gt; + outputFile.getAbsolutePath().replace(&lt;span style="color: #a31515"&gt;'\\'&lt;/span&gt;, &lt;span style="color: #a31515"&gt;'/'&lt;/span&gt;);
    
    &lt;span style="color: green"&gt;// Getting an object that will offer a simple way to store
    // a document to a URL.&lt;/span&gt;
    &lt;span style="color: #2b91af"&gt;XStorable&lt;/span&gt; storable = &lt;span style="color: #2b91af"&gt;UnoRuntime&lt;/span&gt;.queryInterface(&lt;span style="color: #2b91af"&gt;XStorable&lt;/span&gt;.&lt;span style="color: blue"&gt;class&lt;/span&gt;, doc);
    &lt;span style="color: green"&gt;// Storing and converting the document&lt;/span&gt;
    storable.storeAsURL(outputUrl, propertyValues);
}&lt;/pre&gt;

&lt;p&gt;最后还要关闭文档：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;private static void&lt;/span&gt; closeDocument(&lt;span style="color: #2b91af"&gt;Object&lt;/span&gt; doc) &lt;span style="color: blue"&gt;throws&lt;/span&gt; &lt;span style="color: #2b91af"&gt;Exception&lt;/span&gt; {
    &lt;span style="color: green"&gt;// Closing the converted document. Use XCloseable.clsoe if the
    // interface is supported, otherwise use XComponent.dispose&lt;/span&gt;
    &lt;span style="color: #2b91af"&gt;XCloseable&lt;/span&gt; closeable = &lt;span style="color: #2b91af"&gt;UnoRuntime&lt;/span&gt;.queryInterface(&lt;span style="color: #2b91af"&gt;XCloseable&lt;/span&gt;.&lt;span style="color: blue"&gt;class&lt;/span&gt;, doc);
    
    &lt;span style="color: blue"&gt;if &lt;/span&gt;(closeable != null) {
    	closeable.close(&lt;span style="color: blue"&gt;false&lt;/span&gt;);
    } &lt;span style="color: blue"&gt;else &lt;/span&gt;{
        &lt;span style="color: #2b91af"&gt;XComponent&lt;/span&gt; component = &lt;span style="color: #2b91af"&gt;UnoRuntime&lt;/span&gt;.queryInterface(&lt;span style="color: #2b91af"&gt;XComponent&lt;/span&gt;.&lt;span style="color: blue"&gt;class&lt;/span&gt;, doc);
        component.dispose();
    }
}&lt;/pre&gt;

&lt;p&gt;最后便是将上面四个步骤串联起来：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public static void&lt;/span&gt; main(&lt;span style="color: #2b91af"&gt;String&lt;/span&gt; args[]) {
    &lt;span style="color: #2b91af"&gt;String&lt;/span&gt; inputFilePath = &lt;span style="color: #a31515"&gt;&amp;quot;D:\\convert\\input.txt&amp;quot;&lt;/span&gt;;
    &lt;span style="color: #2b91af"&gt;String&lt;/span&gt; outputFilePath = &lt;span style="color: #a31515"&gt;&amp;quot;D:\\convert\\output.doc&amp;quot;&lt;/span&gt;;
    
    &lt;span style="color: green"&gt;// the given type to convert to&lt;/span&gt;
    &lt;span style="color: #2b91af"&gt;String&lt;/span&gt; convertType = &lt;span style="color: #a31515"&gt;&amp;quot;swriter: MS Word 97&amp;quot;&lt;/span&gt;;
    
    &lt;span style="color: blue"&gt;try&lt;/span&gt; {
        &lt;span style="color: #2b91af"&gt;XComponentContext&lt;/span&gt; context = createContext();
        &lt;span style="color: #2b91af"&gt;System&lt;/span&gt;.out.println(&lt;span style="color: #a31515"&gt;&amp;quot;connected to a running office ...&amp;quot;&lt;/span&gt;);
        
        &lt;span style="color: #2b91af"&gt;XComponentLoader &lt;/span&gt;compLoader = createLoader(context);
        &lt;span style="color: #2b91af"&gt;System&lt;/span&gt;.out.println(&lt;span style="color: #a31515"&gt;&amp;quot;loader created ...&amp;quot;&lt;/span&gt;);
        
        &lt;span style="color: #2b91af"&gt;Object&lt;/span&gt; doc = loadDocument(compLoader, inputFilePath);
        &lt;span style="color: #2b91af"&gt;System&lt;/span&gt;.out.println(&lt;span style="color: #a31515"&gt;&amp;quot;document loaded ...&amp;quot;&lt;/span&gt;);
        
        convertDocument(doc, outputFilePath, convertType);
        &lt;span style="color: #2b91af"&gt;System&lt;/span&gt;.out.println(&lt;span style="color: #a31515"&gt;&amp;quot;document converted ...&amp;quot;&lt;/span&gt;);
        
        closeDocument(doc);
        &lt;span style="color: #2b91af"&gt;System&lt;/span&gt;.out.println(&lt;span style="color: #a31515"&gt;&amp;quot;document closed ...&amp;quot;&lt;/span&gt;);
        
        &lt;span style="color: #2b91af"&gt;System&lt;/span&gt;.exit(0);
    } &lt;span style="color: blue"&gt;catch&lt;/span&gt; (&lt;span style="color: #2b91af"&gt;Exception&lt;/span&gt; e) {
        e.printStackTrace(&lt;span style="color: #2b91af"&gt;System&lt;/span&gt;.err);
        &lt;span style="color: #2b91af"&gt;System&lt;/span&gt;.exit(1);            
    }
}&lt;/pre&gt;

&lt;p&gt;总体来说，虽然OOo并没有提供优雅的API，但是它的主要“套路”还是比较容易摸索出来的：加载文档，使用UnoRuntime.queryInterface方法获取各种操作接口，而各种参数都通过PropertyValue数组来提供。如果您像我一样感觉不爽，重新作一层简单的封装也是十分容易的。&lt;/p&gt;

&lt;h1&gt;运行中的问题&lt;/h1&gt;

&lt;p&gt;到目前为止，我们只是重新整理了示例代码，还没有开始运行。当第一次运行的时候便发现有异常抛出：&lt;/p&gt;

&lt;pre class="code"&gt;com.sun.star.comp.helper.BootstrapException: &lt;span style="color: red"&gt;no office executable found!&lt;/span&gt;
	at com.sun.star.comp.helper.Bootstrap.bootstrap(Bootstrap.java:246)
	at jeffz.practices.AnyToDoc.createContext(AnyToDoc.java:19)
	at jeffz.practices.AnyToDoc.main(AnyToDoc.java:87)&lt;/pre&gt;

&lt;p&gt;不过有异常信息之后，查找解决方案一般也很容易（但&lt;a href="http://blog.zhaojie.me/2009/10/about-debugging.html"&gt;就我个人经验来说&lt;/a&gt;，还是有很多朋友会问“抛出XX异常该怎么办”之类的问题）。经过搜索，发现遇到这个问题的人还不少，他们把juh.jar等文件复制到OOo安装目录外（这在生产环境中几乎是必然的）之后便会产生这个异常，但如果直接引用OOo安装目录内的jar便不会有问题了——但是我目前是直接引用OOo安装目录的jar包，不是吗？但我转念一想，我当时为编译通过而挣扎的原因，不就是“juh.jar”等文件不在它本该在的位置吗？既然这个问题和jar包与OOo程序的相对路径有关，那么如果我把jar包放回“原来”的位置，这个问题可能就不存在了。&lt;/p&gt;

&lt;p&gt;不过这些只是推测，我没有去进行尝试。因为既然在生产环境中还是会破坏路径问题，那我还是找一下这个问题的解决方案吧。最终在OOo的论坛上&lt;a href="http://user.services.openoffice.org/en/forum/viewtopic.php?f=44&amp;amp;t=2520"&gt;找到了答案&lt;/a&gt;：有人提供了一个补充包bootstrapconnector.jar，其中提供了一个方法可以让我们指定OOo的程序目录。也就是说，我们需要把之前的createContext改写成：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;private static&lt;/span&gt; &lt;span style="color: #2b91af"&gt;XComponentContext&lt;/span&gt; createContext() &lt;span style="color: blue"&gt;throws&lt;/span&gt; &lt;span style="color: #2b91af"&gt;Exception&lt;/span&gt; {
    &lt;span style="color: green"&gt;// get the remote office component context
    // return Bootstrap.bootstrap();&lt;/span&gt;
    &lt;span style="color: #2b91af"&gt;String&lt;/span&gt; oooExeFolder = &lt;span style="color: #a31515"&gt;&amp;quot;C:/Program Files/OpenOffice.org 3/program/&amp;quot;&lt;/span&gt;;
    &lt;span style="color: blue"&gt;return&lt;/span&gt; &lt;span style="color: #2b91af"&gt;BootstrapSocketConnector&lt;/span&gt;.bootstrap(oooExeFolder);
}&lt;/pre&gt;

&lt;p&gt;当然，生产环境中您一般不会使用硬编码的方式制定路径，您可以把它放在配置文件或是系统变量里。再次运行即告成功。这段代码会将一个txt文件转化成旧有的Word格式，事实上您可以将txt替换成OOo所支持的任何一种格式，比如rtf，docs，odt等等。&lt;/p&gt;

&lt;p&gt;那么接下来的问题便是，如何将目标格式改为PDF文件？很显然，目标格式是Word文件，是因为我们将类型字符串指定为“swriter: MS Word 97”，那么PDF格式是多少？这靠猜测是没法得出结果的，最后还是&lt;a href="http://wiki.services.openoffice.org/wiki/API/Tutorials/PDF_export"&gt;从一篇文档中得到了答案&lt;/a&gt;：writer_pdf_Export。事实上，这么做还是不够，代码还是会在storeAsURL方法中抛出异常，而且这是一个泛泛的ErrorCodeIOException，没有具体信息（message为空）。&lt;a href="http://wiki.services.openoffice.org/wiki/API/Samples/Java/Office/DocumentHandling#Saving_a_document"&gt;又一阵好找&lt;/a&gt;，才发现storeAsURL对应着OOo的“Save as”功能，而如果是“Export”功能，则应该调用storeToURL方法。&lt;/p&gt;

&lt;p&gt;最后，我们终于成功地将其他格式转化为PDF文件了。&lt;/p&gt;

&lt;h1&gt;完整代码&lt;/h1&gt;

&lt;p&gt;在这里贴出“txt转pdf”完整的可运行的示例代码：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;import&lt;/span&gt; java.lang._;
&lt;span style="color: blue"&gt;import&lt;/span&gt; java.io.&lt;span style="color: #2b91af"&gt;File&lt;/span&gt;;
&lt;span style="color: blue"&gt;import&lt;/span&gt; ooo.connector.&lt;span style="color: #2b91af"&gt;BootstrapSocketConnector&lt;/span&gt;;
&lt;span style="color: blue"&gt;import&lt;/span&gt; com.sun.star.lang.&lt;span style="color: #2b91af"&gt;XComponent&lt;/span&gt;;
&lt;span style="color: blue"&gt;import&lt;/span&gt; com.sun.star.uno.&lt;span style="color: #2b91af"&gt;XComponentContext&lt;/span&gt;;
&lt;span style="color: blue"&gt;import&lt;/span&gt; com.sun.star.uno.&lt;span style="color: #2b91af"&gt;UnoRuntime&lt;/span&gt;;
&lt;span style="color: blue"&gt;import&lt;/span&gt; com.sun.star.beans.&lt;span style="color: #2b91af"&gt;PropertyValue&lt;/span&gt;;
&lt;span style="color: blue"&gt;import&lt;/span&gt; com.sun.star.frame.&lt;span style="color: #2b91af"&gt;XComponentLoader&lt;/span&gt;;
&lt;span style="color: blue"&gt;import&lt;/span&gt; com.sun.star.frame.&lt;span style="color: #2b91af"&gt;XStorable&lt;/span&gt;;
&lt;span style="color: blue"&gt;import&lt;/span&gt; com.sun.star.util.&lt;span style="color: #2b91af"&gt;XCloseable&lt;/span&gt;;

&lt;span style="color: blue"&gt;object&lt;/span&gt; &lt;span style="color: #2b91af"&gt;AnyToPdf&lt;/span&gt; &lt;span style="color: blue"&gt;extends&lt;/span&gt; &lt;span style="color: #2b91af"&gt;Application &lt;/span&gt;{
  
  &lt;span style="color: green"&gt;// get the remote office component context&lt;/span&gt;
  &lt;span style="color: blue"&gt;def&lt;/span&gt; createContext() : &lt;span style="color: #2b91af"&gt;XComponentContext&lt;/span&gt; = {
    &lt;span style="color: blue"&gt;val&lt;/span&gt; oooExeFolder = &lt;span style="color: #a31515"&gt;&amp;quot;C:/Program Files/OpenOffice.org 3/program/&amp;quot;&lt;/span&gt;
    &lt;span style="color: #2b91af"&gt;BootstrapSocketConnector&lt;/span&gt;.bootstrap(oooExeFolder)
  }
  
  &lt;span style="color: blue"&gt;def&lt;/span&gt; createComponentLoader(context: &lt;span style="color: #2b91af"&gt;XComponentContext&lt;/span&gt;) : &lt;span style="color: #2b91af"&gt;XComponentLoader &lt;/span&gt;= {
    &lt;span style="color: green"&gt;// get the remote office service manager&lt;/span&gt;
    &lt;span style="color: blue"&gt;val&lt;/span&gt; mcf = context.getServiceManager()
    &lt;span style="color: blue"&gt;val&lt;/span&gt; desktop = mcf.createInstanceWithContext(&lt;span style="color: #a31515"&gt;&amp;quot;com.sun.star.frame.Desktop&amp;quot;&lt;/span&gt;, context)
    &lt;span style="color: #2b91af"&gt;UnoRuntime&lt;/span&gt;.queryInterface(&lt;span style="color: blue"&gt;classOf&lt;/span&gt;[&lt;span style="color: #2b91af"&gt;XComponentLoader&lt;/span&gt;], desktop)
  }
  
  &lt;span style="color: blue"&gt;def&lt;/span&gt; loadDocument(loader: &lt;span style="color: #2b91af"&gt;XComponentLoader&lt;/span&gt;, inputFilePath: &lt;span style="color: #2b91af"&gt;String&lt;/span&gt;) : &lt;span style="color: #2b91af"&gt;Object &lt;/span&gt;= {
    &lt;span style="color: green"&gt;// Preparing properties for loading the document&lt;/span&gt;
    &lt;span style="color: blue"&gt;val&lt;/span&gt; propertyValue = &lt;span style="color: blue"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af"&gt;PropertyValue&lt;/span&gt;()
    propertyValue.Name = &lt;span style="color: #a31515"&gt;&amp;quot;Hidden&amp;quot;&lt;/span&gt;
    propertyValue.Value = &lt;span style="color: blue"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af"&gt;Boolean&lt;/span&gt;(&lt;span style="color: blue"&gt;true&lt;/span&gt;)
    
    &lt;span style="color: green"&gt;// Composing the URL by replacing all backslashs&lt;/span&gt;
    &lt;span style="color: blue"&gt;val&lt;/span&gt; inputFile = &lt;span style="color: blue"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af"&gt;File&lt;/span&gt;(inputFilePath)
    &lt;span style="color: blue"&gt;val&lt;/span&gt; inputUrl = &lt;span style="color: #a31515"&gt;&amp;quot;file:///&amp;quot;&lt;/span&gt; + inputFile.getAbsolutePath().replace(&lt;span style="color: #a31515"&gt;'\\'&lt;/span&gt;, &lt;span style="color: #a31515"&gt;'/'&lt;/span&gt;)
    loader.loadComponentFromURL(inputUrl, &lt;span style="color: #a31515"&gt;&amp;quot;_blank&amp;quot;&lt;/span&gt;, 0, &lt;span style="color: #2b91af"&gt;Array&lt;/span&gt;(propertyValue))
  }
  
  &lt;span style="color: blue"&gt;def&lt;/span&gt; convertDocument(doc: &lt;span style="color: #2b91af"&gt;Object&lt;/span&gt;, outputFilePath: &lt;span style="color: #2b91af"&gt;String&lt;/span&gt;, convertType: &lt;span style="color: #2b91af"&gt;String&lt;/span&gt;) {
    &lt;span style="color: green"&gt;// Preparing properties for converting the document
    // Setting the flag for overwriting&lt;/span&gt;
    &lt;span style="color: blue"&gt;val&lt;/span&gt; overwriteValue = &lt;span style="color: blue"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af"&gt;PropertyValue&lt;/span&gt;()
    overwriteValue.Name = &lt;span style="color: #a31515"&gt;&amp;quot;Overwrite&amp;quot;&lt;/span&gt;
    overwriteValue.Value = &lt;span style="color: blue"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af"&gt;Boolean&lt;/span&gt;(&lt;span style="color: blue"&gt;true&lt;/span&gt;)
    &lt;span style="color: green"&gt;// Setting the filter name&lt;/span&gt;
    &lt;span style="color: blue"&gt;val&lt;/span&gt; filterValue = &lt;span style="color: blue"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af"&gt;PropertyValue&lt;/span&gt;()
    filterValue.Name = &lt;span style="color: #a31515"&gt;&amp;quot;FilterName&amp;quot;&lt;/span&gt;
    filterValue.Value = convertType
    
    &lt;span style="color: green"&gt;// Composing the URL by replacing all backslashs&lt;/span&gt;
    &lt;span style="color: blue"&gt;val&lt;/span&gt; outputFile = &lt;span style="color: blue"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af"&gt;File&lt;/span&gt;(outputFilePath)
    &lt;span style="color: blue"&gt;val&lt;/span&gt; outputUrl = &lt;span style="color: #a31515"&gt;&amp;quot;file:///&amp;quot;&lt;/span&gt; + outputFile.getAbsolutePath().replace(&lt;span style="color: #a31515"&gt;'\\'&lt;/span&gt;, &lt;span style="color: #a31515"&gt;'/'&lt;/span&gt;)
    
    &lt;span style="color: green"&gt;// Getting an object that will offer a simple way to store
    // a document to a URL.&lt;/span&gt;
    &lt;span style="color: blue"&gt;val&lt;/span&gt; storable = &lt;span style="color: #2b91af"&gt;UnoRuntime&lt;/span&gt;.queryInterface(&lt;span style="color: blue"&gt;classOf&lt;/span&gt;[&lt;span style="color: #2b91af"&gt;XStorable&lt;/span&gt;], doc)
    &lt;span style="color: green"&gt;// Storing and converting the document&lt;/span&gt;
    storable.storeToURL(outputUrl, &lt;span style="color: #2b91af"&gt;Array&lt;/span&gt;(overwriteValue, filterValue))
  }
  
  &lt;span style="color: blue"&gt;def&lt;/span&gt; closeDocument(doc: &lt;span style="color: #2b91af"&gt;Object&lt;/span&gt;) {
    &lt;span style="color: green"&gt;// Closing the converted document. Use XCloseable.clsoe if the
    // interface is supported, otherwise use XComponent.dispose&lt;/span&gt;
    &lt;span style="color: blue"&gt;val&lt;/span&gt; closeable = &lt;span style="color: #2b91af"&gt;UnoRuntime&lt;/span&gt;.queryInterface(&lt;span style="color: blue"&gt;classOf&lt;/span&gt;[&lt;span style="color: #2b91af"&gt;XCloseable&lt;/span&gt;], doc)
    &lt;span style="color: blue"&gt;if&lt;/span&gt; (closeable != null) {
      closeable.close(&lt;span style="color: blue"&gt;false&lt;/span&gt;)
    } &lt;span style="color: blue"&gt;else&lt;/span&gt; {
      &lt;span style="color: blue"&gt;val&lt;/span&gt; component = &lt;span style="color: #2b91af"&gt;UnoRuntime&lt;/span&gt;.queryInterface(&lt;span style="color: blue"&gt;classOf&lt;/span&gt;[&lt;span style="color: #2b91af"&gt;XComponent&lt;/span&gt;], doc)
      component.dispose()
    }
  }
  
  &lt;span style="color: blue"&gt;val&lt;/span&gt; inputFilePath = &lt;span style="color: #a31515"&gt;&amp;quot;D:\\convert\\input.txt&amp;quot;&lt;/span&gt;
  &lt;span style="color: blue"&gt;val&lt;/span&gt; outputFilePath = &lt;span style="color: #a31515"&gt;&amp;quot;D:\\convert\\output.pdf&amp;quot;&lt;/span&gt;
		
  &lt;span style="color: green"&gt;// Getting the given type to convert to&lt;/span&gt;
  &lt;span style="color: blue"&gt;val&lt;/span&gt; convertType = &lt;span style="color: #a31515"&gt;&amp;quot;writer_pdf_Export&amp;quot;&lt;/span&gt;
  
  &lt;span style="color: blue"&gt;val&lt;/span&gt; context = createContext()
  println(&lt;span style="color: #a31515"&gt;&amp;quot;connected to a running office ...&amp;quot;&lt;/span&gt;)
  
  &lt;span style="color: blue"&gt;val&lt;/span&gt; loader = createComponentLoader(context)
  println(&lt;span style="color: #a31515"&gt;&amp;quot;loader created ...&amp;quot;&lt;/span&gt;)
  
  &lt;span style="color: blue"&gt;val&lt;/span&gt; doc = loadDocument(loader, inputFilePath)
  println(&lt;span style="color: #a31515"&gt;&amp;quot;document loaded ...&amp;quot;&lt;/span&gt;)
  
  convertDocument(doc, outputFilePath, convertType)
  println(&lt;span style="color: #a31515"&gt;&amp;quot;document converted ...&amp;quot;&lt;/span&gt;)
  
  closeDocument(doc)
  println(&lt;span style="color: #a31515"&gt;&amp;quot;document closed ...&amp;quot;&lt;/span&gt;)
}&lt;/pre&gt;

&lt;p&gt;很显然，这里不是&lt;a href="http://blog.zhaojie.me/2010/04/why-java-sucks-and-csharp-rocks-1-thoughts-and-goals.html"&gt;我所厌恶的Java语言&lt;/a&gt;。这是一段Scala代码，就从最基本的代码使用上看，Scala也已经比Java代码要节省许多了。&lt;/p&gt;

&lt;h1&gt;总结&lt;/h1&gt;

&lt;p&gt;其实解决这个问题还是走了不少弯路的，究其原因可能是从示例代码出发去寻找解决方案，而并没有去系统地阅读各种资料。在这个过程中，我找到了一些比较重要的文档：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="http://wiki.services.openoffice.org/wiki/API/Tutorials/PDF_export"&gt;API/Tutorials/PDF export&lt;/a&gt;：对于PDF导出功能各种参数的详细解释。&lt;/li&gt;

  &lt;li&gt;&lt;a href="http://api.openoffice.org/docs/DevelopersGuide/Text/Text.xhtml"&gt;Text Documents&lt;/a&gt;：关于文本文档相关操作的详细说明。&lt;/li&gt;

  &lt;li&gt;&lt;a href="http://wiki.services.openoffice.org/wiki/API/Samples/Java/Office/DocumentHandling"&gt;DocumentHanding&lt;/a&gt;：“文档操作”示例代码的解释，包括文档打印等等。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;当然，最详细文档莫过于完整的&lt;a href="http://api.openoffice.org/docs/DevelopersGuide/DevelopersGuide.xhtml"&gt;开发人员指南&lt;/a&gt;了，如果您想要详细了解这方面的内容，这应该也属于必读内容之一。&lt;/p&gt;

&lt;p&gt;有了OpenOffice.org，就相当于我们拥有了一套完整的文档操作类库，可以用来实现各种功能。除了转PDF以外，例如我们还可以将一篇数百万字的小说加载为文档，再每十页导出一份图片，方便用户在线预览顺便防点拷贝。此外，虽然我是在Windows下操作OOo，但是OOo和Java本身都是跨平台的，因此同样的代码也可以运行在Linux平台上。我目前正在尝试在Ubuntu Server上部署一份OOo和代码，如果有什么特别的情况，我也会另行记录。&lt;/p&gt;

&lt;p&gt;事实上有一点我之前一直没有提到：如果您使用Windows及.NET进行开发，OOo也提供了C++/CLI接口，可以使用C#、F#进行编程，且代码与本文描述的几乎如出一辙（只要把queryInterface方法调用改成直接转换），在.NET 4.0中也可正常使用。&lt;/p&gt;

&lt;p&gt;如果您有其他解决方案，也请一起交流一下。&lt;/p&gt;</description>
      <comments>http://blog.zhaojie.me/2010/05/convert-document-to-pdf-via-openoffice.html#comments</comments>
      <pubDate>Thu, 27 May 2010 04:37:24 GMT</pubDate>
      <lastBuildDate>Thu, 27 May 2010 04:37:24 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/language/">语言编程</category>
      <category domain="http://blog.zhaojie.me/practice/">实践优化</category>
      <category domain="http://blog.zhaojie.me/parallel/">并行处理</category>
      <category domain="http://blog.zhaojie.me/cutting-edge/">技术尝鲜</category>
      <category domain="http://blog.zhaojie.me/speech/">培训演讲</category>
      <title>盛大创新院赞助首届.NET技术交流会开始报名了！</title>
      <link>http://blog.zhaojie.me/2010/05/first-snda-dotnet-conference-sign-up.html</link>
      <guid>http://blog.zhaojie.me/2010/05/first-snda-dotnet-conference-sign-up.html</guid>
      <description>&lt;img class="floatRight" src="http://img.zhaojie.me/blog/snda-in.png" /&gt; 

&lt;p&gt;自从上次在博客中提到&lt;a href="http://blog.zhaojie.me/2010/01/1651772.html"&gt;盛大创新院&lt;/a&gt;将会&lt;a href="http://blog.zhaojie.me/2010/03/snda-dotnet-conference-advices.html"&gt;赞助.NET技术会议&lt;/a&gt;已经过去了一个半月，如今这件事情终于落实了。我为此准备了数千字的申请书，但老大看也不看便表示支持。他的说法是，只要办得热烈，有影响力，那么这样的活动绝对支持。为此，各场次演讲内容及会场等诸多事宜之后，现在“首届.NET技术交流会”正式进入报名阶段了。&lt;strike&gt;人数不设上限，多多益善，怕只怕会场会显得空旷&lt;/strike&gt;，&lt;span style="color:red;"&gt;目前报名人数已达200人，请抓紧时间报名&lt;/span&gt;。除了.NET社区的群众以外，也欢迎其他技术社区的朋友前来参与交流。事实上，我组织技术交流会的目的之一便是希望能够促进.NET社区与其他技术社区的交流及相互学习。&lt;/p&gt;

&lt;h1&gt;时间及议程安排&lt;/h1&gt;

&lt;p&gt;本次交流会定于&lt;strong&gt;2010年6月19日&lt;/strong&gt;（周六）举行，具体时间如下。会议目前安排了四场演讲，除了与.NET技术直接相关的F#及C#话题以外，我们还邀请了大众点评网的核心架构师来分享他们在多年发展过程中的技术变迁过程。此外，我也联系了即将举办的Rails大会的主办方，邀请他们来分享关于Rails框架的内容。&lt;a href="http://blog.zhaojie.me/2010/05/learn-from-disadvantages.html"&gt;正如我之前说的那样&lt;/a&gt;，在以后每次技术会议上，我都会邀请其他社区的高手来讲解相关技术。&lt;/p&gt;

&lt;table style="text-align: center" border="1" cellspacing="0" cellpadding="5"&gt;&lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;时间&lt;/th&gt;

      &lt;th&gt;议程&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;&lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;12:30 ~ 13:00&lt;/td&gt;

      &lt;td&gt;签到&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;13:00 ~ 14:00&lt;/td&gt;

      &lt;td&gt;F#语言对异步程序设计的支持&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;14:00 ~ 14:10&lt;/td&gt;

      &lt;td&gt;短休&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;14:10 ~ 15:10&lt;/td&gt;

      &lt;td&gt;Rails: Better Framework, Better Life&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;15:10 ~ 15:40&lt;/td&gt;

      &lt;td&gt;茶歇&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;15:40 ~ 16:40&lt;/td&gt;

      &lt;td&gt;C#语言开发模式及实用建议&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;16:40 ~ 16:50&lt;/td&gt;

      &lt;td&gt;短休&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;16:50 ~ 17: 50&lt;/td&gt;

      &lt;td&gt;大众点评网的技术变迁过程&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;&lt;/table&gt;

&lt;h1&gt;演讲内容&lt;/h1&gt;

&lt;p&gt;以下是关于四场演讲的详细描述。&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/snda-dotnet-conf/zhaojie.jpg" target="_blank"&gt;&lt;img class="floatRight" src="http://img.zhaojie.me/blog/snda-dotnet-conf/zhaojie.jpg" height="150" /&gt;&lt;/a&gt; 

&lt;h2&gt;F#语言对异步程序设计的支持&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;讲师：&lt;/strong&gt;赵劼，盛大创新院，研究员。关注前沿技术，并致力于开源社区与微软平台的组合优化。对函数式编程，并行程序开发，代码之美以及程序员能力与修养等相关问题也有着浓厚的兴趣，同时非常希望能够写程序到60岁。最近致力于F#，Scala语言及mono平台在社区中的推广。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;简介：&lt;/strong&gt;如今的Web应用、 Silverlight以及各种分布式系统让异步解决方案有了更进一步的需求。F#是微软.NET平台上的函数式编程语言，并添加了不少让并行及异步编程变得有趣且轻松的特性。本次演讲将讨论F#的核心概念，并探讨F#中的不可变性、函数式设计、异步工作流、代理等特性是如何应对真实应用中的异步挑战的。&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/snda-dotnet-conf/lvguoning.jpg" target="_blank"&gt;&lt;img class="floatRight" src="http://img.zhaojie.me/blog/snda-dotnet-conf/lvguoning.jpg" height="150" /&gt;&lt;/a&gt; 

&lt;h2&gt;Rails: Better Framework, Better Life &lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;讲师：&lt;/strong&gt;吕国宁，Intridea.com，高级工程师。超过三年的Ruby on Rails程序开发经验，先后供职于Red.com, ELCTech.com, 目前在Intridea从事ROR的咨询服务以及为客户提供解决方案。在工作之余热心国内ROR社区建设，长期致力于推动ROR社区在中国的发展，从2007年开始，作为组织者之一，在上海成立了Shanghaionrails组织，并筹办了国内第一，第二届RubyConfChina大会以及首届RailsConference。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;简介：&lt;/strong&gt;RoR是Ruby on Rails的缩写，是一个用于编写Web应用的框架。他基于Ruby语言，给开发人员提供了强大便利的框架支持。Ruby有很多优点，但是一直以来其流行范围仅局限于日本。2004年，当Rails框架横空出世，让人们认识到了一个更符合实际需要并且高效的web框架，在其出现不久就受到了业内的广泛关注。吕国宁将结合自己三年的Rails开发经验，给大家介绍一些Rails的优点，背后的设计文化，以及Rails的前景发展等内容。&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/snda-dotnet-conf/chenlifu.jpg" target="_blank"&gt;&lt;img class="floatRight" src="http://img.zhaojie.me/blog/snda-dotnet-conf/chenlifu.jpg" height="150" /&gt;&lt;/a&gt;

&lt;h2&gt;C#语言开发模式及实用建议&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;讲师：&lt;/strong&gt;陈黎夫，盛大创新院，研究员&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;简介：&lt;/strong&gt;C#语言是微软.NET平台上的核心开发语言，从1.0到4.0的版本推进极其迅速，版本更替也带来了大量改进。在快速的发展过程中，C#的表达能力被一再强化，其功能愈发强大，语言本身也日趋复杂，这往往会让一些开发者在使用中产生迷茫，无法做到最优。希望能借此机会分享一下最新版本C#语言的开发模式以及实用建议。&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/snda-dotnet-conf/wanghong.jpg" target="_blank"&gt;&lt;img class="floatRight" src="http://img.zhaojie.me/blog/snda-dotnet-conf/wanghong.jpg" height="150" /&gt;&lt;/a&gt; 

&lt;h2&gt;大众点评网的技术变迁之路&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;讲师：&lt;/strong&gt;王宏，大众点评网，架构师&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;简介：&lt;/strong&gt;大众点评网从2003年创建以来，已经经历了7个年头，在技术方面从最初构建时期的简单的、低成本的方案，到发展阶段不断“痛苦”的转型演变，到目前比较复杂的技术架构，大众点评网的技术团队一直在关注业界新技术，力求提高可用性、降低成本、优化用户体验，并针对“点评”这一第三方参与的特点，摸索出一些特有的解决方案，借此机会希望能够分享给大家。&lt;/p&gt;

&lt;h1&gt;地点&lt;/h1&gt;

&lt;p&gt;本次交流会举办地为&lt;strong&gt;上海市浦东新区碧波路888号畅星大厦&lt;/strong&gt;（地铁二号线张江高科站下，步行10分钟可达）3楼会议厅举行，地图如下：&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/snda-dotnet-conf/changxing-map.png"&gt;&lt;img src="http://img.zhaojie.me/blog/snda-dotnet-conf/changxing-map.png" width="400" /&gt;&lt;/a&gt; 

&lt;p&gt;鸟瞰图：&lt;/p&gt;

&lt;a href="http://img.zhaojie.me/blog/snda-dotnet-conf/changxing-hybrid.jpg"&gt;&lt;img src="http://img.zhaojie.me/blog/snda-dotnet-conf/changxing-hybrid.jpg" width="400" /&gt;&lt;/a&gt;

&lt;p&gt;畅星大厦外观：&lt;/p&gt;

&lt;a href="http://img.zhaojie.me/blog/snda-dotnet-conf/changxing-building.jpg"&gt;&lt;img src="http://img.zhaojie.me/blog/snda-dotnet-conf/changxing-building.jpg" width="400" /&gt;&lt;/a&gt;

&lt;p&gt;会场实景照片：&lt;/p&gt;
&lt;a href="http://img.zhaojie.me/blog/snda-dotnet-conf/changxing-room.jpg"&gt;&lt;img src="http://img.zhaojie.me/blog/snda-dotnet-conf/changxing-room.jpg" width="400" /&gt;&lt;/a&gt; 

&lt;p&gt;会场容量可以容纳超过200人，希望到时候不会显得太过空旷。:)&lt;/p&gt;

&lt;h1&gt;报名信息&lt;/h1&gt;

&lt;img src="http://img.zhaojie.me/blog/snda-dotnet-conf/sign-up-now.jpg" /&gt;

&lt;p&gt;本次交流会&lt;strike&gt;&lt;a href="http://www.diaochapai.com/survey347021"&gt;现已开始报名，请填写报名表&lt;/a&gt;，报名截止日期为2010年6月13日&lt;/strike&gt;已经截止，请等待后续消息。感谢大家支持！&lt;/p&gt;

&lt;h1&gt;相关文章&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;盛大创新院赞助首届.NET技术交流会开始报名了！ &lt;/li&gt;

  &lt;li&gt;&lt;a href="http://blog.zhaojie.me/2010/06/first-snda-dotnet-conference-is-coming.html"&gt;盛大创新院赞助首届.NET技术交流会即将召开&lt;/a&gt; &lt;/li&gt;

  &lt;li&gt;&lt;a href="http://blog.zhaojie.me/2010/06/first-snda-dotnet-conference-all-slides.html"&gt;盛大创新院赞助首届.NET技术交流会 - 各场演讲幻灯片&lt;/a&gt; &lt;/li&gt;

  &lt;li&gt;&lt;a href="http://blog.zhaojie.me/2010/06/first-snda-dotnet-conference-videos.html"&gt;盛大创新院赞助首届.NET技术交流会 - 演讲录像及下载&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;</description>
      <comments>http://blog.zhaojie.me/2010/05/first-snda-dotnet-conference-sign-up.html#comments</comments>
      <pubDate>Thu, 13 May 2010 06:30:10 GMT</pubDate>
      <lastBuildDate>Thu, 13 May 2010 06:30:10 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/practice/">实践优化</category>
      <category domain="http://blog.zhaojie.me/cutting-edge/">技术尝鲜</category>
      <title>MongoDB与Tokyo Tyrant性能比较（2）：并发写入操作</title>
      <link>http://blog.zhaojie.me/2010/02/mongodb-tokyo-tyrant-benchmark-2-concurrent-insert.html</link>
      <guid>http://blog.zhaojie.me/2010/02/mongodb-tokyo-tyrant-benchmark-2-concurrent-insert.html</guid>
      <description>&lt;p&gt;在&lt;a href="http://blog.zhaojie.me/2010/02/mongodb-tokyo-tyrant-benchmark-1-basic-cru-operations.html"&gt;上一次的测试&lt;/a&gt;中我们比较了MongoDB与Tokyo Tyrant的Table Database两种存储方式的性能。不过由于条件限制，我只能在自己的MBP上测试，而这至少会带来两个问题。首先，真实环境下客户端和服务器是通过内网连接的，它的性能比本地回环要慢不少，一些和网络传输性能有关的问题可能会体现不出。其次，由于无法进行并发测试（并发测试的客户端资源占用较高，放在同一台机器上准确性较差），这又和生产环境有很大区别了。因此，我前两天向同事借了台性能测试用的机器，希望可以得到更可靠的结果。&lt;/p&gt;  &lt;h1&gt;测试环境与数据&lt;/h1&gt;  &lt;p&gt;这次我使用了新的环境进行性能测试：&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;OS：CentOS release 5.3 (Final) &lt;/li&gt;    &lt;li&gt;RAM：4GB &lt;/li&gt;    &lt;li&gt;CPU：Intel(R) Xeon(R) CPU E5405 &amp;#64; 2.00GHz (64 bit, 4 cores * 2)&lt;/li&gt;    &lt;li&gt;其他：SCSI硬盘，ext3文件系统 &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;客户端与服务器端配置相同，两台机器使用百兆网相连，测试时服务器保持空闲。&lt;/p&gt;  &lt;p&gt;测试数据的结构与&lt;a href="http://blog.zhaojie.me/2010/02/mongodb-tokyo-tyrant-benchmark-1-basic-cru-operations.html"&gt;之前&lt;/a&gt;相同（包括索引），数据分布同样保持一致，每个线程插入的数量较少，但每次测试的总数均不低于上次（110万条）。&lt;/p&gt;  &lt;p&gt;为了测试并发插入的性能，我稍微改写了测试脚本。首先，我为它增加init参数，它的作用是初始化存储结构（清除数据，建立索引），拿MongoDB的测试脚本为例：&lt;/p&gt;  &lt;pre class="code"&gt;# ruby mdb-insert.rb init
index for CreateTime created.
index for CategoryID created.
index for UserID created.
index for Tags created.
initialize completed.&lt;/pre&gt;

&lt;p&gt;此外，脚本还支持“分类范围”的指定，例如：&lt;/p&gt;

&lt;pre class="code"&gt;# ruby mdb-insert.rb 101 200&lt;/pre&gt;

&lt;p&gt;这表示我们将插入CategoryID为101至200的新闻，由于每个分类中均匀分布10至100条记录，因此只要范围的上下限保持10的倍数，这样平均每个分类有55条新闻，于是新闻ID也可以此计算出来。例如分类101至200的新闻，其ID便为5501至11000。您可以通过阅读代码了解这些细节。&lt;/p&gt;

&lt;p&gt;为了并行测试，每次我就将同时执行多个脚本进行插入，每个脚本提供不同的参数。我使用类似这样的shell脚本来启动并行任务：&lt;/p&gt;

&lt;pre class="code"&gt;#!/bin/bash

# mdb-insert.sh

echo &amp;quot;=== initialize ===&amp;quot;
ruby mdb-insert.rb init

for((i=1;i&amp;lt;=5;i++))
    do

    let begin=$((4000 * ($i - 1) + 1))
    let end=$((4000 * $i))

    echo === start task $i ===
    ruby mdb-insert.rb $begin $end &amp;gt; logs/mdb-insert-$begin-$end.log &amp;amp;
done&lt;/pre&gt;

&lt;p&gt;这段脚本将启动5个任务，每个任务将插入4000个分类，即22万条记录。5个任务总共插入110万条记录，与前次持平。接下来的测试中，我在增加任务数量的同时也会适当降低每个任务插入的记录数目。最多我将启用100个任务，每个任务插入1000个分类，即所有任务共计插入550万条记录，是之前的5倍。&lt;/p&gt;

&lt;p&gt;在所有的测试中，无论多少个任务都是同时启动，且几乎同时结束（与总耗时相比很小）。因此，在接下来的数据中我不会列出每个任务的开始及结束时间，如果您关心这部分数据，可以在文章结尾处可以获得本次测试生成的所有记录文件。&lt;/p&gt;

&lt;h1&gt;Tokyo Tyrant性能测试&lt;/h1&gt;

&lt;p&gt;第1次测试启动5个任务，每个任务4000个分类，共计插入110万条记录。结果如下（第1行粗体表示“万条记录”，每个数字的单位为“秒”，下同）：&lt;/p&gt;
&lt;iframe height="240" src="https://spreadsheets.google.com/pub?key=tfhm7CF-u60qDi4WEdzgxAg&amp;amp;single=true&amp;amp;gid=0&amp;amp;output=html&amp;amp;widget=true" frameborder="0" width="100%"&gt;&lt;/iframe&gt;

&lt;p&gt;与之前的现象类似，当数据库中的数据越多时，插入速度也会随之减慢：在每个任务插入前1万条记录时，耗时大约为5、6秒。但是到了中后期，每插入1万条数据则需要等待15至20，甚至30秒的时间。值得注意的是，虽然使用了较好的服务器，但是并行插入110万条记录的时间却比上次要来的多（这次耗时340秒，而之前是）。原因可能是客户端与服务器端的分离导致网络速度的下降。另一种可能我猜测是，根据&lt;a href="http://1978th.net/tokyocabinet/"&gt;Tokyo Cabinet的文档&lt;/a&gt;中提到文件读写锁的使用，因此每次只能插入一条记录，且插入（或更新）时无法读取数据，因而在并发环境下Tokyo Tyrant（它其实是Tokyo Cabinet上层的TCP服务器）的表现并不会有所提高。不过据读过Tokyo Cabinet代码的同事说，Tokyo Cabint在使用Table Database的时候锁粒度不会那么大，因此关于这点还需要寻找进一步的资料。&lt;/p&gt;

&lt;p&gt;第2次测试启动10个任务，每个任务还是4000个分类，因此共计插入220万条记录。结果如下：&lt;/p&gt;
&lt;iframe height="320" src="https://spreadsheets.google.com/pub?key=tfhm7CF-u60qDi4WEdzgxAg&amp;amp;single=true&amp;amp;gid=2&amp;amp;output=html&amp;amp;widget=true" frameborder="0" width="100%"&gt;&lt;/iframe&gt;

&lt;p&gt;第2次测试的总数据量为第1次的2倍，而耗时却是第1次的3.5倍，这应该还是由于数据量增大而导致的插入性能降低。但是，我们目前还不能排除这和并发连接数有关的可能——虽然我们有理由相信这个性能问题只和数据量相关（稍后再说）。为了查明并发程度和性能是否有关系，我们再进行第3次测试。&lt;/p&gt;

&lt;p&gt;第3次测试启动20个任务，每个任务2000个分类，因此共计仍旧是220万条记录。结果如下：&lt;/p&gt;
&lt;iframe height="300" src="https://spreadsheets.google.com/pub?key=tfhm7CF-u60qDi4WEdzgxAg&amp;amp;single=true&amp;amp;gid=3&amp;amp;output=html&amp;amp;widget=true" frameborder="0" width="100%"&gt;&lt;/iframe&gt;

&lt;p&gt;这个结果实在是非常能够说明问题：第3次的耗时与上一次几乎完全相同，这意味着加大并发量并不会影响TT的性能。这是因为TT在服务器端维护了一个线程池（现在的测试，也是默认情况下为8个线程），因此请求再多，同时进行的任务也是有限的，而累积的任务会排在队列中。这也是使用队列和固定数量工作线程的好处：即使压力再大，服务器端的吞吐量也能够一直保持较高水准，而客户端请求的响应时间随着请求数量增大而线性增长。如果没有队列，随着压力增大，服务器端吞吐量会剧烈下降（一般至少也是线性的），而客户端请求的响应时间增长更快，直至超时。&lt;/p&gt;

&lt;p&gt;为此，我们也没有必要继续测试更多的并发数量了，因为即便是再多并发，TT的吞吐量（即插入记录的数目）也只是和数据库中记录数量相关。根据测试，我们可以总结出：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;插入110万条记录的平均吞吐量为：大约3225条/秒 &lt;/li&gt;

  &lt;li&gt;插入220万条记录的平均吞吐量为：大约1833条/秒 &lt;/li&gt;

  &lt;li&gt;当数据库包含100万条数据时吞吐量为：1700~1800条/秒 &lt;/li&gt;

  &lt;li&gt;当数据库包含200万条数据时吞吐量为：150~160条/秒 &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;似乎随着数据量的增加，TT的吞吐量下降得也非常明显。这其中可能有索引的因素在里面，因此如果您想要得到适合自己的结果，最好可以亲自进行试验。&lt;/p&gt;

&lt;h1&gt;MongoDB性能测试&lt;/h1&gt;

&lt;p&gt;与TT相同，第1次测试启动5个任务，每个任务4000个分类，共计插入110万条记录。结果如下：&lt;/p&gt;
&lt;iframe height="240" src="https://spreadsheets.google.com/pub?key=tfhm7CF-u60qDi4WEdzgxAg&amp;amp;single=true&amp;amp;gid=4&amp;amp;output=html&amp;amp;widget=true" frameborder="0" width="100%"&gt;&lt;/iframe&gt;

&lt;p&gt;在5个并发任务的情况下，MongoDB的表现较TT要出彩不少。首先，随着数据库中已有记录的增加，插入速度并没有降低的迹象，可以说十分平稳。此外，在同样的客户端和服务器环境下，MongoDB插入110万条数据的耗时比TT的一半还要略少一些。而且，虽然网速带来的一定负面影响，但可能是由于服务器配置的提高，再加上并发写入的性能优势，此次测试比上次单机环境下的表现也要好上许多。&lt;/p&gt;

&lt;p&gt;那么在数据量和并发继续增大的情况下MongoDB表现如何呢？于是第2次测试启动10个任务，每个任务还是4000个分类，共计插入220万条记录。结果如下：&lt;/p&gt;
&lt;iframe height="320" src="https://spreadsheets.google.com/pub?key=tfhm7CF-u60qDi4WEdzgxAg&amp;amp;single=true&amp;amp;gid=6&amp;amp;output=html&amp;amp;widget=true" frameborder="0" width="100%"&gt;&lt;/iframe&gt;

&lt;p&gt;第2次的数据量为第1次的2倍，而耗时则大约为2.08倍，两者基本保持一致，这说明了MongoDB在数据量和并发量增加的情况下，吞吐量几乎没有改变。&lt;/p&gt;

&lt;p&gt;第3次测试依旧与TT相同，启用20个任务，每个任务2000个分类，共计插入220万条记录。结果如下：&lt;/p&gt;
&lt;iframe height="300" src="https://spreadsheets.google.com/pub?key=tfhm7CF-u60qDi4WEdzgxAg&amp;amp;single=true&amp;amp;gid=7&amp;amp;output=html&amp;amp;widget=true" frameborder="0" width="100%"&gt;&lt;/iframe&gt;

&lt;p&gt;在总数据量不变的情况下，我们又将并发量提高了一倍，但是MongoDB依旧表现出的稳定的吞吐量，总耗时与第2次测试几乎完全相同。&lt;/p&gt;

&lt;p&gt;这样看来，似乎在MongoDB在内部也有个类似于TT的队列机制以保证一定的吞吐量。为了验证这个看法，我再次加大了数据量和并发量。在第4次测试中我启用了50个任务，每个任务还是2000个分类，这样插入的记录数据则达到了550万。结果如下：&lt;/p&gt;
&lt;iframe height="300" src="https://spreadsheets.google.com/pub?key=tfhm7CF-u60qDi4WEdzgxAg&amp;amp;single=true&amp;amp;gid=8&amp;amp;output=html&amp;amp;widget=true" frameborder="0" width="100%"&gt;&lt;/iframe&gt;

&lt;p&gt;在50个并发任务下，MongoDB终于略显疲态。第4次测试的数据量为第3次的2.5倍，但耗时却接近3.5倍。为了验证这是由于数据量增加，还是并发量提高引起的问题，我又进行了第最后一次测试。&lt;/p&gt;

&lt;p&gt;第5个测试中启用了100个任务，但每个任务只写入1000个分类，则总条目数还是和第4次相同，为550万。结果如下：&lt;/p&gt;
&lt;iframe height="300" src="https://spreadsheets.google.com/pub?key=tfhm7CF-u60qDi4WEdzgxAg&amp;amp;single=true&amp;amp;gid=9&amp;amp;output=html&amp;amp;widget=true" frameborder="0" width="100%"&gt;&lt;/iframe&gt;

&lt;p&gt;请注意，由于每个任务插入1000个分类，即5.5万条记录，因此上表中最后一栏为5.5而不是6。随着并发量的增大，MongoDB的耗时继续增加了。由于这个表现和之前的预测不同，我又把第4次和第5次测试各执行了一遍，结果并没有太大区别，基本可以排除“环境异常”这样的可能。&lt;/p&gt;

&lt;p&gt;经过5次测试的结果，我们可以得出MongoDB的性能指标：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;5个并发，插入110万条记录的平均吞吐量：大约6600条/秒&lt;/li&gt;

  &lt;li&gt;10个并发，插入220万条记录的平均吞吐量：大约6300条/秒&lt;/li&gt;

  &lt;li&gt;20个并发，插入220万条记录的平均吞吐量：大约6300条/秒&lt;/li&gt;

  &lt;li&gt;50个并发，插入550万条记录的平均吞吐量：大约4500条/秒&lt;/li&gt;

  &lt;li&gt;100个并发，插入550万条记录的平均吞吐量：大约4100条/秒&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;总体来说，虽然在数据量和并发量增大的情况下MongoDB的吞吐量有所下降，但是MongoDB的表现比TT还是要抢眼不少，而且在绝对数值上还是相当出彩的。&lt;/p&gt;

&lt;h1&gt;其他信息&lt;/h1&gt;

&lt;p&gt;其他还有一些信息可能值得参考。&lt;/p&gt;

&lt;p&gt;在进行测试时，我发现TT进程的CPU占有率比较低，除了少量时候出现80~150%以外（top命令的结果，8核服务器），绝大部分时间CPU占有率只有20~40%。MongoDB的CPU占有率比TT要高出不少，基本上保持在80~110%之间（数据量和并发量在这里影响不大）。但是总体来说CPU的占有率都很低，毕竟现在的测试属于IO密集型操作。&lt;/p&gt;

&lt;p&gt;不过在内存占有率方面，两者的区别很大。在测试过程中（服务器内存4G），TT进程的内存占有率一直保持在20%一下，而MongoDB会缓步增加，最后保持在80%上下。&lt;/p&gt;

&lt;p&gt;此外，在插入了550万条数据之后，MongoDB的数据文件增长到了6G。这个数字比上次测试的2G/110万稍有缓解，但还是比TT要大上许多。&lt;/p&gt;

&lt;p&gt;最后再来谈谈为什么仅仅测试了“并发插入”而没有“更新”和“删除”：其实这也是通过使用场景而设计出来的测试用例。因为对于此类存储来说，大量并发插入的场景比较多，例如日志记录，用户行为记录，或是SNS应用中常见的News Feed等等。这些场景的特点就是需要数据的不断增长，而大量密集的更新则很少会出现──删除就更不用说了。至于并行的更新，我接下来也会进行测试的，只是可能会模拟一些实际的场景，例如在更新的同时进行不断地读取和插入吧。&lt;/p&gt;

&lt;p&gt;所有测试代码，及完整测试结果：&lt;a href="http://github.com/JeffreyZhao/mdb-tt-benchmark"&gt;http://github.com/JeffreyZhao/mdb-tt-benchmark&lt;/a&gt;&lt;/p&gt;</description>
      <comments>http://blog.zhaojie.me/2010/02/mongodb-tokyo-tyrant-benchmark-2-concurrent-insert.html#comments</comments>
      <pubDate>Fri, 26 Feb 2010 11:38:00 GMT</pubDate>
      <lastBuildDate>Fri, 26 Feb 2010 11:38:00 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/practice/">实践优化</category>
      <category domain="http://blog.zhaojie.me/cutting-edge/">技术尝鲜</category>
      <title>MongoDB与Tokyo Tyrant性能比较（1）：基础CRU操作</title>
      <link>http://blog.zhaojie.me/2010/02/mongodb-tokyo-tyrant-benchmark-1-basic-cru-operations.html</link>
      <guid>http://blog.zhaojie.me/2010/02/mongodb-tokyo-tyrant-benchmark-1-basic-cru-operations.html</guid>
      <description>&lt;p&gt;以前的项目大都把数据存放在关系型数据库中，关系型数据库的优势在于使用普及，资料丰富，且有大量辅助类库来简化开发。当然它们的问题比较明显的，一是在数据量上升的情况下伸缩性比较差，且进行结构调整的代价比较高。因此现在有个所谓NoSQL的“运动”也逐渐普遍起来了，它便是借助一些非关系型存储方式来开发项目（个人认为其实将它解释为Not Only SQL更为合适）。因此在新项目里，我也想尝试一下使用之前一直只是“听说”的存储方式。&lt;/p&gt;  &lt;p&gt;在和同事的交流过程中，我了解到他们的项目正在尝试使用&lt;a href="http://1978th.net/tokyotyrant/"&gt;Tokyo Tyrant&lt;/a&gt;（后称TT）进行存储，并且据说效果不错，因此我一开始也打算尝试使用TT进行主要存储，为此也花了一定时间为其编写.NET平台下的驱动程序。不过在驱动程序的开发过程中，我逐渐意识到TT的功能有着严重的限制，似乎并不适合作为接下来项目的主要存储方式。因此，我又将眼光转向了之前关注过的&lt;a href="http://mongodb.org"&gt;MongoDB&lt;/a&gt;上。MongoDB也是NoSQL的代表之一，是一个面向文档的，架构灵活（Schema-less）的存储方式，在仔细阅读相关资料之后，我发现它的功能与TT相比可谓天上地下，非常适合许搭建各类项目（关于这点以后有机会再谈）。&lt;/p&gt;  &lt;p&gt;不过，既然选择NoSQL的原因是性能，那么他们的性能表现究竟如何呢？TT的性能表现在业界非常出名，而MongoDB的使用便相对较少了（当然，官网&lt;a href="http://www.mongodb.org/display/DOCS/Production+Deployments"&gt;列举了不少案例&lt;/a&gt;，最近&lt;a href="http://www.thebitsource.com/software-engineering/python/sourceforgenet-chooses-python-turbogears-and-mongodb-to-redesign-their-web-site/"&gt;著名的开源网站SourceForge也打算使用MongoDB重新设计他们的网站&lt;/a&gt;）。为此，我决定亲手比较一下两者的性能表现。&lt;/p&gt;  &lt;h1&gt;测试环境及数据&lt;/h1&gt;  &lt;p&gt;由于缺乏合适的环境，因此我不得不在我的MBP上进行这次性能比较，参数如下：&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;OS：Mac OS X v10.6.2（Snow Leopard） &lt;/li&gt;    &lt;li&gt;RAM：4GB / 1067MHz / DDR 3 &lt;/li&gt;    &lt;li&gt;CPU：2.53GHz Intel Core 2 Duo &lt;/li&gt;    &lt;li&gt;64-bit Kernel and Extensions：Yes&lt;/li&gt;    &lt;li&gt;TT在64 bit环境下编译，MongoDB使用64 bit版本。 &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;在测试执行时，我尽量关闭多余的应用程序，避免其它因素造成影响。同样，由于条件限制，我只得把客户端和服务器跑在同一台机器上。测试代码使用Ruby编写，这是由于两者都有官方提供的驱动程序。此外，由于我对于两者的优化都不太熟悉，因此它们都使用了默认的配置。&lt;/p&gt;  &lt;p&gt;关于测试数据，我将存入110万条“新闻”数据，包含以下字段：&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;ID：标识，32位整数，带索引 &lt;/li&gt;    &lt;li&gt;Title：标题，字符串 &lt;/li&gt;    &lt;li&gt;CategoryID：分类ID，32位整数，带索引 &lt;/li&gt;    &lt;li&gt;CreateTime：日期，保存为32位整数，带索引 &lt;/li&gt;    &lt;li&gt;UserID：用户ID，32位整数，带索引 &lt;/li&gt;    &lt;li&gt;Tags：标签集合，字符串数组，带索引 &lt;/li&gt;    &lt;li&gt;Source：来源，字符串 &lt;/li&gt;    &lt;li&gt;SourceUrl：来源URL，字符串 &lt;/li&gt;    &lt;li&gt;Status：状态，32位整数 &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;为了相对接近真实的环境的数据分布特征（便于以后进行查询操作比较），我设计了这样的测试数据（具体可阅读代码）：&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;2万个分类，分别拥有10个至100条新闻，总共110万条记录。 &lt;/li&gt;    &lt;li&gt;1万个用户，根据分类id取模得到其归属。 &lt;/li&gt;    &lt;li&gt;创建时间从2010年1月1日起递增，每条记录增加1秒。 &lt;/li&gt;    &lt;li&gt;每条记录拥有2到6个Tag，除了其中一个之外，都从一个1.7万个Tag库中获取。 &lt;/li&gt;    &lt;li&gt;每条记录的字符串字段都不长（20-30字符） &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;由于TT只支持字符串的值（但可以建立数字索引，会将字符串当作数字来识别），因此事实上所有的值都会转化为字符串进行保存。此外，由于存在“根据Tag查找新闻”的业务，因此对于Tags字段也建立了索引，其中MongoDB直接支持对字符串数组的索引（索引其中每个元素），而在存入TT时则转化为空格分隔的字符串，并为其建立倒排索引（Token Inverted Index）以便进行全文查找。&lt;/p&gt;  &lt;p&gt;在存储方式上，所有数据将放入MongoDB的同一个集合内，而TT则选用Table Database存储结构。在使用TT时，另一种做法是完全使用键值对来保存一条记录的各个字段，不过这样做会大大限制TT的功能，或是会为系统编写带来额外的复杂度，便不考虑Hash / B+ Tree / Fixed-length等存储方式了。&lt;/p&gt;  &lt;h1&gt;插入操作性能比较&lt;/h1&gt;  &lt;p&gt;具体代码在tt-insert.rb及mdb-insert.rb文件中。两段代码均使用一个连接，使用循环每次插入一条：由于如果每次都建立连接，会在TCP/IP连接的打开关闭上消耗大部分时间，由于实际项目中基本都会使用连接池等机制来复用连接，因此这方面便不多做考虑；再者，由于实际插入时几乎不可能批量操作，因此这里并不使用两者提供的批量插入功能。脚本每插入10万条记录便打印出所耗时间，结果如下：&lt;/p&gt; &lt;iframe height="300" src="https://spreadsheets.google.com/pub?key=t-dWQBER43lmfgsYKdpbPtw&amp;amp;single=true&amp;amp;gid=1&amp;amp;output=html&amp;amp;widget=true" frameborder="0" width="100%"&gt;&lt;/iframe&gt;  &lt;p&gt;从结果上看，MongoDB大约有10%的领先，不过总体来说两者的差距不大。值得一提的是，TT在数据量越大的情况下，每插入10万条记录的耗时越长（也从同事的使用过程中确认了这一点）。因此，一开始两者插入速度几乎没有差距，但是慢慢地TT便落后于MongoDB了。目前推测这可能是TT的Table Database存储结构特有的问题，不知道随着数据量的增长TT表现如何，因为对于一个大型系统来说，100多万条记录实际上只是一个很小的数目。&lt;/p&gt;  &lt;p&gt;有同事推测，TT插入性能低是因为建立了Tags字段的倒排索引，于是我也测试了不在Tags字段上建索引的情况。令人惊讶的是，同样去除Tags字段的索引之后，MongoDB的性能提升超过20%，而TT的性能提升却微乎其微。&lt;/p&gt;  &lt;p&gt;值得一提的是，放入相同的记录之后，TT的文件为400多M，但MongoDB则为整整2G。因此推测这是MongoDB进行空间预分配的结果，邮件列表上的&lt;a href="http://groups.google.com/group/mongodb-user/browse_thread/thread/191df9d1dbfdfc79"&gt;这个讨论&lt;/a&gt;也证实了这一点。此外，上面每次测试都是从零开始的，经测试如果在插入前为MongoDB预分配文件空间，则性能还会有些许提高。&lt;/p&gt;  &lt;h1&gt;通过主键获取记录性能比较&lt;/h1&gt;  &lt;p&gt;具体代码在tt-get-by-key.rb及mdb-get-by-key.rb文件中。两段代码同样均使用一个连接，使用循环进行100万次Get操作，每次都随机获取一个110万以内的数字，并作为ID进行Get操作。同样，每10万次Get操作后打印出所耗时间，结果如下：&lt;/p&gt; &lt;iframe height="300" src="https://spreadsheets.google.com/pub?key=t-dWQBER43lmfgsYKdpbPtw&amp;amp;single=true&amp;amp;gid=5&amp;amp;output=html&amp;amp;widget=true" frameborder="0" width="100%"&gt;&lt;/iframe&gt;  &lt;p&gt;在Get操作方面，MongoDB有大约20%的领先。不过从实际情况分析，这方面的差距也不是太大，因为在项目中根据主键获取记录的操作8成以上都是落在缓存上的，因此在这方面对存储的要求并不高。&lt;/p&gt;  &lt;h1&gt;通过主键更新记录性能比较&lt;/h1&gt;  &lt;p&gt;具体代码在tt-update-by-key.rb及mdb-update-by-key.rb文件中。两段代码各自使用同一个连接，使用循环进行大量的更新操作。每次随机获取一个110万以内的数字，并作为ID更新其CreateTime、Title、Source、SourceUrl、Status五个字段。结果如下：&lt;/p&gt; &lt;iframe height="280" src="https://spreadsheets.google.com/pub?key=t-dWQBER43lmfgsYKdpbPtw&amp;amp;single=true&amp;amp;gid=6&amp;amp;output=html&amp;amp;widget=true" frameborder="0" width="100%"&gt;&lt;/iframe&gt;  &lt;p&gt;首先是MongoDB的三次测试结果，每次更新100万条数据。从数据上看，三次查询的性能越来越高，这个现象在重启服务器之后可以重现（三次测试之间并没有重启服务器）。&lt;/p&gt; &lt;iframe height="280" src="https://spreadsheets.google.com/pub?key=t-dWQBER43lmfgsYKdpbPtw&amp;amp;single=true&amp;amp;gid=7&amp;amp;output=html&amp;amp;widget=true" frameborder="0" width="100%"&gt;&lt;/iframe&gt;  &lt;p&gt;请注意，TT的三次测试均只更新了10万条记录（因为100万条记录耗时太长）。和MongoDB类似，一开始查询性能较差，但是会慢慢提高，这个现象在重启服务器后也能重现，于是猜测是缓存的结果。即便如此，TT的更新时的最高速度只有大约没秒1500次，而MongoDB却超过了每秒5000次。这是因为TT在功能上有硬伤：它无法像SQL的UPDATE语句那样更新某条记录的部分字段，因此必须全部取出，修改后再整体写入。而MongoDB支持高效的直接修改——这也成为MongoDB&lt;a href="http://blog.mongodb.org/post/248614779/fast-updates-with-mongodb-update-in-place"&gt;放在首页上的“招牌功能”&lt;/a&gt;。&lt;/p&gt;  &lt;p&gt;因此，TT对于“更新某个分类下所有新闻的状态”这样的操作会很不适应，而它的这个限制导致我们很难实现如“乐观并发控制”这样的手段。此外，在实际应用中客户端与服务器不会使用本地连接，因此在生产环境中TT和MongoDB在这方面的差距可能会更明显一些。&lt;/p&gt;  &lt;h1&gt;总结&lt;/h1&gt;  &lt;p&gt;到目前为止，我们测试了TT和MongoDB在CRU三种基本操作下的性能，似乎MongoDB全面胜过Tokyo Tyrant。不过需要强调的是，这个测试还很不全面：它没有使用合适的环境，也没有对两者进行适当的优化。此外，两者在并发情况下，或是同时读写下的表现如何也是值得进一步考察的，我也会设计更多的测试用例。因此，这里的数据仅供参考，如果有合适的环境我也会重新进行测试。&lt;/p&gt;  &lt;p&gt;本文所有代码：&lt;a title="http://github.com/JeffreyZhao/mdb-tt-benchmark" href="http://github.com/JeffreyZhao/mdb-tt-benchmark"&gt;http://github.com/JeffreyZhao/mdb-tt-benchmark&lt;/a&gt;&lt;/p&gt;</description>
      <comments>http://blog.zhaojie.me/2010/02/mongodb-tokyo-tyrant-benchmark-1-basic-cru-operations.html#comments</comments>
      <pubDate>Wed, 24 Feb 2010 15:45:00 GMT</pubDate>
      <lastBuildDate>Wed, 24 Feb 2010 15:45:00 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/cutting-edge/">技术尝鲜</category>
      <category domain="http://blog.zhaojie.me/life/">生活心情</category>
      <title>从今日起正式加入水果党</title>
      <link>http://blog.zhaojie.me/2010/02/use-mac.html</link>
      <guid>http://blog.zhaojie.me/2010/02/use-mac.html</guid>
      <description>&lt;p&gt;想来我现在的笔记本也用了将近3年，虽然至今没有出现过任何问题，但更新换代似乎也不是件让人无法接受的事情——再加上老爸正好也需要一台笔记本，于是我想，不如就乘此机会升一下级吧。不过其实我本没有打算那么着急，只是两天前忽然出现了一个千载难逢的机会，一台十分便宜的MBP放在我面前，于是我当机立断，即刻入手。因此我在此庄严宣布：从今日起，我正式加入水果党。&lt;/p&gt;  &lt;p&gt;以下是我今天新到的Mac Book Pro（&lt;a href="http://search.taobao.com/search?commend=all&amp;amp;isnew=2&amp;amp;q=MB471&amp;amp;source=search1"&gt;MB471&lt;/a&gt;）。&lt;/p&gt; &lt;a href="http://img.zhaojie.me/blog/mac/mbp.jpg"&gt;&lt;img src="http://img.zhaojie.me/blog/mac/mbp_s.jpg" /&gt;&lt;/a&gt;   &lt;p&gt;有不少朋友问我：你怎么放弃.NET了？更有一些*nix界（不好说是自由/开源界，毕竟Mac也是个封闭的平台）的朋友认为，作为一个微软MVP，又是在国内.NET社区小有影响的人物忽然转投*nix平台，这又是微软平台衰败的一个证据。当然，我没想这么多。我只是觉得：好玩。&lt;/p&gt;  &lt;p&gt;唉，毕竟Windows平台上玩了这么多年，虽然不可能什么都玩遍，但多少还是有些厌倦了。再者，的确有很多东西在Windows平台上玩起来不是那么方便。例如.NET平台的跨平台实现mono，如果没有一个非Windows平台作为运行环境，想要真正玩好也是十分不容易的——新的工作环境让我有机会验证一些想法，我又怎能不牢牢把握住这个机会呢？一直有人坚持认为mono只是个玩具，那么也就让我亲自尝试一下吧。至于其他平台，如Java、Ruby、Python亦或是Haskell等等，自然就更不在话下了——再者，如果我要尝试Mac平台开发的话，也只能用Mac了……&lt;/p&gt;  &lt;p&gt;谁说Windows平台的程序员视野狭隘呢？我就爱玩各种东西。&lt;/p&gt;  &lt;p&gt;不过，仅仅是从这个角度来讲，我买一台PC装一个Linux操作系统，或是用虚拟机也可以达到相同的目的。可惜总能听到一些搞技术的朋友对我说Mac有多么多么好，Windows有多么多么差。对于这样的言论，我当然不服气了。但是我既然没有用过Mac，又能如何给出令人信服的反对意见呢？因此我也想乘此机会体会一下Mac系统的优秀之处，无论它是否真的优于Windows，我终究会有一个理性认识。爱吵架的兄弟们，先等我个一年半载啊。&lt;/p&gt;  &lt;p&gt;当然，我肯定还是会装一个双系统跑个Win 7什么的，因为我实在离不开可恶的网银和可爱的游戏。&lt;/p&gt;</description>
      <comments>http://blog.zhaojie.me/2010/02/use-mac.html#comments</comments>
      <pubDate>Mon, 01 Feb 2010 16:08:00 GMT</pubDate>
      <lastBuildDate>Mon, 01 Feb 2010 16:08:00 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/dotnet/">.Net框架</category>
      <category domain="http://blog.zhaojie.me/language/">语言编程</category>
      <category domain="http://blog.zhaojie.me/cutting-edge/">技术尝鲜</category>
      <title>按月统计博客园单个用户的发文数量</title>
      <link>http://blog.zhaojie.me/2010/01/fsharp-per-user-posts-by-month-statistics.html</link>
      <guid>http://blog.zhaojie.me/2010/01/fsharp-per-user-posts-by-month-statistics.html</guid>
      <description>&lt;p&gt;这几天在家闲着，便试着写一些小程序。之前有朋友问到“F#能不能写Web”，于是我也就打算这么一试。虽然我能肯定，用F#写Web应用程序不会是问题，不过倒真还没有做过这方面的尝试。我想，如果用F#写Web应用程序，那么它很重要的一点，应该是利用其在异步编程方面的强大特性。最后我决定，使用F#编写一个按月统计博客园单个用户发文数量的简单服务。尝试的结果是——还有些问题没有解决。不管怎么样，我先把其主体逻辑描述一下吧。&lt;/p&gt;  &lt;p&gt;按月统计博客园单个用户的发文数量，这个并不困难，只要利用博客园的“按月汇总”页面就行了——前几天我也利用这个页面来捕获我所有文章ID，这次还是使用这个方法。由于这是一个打算公开的服务，为了性能着想我打算利用起博客园的gzip压缩，因此我们这里为WebClient类扩展一个异步获取数据流的GetDataAsync函数：&lt;/p&gt;  &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;type &lt;/span&gt;WebClient &lt;span style="color: blue"&gt;with 

    member &lt;/span&gt;c.GetDataAsync(url) =
        async {
            &lt;span style="color: blue"&gt;do &lt;/span&gt;c.DownloadDataAsync(&lt;span style="color: blue"&gt;new &lt;/span&gt;Uri(url))
            &lt;span style="color: blue"&gt;let! &lt;/span&gt;args = Async.AwaitEvent(c.DownloadDataCompleted)
            &lt;span style="color: blue"&gt;return &lt;/span&gt;args.Result
        } &lt;/pre&gt;

&lt;p&gt;当得到了页面的数据流之后，我们便可以使用GZipStream将其解压缩了。如此，我们便可以写一个函数，生成一个异步工作流，其效果是返回某个月指定用户所有文章的URL：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;let &lt;/span&gt;getPostUrlsAsync alias (beginMonth: DateTime) (endMonth: DateTime) = 

    &lt;span style="color: blue"&gt;if &lt;/span&gt;(beginMonth &amp;gt; endMonth) &lt;span style="color: blue"&gt;then
        &lt;/span&gt;failwith &lt;span style="color: maroon"&gt;&amp;quot;beginMonth must smaller then or equals to endMonth&amp;quot;

    &lt;/span&gt;&lt;span style="color: blue"&gt;let &lt;/span&gt;getPostUrlsAsync' alias (m: DateTime) = 
        async {
            &lt;span style="color: blue"&gt;let &lt;/span&gt;webClient = &lt;span style="color: blue"&gt;new &lt;/span&gt;WebClient();
            webClient.Headers.Add(HttpRequestHeader.AcceptEncoding, &lt;span style="color: maroon"&gt;&amp;quot;gzip&amp;quot;&lt;/span&gt;)

            &lt;span style="color: blue"&gt;let &lt;/span&gt;url = sprintf &lt;span style="color: maroon"&gt;&amp;quot;http://%s.cnblogs.com/archive/%i/%i.html&amp;quot; &lt;/span&gt;alias m.Year m.Month
            &lt;span style="color: blue"&gt;let! &lt;/span&gt;data = webClient.GetDataAsync(url)
            
            &lt;span style="color: blue"&gt;let &lt;/span&gt;rawStream = &lt;span style="color: blue"&gt;new &lt;/span&gt;MemoryStream(data)
            &lt;span style="color: blue"&gt;let &lt;/span&gt;gzipStream = &lt;span style="color: blue"&gt;new &lt;/span&gt;GZipStream(rawStream, CompressionMode.Decompress)
            &lt;span style="color: blue"&gt;let &lt;/span&gt;reader = &lt;span style="color: blue"&gt;new &lt;/span&gt;StreamReader(gzipStream)
            &lt;span style="color: blue"&gt;let &lt;/span&gt;html = reader.ReadToEnd()

            &lt;span style="color: blue"&gt;let &lt;/span&gt;regex = &lt;span style="color: maroon"&gt;&amp;#64;&amp;quot;...&amp;quot;
            &lt;/span&gt;&lt;span style="color: blue"&gt;return &lt;/span&gt;[ &lt;span style="color: blue"&gt;for &lt;/span&gt;m &lt;span style="color: blue"&gt;in &lt;/span&gt;Regex.Matches(html, regex) &lt;span style="color: blue"&gt;-&amp;gt; &lt;/span&gt;m.Groups.Item(&lt;span style="color: brown"&gt;1&lt;/span&gt;).Value ]
        }

    ...&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;在getPostUrlsAsync'函数中，我们首先拼接出该用户月份汇总页的URL——使用子域名的方式。博客园有两种方式可以访问某个博客，一是子域名，二是普通的URL形式。在这里我使用子域名的访问方式是避免.NET类库中对单个域名2个连接的限制。现在这个服务可以同时统计不同用户的信息而不会冲突。不过对于单个用户，还是只能同时出现2个连接——嗯，这是个Feature，避免在虚拟主机上消耗太多资源的Feature。&lt;/p&gt;

&lt;p&gt;上面还省略了一个正则表达式，其实它是这样的：&lt;/p&gt;

&lt;pre class="code"&gt;&amp;lt;a\s[^&amp;gt;]*href=[&amp;quot;|'](http://www.cnblogs.com/\w+/archive/\d{4}/\d{2}/\d{2}/[^.]*\.html)[&amp;quot;|'][^&amp;gt;]*&amp;gt;\s*阅读全文\s*&amp;lt;/a&amp;gt;&lt;/pre&gt;

&lt;p&gt;这个正则表达式实在不容易找。博客园的不同皮肤的HTML可能截然相反，我原本以为都会有EditPosts.aspx?postid=12345这样的链接，但事实证明……有些模板中这样的链接是使用JavaScript生成的，于是“此路不通”。后来我又想通过“评论”链接来捕获URL，但发现有的皮肤使用#FeedBack，有的却使用#Comments。总之，很难统一起来便是了。&lt;/p&gt;

&lt;p&gt;最后，我决定通过使用每篇文章中的“阅读全文”链接来识别一篇文章——便是这样，您从这个正则表达式中也可以发现，这是一个较为宽泛的Pattern，甚至href属性还要分单引号和双引号两种情况。这个方法有缺陷，因为对于一些非常短的文章，博客园是不会为其生成“阅读全文”链接的——不过，这也算是个Feature吧，太短的文章咱就不算了。:P&lt;/p&gt;

&lt;p&gt;接下来便是从beginMonth和endMonth参数中收集任务，并进行“汇总”了：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;let &lt;/span&gt;getPostUrlsAsync alias (beginMonth: DateTime) (endMonth: DateTime) = 

    ...

    &lt;span style="color: blue"&gt;let &lt;/span&gt;executeAsync tasks =
        &lt;span style="color: blue"&gt;let rec &lt;/span&gt;executeAsync' (tasks: (_ * Async&amp;lt;_&amp;gt;) list) acc = 
            async {
                &lt;span style="color: blue"&gt;match &lt;/span&gt;tasks &lt;span style="color: blue"&gt;with
                &lt;/span&gt;| [] &lt;span style="color: blue"&gt;-&amp;gt; return &lt;/span&gt;acc |&amp;gt; List.rev
                | (pre, task) :: ts &lt;span style="color: blue"&gt;-&amp;gt;
                    let! &lt;/span&gt;result = task
                    &lt;span style="color: blue"&gt;return! &lt;/span&gt;executeAsync' ts ((pre, result) :: acc)
            }
        
        executeAsync' tasks List.empty

    Seq.initInfinite (&lt;span style="color: blue"&gt;fun &lt;/span&gt;i &lt;span style="color: blue"&gt;-&amp;gt; &lt;/span&gt;endMonth.AddMonths(-i))
    |&amp;gt; Seq.takeWhile (&lt;span style="color: blue"&gt;fun &lt;/span&gt;m &lt;span style="color: blue"&gt;-&amp;gt; &lt;/span&gt;m &amp;gt;= beginMonth)
    |&amp;gt; Seq.map (&lt;span style="color: blue"&gt;fun &lt;/span&gt;m &lt;span style="color: blue"&gt;-&amp;gt; &lt;/span&gt;(m, getPostUrlsAsync' alias m))
    |&amp;gt; Seq.toList
    |&amp;gt; executeAsync&lt;/pre&gt;

&lt;p&gt;F#与Haskell不同，它不是延迟的语言，因此它的List必须是有限的，即时生成的。不过Seq便不同了，F#中的Seq可以认作是IEnumerable的对应物，可以是无限的，而Seq.initInfinite便是初始化这样一个无限的序列。不过Seq.takeWhile却只是取到这个序列大于等于beginMonth的那些元素——然后我们再将其映射成月份与“获取单月文章URL”这个异步工作流的“元组”。最后，再使用executeAsync将DateTime * Async&amp;lt;string list&amp;gt;汇总成Async&amp;lt;(DateTime * string list) list&amp;gt;类型。由于我打算把它部署在虚拟主机上，为了节省资源没有把它们并行处理——因此在最后执行时耗时会有些长，不过最后感觉下来，速度基本还可以接受。&lt;/p&gt;

&lt;p&gt;最后，我们&lt;a href="http://blog.zhaojie.me/2009/12/fsharp-comet-prototype.html"&gt;与上次相同&lt;/a&gt;，写个异步Handler用于处理请求：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;#light

namespace &lt;/span&gt;CnBlogsMonitoring

&lt;span style="color: blue"&gt;open &lt;/span&gt;System
&lt;span style="color: blue"&gt;open &lt;/span&gt;System.Web

&lt;span style="color: blue"&gt;type &lt;/span&gt;PostsOfMonthsHandler() =
    &lt;span style="color: blue"&gt;let mutable &lt;/span&gt;m_context = &lt;span style="color: blue"&gt;null
    let mutable &lt;/span&gt;m_endWork = &lt;span style="color: blue"&gt;null

    interface &lt;/span&gt;IHttpAsyncHandler &lt;span style="color: blue"&gt;with
        member &lt;/span&gt;h.IsReusable = &lt;span style="color: blue"&gt;false
        member &lt;/span&gt;h.ProcessRequest(context) = failwith &lt;span style="color: maroon"&gt;&amp;quot;not supported&amp;quot;

        &lt;/span&gt;&lt;span style="color: blue"&gt;member &lt;/span&gt;h.BeginProcessRequest(c, cb, state) =
            m_context &amp;lt;- c

            &lt;span style="color: blue"&gt;let &lt;/span&gt;alias = c.Request.QueryString.Item(&lt;span style="color: maroon"&gt;&amp;quot;alias&amp;quot;&lt;/span&gt;).Trim()
            &lt;span style="color: blue"&gt;let &lt;/span&gt;bm = DateTime.ParseExact(c.Request.QueryString.Item(&lt;span style="color: maroon"&gt;&amp;quot;begin&amp;quot;&lt;/span&gt;), &lt;span style="color: maroon"&gt;&amp;quot;yyyy/MM&amp;quot;&lt;/span&gt;, &lt;span style="color: blue"&gt;null&lt;/span&gt;)
            &lt;span style="color: blue"&gt;let &lt;/span&gt;em = DateTime.ParseExact(c.Request.QueryString.Item(&lt;span style="color: maroon"&gt;&amp;quot;end&amp;quot;&lt;/span&gt;), &lt;span style="color: maroon"&gt;&amp;quot;yyyy/MM&amp;quot;&lt;/span&gt;, &lt;span style="color: blue"&gt;null&lt;/span&gt;)

            &lt;span style="color: blue"&gt;let &lt;/span&gt;monthDiff = (em.Month - bm.Month) + (em.Year - bm.Year) * &lt;span style="color: brown"&gt;12
            &lt;/span&gt;&lt;span style="color: blue"&gt;if &lt;/span&gt;monthDiff &amp;gt; &lt;span style="color: brown"&gt;12 &lt;/span&gt;&lt;span style="color: blue"&gt;then &lt;/span&gt;failwith &lt;span style="color: maroon"&gt;&amp;quot;Please pick a range no larger than 12 months.&amp;quot;

            &lt;/span&gt;&lt;span style="color: blue"&gt;let &lt;/span&gt;title = sprintf &lt;span style="color: maroon"&gt;&amp;quot;%s: %i/%i ~ %i/%i&amp;quot; &lt;/span&gt;alias bm.Year bm.Month em.Year em.Month
            m_context.Items.Item(&lt;span style="color: maroon"&gt;&amp;quot;Title&amp;quot;&lt;/span&gt;) &amp;lt;- title

            &lt;span style="color: blue"&gt;let &lt;/span&gt;work = PostMonitor.getPostUrlsAsync alias bm em
            &lt;span style="color: blue"&gt;let &lt;/span&gt;beginWork, endWork, _ = Async.AsBeginEnd work
            m_endWork &amp;lt;- &lt;span style="color: blue"&gt;new &lt;/span&gt;Func&amp;lt;_, _&amp;gt;(endWork)

            beginWork (cb, state)

        &lt;span style="color: blue"&gt;member &lt;/span&gt;h.EndProcessRequest(ar) =
            m_context.Items.Item(&lt;span style="color: maroon"&gt;&amp;quot;PostsOfMonths&amp;quot;&lt;/span&gt;) &amp;lt;- m_endWork.Invoke ar
            m_context.Server.Transfer(&lt;span style="color: maroon"&gt;&amp;quot;PostsOfMonths.aspx&amp;quot;&lt;/span&gt;)&lt;/pre&gt;

&lt;p&gt;在EndProcessRequest方法中，我们得到了统计结果。在这里我的处理方式是将请求Transfer到PostsOfMonths.aspx这个页面去显示HTML——传递数据的方式是利用HttpContext.Items集合。&lt;/p&gt;

&lt;p&gt;在PostsOfMonths.aspx中，显示HTML的方式与普通页面毫无二致：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public partial class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;PostsOfMonths &lt;/span&gt;: System.Web.UI.&lt;span style="color: #2b91af"&gt;Page
&lt;/span&gt;{
    &lt;span style="color: blue"&gt;protected void &lt;/span&gt;Page_Load(&lt;span style="color: blue"&gt;object &lt;/span&gt;sender, &lt;span style="color: #2b91af"&gt;EventArgs &lt;/span&gt;e)
    {
        &lt;span style="color: blue"&gt;this&lt;/span&gt;.Title = &lt;span style="color: blue"&gt;this&lt;/span&gt;.Context.Items[&lt;span style="color: #a31515"&gt;&amp;quot;Title&amp;quot;&lt;/span&gt;].ToString();

        &lt;span style="color: blue"&gt;this&lt;/span&gt;.rptPostsOfMonths.DataSource = &lt;span style="color: blue"&gt;this&lt;/span&gt;.Context.Items[&lt;span style="color: #a31515"&gt;&amp;quot;PostsOfMonths&amp;quot;&lt;/span&gt;];
        &lt;span style="color: blue"&gt;this&lt;/span&gt;.rptPostsOfMonths.DataBind();
    }
}&lt;/pre&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: maroon"&gt;html &lt;/span&gt;&lt;span style="color: red"&gt;xmlns&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;http://www.w3.org/1999/xhtml&amp;quot;&amp;gt;
&amp;lt;&lt;/span&gt;&lt;span style="color: maroon"&gt;head &lt;/span&gt;&lt;span style="color: red"&gt;runat&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;server&amp;quot;&amp;gt;
    &amp;lt;&lt;/span&gt;&lt;span style="color: maroon"&gt;title&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: maroon"&gt;title&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
&amp;lt;/&lt;/span&gt;&lt;span style="color: maroon"&gt;head&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
&amp;lt;&lt;/span&gt;&lt;span style="color: maroon"&gt;body&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
    &amp;lt;&lt;/span&gt;&lt;span style="color: maroon"&gt;h1&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;&lt;span style="background: yellow"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color: blue"&gt;= this&lt;/span&gt;.Title &lt;span style="background: yellow"&gt;%&amp;gt;&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: maroon"&gt;h1&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
    
    &amp;lt;&lt;/span&gt;&lt;span style="color: maroon"&gt;asp&lt;/span&gt;&lt;span style="color: blue"&gt;:&lt;/span&gt;&lt;span style="color: maroon"&gt;Repeater &lt;/span&gt;&lt;span style="color: red"&gt;runat&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;server&amp;quot; &lt;/span&gt;&lt;span style="color: red"&gt;ID&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;rptPostsOfMonths&amp;quot;&amp;gt;
        &amp;lt;&lt;/span&gt;&lt;span style="color: maroon"&gt;ItemTemplate&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
            &amp;lt;&lt;/span&gt;&lt;span style="color: maroon"&gt;h2&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;&lt;span style="background: yellow"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color: blue"&gt;# &lt;/span&gt;Eval(&lt;span style="color: #a31515"&gt;&amp;quot;Item1&amp;quot;&lt;/span&gt;, &lt;span style="color: #a31515"&gt;&amp;quot;{0:yyyy/MM}&amp;quot;&lt;/span&gt;) &lt;span style="background: yellow"&gt;%&amp;gt;&lt;/span&gt; - &lt;span style="background: yellow"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color: blue"&gt;# &lt;/span&gt;Eval(&lt;span style="color: #a31515"&gt;&amp;quot;Item2.Length&amp;quot;&lt;/span&gt;) &lt;span style="background: yellow"&gt;%&amp;gt;&lt;/span&gt; post(s)&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: maroon"&gt;h2&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
            
            &amp;lt;&lt;/span&gt;&lt;span style="color: maroon"&gt;asp&lt;/span&gt;&lt;span style="color: blue"&gt;:&lt;/span&gt;&lt;span style="color: maroon"&gt;Repeater &lt;/span&gt;&lt;span style="color: red"&gt;runat&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;server&amp;quot; &lt;/span&gt;&lt;span style="color: red"&gt;DataSource&lt;/span&gt;&lt;span style="color: blue"&gt;='&lt;/span&gt;&lt;span style="background: yellow"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color: blue"&gt;# &lt;/span&gt;Eval(&amp;quot;Item2&amp;quot;) &lt;span style="background: yellow"&gt;%&amp;gt;&lt;/span&gt;&lt;span style="color: blue"&gt;'&amp;gt;
                &amp;lt;&lt;/span&gt;&lt;span style="color: maroon"&gt;HeaderTemplate&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: maroon"&gt;ul&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: maroon"&gt;HeaderTemplate&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                &amp;lt;&lt;/span&gt;&lt;span style="color: maroon"&gt;ItemTemplate&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                    &amp;lt;&lt;/span&gt;&lt;span style="color: maroon"&gt;li&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                        &amp;lt;&lt;/span&gt;&lt;span style="color: maroon"&gt;a &lt;/span&gt;&lt;span style="color: red"&gt;href&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;&lt;/span&gt;&lt;span style="background: yellow"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color: blue"&gt;# &lt;/span&gt;Container.DataItem &lt;span style="background: yellow"&gt;%&amp;gt;&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="background: yellow"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color: blue"&gt;# &lt;/span&gt;Container.DataItem &lt;span style="background: yellow"&gt;%&amp;gt;&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: maroon"&gt;a&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                    &amp;lt;/&lt;/span&gt;&lt;span style="color: maroon"&gt;li&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                &amp;lt;/&lt;/span&gt;&lt;span style="color: maroon"&gt;ItemTemplate&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                &amp;lt;&lt;/span&gt;&lt;span style="color: maroon"&gt;FooterTemplate&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: maroon"&gt;ul&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: maroon"&gt;FooterTemplate&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
            &amp;lt;/&lt;/span&gt;&lt;span style="color: maroon"&gt;asp&lt;/span&gt;&lt;span style="color: blue"&gt;:&lt;/span&gt;&lt;span style="color: maroon"&gt;Repeater&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
        &amp;lt;/&lt;/span&gt;&lt;span style="color: maroon"&gt;ItemTemplate&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
    &amp;lt;/&lt;/span&gt;&lt;span style="color: maroon"&gt;asp&lt;/span&gt;&lt;span style="color: blue"&gt;:&lt;/span&gt;&lt;span style="color: maroon"&gt;Repeater&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
&amp;lt;/&lt;/span&gt;&lt;span style="color: maroon"&gt;body&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
&amp;lt;/&lt;/span&gt;&lt;span style="color: maroon"&gt;html&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;从F#代码中我们知道，HttpContext.Items[&amp;quot;PostsOfMonths&amp;quot;]的类型是(DateTime * string list) list，也就是说，绑定至rptPostsOfMonths中的每一项都是个DateTime * string list对象——写成C#的形式便是Tuple&amp;lt;DateTime, FSharpList&amp;lt;string&amp;gt;&amp;gt;，其中包含Item1和Item2两个属性，分别是DateTime和FSharpList&amp;lt;string&amp;gt;类型，而后者又会绑定至内层的Repeater中，最终生成整页的HTML。&lt;/p&gt;

&lt;p&gt;那么我为什么不写个异步的WebForm页面呢？因为经过我的简单尝试，在WebClient.GetDataAsync扩展里的Async.AwaitEvent操作中会抛出InvalidOperationException异常：&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Asynchronous operations are not allowed in this context. Page starting an asynchronous operation has to have the Async attribute set to true and an asynchronous operation can only be started on a page prior to PreRenderComplete event.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;经过了多番检查和比对，我始终没有发现出了什么问题，因此最后还是使用了异步Handler的方式编写这个服务。按理说，异步Hander可以正常工作，异步页面也应该没有什么问题，具体原因我会继续探究一下。不过，如果只是编写一个同步页面的话，不会出现任何问题。&lt;/p&gt;

&lt;p&gt;最后，我把这个简单服务部署到了免费的虚拟主机上（以前用的Hosting由于众所周知的原因，在国内已经无法使用了——现在这个只能用到1月底），您可以在文末访问到该服务的入口页：这是一个简单的静态页面，填好信息后点击Submit便会提交至那个异步Handler进行处理——稍等片刻，便会得到结果。F#的方便之处，在于它编译后的结果便是标准的.NET程序集，使用时也只是复制一些dll便可——无需额外支持。这样看来，有一个统一的虚拟机平台的确方便，例如GAE在支持Java平台之后便相当于直接支持Scala语言了。同理，在.NET平台上使用Rails（Ruby）、Django（Python）等框架似乎都不是个梦想。&lt;/p&gt;

&lt;p&gt;谁说.NET封闭？我感觉没有比.NET更海纳百川的平台了，呵呵——这也是我喜欢.NET平台的最大原因。&lt;/p&gt;

&lt;p&gt;服务入口：&lt;a title="http://user868.netfx4lab.discountasp.net/PostsOfMonths.html" href="http://user868.netfx4lab.discountasp.net/PostsOfMonths.html"&gt;http://user868.netfx4lab.discountasp.net/PostsOfMonths.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;本文代码：&lt;a href="http://gist.github.com/273556"&gt;http://gist.github.com/273556&lt;/a&gt;&lt;/p&gt;</description>
      <comments>http://blog.zhaojie.me/2010/01/fsharp-per-user-posts-by-month-statistics.html#comments</comments>
      <pubDate>Sun, 10 Jan 2010 16:07:00 GMT</pubDate>
      <lastBuildDate>Sun, 10 Jan 2010 16:07:00 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/language/">语言编程</category>
      <category domain="http://blog.zhaojie.me/cutting-edge/">技术尝鲜</category>
      <title>五十种语言的“圣诞快乐”（下）：F#实现</title>
      <link>http://blog.zhaojie.me/2009/12/merry-christmas-in-fifty-languages-2-fsharp-async-workflow.html</link>
      <guid>http://blog.zhaojie.me/2009/12/merry-christmas-in-fifty-languages-2-fsharp-async-workflow.html</guid>
      <description>&lt;p&gt;不知道大家的圣诞节过的如何？有没有玩点啥有趣的东西？&lt;a href="http://blog.zhaojie.me/2009/12/merry-christmas-in-fifty-languages-1-analysis.html"&gt;上次的文章&lt;/a&gt;中我们主要分析了使用Google Translate进行文字翻译的方式，并使用C#写了一个简单的的翻译程序，效果良好。不过，在平时开发过程中，对于此类问题我常用F#来解决这样的问题。那么使用F#来实现此类任务有什么优势吗？不错，我们现在便来看看这个问题。&lt;/p&gt;  &lt;h1&gt;简单的F#实现&lt;/h1&gt;  &lt;p&gt;话说F#和.NET框架可以无缝集成，因此理论上之前我们的C#代码怎么写，便可以使用F#来照着抄一遍。例如，我们先定义一个Sync模块，其中先定义一个获取全部目标语言的getLanguages函数：&lt;/p&gt;  &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;#light

module &lt;/span&gt;Sync

&lt;span style="color: blue"&gt;open &lt;/span&gt;System
&lt;span style="color: blue"&gt;open &lt;/span&gt;System.Text.RegularExpressions
&lt;span style="color: blue"&gt;open &lt;/span&gt;System.Net
&lt;span style="color: blue"&gt;open &lt;/span&gt;System.Web
&lt;span style="color: blue"&gt;open &lt;/span&gt;System.Web.Script.Serialization
&lt;span style="color: blue"&gt;open &lt;/span&gt;System.Collections.Generic
&lt;span style="color: blue"&gt;open &lt;/span&gt;System.Text

&lt;span style="color: blue"&gt;type private &lt;/span&gt;LangMap = Dictionary&amp;lt;string, string&amp;gt;

&lt;span style="color: blue"&gt;let private &lt;/span&gt;getLanguages() = 
    &lt;span style="color: blue"&gt;let &lt;/span&gt;url =
        &lt;span style="color: maroon"&gt;&amp;quot;http://translate.googleapis.com&amp;quot; &lt;/span&gt;+
        &lt;span style="color: maroon"&gt;&amp;quot;/translate_a/l?client=te&amp;amp;hl=zh-CN&amp;amp;cb=_callbacks_._0g3mb650r&amp;quot;
    
    &lt;/span&gt;&lt;span style="color: blue"&gt;let &lt;/span&gt;webClient = &lt;span style="color: blue"&gt;new &lt;/span&gt;WebClient()
    &lt;span style="color: blue"&gt;let &lt;/span&gt;script = webClient.DownloadString(url)

    &lt;span style="color: blue"&gt;let &lt;/span&gt;json = Regex.Match(script, &lt;span style="color: maroon"&gt;&amp;#64;&amp;quot;'tl':({.+})}\)&amp;quot;&lt;/span&gt;).Groups.Item(&lt;span style="color: brown"&gt;1&lt;/span&gt;).Value
    &lt;span style="color: blue"&gt;let &lt;/span&gt;serializer = &lt;span style="color: blue"&gt;new &lt;/span&gt;JavaScriptSerializer()
    serializer.Deserialize&amp;lt;LangMap&amp;gt;(json)&lt;/pre&gt;

&lt;p&gt;这个函数与之前C#版本的GetLanguages方法可谓一模一样，其返回结果便是一个字典，存储了目标语言的代号和名称——当然，这边我为Dictionary&amp;lt;string, string&amp;gt;取了一个别名LangMap，这样使用起来感觉更为方便，语义也更加清晰。&lt;/p&gt;

&lt;p&gt;同样的，我们“翻译”一遍之前的Translate方法，变成如今的translateText函数：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;let private &lt;/span&gt;translateText (text:string) sl tl =
    &lt;span style="color: blue"&gt;let &lt;/span&gt;url = 
        &lt;span style="color: maroon"&gt;&amp;quot;https://translate.googleapis.com&amp;quot; &lt;/span&gt;+
        &lt;span style="color: maroon"&gt;&amp;quot;/translate_a/t?client=te&amp;amp;format=html&amp;amp;v=1.0&amp;quot;

    &lt;/span&gt;&lt;span style="color: blue"&gt;let &lt;/span&gt;encoded = text |&amp;gt; HttpUtility.UrlEncode
    &lt;span style="color: blue"&gt;let &lt;/span&gt;data = sprintf &lt;span style="color: maroon"&gt;&amp;quot;q=%s&amp;amp;sl=%s&amp;amp;tl=%s&amp;amp;tc=1&amp;quot; &lt;/span&gt;encoded sl tl

    &lt;span style="color: blue"&gt;let &lt;/span&gt;webClient = &lt;span style="color: blue"&gt;new &lt;/span&gt;WebClient()
    webClient.Encoding &amp;lt;- Encoding.UTF8
    &lt;span style="color: blue"&gt;let &lt;/span&gt;userAgent = &lt;span style="color: maroon"&gt;&amp;quot;Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0;)&amp;quot;
    &lt;/span&gt;webClient.Headers.Add(HttpRequestHeader.UserAgent, userAgent)

    &lt;span style="color: blue"&gt;let &lt;/span&gt;json = webClient.UploadString(url, data)
    &lt;span style="color: blue"&gt;let &lt;/span&gt;serializer = &lt;span style="color: blue"&gt;new &lt;/span&gt;JavaScriptSerializer()
    serializer.Deserialize&amp;lt;string&amp;gt;(json)&lt;/pre&gt;

&lt;p&gt;而最终进行多种语言翻译的，则是使用公有的translate函数：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;let &lt;/span&gt;translate text sl = 
    &lt;span style="color: blue"&gt;let &lt;/span&gt;languages = getLanguages()

    &lt;span style="color: blue"&gt;let &lt;/span&gt;translated =
        languages
        |&amp;gt; Seq.map (&lt;span style="color: blue"&gt;fun &lt;/span&gt;p &lt;span style="color: blue"&gt;-&amp;gt; &lt;/span&gt;translateText text sl p.Key)

    &lt;span style="color: blue"&gt;let &lt;/span&gt;names = languages  |&amp;gt; Seq.map (&lt;span style="color: blue"&gt;fun &lt;/span&gt;p &lt;span style="color: blue"&gt;-&amp;gt; &lt;/span&gt;p.Value)
    Seq.zip names translated |&amp;gt; Seq.toArray&lt;/pre&gt;

&lt;p&gt;首先，所有语言会存入一个叫做languages的容器中，它是一个字典，实现了IEnumerable&amp;lt;KeyValuePair&amp;lt;string, string&amp;gt;&amp;gt;，在F#中便是seq&amp;lt;KeyValuePair&amp;lt;string, string&amp;gt;&amp;gt;，因此我们使用Seq模块的map方法将其转化为翻译后的结果，并存放在translated中。然后，我们获得每种语言的名称，最终与翻译的结果zip即可。translate函数最终返回的是一个存放着元组的数组，元组的类型是string * string。&lt;/p&gt;

&lt;p&gt;至于调用，自然是很容易的。F#控制台程序也需要定义main函数，如下：&lt;/p&gt;

&lt;pre class="code"&gt;[&amp;lt;EntryPoint&amp;gt;]
&lt;span style="color: blue"&gt;let &lt;/span&gt;main args =

    &lt;span style="color: blue"&gt;let &lt;/span&gt;output = 
        Sync.translate &lt;span style="color: maroon"&gt;&amp;quot;圣诞快乐&amp;quot; &amp;quot;zh-CN&amp;quot;
        &lt;/span&gt;|&amp;gt; Array.map (&lt;span style="color: blue"&gt;fun &lt;/span&gt;(lang, text) &lt;span style="color: blue"&gt;-&amp;gt; &lt;/span&gt;sprintf &lt;span style="color: maroon"&gt;&amp;quot;%s：o%s&amp;quot; &lt;/span&gt;lang text)&lt;span style="color: green"&gt;

    &lt;/span&gt;File.WriteAllLines(&lt;span style="color: maroon"&gt;&amp;quot;output.txt&amp;quot;&lt;/span&gt;, output)
    
    Console.ReadLine() |&amp;gt; ignore
    &lt;span style="color: brown"&gt;0
&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;当然，如果我们只是把F#用成这样，那实在就没有多大价值了。&lt;/p&gt;

&lt;h1&gt;异步编程&lt;/h1&gt;

&lt;p&gt;刚才的代码放在名为Sync的模块中，很明显这是“同步”的。对于此类IO操作，使用同步IO是一件非常不明智的事情。当然，对于目前这样的小程序来说，使用同步IO并没有什么问题。但是您一会儿也会发现，异步IO对目前的情形也是十分有价值的。&lt;/p&gt;

&lt;p&gt;异步IO除了“不阻塞”的含义在里面之外，我认为还需要包括“事件触发”这个含义在里面。例如，JDK很早就支持了异步IO，但是直到目前为止（JDK 6），它在Windows平台上的相关实现，依旧只是简单的“非阻塞”，而非基于Windows的异步IO机制IOCP。于此相对，它在Linux平台上的实现却使用了高效的epoll。因此，如&lt;a href="http://mina.apache.org/"&gt;Mina&lt;/a&gt;，&lt;a href="http://www.mortbay.org/jetty/"&gt;Jetty&lt;/a&gt;等高性能IO通信框架在Windows下的表现要比Linux差很多——您会经常看到时不时有人以此来证明Windows性能低下，但我倒认为这只能证明Java的跨平台只是“功能”而不是“性能”，意义大打折扣。&lt;/p&gt;

&lt;p&gt;至于跨平台的IO类库并非没有，例如著名的&lt;a href="http://monkey.org/~provos/libevent/"&gt;libevent&lt;/a&gt;便是一例。不过在JDK 7中“据说”会修复这方面问题，拭目以待。&lt;/p&gt;

&lt;p&gt;对于在Windows平台下真正的异步IO机制IOCP，我之前在多篇文章中&lt;a href="http://blog.zhaojie.me/2008/02/use-async-operation-properly.html"&gt;有所提及&lt;/a&gt;（包括与其有关的&lt;a href="http://blog.zhaojie.me/2009/07/thread-pool-2-dedicate-pool-and-io-pool.html"&gt;IO线程池&lt;/a&gt;）。在.NET平台上，各种类库的异步通信方式自然使用了IOCP，自不必提。但是，异步编程的性能虽然好，但它的最大问题还是“方便性”，最基础的一点，由于任务流需要分两部分进行，那么我们自然需要保留上下文吧？即便是如C#中提供了匿名函数，可以自动生成闭包来保持上下文，但是还是有其他问题——例如，异常处理怎么办？&lt;/p&gt;

&lt;p&gt;当然，&lt;a href="http://kb.cnblogs.com/a/1394645/"&gt;利用C#中的yield关键字可以简化这些问题&lt;/a&gt;，但是F#给我们更好的解决方案。F#应对异步编程提供了一个名为“异步工作流”的结构，它基于F#的“工作流”特性开发了一套异步类库，关于这一点在上次的&lt;a href="http://blog.zhaojie.me/2009/12/fsharp-comet-prototype.html"&gt;Comet原型&lt;/a&gt;中也有提及。异步工作流的优势在于把一个“二段式”的异步调用合并在一起，这样在调用的时候便可以同步操作的方式进行。如此，无论是逻辑中的上下文信息还是异常处理都变得异常简单。&lt;/p&gt;

&lt;p&gt;对于异步操作的“合并”，例如可以根据最常见的APM模式（即Begin/End）生成“单步”的工作流。不过对于WebClient来说，它的异步操作并非APM形式，而是基于“事件”。不过F#对此也提供了支持，因此我们可以为WebClient扩展两个函数：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;type &lt;/span&gt;WebClient &lt;span style="color: blue"&gt;with
    member &lt;/span&gt;c.GetStringAsync(url) = 
        async {
            c.DownloadStringAsync(&lt;span style="color: blue"&gt;new &lt;/span&gt;Uri(url))
            &lt;span style="color: blue"&gt;let! &lt;/span&gt;args = c.DownloadStringCompleted |&amp;gt; Async.AwaitEvent
            &lt;span style="color: blue"&gt;return &lt;/span&gt;args.Result
        }

    &lt;span style="color: blue"&gt;member &lt;/span&gt;c.PostStringAsync(url, data) = 
        async {
            c.UploadStringAsync(&lt;span style="color: blue"&gt;new &lt;/span&gt;Uri(url), data)
            &lt;span style="color: blue"&gt;let! &lt;/span&gt;args = c.UploadStringCompleted |&amp;gt; Async.AwaitEvent
            &lt;span style="color: blue"&gt;return &lt;/span&gt;args.Result
        }&lt;/pre&gt;

&lt;p&gt;我们在F#中可以“打开”任意一个类型，为其添加新的成员——不过自然这只是如C#中扩展方法那样的语法糖而已。我们为WebClient添加了GetStringAsync与PostStringAsync两个方法，它们返回的都是结果为一个字符串的异步数据流（即Async&amp;lt;string&amp;gt;），执行这个异步数据流之后便可以得到最终的结果。值得注意的是，async块只是在构造一个逻辑块，并没有真正调用。&lt;/p&gt;

&lt;p&gt;于是，我们的getLanguages函数也可进行改写：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;let private &lt;/span&gt;getLanguages() = 
    async {
        &lt;span style="color: blue"&gt;let &lt;/span&gt;url =
            &lt;span style="color: maroon"&gt;&amp;quot;http://translate.googleapis.com&amp;quot; &lt;/span&gt;+
            &lt;span style="color: maroon"&gt;&amp;quot;/translate_a/l?client=te&amp;amp;hl=zh-CN&amp;amp;cb=_callbacks_._0g3mb650r&amp;quot;
        
        &lt;/span&gt;&lt;span style="color: blue"&gt;let &lt;/span&gt;webClient = &lt;span style="color: blue"&gt;new &lt;/span&gt;WebClient()
        &lt;span style="color: green"&gt;// let script = webClient.DownloadString(url)
        &lt;/span&gt;&lt;span style="color: blue"&gt;let! &lt;/span&gt;script = webClient.GetStringAsync(url)

        &lt;span style="color: blue"&gt;let &lt;/span&gt;json = Regex.Match(script, &lt;span style="color: maroon"&gt;&amp;#64;&amp;quot;'tl':({.+})}\)&amp;quot;&lt;/span&gt;).Groups.Item(&lt;span style="color: brown"&gt;1&lt;/span&gt;).Value
        &lt;span style="color: blue"&gt;let &lt;/span&gt;serializer = &lt;span style="color: blue"&gt;new &lt;/span&gt;JavaScriptSerializer()
        &lt;span style="color: green"&gt;// serializer.Deserialize&amp;lt;LangMap&amp;gt;(json)
        &lt;/span&gt;&lt;span style="color: blue"&gt;return &lt;/span&gt;serializer.Deserialize&amp;lt;LangMap&amp;gt;(json)
    }&lt;/pre&gt;

&lt;p&gt;您是否发现这段代码与之前的变化？没错，两者几乎一模一样。除了它变成了async构造块之外，唯一的区别只是被注释的两行代码。第一行代码中，原本我们使用的是同步的DownloadString函数，而现在我们则通过执行一个异步数据流（使用let!）来得到结果script——当然，执行的形式却是同步的。除此之外，最后返回结果需要使用return来标明。let!和return（以及其他的如return!）等操作符，都是F#编译器对“工作流”构造块（如async）使用中的“强制措施”，以此避免开发人员的误操作。&lt;/p&gt;

&lt;p&gt;同样，translateText函数也将构造一个异步工作流：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;let private &lt;/span&gt;translateText (text:string) sl tl =
    async {
        &lt;span style="color: blue"&gt;let &lt;/span&gt;url = 
            &lt;span style="color: maroon"&gt;&amp;quot;https://translate.googleapis.com&amp;quot; &lt;/span&gt;+
            &lt;span style="color: maroon"&gt;&amp;quot;/translate_a/t?client=te&amp;amp;format=html&amp;amp;v=1.0&amp;quot;

        &lt;/span&gt;&lt;span style="color: blue"&gt;let &lt;/span&gt;encoded = text |&amp;gt; HttpUtility.UrlEncode
        &lt;span style="color: blue"&gt;let &lt;/span&gt;data = sprintf &lt;span style="color: maroon"&gt;&amp;quot;q=%s&amp;amp;sl=%s&amp;amp;tl=%s&amp;amp;tc=1&amp;quot; &lt;/span&gt;encoded sl tl

        &lt;span style="color: blue"&gt;let &lt;/span&gt;webClient = &lt;span style="color: blue"&gt;new &lt;/span&gt;WebClient()
        webClient.Encoding &amp;lt;- Encoding.UTF8
        &lt;span style="color: blue"&gt;let &lt;/span&gt;userAgent = &lt;span style="color: maroon"&gt;&amp;quot;Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0;)&amp;quot;
        &lt;/span&gt;webClient.Headers.Add(HttpRequestHeader.UserAgent, userAgent)

        &lt;span style="color: blue"&gt;let! &lt;/span&gt;json = webClient.PostStringAsync(url, data) &lt;span style="color: green"&gt;// changed
        &lt;/span&gt;&lt;span style="color: blue"&gt;let &lt;/span&gt;serializer = &lt;span style="color: blue"&gt;new &lt;/span&gt;JavaScriptSerializer()
        &lt;span style="color: blue"&gt;return &lt;/span&gt;serializer.Deserialize&amp;lt;string&amp;gt;(json) &lt;span style="color: green"&gt;// changed
    &lt;/span&gt;}&lt;/pre&gt;

&lt;p&gt;使用异步工作流的另一个好处在于，我们可以轻易地将异步工作流并行地执行。例如在目前的场景中，我们可以同时发起50多个异步IO请求，但同时却不占用任何线程——它们可能都在等着IO设备（即网卡）发送设备信号呢。于是乎，我们的translate函数便可以这样写：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;let &lt;/span&gt;translate text sl = 
    async {
        &lt;span style="color: blue"&gt;let! &lt;/span&gt;languages = getLanguages()
        &lt;span style="color: blue"&gt;let! &lt;/span&gt;translated =
            languages
            |&amp;gt; Seq.map (&lt;span style="color: blue"&gt;fun &lt;/span&gt;p &lt;span style="color: blue"&gt;-&amp;gt; &lt;/span&gt;translateText text sl p.Key)
            |&amp;gt; &lt;font color="#ff0000"&gt;Async.Parallel&lt;/font&gt;

        &lt;span style="color: blue"&gt;let &lt;/span&gt;names = languages |&amp;gt; Seq.map (&lt;span style="color: blue"&gt;fun &lt;/span&gt;p &lt;span style="color: blue"&gt;-&amp;gt; &lt;/span&gt;p.Value)
        &lt;span style="color: blue"&gt;return &lt;/span&gt;Seq.zip names translated |&amp;gt; Seq.toArray
    }&lt;/pre&gt;

&lt;p&gt;并这样调用：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;let &lt;/span&gt;output = 
    Parallel.translate &lt;span style="color: maroon"&gt;&amp;quot;圣诞快乐&amp;quot; &amp;quot;zh-CN&amp;quot;
    &lt;/span&gt;|&amp;gt; Async.RunSynchronously
    |&amp;gt; Array.map (&lt;span style="color: blue"&gt;fun &lt;/span&gt;(lang, text) &lt;span style="color: blue"&gt;-&amp;gt; &lt;/span&gt;sprintf &lt;span style="color: maroon"&gt;&amp;quot;%s：%s&amp;quot; &lt;/span&gt;lang text)&lt;/pre&gt;

&lt;p&gt;这句代码中的Parallel便是指我们刚才开发的模块。这段代码的执行速度会比Sync模块要快很多，因此此时50多个翻译的请求并不是依次发出，而是同时发出，并通过响应IO设备的事件来工作。不阻塞，高效。&lt;/p&gt;

&lt;h1&gt;异步工作流的同步执行&lt;/h1&gt;

&lt;p&gt;之前的代码中，我们是将languages集合转化为一组translateText所生成的异步任务，然后由Async.Parallel合并成一个并行的异步任务。这种调用方式很简单，反而是如果您要将这组异步任务按照顺序一一执行起来比较麻烦。当然，这只是麻烦，并不困难，而且其实同样是非常自然的：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;let &lt;/span&gt;translateSeq text sl = 
    &lt;span style="color: blue"&gt;let rec &lt;/span&gt;translateSeq' targets acc =
        async {
            &lt;span style="color: blue"&gt;match &lt;/span&gt;targets &lt;span style="color: blue"&gt;with
            &lt;/span&gt;| [] &lt;span style="color: blue"&gt;-&amp;gt; return &lt;/span&gt;acc |&amp;gt; List.rev
            | t :: ts &lt;span style="color: blue"&gt;-&amp;gt; 
                let! &lt;/span&gt;result = translateText text sl t
                &lt;span style="color: blue"&gt;return! &lt;/span&gt;translateSeq' ts (t :: acc)
        }

    async {
        &lt;span style="color: blue"&gt;let! &lt;/span&gt;languages = getLanguages()
        &lt;span style="color: blue"&gt;let &lt;/span&gt;targets = languages |&amp;gt; Seq.map (&lt;span style="color: blue"&gt;fun &lt;/span&gt;p &lt;span style="color: blue"&gt;-&amp;gt; &lt;/span&gt;p.Key) |&amp;gt; Seq.toList

        &lt;span style="color: blue"&gt;let! &lt;/span&gt;translated = translateSeq' targets List.empty
        &lt;span style="color: blue"&gt;let &lt;/span&gt;names = languages |&amp;gt; Seq.map (&lt;span style="color: blue"&gt;fun &lt;/span&gt;p &lt;span style="color: blue"&gt;-&amp;gt; &lt;/span&gt;p.Value)
        &lt;span style="color: blue"&gt;return &lt;/span&gt;Seq.zip names translated |&amp;gt; Seq.toArray
    }&lt;/pre&gt;

&lt;p&gt;您能解释一下这段代码的写法吗？&lt;/p&gt;

&lt;p&gt;最后还是来看看执行效果吧。圣诞已过，新年将至。那么在这里就来祝各位兄弟们&lt;a onclick="document.getElementById('happy-new-year-Ni8_uK').style.display = 'block';" href="javascript:;"&gt;新年快乐&lt;/a&gt;吧！&lt;/p&gt;

&lt;ul style="display: none" id="happy-new-year-Ni8_uK"&gt;
  &lt;li&gt;阿尔巴尼亚语：Gëzuar vitin e ri &lt;/li&gt;

  &lt;li&gt;阿拉伯语：كل عام وأنتم بخير &lt;/li&gt;

  &lt;li&gt;爱尔兰语：Sona &lt;/li&gt;

  &lt;li&gt;爱沙尼亚语：Head uut aastat &lt;/li&gt;

  &lt;li&gt;白俄罗斯语：З новым годам &lt;/li&gt;

  &lt;li&gt;保加利亚语：Честита нова година &lt;/li&gt;

  &lt;li&gt;冰岛语：Gleðilegt nýtt ár &lt;/li&gt;

  &lt;li&gt;波兰语：Szczęśliwego nowego roku &lt;/li&gt;

  &lt;li&gt;波斯语：سال نو مبارک &lt;/li&gt;

  &lt;li&gt;布尔文(南非荷兰语)：Gelukkige nuwe jaar &lt;/li&gt;

  &lt;li&gt;丹麦语：Godt nytår &lt;/li&gt;

  &lt;li&gt;德语：Frohes neues Jahr &lt;/li&gt;

  &lt;li&gt;俄语：С новым годом &lt;/li&gt;

  &lt;li&gt;法语：Bonne année &lt;/li&gt;

  &lt;li&gt;菲律宾语：Manigong bagong taon &lt;/li&gt;

  &lt;li&gt;芬兰语：Hyvää uuttavuotta &lt;/li&gt;

  &lt;li&gt;韩语：새해 복 많이 받으세요 &lt;/li&gt;

  &lt;li&gt;荷兰语：Gelukkig nieuwjaar &lt;/li&gt;

  &lt;li&gt;加利西亚语：Feliz ano novo &lt;/li&gt;

  &lt;li&gt;加泰罗尼亚语：Feliç any nou &lt;/li&gt;

  &lt;li&gt;捷克语：Šťastný nový rok &lt;/li&gt;

  &lt;li&gt;克罗地亚语：Sretna nova godina &lt;/li&gt;

  &lt;li&gt;拉脱维亚语：Laimīgu Jauno gadu &lt;/li&gt;

  &lt;li&gt;立陶宛语：Laimingų Naujųjų metų &lt;/li&gt;

  &lt;li&gt;罗马尼亚语：An nou fericit &lt;/li&gt;

  &lt;li&gt;马耳他语：Is-sena t-tajba &lt;/li&gt;

  &lt;li&gt;马来语：Selamat tahun baru &lt;/li&gt;

  &lt;li&gt;马其顿语：Среќна нова година &lt;/li&gt;

  &lt;li&gt;挪威语：Godt nytt år &lt;/li&gt;

  &lt;li&gt;葡萄牙语：Feliz ano novo &lt;/li&gt;

  &lt;li&gt;日语：あけましておめでとう &lt;/li&gt;

  &lt;li&gt;瑞典语：Gott nytt år &lt;/li&gt;

  &lt;li&gt;塞尔维亚语：Срећна нова година &lt;/li&gt;

  &lt;li&gt;斯洛伐克语：Šťastný nový rok &lt;/li&gt;

  &lt;li&gt;斯洛文尼亚语：Srečno novo leto &lt;/li&gt;

  &lt;li&gt;斯瓦希里语：Furahia mwaka mpya &lt;/li&gt;

  &lt;li&gt;泰语：สวัสดีปีใหม่ &lt;/li&gt;

  &lt;li&gt;土耳其语：Yeni yılın kutlu olsun &lt;/li&gt;

  &lt;li&gt;威尔士语：Happy flwyddyn newydd &lt;/li&gt;

  &lt;li&gt;乌克兰语：З новим роком &lt;/li&gt;

  &lt;li&gt;西班牙语：Feliz año nuevo &lt;/li&gt;

  &lt;li&gt;希伯来语：שנה טובה &lt;/li&gt;

  &lt;li&gt;希腊语：Ευτυχισμένο το νέο έτος &lt;/li&gt;

  &lt;li&gt;匈牙利语：Boldog újévet &lt;/li&gt;

  &lt;li&gt;意大利语：Buon anno &lt;/li&gt;

  &lt;li&gt;意第绪语：גליקלעכן נייעם יאָר &lt;/li&gt;

  &lt;li&gt;印地语：नया साल मुबारक हो &lt;/li&gt;

  &lt;li&gt;印尼语：Selamat tahun baru &lt;/li&gt;

  &lt;li&gt;英语：Happy new year &lt;/li&gt;

  &lt;li&gt;越南语：Chúc mừng năm mới &lt;/li&gt;

  &lt;li&gt;中文(繁体)：新年快樂 &lt;/li&gt;

  &lt;li&gt;中文(简体)：新年快乐&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="http://gist.github.com/263486"&gt;所有代码&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;相关文章&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://blog.zhaojie.me/2009/12/merry-christmas-in-fifty-languages-1-analysis.html"&gt;五十种语言的“圣诞快乐”（上）：分析与实现&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;五十种语言的“圣诞快乐”（下）：F#实现&lt;/li&gt;
&lt;/ul&gt;</description>
      <comments>http://blog.zhaojie.me/2009/12/merry-christmas-in-fifty-languages-2-fsharp-async-workflow.html#comments</comments>
      <pubDate>Mon, 28 Dec 2009 03:18:00 GMT</pubDate>
      <lastBuildDate>Mon, 28 Dec 2009 03:18:00 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/cutting-edge/">技术尝鲜</category>
      <category domain="http://blog.zhaojie.me/language/">语言编程</category>
      <title>五十种语言的“圣诞快乐”（上）：分析与实现</title>
      <link>http://blog.zhaojie.me/2009/12/merry-christmas-in-fifty-languages-1-analysis.html</link>
      <guid>http://blog.zhaojie.me/2009/12/merry-christmas-in-fifty-languages-1-analysis.html</guid>
      <description>&lt;p&gt;圣诞节到了，于是在某个邮件列表上收到了这样一封信，“五种语言的圣诞快乐”：&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;汉语版：圣诞快乐！ &lt;/li&gt;    &lt;li&gt;英语版：麦瑞克瑞死没死！ &lt;/li&gt;    &lt;li&gt;俄语版：买个萝卜切吧切吧炖了吧！ &lt;/li&gt;    &lt;li&gt;韩语版：空起哇撒起哇, 米死搭！ &lt;/li&gt;    &lt;li&gt;日语版：锅你得洗哇，碗你得洗哇，盆你得洗哇，锅碗盆你都得洗了哇！ &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;后来有人贴了个更全的，于是有人猜测“这不是使用Google翻译做的吧？”哗，有意思的，我心想。以前也用过一个别人封装好的程序集，可以调用在线的Google Translate服务进行翻译。那么，我们现在自己来试试看吧。&lt;/p&gt;  &lt;h1&gt;使用Google Translate&lt;/h1&gt;  &lt;p&gt;&lt;a href="http://translate.google.cn/"&gt;Google Translate&lt;/a&gt;是一个在线工具，可以翻译五十多种语言。可惜的是，Google Translate并没有像&lt;a href="http://www.microsofttranslator.com/"&gt;Bing翻译&lt;/a&gt;那样直接提供&lt;a href="http://msdn.microsoft.com/en-us/library/dd576285.aspx"&gt;RESTful&lt;/a&gt;和&lt;a href="http://msdn.microsoft.com/en-us/library/dd576292.aspx"&gt;SOAP&lt;/a&gt;形式的API，不过这也给了我们一些探索的乐趣。目前Google Translate只提供&lt;a href="http://translate.google.cn/translate_tools?hl=zh-CN&amp;amp;layout=1&amp;amp;eotf=1"&gt;一个脚本&lt;/a&gt;，您可以把它嵌入到网页中，这样便可以使用其翻译功能了。例如，您可以在页面上放置这样的内容：&lt;/p&gt;  &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;div &lt;/span&gt;&lt;span style="color: red"&gt;id&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;google_translate_element&amp;quot;&amp;gt;&lt;/span&gt;圣诞快乐&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;div&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;

&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;script&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
    function &lt;/span&gt;googleTranslateElementInit() {
        &lt;span style="color: blue"&gt;new &lt;/span&gt;google.translate.TranslateElement({
            pageLanguage: &lt;span style="color: #a31515"&gt;'zh-CN'
        &lt;/span&gt;}, &lt;span style="color: #a31515"&gt;'google_translate_element'&lt;/span&gt;);
    }
&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;script&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;

&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;script &lt;/span&gt;&lt;span style="color: red"&gt;src&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;http://translate.google.com/translate_a/element.js?cb=googleTranslateElementInit&amp;quot;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;script&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;于是乎：&lt;/p&gt;
&lt;img src="http://img.zhaojie.me/blog/168980/o_translate-merry-chistmas-1.png" /&gt; 

&lt;p&gt;以上是我选择将其翻译为英语后的结果——当然Google Translate可以让你选择五十多种目标语言。&lt;/p&gt;

&lt;h1&gt;获取语言信息&lt;/h1&gt;

&lt;p&gt;使用Fiddler抓包后便可以发现，在页面加载时Google Translate的脚本首先会去加载所有它支持的语言：&lt;/p&gt;

&lt;pre class="code"&gt;GET /translate_a/l?client=te&amp;amp;hl=en&amp;amp;cb=_callbacks_._0g3matv3f HTTP/1.1
Accept: */*
Referer: http://localhost:46714/translate.html
Accept-Language: en-us
User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; SLCC1; .NET CLR 2.0.50727; .NET CLR 3.0.30729; .NET CLR 3.5.30729; .NET4.0C; .NET4.0E; OfficeLiveConnector.1.3; OfficeLivePatch.0.0)
Accept-Encoding: gzip, deflate
Host: translate.googleapis.com
Connection: Keep-Alive&lt;/pre&gt;

&lt;p&gt;这样便会得到这样的结果：&lt;/p&gt;

&lt;pre class="code"&gt;_callbacks_._0g3matv3f({'sl':{'auto':'Detect language','af':'Afrikaans','sq':'Albanian','ar':'Arabic','be':'Belarusian','bg':'Bulgarian','ca':'Catalan','zh-CN':'Chinese','hr':'Croatian','cs':'Czech','da':'Danish','nl':'Dutch','en':'English','et':'Estonian','tl':'Filipino','fi':'Finnish','fr':'French','gl':'Galician','de':'German','el':'Greek','iw':'Hebrew','hi':'Hindi','hu':'Hungarian','is':'Icelandic','id':'Indonesian','ga':'Irish','it':'Italian','ja':'Japanese','ko':'Korean','lv':'Latvian','lt':'Lithuanian','mk':'Macedonian','ms':'Malay','mt':'Maltese','no':'Norwegian','fa':'Persian','pl':'Polish','pt':'Portuguese','ro':'Romanian','ru':'Russian','sr':'Serbian','sk':'Slovak','sl':'Slovenian','es':'Spanish','sw':'Swahili','sv':'Swedish','th':'Thai','tr':'Turkish','uk':'Ukrainian','vi':'Vietnamese','cy':'Welsh','yi':'Yiddish'},'tl':{'af':'Afrikaans','sq':'Albanian','ar':'Arabic','be':'Belarusian','bg':'Bulgarian','ca':'Catalan','zh-CN':'Chinese (Simplified)','zh-TW':'Chinese (Traditional)','hr':'Croatian','cs':'Czech','da':'Danish','nl':'Dutch','en':'English','et':'Estonian','tl':'Filipino','fi':'Finnish','fr':'French','gl':'Galician','de':'German','el':'Greek','iw':'Hebrew','hi':'Hindi','hu':'Hungarian','is':'Icelandic','id':'Indonesian','ga':'Irish','it':'Italian','ja':'Japanese','ko':'Korean','lv':'Latvian','lt':'Lithuanian','mk':'Macedonian','ms':'Malay','mt':'Maltese','no':'Norwegian','fa':'Persian','pl':'Polish','pt':'Portuguese','ro':'Romanian','ru':'Russian','sr':'Serbian','sk':'Slovak','sl':'Slovenian','es':'Spanish','sw':'Swahili','sv':'Swedish','th':'Thai','tr':'Turkish','uk':'Ukrainian','vi':'Vietnamese','cy':'Welsh','yi':'Yiddish'}})&lt;/pre&gt;

&lt;p&gt;不过，您一定发现了，这些数据为什么是英文的呢？根据经验，这是由浏览器的语言首选项决定的。因此，我将zh-CN加入语言列表中的最上方，在IE里可以在Tools – Internet Options的General标签中设置Languages：&lt;/p&gt;
&lt;img src="http://img.zhaojie.me/blog/168980/o_translate-merry-chistmas-2.png" /&gt; 

&lt;p&gt;此时再次刷新页面，就会发现界面变成了中文，而Google Translate也会使用另外的地址来加载语言信息：&lt;/p&gt;

&lt;pre class="code"&gt;GET /translate_a/l?client=te&amp;amp;hl=&lt;font color="#ff0000"&gt;zh-CN&lt;/font&gt;&amp;amp;cb=_callbacks_._0g3mb650r HTTP/1.1
Accept: */*
Referer: http://localhost:46714/translate.html
Accept-Language: zh-CN,en-US;q=0.5
User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; SLCC1; .NET CLR 2.0.50727; .NET CLR 3.0.30729; .NET CLR 3.5.30729; .NET4.0C; .NET4.0E; OfficeLiveConnector.1.3; OfficeLivePatch.0.0)
Accept-Encoding: gzip, deflate
Host: translate.googleapis.com
Connection: Keep-Alive&lt;/pre&gt;

&lt;p&gt;其得到的结果是：&lt;/p&gt;

&lt;pre class="code"&gt;_callbacks_._0g3mb650r({'sl':{'auto':'检测语言','sq':'阿尔巴尼亚语','ar':'阿拉伯语','ga':'爱尔兰语','et':'爱沙尼亚语','be':'白俄罗斯语','bg':'保加利亚语','is':'冰岛语','pl':'波兰语','fa':'波斯语','af':'布尔文(南非荷兰语)','da':'丹麦语','de':'德语','ru':'俄语','fr':'法语','tl':'菲律宾语','fi':'芬兰语','ko':'韩语','nl':'荷兰语','gl':'加利西亚语','ca':'加泰罗尼亚语','cs':'捷克语','hr':'克罗地亚语','lv':'拉脱维亚语','lt':'立陶宛语','ro':'罗马尼亚语','mt':'马耳他语','ms':'马来语','mk':'马其顿语','no':'挪威语','pt':'葡萄牙语','ja':'日语','sv':'瑞典语','sr':'塞尔维亚语','sk':'斯洛伐克语','sl':'斯洛文尼亚语','sw':'斯瓦希里语','th':'泰语','tr':'土耳其语','cy':'威尔士语','uk':'乌克兰语','es':'西班牙语','iw':'希伯来语','el':'希腊语','hu':'匈牙利语','it':'意大利语','yi':'意第绪语','hi':'印地语','id':'印尼语','en':'英语','vi':'越南语','zh-CN':'中文'},'tl':&lt;span style="color: red"&gt;{'sq':'阿尔巴尼亚语','ar':'阿拉伯语','ga':'爱尔兰语','et':'爱沙尼亚语','be':'白俄罗斯语','bg':'保加利亚语','is':'冰岛语','pl':'波兰语','fa':'波斯语','af':'布尔文(南非荷兰语)','da':'丹麦语','de':'德语','ru':'俄语','fr':'法语','tl':'菲律宾语','fi':'芬兰语','ko':'韩语','nl':'荷兰语','gl':'加利西亚语','ca':'加泰罗尼亚语','cs':'捷克语','hr':'克罗地亚语','lv':'拉脱维亚语','lt':'立陶宛语','ro':'罗马尼亚语','mt':'马耳他语','ms':'马来语','mk':'马其顿语','no':'挪威语','pt':'葡萄牙语','ja':'日语','sv':'瑞典语','sr':'塞尔维亚语','sk':'斯洛伐克语','sl':'斯洛文尼亚语','sw':'斯瓦希里语','th':'泰语','tr':'土耳其语','cy':'威尔士语','uk':'乌克兰语','es':'西班牙语','iw':'希伯来语','el':'希腊语','hu':'匈牙利语','it':'意大利语','yi':'意第绪语','hi':'印地语','id':'印尼语','en':'英语','vi':'越南语','zh-TW':'中文(繁体)','zh-CN':'中文(简体)'}&lt;/span&gt;})&lt;/pre&gt;

&lt;p&gt;而其中标红的部分，便是tl（我猜测是Target Language的意思）所对应的JSON格式，我们可以使用以下代码来获取所有的语言信息：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;private static &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Dictionary&lt;/span&gt;&amp;lt;&lt;span style="color: blue"&gt;string&lt;/span&gt;, &lt;span style="color: blue"&gt;string&lt;/span&gt;&amp;gt; GetLanguages()
{
    &lt;span style="color: blue"&gt;var &lt;/span&gt;url =
        &lt;span style="color: #a31515"&gt;&amp;quot;http://translate.googleapis.com&amp;quot; &lt;/span&gt;+
        &lt;span style="color: #a31515"&gt;&amp;quot;/translate_a/l?client=te&amp;amp;hl=zh-CN&amp;amp;cb=_callbacks_._0g3mb650r&amp;quot;&lt;/span&gt;;

    &lt;span style="color: blue"&gt;var &lt;/span&gt;webClient = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;WebClient&lt;/span&gt;();
    &lt;span style="color: blue"&gt;var &lt;/span&gt;script = webClient.DownloadString(url);

    &lt;span style="color: blue"&gt;var &lt;/span&gt;json = &lt;span style="color: #2b91af"&gt;Regex&lt;/span&gt;.Match(script, &lt;span style="color: #a31515"&gt;&amp;#64;&amp;quot;'tl':({.+})}\)&amp;quot;&lt;/span&gt;).Groups[1].Value;
    &lt;span style="color: blue"&gt;var &lt;/span&gt;serializer = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;JavaScriptSerializer&lt;/span&gt;();
    &lt;span style="color: blue"&gt;return &lt;/span&gt;serializer.Deserialize&amp;lt;&lt;span style="color: #2b91af"&gt;Dictionary&lt;/span&gt;&amp;lt;&lt;span style="color: blue"&gt;string&lt;/span&gt;, &lt;span style="color: blue"&gt;string&lt;/span&gt;&amp;gt;&amp;gt;(json);
}&lt;/pre&gt;

&lt;h1&gt;进行翻译&lt;/h1&gt;

&lt;p&gt;点击页面上的下拉列表可以进行翻译。例如我们选择“英语”之后，Fiddler便会捕获到一个POST请求：&lt;/p&gt;

&lt;pre class="code"&gt;POST /translate_a/t?client=te&amp;amp;format=html&amp;amp;v=1.0 HTTP/1.1
Accept: */*
Accept-Language: zh-CN
Referer: http://translate.googleapis.com/translate_static/js/element/hrs.swf
x-flash-version: 10,0,32,18
Content-Type: application/x-www-form-urlencoded
Google-Translate-Referer: http://localhost:46714/translate.html
Content-Length: 58
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; SLCC1; .NET CLR 2.0.50727; .NET CLR 3.0.30729; .NET CLR 3.5.30729; .NET4.0C; .NET4.0E; OfficeLiveConnector.1.3; OfficeLivePatch.0.0)
Host: translate.googleapis.com
Connection: Keep-Alive
Pragma: no-cache

q=%E5%9C%A3%E8%AF%9E%E5%BF%AB%E4%B9%90&amp;amp;sl=zh-CN&amp;amp;tl=en&amp;amp;tc=1&lt;/pre&gt;

&lt;p&gt;可以看到，需要翻译的文字将作为q被传输到服务器端。这个请求会得到翻译后的结果：&lt;/p&gt;

&lt;pre class="code"&gt;&amp;quot;Merry Christmas&amp;quot;&lt;/pre&gt;

&lt;p&gt;于是代码也就很容易写出了：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;private static string &lt;/span&gt;Translate(&lt;span style="color: blue"&gt;string &lt;/span&gt;source, &lt;span style="color: blue"&gt;string &lt;/span&gt;sl, &lt;span style="color: blue"&gt;string &lt;/span&gt;tl)
{
    &lt;span style="color: blue"&gt;var &lt;/span&gt;url =
        &lt;span style="color: #a31515"&gt;&amp;quot;https://translate.googleapis.com&amp;quot; &lt;/span&gt;+
        &lt;span style="color: #a31515"&gt;&amp;quot;/translate_a/t?client=te&amp;amp;format=html&amp;amp;v=1.0&amp;quot;&lt;/span&gt;;

    &lt;span style="color: blue"&gt;var &lt;/span&gt;data = &lt;span style="color: #2b91af"&gt;String&lt;/span&gt;.Format(
        &lt;span style="color: #a31515"&gt;&amp;quot;q={0}&amp;amp;sl={1}&amp;amp;tl={2}&amp;amp;tc=1&amp;quot;&lt;/span&gt;,
        &lt;span style="color: #2b91af"&gt;HttpUtility&lt;/span&gt;.UrlEncode(source), sl, tl);

    &lt;span style="color: blue"&gt;var &lt;/span&gt;webClient = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;WebClient&lt;/span&gt;();
    webClient.Encoding = &lt;span style="color: #2b91af"&gt;Encoding&lt;/span&gt;.UTF8;
    webClient.Headers.Add(
        &lt;span style="color: #2b91af"&gt;HttpRequestHeader&lt;/span&gt;.UserAgent,
        &lt;span style="color: #a31515"&gt;&amp;quot;Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0;)&amp;quot;&lt;/span&gt;);

    &lt;span style="color: blue"&gt;var &lt;/span&gt;json = webClient.UploadString(url, data);
    &lt;span style="color: blue"&gt;var &lt;/span&gt;serializer = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;JavaScriptSerializer&lt;/span&gt;();
    &lt;span style="color: blue"&gt;return &lt;/span&gt;serializer.Deserialize&amp;lt;&lt;span style="color: blue"&gt;string&lt;/span&gt;&amp;gt;(json);
}&lt;/pre&gt;

&lt;p&gt;在试验过程中，您可以使用Fiddler的Request Builder功能来发起一些测试请求，这样便可以得知怎么样的Header信息可以获得正确的结果。例如在这里，我发现如果不添加User Agent信息，Google Translate便会返回一些非常奇怪的内容。&lt;/p&gt;

&lt;h1&gt;组合&lt;/h1&gt;

&lt;p&gt;既然有了以上两个方法，输出翻译结果也再简单不过了：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;var &lt;/span&gt;languages = GetLanguages();

&lt;span style="color: blue"&gt;var &lt;/span&gt;targetLanguages = languages.Select(
    p =&amp;gt; &lt;span style="color: #2b91af"&gt;String&lt;/span&gt;.Format(
        &lt;span style="color: #a31515"&gt;&amp;quot;{0}: {1}&amp;quot;&lt;/span&gt;,
        p.Value,
        Translate(&lt;span style="color: #a31515"&gt;&amp;quot;圣诞快乐&amp;quot;&lt;/span&gt;, &lt;span style="color: #a31515"&gt;&amp;quot;zh-CN&amp;quot;&lt;/span&gt;, p.Key)));

&lt;span style="color: #2b91af"&gt;File&lt;/span&gt;.WriteAllLines(&lt;span style="color: #a31515"&gt;&amp;quot;output.txt&amp;quot;&lt;/span&gt;, targetLanguages.ToArray());&lt;/pre&gt;

&lt;p&gt;由于语言非常古怪，因此无法在Console上输出，我只能将其直接写到UTF-8的文件中去——最后的结果还是&lt;a href="javascript:;" onclick="document.getElementById('result_dNfOIj').style.display = 'block';"&gt;相当有趣&lt;/a&gt;的。&lt;/p&gt;

&lt;ul style="display: none" id="result_dNfOIj"&gt;
  &lt;li&gt;阿尔巴尼亚语：Gëzuar Krishtlindjet &lt;/li&gt;

  &lt;li&gt;阿拉伯语：عيد ميلاد مجيد &lt;/li&gt;

  &lt;li&gt;爱尔兰语：Nollaig Shona &lt;/li&gt;

  &lt;li&gt;爱沙尼亚语：Häid jõule &lt;/li&gt;

  &lt;li&gt;白俄罗斯语：З Калядамі &lt;/li&gt;

  &lt;li&gt;保加利亚语：Весела Коледа &lt;/li&gt;

  &lt;li&gt;冰岛语：Gleðlieg jól &lt;/li&gt;

  &lt;li&gt;波兰语：Wesołych Świąt &lt;/li&gt;

  &lt;li&gt;波斯语：کریسمس مبارک &lt;/li&gt;

  &lt;li&gt;布尔文(南非荷兰语)：Geseënde Kersfees &lt;/li&gt;

  &lt;li&gt;丹麦语：Glædelig jul &lt;/li&gt;

  &lt;li&gt;德语：Frohe Weihnachten &lt;/li&gt;

  &lt;li&gt;俄语：С Рождеством &lt;/li&gt;

  &lt;li&gt;法语：Joyeux Noël &lt;/li&gt;

  &lt;li&gt;菲律宾语：Maligayang Pasko &lt;/li&gt;

  &lt;li&gt;芬兰语：Hyvää joulua &lt;/li&gt;

  &lt;li&gt;韩语：즐거운 성탄절 되세요 &lt;/li&gt;

  &lt;li&gt;荷兰语：Vrolijk kerstfeest &lt;/li&gt;

  &lt;li&gt;加利西亚语：Feliz Nadal &lt;/li&gt;

  &lt;li&gt;加泰罗尼亚语：Bon Nadal &lt;/li&gt;

  &lt;li&gt;捷克语：Veselé vánoce &lt;/li&gt;

  &lt;li&gt;克罗地亚语：Sretan Božić &lt;/li&gt;

  &lt;li&gt;拉脱维亚语：Priecīgus Ziemassvētkus &lt;/li&gt;

  &lt;li&gt;立陶宛语：Linksmų Kalėdų &lt;/li&gt;

  &lt;li&gt;罗马尼亚语：Crăciun fericit &lt;/li&gt;

  &lt;li&gt;马耳他语：li-Mliied it-Tajjeb &lt;/li&gt;

  &lt;li&gt;马来语：Selamat Hari Krismas &lt;/li&gt;

  &lt;li&gt;马其顿语：Среќен Божиќ &lt;/li&gt;

  &lt;li&gt;挪威语：God jul &lt;/li&gt;

  &lt;li&gt;葡萄牙语：Feliz Natal &lt;/li&gt;

  &lt;li&gt;日语：メリークリスマス &lt;/li&gt;

  &lt;li&gt;瑞典语：God jul &lt;/li&gt;

  &lt;li&gt;塞尔维亚语：Срећан Божић &lt;/li&gt;

  &lt;li&gt;斯洛伐克语：Veselé vánoce &lt;/li&gt;

  &lt;li&gt;斯洛文尼亚语：Vesel božič &lt;/li&gt;

  &lt;li&gt;斯瓦希里语：Krisimasi Njema &lt;/li&gt;

  &lt;li&gt;泰语：สุขสันต์วันคริสต์มาส &lt;/li&gt;

  &lt;li&gt;土耳其语：Mutlu Noeller &lt;/li&gt;

  &lt;li&gt;威尔士语：Nadolig Llawen &lt;/li&gt;

  &lt;li&gt;乌克兰语：З Різдвом &lt;/li&gt;

  &lt;li&gt;西班牙语：Feliz Navidad &lt;/li&gt;

  &lt;li&gt;希伯来语：חג מולד שמח &lt;/li&gt;

  &lt;li&gt;希腊语：Καλά Χριστούγεννα &lt;/li&gt;

  &lt;li&gt;匈牙利语：Boldog Karácsonyt &lt;/li&gt;

  &lt;li&gt;意大利语：Buon Natale &lt;/li&gt;

  &lt;li&gt;意第绪语：לעבעדיק ניטל &lt;/li&gt;

  &lt;li&gt;印地语：क्रिसमस की शुभकामनाएँ &lt;/li&gt;

  &lt;li&gt;印尼语：Selamat Hari Natal &lt;/li&gt;

  &lt;li&gt;英语：Merry Christmas &lt;/li&gt;

  &lt;li&gt;越南语：Giáng sinh Vui vẻ &lt;/li&gt;

  &lt;li&gt;中文(繁体)：聖誕快樂 &lt;/li&gt;

  &lt;li&gt;中文(简体)：圣诞快乐 &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="http://gist.github.com/263486#file_merry_christmas_in_fifty_languages.cs"&gt;完整代码&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;相关文章&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;五十种语言的“圣诞快乐”（上）：分析与实现&lt;/li&gt;
&lt;li&gt;&lt;a href="http://blog.zhaojie.me/2009/12/merry-christmas-in-fifty-languages-2-fsharp-async-workflow.html"&gt;五十种语言的“圣诞快乐”（下）：F#实现&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <comments>http://blog.zhaojie.me/2009/12/merry-christmas-in-fifty-languages-1-analysis.html#comments</comments>
      <pubDate>Fri, 25 Dec 2009 03:17:00 GMT</pubDate>
      <lastBuildDate>Fri, 25 Dec 2009 03:17:00 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/asp-net/">ASP.NET</category>
      <category domain="http://blog.zhaojie.me/language/">语言编程</category>
      <category domain="http://blog.zhaojie.me/cutting-edge/">技术尝鲜</category>
      <title>数十行F#打造简易Comet聊天服务</title>
      <link>http://blog.zhaojie.me/2009/12/fsharp-comet-prototype.html</link>
      <guid>http://blog.zhaojie.me/2009/12/fsharp-comet-prototype.html</guid>
      <description>&lt;p&gt;普通的Web应用程序，都是靠大量HTTP短连接维持的。如实现一个聊天服务时，客户端会不断轮询服务器端索要新消息。这种做法的优势在于简单有效，因此广为目前的聊天服务所采用。不过Comet技术与之不同，简单地说，&lt;a href="http://en.wikipedia.org/wiki/Comet_(programming)"&gt;Comet&lt;/a&gt;便是指服务器推（Server-Push）技术。它的实现方式是（这里只讨论基于浏览器的Web平台）在浏览器与服务器之间建立一个长连接，待获得消息之后立即返回。否则持续等待，直至超时。客户端得到消息或超时之后，又会立即建立另一个长连接。Comet技术的最大优势，自然就是很高的即使性。&lt;/p&gt;  &lt;p&gt;如果要在ASP.NET平台上实现Comet技术，那么自然需要在服务器端使用异步请求处理。如果是普通处理方式的话，每个请求都会占用一个工作线程，要知道Comet是“长连接”，因此不需要多少客户端便会占用大量的线程，这对资源消耗是巨大的。如果是异步请求的话，虽然客户端和服务器端之间一直保持着连接，但是客户端在等待消息的时候是不占用线程的，直到“超时”或“消息到达”时才继续执行。&lt;/p&gt;  &lt;p&gt;以前&lt;a href="http://www.codeproject.com/KB/aspnet/CometAsync.aspx"&gt;也有人实现过基于ASP.NET的Comet服务原型&lt;/a&gt;，不过是使用C#的。而现在我们用F#来实现这个功能。您会发现F#对于此类异步场景有其独特的优势。&lt;/p&gt;  &lt;p&gt;F#常用的工作单元是“模块”，其中定义了大量函数或字段。例如我们要打造一个聊天服务的话，我便定义了一个Chat模块：&lt;/p&gt;  &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;#light

module internal &lt;/span&gt;Comet.Chating.Chat

&lt;span style="color: blue"&gt;open &lt;/span&gt;System
&lt;span style="color: blue"&gt;open &lt;/span&gt;System.Collections.Concurrent

&lt;span style="color: blue"&gt;type &lt;/span&gt;ChatMsg = {
    From: string;
    Text: string;&lt;span style="color: green"&gt;
&lt;/span&gt;}

&lt;span style="color: blue"&gt;let private &lt;/span&gt;agentCache = &lt;span style="color: blue"&gt;new &lt;/span&gt;ConcurrentDictionary&amp;lt;string, MailboxProcessor&amp;lt;ChatMsg&amp;gt;&amp;gt;()

&lt;span style="color: blue"&gt;let private &lt;/span&gt;agentFactory = &lt;span style="color: blue"&gt;new &lt;/span&gt;Func&amp;lt;string, MailboxProcessor&amp;lt;ChatMsg&amp;gt;&amp;gt;(&lt;span style="color: blue"&gt;fun &lt;/span&gt;_ &lt;span style="color: blue"&gt;-&amp;gt; 
    &lt;/span&gt;MailboxProcessor.Start(&lt;span style="color: blue"&gt;fun &lt;/span&gt;o &lt;span style="color: blue"&gt;-&amp;gt; &lt;/span&gt;async { o |&amp;gt; ignore }))

&lt;span style="color: blue"&gt;let private &lt;/span&gt;GetAgent name = agentCache.GetOrAdd(name, agentFactory)&lt;/pre&gt;

&lt;p&gt;在这里我构建了一个名为ChatMsg的Record类型，一个ChatMsg对象便是一条消息。然后，我使用一个名为agentCache的ConcurrentDictionary对象来保存每个用户所对应的聊天队列——MailboxProcessor。它是F#核心库中内置的，用于实现消息传递式并发的组件，非常轻量级，因此我为每个用户分配一个也只使用很少的资源。GetAgent函数的作用是根据用户的名称获取对应的MailboxProcessor对象，自不必多说。&lt;/p&gt;

&lt;p&gt;Chat模块中还定义了send和receive两个公开方法，如下：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;let &lt;/span&gt;send fromName toName msg = 
    &lt;span style="color: blue"&gt;let &lt;/span&gt;agent = GetAgent toName&lt;span style="color: green"&gt;
    &lt;/span&gt;{ From = fromName; Text = msg; } |&amp;gt; agent.Post

&lt;span style="color: blue"&gt;let &lt;/span&gt;receive name = 
    &lt;span style="color: blue"&gt;let rec &lt;/span&gt;receive' (agent: MailboxProcessor&amp;lt;ChatMsg&amp;gt;) messages = 
        async {
            &lt;span style="color: blue"&gt;let! &lt;/span&gt;msg = agent.TryReceive &lt;span style="color: brown"&gt;0
            &lt;/span&gt;&lt;span style="color: blue"&gt;match &lt;/span&gt;msg &lt;span style="color: blue"&gt;with
            &lt;/span&gt;| None &lt;span style="color: blue"&gt;-&amp;gt; return &lt;/span&gt;messages
            | Some s &lt;span style="color: blue"&gt;-&amp;gt; return! &lt;/span&gt;receive' agent (s :: messages)
        }

    &lt;span style="color: blue"&gt;let &lt;/span&gt;agent = GetAgent name

    async {
        &lt;span style="color: blue"&gt;let! &lt;/span&gt;messages = receive' agent List.empty
        &lt;span style="color: blue"&gt;if &lt;/span&gt;(not messages.IsEmpty) &lt;span style="color: blue"&gt;then return &lt;/span&gt;messages
        &lt;span style="color: blue"&gt;else
            let! &lt;/span&gt;msg = agent.TryReceive &lt;span style="color: brown"&gt;3000
            &lt;/span&gt;&lt;span style="color: blue"&gt;match &lt;/span&gt;msg &lt;span style="color: blue"&gt;with
            &lt;/span&gt;| None &lt;span style="color: blue"&gt;-&amp;gt; return &lt;/span&gt;[]
            | Some s &lt;span style="color: blue"&gt;-&amp;gt; return &lt;/span&gt;[s]
    }&lt;/pre&gt;

&lt;p&gt;send方法接受3个参数，没有返回值，它的实现只是简单地构造一个ChatMsg对象，并塞入对应的MailboxProcessor。不过receive方法是这里最关键的部分（没有之一）。receive函数的作用是接受并返回MailboxProcessor中已有的对象，或者等待3秒钟后超时——这么说其实不太妥当，因为receive方法其实只是构造了一个“做这件事情”的Async Workflow，而还没有真正执行它。至于它是如何执行的，我们稍候再谈。&lt;/p&gt;

&lt;p&gt;receive函数的逻辑是这样的：首先我们构造一个辅助函数receive’来“尝试获取”队列中已有的所有消息。receive’是一个递归函数，每次获取一个，并递归获取剩余的消息。agent.TryReceive函数接受0，表示查询队列，并立即返回一个Option&amp;lt;ChatMsg&amp;gt;结果，如果这个结果为None，则表示队列已为空。于是在receive这个主函数中，便先使用receive’函数获取已有消息，如果存在则立即返回，否则便接收3秒钟内获得的第一个消息，如果3秒结束还没有收到则返回None。&lt;/p&gt;

&lt;p&gt;在receive和receive’函数中都使用了let!获取agent.TryReceive函数的结果。let!是F#中构造Workflow的关键字，它起到了“语法糖”的作用。例如，以下的Async Workflow：&lt;/p&gt;

&lt;pre class="code"&gt;async {
    &lt;span style="color: blue"&gt;let &lt;/span&gt;req = WebRequest.Create(&lt;span style="color: maroon"&gt;&amp;quot;http://www.cnblogs.com/&amp;quot;&lt;/span&gt;)
    &lt;span style="color: blue"&gt;let! &lt;/span&gt;resp = req.GetResponseAsync()
    &lt;span style="color: blue"&gt;let &lt;/span&gt;stream = resp.GetResponseStream()
    &lt;span style="color: blue"&gt;let &lt;/span&gt;reader = &lt;span style="color: blue"&gt;new &lt;/span&gt;StreamReader(stream)
    &lt;span style="color: blue"&gt;let! &lt;/span&gt;html = reader.ReadToEndAsync()
    html
}&lt;/pre&gt;

&lt;p&gt;事实上在“解糖”后就变成了：&lt;/p&gt;

&lt;pre class="code"&gt;async.Delay(&lt;span style="color: blue"&gt;fun &lt;/span&gt;() &lt;span style="color: blue"&gt;-&amp;gt;
    &lt;/span&gt;async.Let(WebRequest.Create(&lt;span style="color: maroon"&gt;&amp;quot;http://www.cnblogs.com/&amp;quot;&lt;/span&gt;), (&lt;span style="color: blue"&gt;fun &lt;/span&gt;req &lt;span style="color: blue"&gt;-&amp;gt;
        &lt;/span&gt;&lt;font color="#ff0000"&gt;async.Bind&lt;/font&gt;(req.GetResponseAsync(), (&lt;span style="color: blue"&gt;fun &lt;/span&gt;resp &lt;span style="color: blue"&gt;-&amp;gt;
            &lt;/span&gt;async.Let(resp.GetResponseStream(), (&lt;span style="color: blue"&gt;fun &lt;/span&gt;stream &lt;span style="color: blue"&gt;-&amp;gt;
                &lt;/span&gt;async.Let(&lt;span style="color: blue"&gt;new &lt;/span&gt;StreamReader(stream), (&lt;span style="color: blue"&gt;fun &lt;/span&gt;reader &lt;span style="color: blue"&gt;-&amp;gt;
                    &lt;/span&gt;&lt;font color="#ff0000"&gt;async.Bind&lt;/font&gt;(reader.ReadToEndAsync(), (&lt;span style="color: blue"&gt;fun &lt;/span&gt;html &lt;span style="color: blue"&gt;-&amp;gt;
                        &lt;/span&gt;async.Return(html))))))))))&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;let!关键字则会转化为Bind函数调用，Bind调用有两个参数，第一个参数为Async&amp;lt;’a&amp;gt;类型，它便负责一个“回调”，待回调后才执行一个匿名函数——也就是Bind函数的第二个参数。可见，let!关键字的一个重要作用，便是将流程的“控制权”转交给“系统”，待合适的时候再继续执行下去。这便是关键，因为这样的话，在接受一个消息的时候，这等待的3秒钟是不占用任何线程的，也就是真正的纯异步。但是如果观察代码——难道不是纯粹的顺序型写法吗？&lt;/p&gt;

&lt;p&gt;这就是F#的神奇之处。&lt;/p&gt;

&lt;p&gt;在ASP.NET处理时需要Handler，于是在Send阶段便是简单的IHttpHandler：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;#light

namespace &lt;/span&gt;Comet.Chating

&lt;span style="color: blue"&gt;open &lt;/span&gt;Comet
&lt;span style="color: blue"&gt;open &lt;/span&gt;System
&lt;span style="color: blue"&gt;open &lt;/span&gt;System.Web

&lt;span style="color: blue"&gt;type &lt;/span&gt;SendHandler() =

    &lt;span style="color: blue"&gt;interface &lt;/span&gt;IHttpHandler &lt;span style="color: blue"&gt;with
        member &lt;/span&gt;h.IsReusable = &lt;span style="color: blue"&gt;false
        member &lt;/span&gt;h.ProcessRequest(context) = 
            &lt;span style="color: blue"&gt;let &lt;/span&gt;fromName = context.Request.Form.Item(&lt;span style="color: maroon"&gt;&amp;quot;from&amp;quot;&lt;/span&gt;);
            &lt;span style="color: blue"&gt;let &lt;/span&gt;toName = context.Request.Form.Item(&lt;span style="color: maroon"&gt;&amp;quot;to&amp;quot;&lt;/span&gt;)
            &lt;span style="color: blue"&gt;let &lt;/span&gt;msg = context.Request.Form.Item(&lt;span style="color: maroon"&gt;&amp;quot;msg&amp;quot;&lt;/span&gt;)
            Chat.send fromName toName msg
            context.Response.Write &lt;span style="color: maroon"&gt;&amp;quot;sent&amp;quot;
&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;而Receive阶段则是个异步的IHttpAsyncHandler：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;#light

namespace &lt;/span&gt;Comet.Chating

&lt;span style="color: blue"&gt;open &lt;/span&gt;Comet
&lt;span style="color: blue"&gt;open &lt;/span&gt;System
&lt;span style="color: blue"&gt;open &lt;/span&gt;System.Collections.Generic
&lt;span style="color: blue"&gt;open &lt;/span&gt;System.Web
&lt;span style="color: blue"&gt;open &lt;/span&gt;System.Web.Script.Serialization

&lt;span style="color: blue"&gt;type &lt;/span&gt;ReceiveHandler() =

    &lt;span style="color: blue"&gt;let mutable &lt;/span&gt;m_context = &lt;span style="color: blue"&gt;null
    let mutable &lt;/span&gt;m_endReceive = &lt;span style="color: blue"&gt;null

    interface &lt;/span&gt;IHttpAsyncHandler &lt;span style="color: blue"&gt;with
        member &lt;/span&gt;h.IsReusable = &lt;span style="color: blue"&gt;false
        member &lt;/span&gt;h.ProcessRequest(context) = failwith &lt;span style="color: maroon"&gt;&amp;quot;not supported&amp;quot;

        &lt;/span&gt;&lt;span style="color: blue"&gt;member &lt;/span&gt;h.BeginProcessRequest(c, cb, state) =
            m_context &amp;lt;- c

            &lt;span style="color: blue"&gt;let &lt;/span&gt;name = c.Request.QueryString.Item(&lt;span style="color: maroon"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;)
            &lt;span style="color: blue"&gt;let &lt;/span&gt;receive = Chat.receive name
            &lt;span style="color: blue"&gt;let &lt;/span&gt;beginReceive, e, _ = &lt;font color="#ff0000"&gt;Async.AsBeginEnd&lt;/font&gt; receive
            m_endReceive &amp;lt;- &lt;span style="color: blue"&gt;new &lt;/span&gt;Func&amp;lt;_, _&amp;gt;(e)

            beginWork (cb, state)

        &lt;span style="color: blue"&gt;member &lt;/span&gt;h.EndProcessRequest(ar) =
            &lt;span style="color: blue"&gt;let &lt;/span&gt;convert (m: Chat.ChatMsg) =
                &lt;span style="color: blue"&gt;let &lt;/span&gt;o = &lt;span style="color: blue"&gt;new &lt;/span&gt;Dictionary&amp;lt;_, _&amp;gt;();
                o.Add(&lt;span style="color: maroon"&gt;&amp;quot;from&amp;quot;&lt;/span&gt;, m.From)
                o.Add(&lt;span style="color: maroon"&gt;&amp;quot;text&amp;quot;&lt;/span&gt;, m.Text)&lt;span style="color: green"&gt;
                &lt;/span&gt;o

            &lt;span style="color: blue"&gt;let &lt;/span&gt;result = m_endReceive.Invoke ar
            &lt;span style="color: blue"&gt;let &lt;/span&gt;serializer = &lt;span style="color: blue"&gt;new &lt;/span&gt;JavaScriptSerializer()
            result
            |&amp;gt; List.map convert
            |&amp;gt; serializer.Serialize
            |&amp;gt; m_context.Response.Write&lt;/pre&gt;

&lt;p&gt;这里的关键是Async.AsBeginEnd函数，它将Chat.receive函数生成的Async Workflow转化成一组标准APM形式的begin/end对，然后我们只要把BeginProcessRequest和EndProcessReqeust的职责直接交给即可。剩下的，便是一些序列化成JSON的工作了。&lt;/p&gt;
&lt;script language="javascript" type="text/javascript"&gt;
function __openDemo__() {
    var uid = "u_" + Math.round(Math.random() * 100000) + "_" + new Date().getTime();
    window.open("http://51programming.com/Chat.aspx?name=" + uid);
}
&lt;/script&gt;

&lt;p&gt;于是我们可以新建一个Web项目，引用F#工程，在Web.config里配置两个Handler，再准备一个Chat.aspx页面即可。您可以在文末的链接中查看该页面的代码，&lt;a href="javascript:__openDemo__()"&gt;也可以在这里试用其效果&lt;/a&gt;。作为演示页面，您其实只能“自己给自己”发送消息，其主要目的是查看其响应时间而已。例如，以下便是使用效果一例：&lt;/p&gt;

&lt;pre class="code"&gt;2 - receiving...
3026 - received nothing (3024ms)
3026 - receiving...
6055 - received nothing (3028ms)
6055 - receiving...
7256 - sending 123654...
7268 - received: 123654 (&lt;font color="#ff0000"&gt;1213ms&lt;/font&gt;)
7268 - receiving...
10281 - received nothing (3013ms)
10281 - receiving...
13298 - received nothing (3017ms)
13298 - receiving...
13679 - sending 123456...
13698 - received: 123456 (&lt;font color="#ff0000"&gt;400ms&lt;/font&gt;)
13698 - receiving...
16716 - received nothing (3018ms)
16716 - receiving...
18256 - sending hello world...
18265 - received: hello world (&lt;font color="#ff0000"&gt;1549ms&lt;/font&gt;)
18266 - receiving...
21281 - received nothing (3015ms)
21281 - receiving...&lt;/pre&gt;

&lt;p&gt;可见，如果没有收到消息，那么receive操作会在3秒钟后返回。当send一条消息后，先前的receive操作便会立即获得消息了，即无需等待3秒便可提前返回。这便是Comet的效果。&lt;/p&gt;

&lt;p&gt;至于性能，我写了一个客户端小程序，用于模拟大量用户同时聊天，每个用户每隔1秒便给另外5个用户发送一条消息，然后查看这条消息收到时产生多少的延迟。经过本机测试（2.4GHz双核，2G内存），当超过2K个在线用户时（即2000个长连接）延迟便超过了1秒——到20K还差不多。这个性能其实并不理想。不过，我这个测试也很一般。因为测试环境相当马虎，大量程序（如N个VS）基本上已经完全用满了所有的物理内存，测试客户端和服务器也是同一台机器，甚至代码也是Debug编译的……而根据监视，测试用的客户端小程序CPU占用超过50%，而服务器进程对应的w3wp.exe的CPU占用却小于10%。因此，我们可以这样推断，其实服务器端的性能并没有用足，也有可能是MailboxProcessor的调度方式不甚理想。至于具体是什么原因，我还在调查之中。&lt;/p&gt;

&lt;p&gt;最后我想说的是，这个Comet实现只是一个原型，我最想说明的问题其实是F#在异步编程中的优势。目前我写的一些程序，例如一些网络爬虫，都已经使用F#进行开发了，因为它的Async Workflow实在是过于好用，为我省了太多力气。同时我还想证明，“语言特性”并非不重要，它对于编程的简化也是至关重要的。在我看来，“类库”也好，“框架”也罢都是可以补充的，但是语言特性是个无法突破的“限制”。例如，异步编程对于F#来说简化了不少，这是因为我们可以使用顺序的方式编写异步程序。在C#中略有不足，但还有yield可以起到相当作用，因此我们可以&lt;a href="http://blog.zhaojie.me/2009/02/simplify-async-programming-1.html"&gt;使用CCR和AsyncEnumerator简化异步操作&lt;/a&gt;。但如果您使用的是Java这种劣质语言……因此，放弃Java，使用Scala吧。&lt;/p&gt;

&lt;p&gt;值得一提的是，Async Workflow并不是F#的语言特性，F#的语言特性是Workflow，而Async Workflow其实只是实现了一个Workflow Builder，也就是那个async { ... }，以此来简化异步编程而已。PDC 09上关于F#对异步编程的支持&lt;a href="http://www.infoq.com/cn/news/2009/11/pdc09-fsharp"&gt;也有相应的介绍&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;&lt;a href="http://gist.github.com/253968"&gt;本文代码&lt;/a&gt;&lt;/p&gt;</description>
      <comments>http://blog.zhaojie.me/2009/12/fsharp-comet-prototype.html#comments</comments>
      <pubDate>Fri, 11 Dec 2009 04:00:00 GMT</pubDate>
      <lastBuildDate>Fri, 11 Dec 2009 04:00:00 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/dotnet/">.Net框架</category>
      <category domain="http://blog.zhaojie.me/cutting-edge/">技术尝鲜</category>
      <title>再谈Attribute性能优化方式：使用CCI Metadata</title>
      <link>http://blog.zhaojie.me/2009/11/more-on-attribute-cci.html</link>
      <guid>http://blog.zhaojie.me/2009/11/more-on-attribute-cci.html</guid>
      <description>&lt;p&gt;Attribute使用了反射，密集调用时会带来较大开销，因此我们上次&lt;a href="http://blog.zhaojie.me/2009/11/attribute-performance-improvement.html"&gt;提出了一些优化方式&lt;/a&gt;，这样就不会产生性能方面的问题了。这个优化方式的关键，主要是使用直接获得构造Attribute的元数据，然后自定义它们的生成方式并缓存，这样就避免了每次获取元数据及反射构造Attribute的开销。我从一开始就抱有这个优化的“思路”，但是上篇文章中最终的做法是受到了&lt;a href="http://www.cnblogs.com/heros/"&gt;heros&lt;/a&gt;同学的&lt;a href="http://blog.zhaojie.me/2009/11/getcustomattribute-always-returns-new-instances.html#1694231"&gt;提示&lt;/a&gt;才得出的，因为我一开始还根本不知道CustomAttributeData这个已然内置的类库。我当时在探索的方向是使用CCI Metadata读取程序集中与Attribute相关的元数据。&lt;/p&gt;  &lt;p&gt;我们知道，Attribute的数据是在编译期就确定的，它虽然涉及到构造函数，涉及到属性赋值，但是无论是构造函数的参数还是属性的值，都是在编译期已然确定的——例如常量，例如typeof。代码在编译成程序集之后，这些数据就存放在程序集的元数据中，我们可以直接通过既定的格式“读取”而不用“加载”到程序中。&lt;/p&gt;  &lt;p&gt;那么谁会去读取它呢？需要的程序就会去读，例如：编译器。编译器在编译一段代码时，需要了解代码引用了哪些程序集，是否使用了程序集中正确的成员。被引用的程序集可能很多又很大，因此不可能“加载”进来再来判断，因此它读取的其实便是程序集的“元数据”。还是以Attribute打个比方，如果我的代码使用了某个Attribute，那么编译器便会通过“元数据”去查看这个Attribute的AttributeUsageAttribute标记，检查它的AllowMultiple属性，以此判断我的用法是否正确。其他一些使用场景还包括程序集的静态检查工具等等，例如著名的&lt;a href="http://msdn.microsoft.com/en-us/library/bb429476(VS.80).aspx"&gt;FxCop&lt;/a&gt;。那么FxCop是如何读取程序集元数据的呢？它便使用了CCI相关组件。&lt;/p&gt;
&lt;p&gt;CCI（Common Compiler Infrastructure）相关组件有两个：&lt;a href="http://ccimetadata.codeplex.com/"&gt;CCI Metadata&lt;/a&gt;和&lt;a href="http://cciast.codeplex.com/"&gt;CCI Code and AST&lt;/a&gt;。这两个组件由微软研究院构建，现在都已经在CodePlex上开源。CCI Metadata的作用是用于读取和写入CLR程序集和pdb文件。它的作用和System.Reflection和System.Reflection.Emit有些类似，但它们最关键的一点不同是CCI Metadata直接读取“文件”，而System.Reflection需要“加载”。与CCI Code and AST组件功能相对应的就类似于System.CodeDom了，它会将一个程序集和pdb文件读取成层级化的，树状的对象结构。当然，它也不用加载程序集。从理论上说，CCI的这两个组件构成了.NET Reflector的基础功能。换句话说，你有需要像.NET Reflector那样读取程序集的原数据和IL代码，甚至要去简单了解IL的含义吗？那么可以参考CCI的这两个组件。&lt;/p&gt;  &lt;p&gt;不过，微软似乎从来没有想过要发布这两个组件，毕竟太小众了，而且一旦发布压力就大了，例如要在升级前后保证API的兼容性等等。从它们的源代码来，至今还在不断修改（这星期还都有check in）。不过它们也不是没有稳定的发布，它便是&lt;a href="http://ccisamples.codeplex.com/"&gt;CCI Samples&lt;/a&gt;项目，我们可以下载那个80几兆的压缩包，其中包括了所有的源代码、构建信息，文档和开发工具（如xUnit）——还有多余svn的托管数据（删除这些数据后其实只有不到40兆，真是浪费）。在下载了代码之后，便可以打开其中的解决方案（其中高亮的GeneralXp项目是我自己的试验项目，本不包含在解决方案中）：&lt;/p&gt; &lt;img src="http://img.zhaojie.me/blog/168980/o_cci-sample-sln.png" /&gt;   &lt;p&gt;Metadata目录中包含的便是CCI Metadata项目，而直接放在解决方案中的便是CCI Code and AST了。在这里，我们并不关心具体的Code和AST，因为我们只需要知道Attribute的数据，属于元数据，因此我们只需要使用CCI Metadata。&lt;/p&gt;  &lt;p&gt;假设我们需要获取的是这样的Attribute信息：&lt;/p&gt;  &lt;pre class="code"&gt;[&lt;span style="color: #2b91af"&gt;AttributeUsage&lt;/span&gt;(&lt;span style="color: #2b91af"&gt;AttributeTargets&lt;/span&gt;.Class, AllowMultiple = &lt;span style="color: blue"&gt;true&lt;/span&gt;)]
&lt;span style="color: blue"&gt;public class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;TestAttribute &lt;/span&gt;: &lt;span style="color: #2b91af"&gt;Attribute
&lt;/span&gt;{
    &lt;span style="color: blue"&gt;public &lt;/span&gt;TestAttribute(&lt;span style="color: blue"&gt;string &lt;/span&gt;s)
    {
        &lt;span style="color: #2b91af"&gt;Console&lt;/span&gt;.WriteLine(s);
    }

    &lt;span style="color: blue"&gt;public &lt;/span&gt;TestAttribute(&lt;span style="color: #2b91af"&gt;Type &lt;/span&gt;type)
    {
        &lt;span style="color: #2b91af"&gt;Console&lt;/span&gt;.WriteLine(type);
    }
}

[&lt;span style="color: #2b91af"&gt;Test&lt;/span&gt;(&lt;span style="color: blue"&gt;typeof&lt;/span&gt;(&lt;span style="color: blue"&gt;string&lt;/span&gt;))]
[&lt;span style="color: #2b91af"&gt;Test&lt;/span&gt;(&lt;span style="color: #a31515"&gt;&amp;quot;Hello World&amp;quot;&lt;/span&gt;)]
&lt;span style="color: blue"&gt;public class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;SomeClass &lt;/span&gt;{ }&lt;/pre&gt;

&lt;p&gt;首先，我们需要创建一个HostEnvironment：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;internal class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;HostEnvironment &lt;/span&gt;: &lt;span style="color: #2b91af"&gt;MetadataReaderHost
&lt;/span&gt;{
    &lt;span style="color: blue"&gt;private &lt;/span&gt;&lt;span style="color: #2b91af"&gt;PeReader &lt;/span&gt;peReader;

    &lt;span style="color: blue"&gt;internal &lt;/span&gt;HostEnvironment()
        : &lt;span style="color: blue"&gt;base&lt;/span&gt;(&lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;NameTable&lt;/span&gt;(), 4)
    {
        &lt;span style="color: blue"&gt;this&lt;/span&gt;.peReader = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;PeReader&lt;/span&gt;(&lt;span style="color: blue"&gt;this&lt;/span&gt;);
    }

    &lt;span style="color: blue"&gt;public override &lt;/span&gt;&lt;span style="color: #2b91af"&gt;IUnit &lt;/span&gt;LoadUnitFrom(&lt;span style="color: blue"&gt;string &lt;/span&gt;location)
    {
        &lt;span style="color: blue"&gt;var &lt;/span&gt;document = &lt;span style="color: #2b91af"&gt;BinaryDocument&lt;/span&gt;.GetBinaryDocumentForFile(location, &lt;span style="color: blue"&gt;this&lt;/span&gt;);
        &lt;span style="color: blue"&gt;var &lt;/span&gt;unit = &lt;span style="color: blue"&gt;this&lt;/span&gt;.peReader.OpenModule(document);
        &lt;span style="color: blue"&gt;this&lt;/span&gt;.RegisterAsLatest(unit);
        &lt;span style="color: blue"&gt;return &lt;/span&gt;unit;
    }
}&lt;/pre&gt;

&lt;p&gt;然后，便可以用它来获得构建Attribute对象的工厂委托：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;static void &lt;/span&gt;Main(&lt;span style="color: blue"&gt;string&lt;/span&gt;[] args)
{
    &lt;span style="color: blue"&gt;var &lt;/span&gt;type = &lt;span style="color: blue"&gt;typeof&lt;/span&gt;(&lt;span style="color: #2b91af"&gt;SomeClass&lt;/span&gt;);
    &lt;span style="color: blue"&gt;var &lt;/span&gt;attrType = &lt;span style="color: blue"&gt;typeof&lt;/span&gt;(&lt;span style="color: #2b91af"&gt;TestAttribute&lt;/span&gt;);

    &lt;span style="color: green"&gt;// 打开SomeClass所在程序集
    &lt;/span&gt;&lt;span style="color: #2b91af"&gt;HostEnvironment &lt;/span&gt;host = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;HostEnvironment&lt;/span&gt;();
    &lt;span style="color: blue"&gt;var &lt;/span&gt;assemblyFile = type.Assembly.Location;
    &lt;span style="color: blue"&gt;var &lt;/span&gt;assembly = host.LoadUnitFrom(assemblyFile) &lt;span style="color: blue"&gt;as &lt;/span&gt;&lt;span style="color: #2b91af"&gt;IAssembly&lt;/span&gt;;

    &lt;span style="color: green"&gt;// 找到SomeClass的原数据
    &lt;/span&gt;&lt;span style="color: blue"&gt;var &lt;/span&gt;typeDef = assembly.GetAllTypes().Single(
        t =&amp;gt; &lt;span style="color: #2b91af"&gt;TypeHelper&lt;/span&gt;.GetTypeName(t) == type.FullName);

    &lt;span style="color: green"&gt;// 获得TestAttribute元数据
    &lt;/span&gt;&lt;span style="color: blue"&gt;var &lt;/span&gt;attrDefs = typeDef.Attributes.Where(
        t =&amp;gt; &lt;span style="color: #2b91af"&gt;TypeHelper&lt;/span&gt;.GetTypeName(t.Type) == attrType.FullName);

    &lt;span style="color: green"&gt;// 构建工厂委托
    &lt;/span&gt;&lt;span style="color: blue"&gt;var &lt;/span&gt;factories = attrDefs.Select(a =&amp;gt; GetAttributeFactory(a)).ToList();
    factories.ForEach(f =&amp;gt; f());

    &lt;span style="color: #2b91af"&gt;Console&lt;/span&gt;.WriteLine(&lt;span style="color: #a31515"&gt;&amp;quot;press enter to continue...&amp;quot;&lt;/span&gt;);
    &lt;span style="color: #2b91af"&gt;Console&lt;/span&gt;.ReadLine();
}

&lt;span style="color: blue"&gt;static &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Func&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;Attribute&lt;/span&gt;&amp;gt; GetAttributeFactory(&lt;span style="color: #2b91af"&gt;ICustomAttribute &lt;/span&gt;attrDef)
{
    &lt;span style="color: blue"&gt;var &lt;/span&gt;type = &lt;span style="color: #2b91af"&gt;Type&lt;/span&gt;.GetType(&lt;span style="color: #2b91af"&gt;TypeHelper&lt;/span&gt;.GetTypeName(attrDef.Type));
    &lt;span style="color: blue"&gt;var &lt;/span&gt;args = attrDef.Arguments.Select(a =&amp;gt; GetArgumentValue(a)).ToArray();

    &lt;span style="color: blue"&gt;return &lt;/span&gt;() =&amp;gt; (&lt;span style="color: #2b91af"&gt;Attribute&lt;/span&gt;)&lt;span style="color: #2b91af"&gt;Activator&lt;/span&gt;.CreateInstance(type, args);
}

&lt;span style="color: blue"&gt;static object &lt;/span&gt;GetArgumentValue(&lt;span style="color: #2b91af"&gt;IMetadataExpression &lt;/span&gt;expression)
{
    &lt;span style="color: green"&gt;// 如果这个参数是常量
    &lt;/span&gt;&lt;span style="color: blue"&gt;var &lt;/span&gt;constant = expression &lt;span style="color: blue"&gt;as &lt;/span&gt;&lt;span style="color: #2b91af"&gt;IMetadataConstant&lt;/span&gt;;
    &lt;span style="color: blue"&gt;if &lt;/span&gt;(constant != &lt;span style="color: blue"&gt;null&lt;/span&gt;) &lt;span style="color: blue"&gt;return &lt;/span&gt;constant.Value;

    &lt;span style="color: green"&gt;// 如果这个参数是typeof
    &lt;/span&gt;&lt;span style="color: blue"&gt;var &lt;/span&gt;typeGet = expression &lt;span style="color: blue"&gt;as &lt;/span&gt;&lt;span style="color: #2b91af"&gt;IMetadataTypeOf&lt;/span&gt;;
    &lt;span style="color: blue"&gt;if &lt;/span&gt;(typeGet != &lt;span style="color: blue"&gt;null&lt;/span&gt;)
    {
        &lt;span style="color: blue"&gt;return &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Type&lt;/span&gt;.GetType(&lt;span style="color: #2b91af"&gt;TypeHelper&lt;/span&gt;.GetTypeName(typeGet.TypeToGet));
    }

    &lt;span style="color: blue"&gt;throw new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;NotSupportedException&lt;/span&gt;();
}&lt;/pre&gt;

&lt;p&gt;这段代码是可以工作的（不过还不支持对Attribute参数的设置）。但是，如果您想要我解释API的使用方式或者更具体的细节，我也说不出，而且要不是MetadataHelper中的那些辅助函数（如TypeHelper类），我根本也无法在短时间内写出这段代码。&lt;/p&gt;

&lt;p&gt;由于CCI并不会加载程序集，因此所有对的元数据的访问都是陌生的类型，例如使用ITypeReference来表示一个类型，ICustomAttribute表示一个Attribute定义，以及IMetadataExpression来表示一个表达式。由于我现在已经知道了CustomAttributeData这个方便好用的类库，因此也已经没有深入CCI的动力了。如果您感兴趣，也不妨研究并分享一下。这方面的内容似乎全世界范围内都很少见。&lt;/p&gt;

&lt;p&gt;嗯，没错，您一定发现了，这篇文章其实只是记录了一个花絮。&lt;/p&gt;</description>
      <comments>http://blog.zhaojie.me/2009/11/more-on-attribute-cci.html#comments</comments>
      <pubDate>Fri, 20 Nov 2009 02:47:00 GMT</pubDate>
      <lastBuildDate>Fri, 20 Nov 2009 02:47:00 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/language/">语言编程</category>
      <category domain="http://blog.zhaojie.me/cutting-edge/">技术尝鲜</category>
      <title>二十行C#代码打造Ruby Markup Builder</title>
      <link>http://blog.zhaojie.me/2009/10/implement-ruby-markup-builder-in-20-lines-of-c-sharp-codes.html</link>
      <guid>http://blog.zhaojie.me/2009/10/implement-ruby-markup-builder-in-20-lines-of-c-sharp-codes.html</guid>
      <description>&lt;p&gt;从.NET诞生之日起就有了XML类库，但是从使用上来说非常不方便。例如我们需要构造一个XML文档时，使用DOM API就要这样搞：&lt;/p&gt;  &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;var &lt;/span&gt;xmlDoc = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;XmlDocument&lt;/span&gt;();
&lt;span style="color: blue"&gt;var &lt;/span&gt;rootEle = xmlDoc.CreateElement(&lt;span style="color: #a31515"&gt;&amp;quot;persons&amp;quot;&lt;/span&gt;);
xmlDoc.AppendChild(rootEle);

&lt;span style="color: blue"&gt;var &lt;/span&gt;person1 = xmlDoc.CreateElement(&lt;span style="color: #a31515"&gt;&amp;quot;person&amp;quot;&lt;/span&gt;);
person1.InnerText = &lt;span style="color: #a31515"&gt;&amp;quot;Tom&amp;quot;&lt;/span&gt;;
&lt;span style="color: blue"&gt;var &lt;/span&gt;person1Age = xmlDoc.CreateAttribute(&lt;span style="color: #a31515"&gt;&amp;quot;age&amp;quot;&lt;/span&gt;);
person1Age.Value = &lt;span style="color: #a31515"&gt;&amp;quot;10&amp;quot;&lt;/span&gt;;
person1.Attributes.Append(person1Age);
rootEle.AppendChild(person1);

&lt;span style="color: blue"&gt;var &lt;/span&gt;person2 = xmlDoc.CreateElement(&lt;span style="color: #a31515"&gt;&amp;quot;person&amp;quot;&lt;/span&gt;);
person2.InnerText = &lt;span style="color: #a31515"&gt;&amp;quot;Jerry&amp;quot;&lt;/span&gt;;
&lt;span style="color: blue"&gt;var &lt;/span&gt;person2Age = xmlDoc.CreateAttribute(&lt;span style="color: #a31515"&gt;&amp;quot;age&amp;quot;&lt;/span&gt;);
person2Age.Value = &lt;span style="color: #a31515"&gt;&amp;quot;8&amp;quot;&lt;/span&gt;;
person2.Attributes.Append(person2Age);
rootEle.AppendChild(person2);&lt;/pre&gt;

&lt;p&gt;别看这么多行代码，但实际上它只构造了这么简单的一个XML：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;persons&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
  &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;person &lt;/span&gt;&lt;span style="color: red"&gt;age&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;10&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;Tom&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;person&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
  &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;person &lt;/span&gt;&lt;span style="color: red"&gt;age&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;8&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;Jerry&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;person&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;persons&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;我承认，DOM API的确非常严谨（如XmlDocument和XmlElement的归属关系），非常符合定义，也非常的面向对象，但是这易用性也实在太差了。记得在03还是04年的时候，我为在为项目做一个编辑XML文档的WinForm应用程序，当时也不像现在那么容易想到“偷懒”的法门，而VS 2003也不像VS 2005/2008那么好用，因此可谓做的劳心费神。这个情况在.NET 2.0中也没有得到改变，直到有一天，LINQ to XML随.NET 3.5横空出世，于是乎XML的生活一下子变得美好了很多。例如上面的功能只需寥寥数行便可以实现：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;var &lt;/span&gt;xmlDoc = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;XElement&lt;/span&gt;(&lt;span style="color: #a31515"&gt;&amp;quot;persons&amp;quot;&lt;/span&gt;,
    &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;XElement&lt;/span&gt;(&lt;span style="color: #a31515"&gt;&amp;quot;person&amp;quot;&lt;/span&gt;,
        &lt;span style="color: #a31515"&gt;&amp;quot;Tom&amp;quot;&lt;/span&gt;,
        &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;XAttribute&lt;/span&gt;(&lt;span style="color: #a31515"&gt;&amp;quot;age&amp;quot;&lt;/span&gt;, &lt;span style="color: brown"&gt;10&lt;/span&gt;)),
    &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;XElement&lt;/span&gt;(&lt;span style="color: #a31515"&gt;&amp;quot;person&amp;quot;&lt;/span&gt;,
        &lt;span style="color: #a31515"&gt;&amp;quot;Jerry&amp;quot;&lt;/span&gt;,
        &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;XAttribute&lt;/span&gt;(&lt;span style="color: #a31515"&gt;&amp;quot;age&amp;quot;&lt;/span&gt;, &lt;span style="color: brown"&gt;8&lt;/span&gt;))); &lt;/pre&gt;

&lt;p&gt;虽然LINQ to XML一直是所谓C# 3.0中LINQ特性的一部分，与LINQ to SQL，LINQ to Object及LINQ to……某个别的并列，但我始终认为LINQ to XML实则还是LINQ to Object的一种特殊形式，只是它用于操作XML而已。它的一切都是System.Xml.Linq命名空间下相关类库（如XElement）在起作用，不关LINQ什么事情。XElement等相关类型大大简化了我们的开发，与DOM API相比，无论是XML的构造还是读取都容易了许多。不过俗话说得好：“不怕不识货，就怕货比货”，这样的API与&lt;a href="http://builder.rubyforge.org/"&gt;Ruby Markup Builder&lt;/a&gt;相比还是有明显差距。请看：&lt;/p&gt;

&lt;pre class="code"&gt;builder = Builder::XmlMarkup.new
xml = &lt;font color="#ff0000"&gt;builder.&lt;/font&gt;persons &lt;font color="#ff0000"&gt;{ |b|&lt;/font&gt;
    &lt;font color="#ff0000"&gt;b.&lt;/font&gt;person&lt;font color="#ff0000"&gt;(&amp;quot;&lt;/font&gt;Tom&lt;font color="#ff0000"&gt;&amp;quot;, :&lt;/font&gt;age &lt;font color="#ff0000"&gt;=&amp;gt; &amp;quot;&lt;/font&gt;10&lt;font color="#ff0000"&gt;&amp;quot;)&lt;/font&gt;
    &lt;font color="#ff0000"&gt;b.&lt;/font&gt;person&lt;font color="#ff0000"&gt;(&amp;quot;&lt;/font&gt;Jerry&lt;font color="#ff0000"&gt;&amp;quot;, :&lt;/font&gt;age &lt;font color="#ff0000"&gt;=&amp;gt; &amp;quot;&lt;/font&gt;8&lt;font color="#ff0000"&gt;&amp;quot;)&lt;/font&gt;
&lt;font color="#ff0000"&gt;}&lt;/font&gt;&lt;/pre&gt;

&lt;p&gt;请看上面这段代码，它自然没有使用Ruby语言的标准着色方式。我着色的目的是体现这个构造方式中的“噪音”——也就是与XML内容无关的部分。从中可以发现，Ruby不愧是一种噪音较少的语言，如果您尝试使用这个方式来观察C#中LINQ to XML的做法，就会发现两者之间的确有明显的差距。当然，如果使用VB.NET的XML Literal可能噪音也很少，但是在我看来，XML Literal在XML构造方面的表现有些罗嗦，例如它需要开发人员同时提供元素的开始标签和闭合标签，可能在IDE的帮助下此类代码输入较为简单，但是代码还是略显冗余。&lt;/p&gt;

&lt;p&gt;但是我们这些可怜的C#程序员难道只有在一边眼馋的份吗？不见得，我们也可以来“享受”一把：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;dynamic &lt;/span&gt;b = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;XmlMarkupBuilder&lt;/span&gt;();
&lt;span style="color: #2b91af"&gt;XElement &lt;/span&gt;xml =
    b.persons(
        b.person(&lt;span style="color: #a31515"&gt;&amp;quot;Tom&amp;quot;&lt;/span&gt;, age: &lt;span style="color: brown"&gt;10&lt;/span&gt;),
        b.person(&lt;span style="color: #a31515"&gt;&amp;quot;Jerry&amp;quot;&lt;/span&gt;, age: &lt;span style="color: brown"&gt;8&lt;/span&gt;));&lt;/pre&gt;

&lt;p&gt;哇，这是什么，怎么代码那么简单。很明显，从dynamic关键字上可以看出，这是C# 4.0中新增的功能。您可能会想“原来.NET 4.0对XML又有增强了”……其实并非如此，这是我们自己扩展的功能。不过这应该算是更好的消息，因为这说明我们已经有能力自行扩展，自行设计这样的API了——这可是“渔”，比“鱼”可要值钱多了。而实现这样的功能也只需要&lt;font color="#ff0000"&gt;短短二十几行&lt;/font&gt;C#代码：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;XmlMarkupBuilder &lt;/span&gt;: &lt;span style="color: #2b91af"&gt;DynamicObject
&lt;/span&gt;{
    &lt;span style="color: blue"&gt;public override bool &lt;/span&gt;TryInvokeMember(&lt;span style="color: #2b91af"&gt;InvokeMemberBinder &lt;/span&gt;binder, &lt;span style="color: blue"&gt;object&lt;/span&gt;[] args, &lt;span style="color: blue"&gt;out object &lt;/span&gt;result)
    {
        &lt;span style="color: #2b91af"&gt;XElement &lt;/span&gt;xml = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;XElement&lt;/span&gt;(binder.Name);

        &lt;span style="color: blue"&gt;var &lt;/span&gt;attrCount = binder.CallInfo.ArgumentNames.Count;
        &lt;span style="color: blue"&gt;var &lt;/span&gt;elementCount = args.Length - attrCount;

        &lt;span style="color: blue"&gt;for &lt;/span&gt;(&lt;span style="color: blue"&gt;int &lt;/span&gt;i = &lt;span style="color: brown"&gt;0&lt;/span&gt;; i &amp;lt; elementCount; i++)
        {
            xml.Add(args[i]);
        }

        &lt;span style="color: blue"&gt;for &lt;/span&gt;(&lt;span style="color: blue"&gt;var &lt;/span&gt;i = &lt;span style="color: brown"&gt;0&lt;/span&gt;; i &amp;lt; attrCount; i++)
        {
            &lt;span style="color: blue"&gt;var &lt;/span&gt;attrName = binder.CallInfo.ArgumentNames[i];
            &lt;span style="color: blue"&gt;if &lt;/span&gt;(attrName[&lt;span style="color: brown"&gt;0&lt;/span&gt;] == &lt;span style="color: #a31515"&gt;'&amp;#64;'&lt;/span&gt;) attrName = attrName.Substring(&lt;span style="color: brown"&gt;1&lt;/span&gt;);

            xml.Add(&lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;XAttribute&lt;/span&gt;(attrName, args[i + elementCount]));
        }

        result = xml;
        &lt;span style="color: blue"&gt;return true&lt;/span&gt;;
    }
}&lt;/pre&gt;

&lt;p&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/system.dynamic.dynamicobject(VS.100).aspx"&gt;DynamicObject&lt;/a&gt;是个特殊的对象，简单地说它的行为可以被“扩展”——是如动态语言般真正的扩展，而非静态的多态。当我们使用dynamic修饰变量后，在它之上的方法调用会由编译器和DLR配合出不一样的行为。例如，我们在调用一个方法的时候，DLR会先检查这个动态对象上是否存在符合这个签名的方法，存在则最好，否则便会调用TryInvokeMember来“执行”一个动态方法，而它的参数便是此次调用的全部信息。这样的做法被称为“Method Missing”操作，事实上Ruby Markup Builder也是使用Ruby对象中的这个特性来实现“调用什么方法，便生成什么元素”的功能。此外，我们还可以这么用：&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;var &lt;/span&gt;persons = &lt;span style="color: blue"&gt;new &lt;/span&gt;[] { &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Person&lt;/span&gt;(&lt;span style="color: #a31515"&gt;&amp;quot;Tom&amp;quot;&lt;/span&gt;, &lt;span style="color: brown"&gt;10&lt;/span&gt;), &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Person&lt;/span&gt;(&lt;span style="color: #a31515"&gt;&amp;quot;Jerry&amp;quot;&lt;/span&gt;, &lt;span style="color: brown"&gt;8&lt;/span&gt;) };
&lt;span style="color: #2b91af"&gt;XElement &lt;/span&gt;xml2 = 
    b.persons(
        &lt;span style="color: blue"&gt;from &lt;/span&gt;p &lt;span style="color: blue"&gt;in &lt;/span&gt;persons
        &lt;span style="color: blue"&gt;select &lt;/span&gt;b.person(p.Name, age: p.Age));&lt;/pre&gt;

&lt;p&gt;XmlMarkupBuilder对LINQ的直接支持得益于XElement无与伦比的“包容性”（因此我认为LINQ to XML其实只是LINQ to Object + 类库）。至于age: 10这样的代码，其实是使用了C# 4.0的新特性：&lt;a href="http://channel9.msdn.com/posts/mike+ormond/C-40-New-Features-Named-Parameters/"&gt;命名参数（Named Parameters）&lt;/a&gt;——C#还真把什么都为我们准备好了。&lt;/p&gt;

&lt;p&gt;即便是大部分&lt;a href="http://blogs.msdn.com/csharpfaq/archive/2009/10/19/dynamic-in-c-4-0-creating-wrappers-with-dynamicobject.aspx"&gt;DynamicObject的示例&lt;/a&gt;都喜欢拿XML操作开涮（但还是没有出现我这篇的用法，所以我还是“原创”），但事实上这个功能可发挥的余地非常之大。例如，&lt;a href="http://www.cnblogs.com/cathsfz/"&gt;陈猫&lt;/a&gt;同学提到他想用这个功能来简化Silverlight中的JSON操作，刚“喜得贵女”的&lt;a href="http://haacked.com/articles/AboutHaacked.aspx"&gt;Phil Haack&lt;/a&gt;同学在上个月也&lt;a href="http://haacked.com/archive/2009/08/26/method-missing-csharp-4.aspx"&gt;提到一个设想&lt;/a&gt;，它在ASP.NET MVC中使用dynamic关键字来修饰View的Model，这样在访问Model的属性时变可附加一些约定好的操作。例如，Model.Content表示读取Content属性的内容，而Model._Content则表示在读取Content之后自动进行HTML编码。这无疑简化了我们的开发——当然，强类型的各种优势就不复存在了。&lt;/p&gt;

&lt;p&gt;而这个功能对我的意义在于，我又找到了一种设计API的方式，它可以使类库变得简单好用——就好比上面的XmlMarkupBuilder一样。虽然，这个示例的功能非常简单，但是这也足以证明C# 4.0中的dynamic特性并不仅仅是“方便Interop操作”或是“简化反射”这么简单，如果我们可以发挥想象能力，加以&lt;font color="#ff0000"&gt;充分利用同时又不滥用&lt;/font&gt;，我们的程序开发生活就会变得越来越美好。&lt;/p&gt;

&lt;p&gt;最后……我还是承认了吧，这篇文章其实是标题党，真正Ruby Markup Builder功能非常强大而复杂，我们的XmlMarkupBuilder类只能算是冰山一角而已。&lt;/p&gt;</description>
      <comments>http://blog.zhaojie.me/2009/10/implement-ruby-markup-builder-in-20-lines-of-c-sharp-codes.html#comments</comments>
      <pubDate>Mon, 26 Oct 2009 16:47:00 GMT</pubDate>
      <lastBuildDate>Mon, 26 Oct 2009 16:47:00 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/dotnet/">.Net框架</category>
      <category domain="http://blog.zhaojie.me/cutting-edge/">技术尝鲜</category>
      <title>尝试使用IKVM运行Lucene 2.9.0版</title>
      <link>http://blog.zhaojie.me/2009/10/ikvm-simple-lucene-benchmark.html</link>
      <guid>http://blog.zhaojie.me/2009/10/ikvm-simple-lucene-benchmark.html</guid>
      <description>&lt;p&gt;上月末Lucene发布了2.9.0版，&lt;a href="http://www.infoq.com/cn/news/2009/10/lucene29"&gt;这个版本的改进比较明显&lt;/a&gt;，主要是各方面性能的增强，以及对数字字段范围查询的直接支持。这个版本还有个重要的意义，就是它标记了Lucene 3在API上的改变，及早跟进的话对Lucene 3的未来接受程度会比较好。Lucene的更新很慢，而移植到.NET平台上的&lt;a href="http://incubator.apache.org/lucene.net/"&gt;Lucene.NET&lt;/a&gt;的&lt;a href="http://incubator.apache.org/lucene.net/download/"&gt;二进制发布&lt;/a&gt;则更是一直停留在07年三月的2.0版本。虽然我们可以通过svn获取到&lt;a href="https://svn.apache.org/repos/asf/incubator/lucene.net/tags/Lucene.Net_2_3_2/"&gt;Lucene.Net 2.3.2的源代码&lt;/a&gt;自行编译，但这次我还是想直接使用最新的2.9.0版本。&lt;/p&gt; &lt;p&gt;至于如何在.NET平台上调用Java代码，我想过各种方式，例如我最初设想使用Java =&amp;gt; JNI =&amp;gt; C++/CLI =&amp;gt; C#的“曲线救国”方式，也考虑过最保险的借助HTTP做Proxy的方式。不过最后在&lt;a href="http://www.cnblogs.com/RednaxelaFX/"&gt;RednaxelaFX&lt;/a&gt;的建议下，我决定趁这个机会尝试一下&lt;a href="http://www.ikvm.net/"&gt;IKVM.NET&lt;/a&gt;（下文称为IKVM）。IKVM的目的是在.NET平台（包括mono）上实现一个Java执行环境（也就是JVM），它可以将jar包直接运行在.NET平台上，将Java语言的源文件编译为.NET的程序集，而现在我们使用它的另一个功能，直接把Lucene 2.9.0的二进制jar包转化为.NET下的dll。&lt;/p&gt; &lt;p&gt;IKVM在我博客的侧边栏上停留了很久，不过我一直认为它还不太成熟于是没有怎么去接触。现在从&lt;a href="http://www.ikvm.net/stories.html"&gt;Case Studies&lt;/a&gt;上来看，IKVM的可用性似乎还是有一定保障的。IKVM目前实现了JDK 1.6，也可谓紧跟Java脚步。对于这种转化，首先要看中的应该是“正确性”，对于纯粹内存中的对象来说，我猜想应该不会有什么正确性方面的问题。而IO操作就相对值得斟酌了，例如对于文件锁的处理，对于数据流的读写，即使差1个字节可能也会造成大问题。不过，就我初步使用下来的感受，效果比想象中要好很多。在我测试的场景下，使用IKVM Lucene和Java Lucene的索引可以互相读写，没有发生任何问题。当然，这还需要更进一步的测试，这也是我写这篇文章的目的。&lt;/p&gt; &lt;p&gt;在保证了正确性之后，要关注的便是性能了。根据我的推测，由于IKVM需要在Java生成的.NET程序集和BCL之间加上一层Runtime和JDK，因此其性能几乎一定会比Java原有的程序要差。不过，对于Lucene这种项目来说，算法才是性能的关键。例如，&lt;a href="http://www.lucidimagination.com/blog/2009/09/22/contrived-fieldcache-load-test-lucene-2-4-vs-lucene-2-9/"&gt;有人测试Lucene 2.9.0在某些情况下会比2.4有15倍左右的性能提升&lt;/a&gt;。不过由于没有很好的测试数据和场景，目前我只进行了最最简单的，不涉及磁盘IO的性能比较。&lt;/p&gt; &lt;p&gt;性能比较的场景很简单，我准备了《神雕侠侣》全文作为索引数据，2兆多的文本文件，反复使用StandardAnalyzer向RAMDirectory中添加索引，并在以下四种环境下统计索引100遍所消耗的时间（统计时都会对JIT进行“预热”）。&lt;/p&gt; &lt;ul&gt; &lt;li&gt;在.NET平台下使用Lucene.Net 2.3.2（需获取源代码自行编译）。  &lt;li&gt;在.NET平台下使用IKVM运行Lucene 2.9.0。  &lt;li&gt;在Java平台下使用默认的Client VM运行Lucene 2.9.0。  &lt;li&gt;在Java平台下使用Server VM（加-server参数）运行Lucene 2.9.0。&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;我将&lt;a href="http://cid-fba4447598b1d752.skydrive.live.com/self.aspx/Public/LuceneBenchmark-20091009.zip"&gt;所有的测试数据、类库、源文件&lt;/a&gt;都打包了，感兴趣的朋友可以下载以后查看。压缩包内的DotNet和Java目录中有着相似的内容：&lt;/p&gt; &lt;ul&gt; &lt;li&gt;lib目录：保存所需的类库（dll或jar文件）  &lt;li&gt;src目录：保存测试用源代码（cs或java文件）  &lt;li&gt;build.bat：调用csc或javac编译src下的源文件，将结果输出至bin目录  &lt;li&gt;clean.bat：清除编译结果（即删除build文件）  &lt;li&gt;run.bat：运行测试程序&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;在执行build.bat文件的时候，需要保证PATH中包含了正确的目录，可以访问到csc或者javac。在使用run.bat运行测试程序时，也可以添加参数进入不同的分支。例如对.NET的测试中：&lt;/p&gt;&lt;pre class="code"&gt;...\DotNet&amp;gt; build

...
...

...\DotNet&amp;gt; :: 测试Lucene.Net 2.3.2
...\DotNet&amp;gt; run

...
...

...\DotNet&amp;gt; :: 测试IKVM Lucene 2.9.0
...\DotNet&amp;gt; run -ikvm

...&lt;/pre&gt;
&lt;p&gt;而在Java的测试中：&lt;/p&gt;&lt;pre class="code"&gt;...\Java&amp;gt; build

...
...

...\Java&amp;gt; :: Client VM
...\Java&amp;gt; run

...
...

...\Java&amp;gt; :: Server VM
...\Java&amp;gt; run -server

...&lt;/pre&gt;
&lt;p&gt;在我的笔记本上（Windows 7，双核2.0 Ghz CPU，2G RAM），&lt;a href="http://spreadsheets.google.com/pub?key=tPZ2FEFPjkMsBVFK7rfUKcQ&amp;amp;output=html"&gt;执行结果&lt;/a&gt;如下：&lt;/p&gt;&lt;img src="http://spreadsheets.google.com/pub?key=tPZ2FEFPjkMsBVFK7rfUKcQ&amp;amp;oid=1&amp;amp;output=image"&gt; 
&lt;p&gt;以上图表展示的是每种环境下各执行3次的平均耗时。可见，性能从高到低依次如下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Java Server VM + Lucene 2.9.0&lt;/li&gt;
&lt;li&gt;.NET + Lucene.Net 2.3.2&lt;/li&gt;
&lt;li&gt;Java Client VM + Lucene 2.9.0&lt;/li&gt;
&lt;li&gt;.NET + IKVM + Lucene 2.9.0&lt;/li&gt;&lt;/ol&gt;
&lt;p&gt;从结果上看，Java Server VM的表现最好，而且领先幅度较大，相对于IKVM有35%左右的性能优势。不过这个结果让我非常满意，因为在我看来，这完全处在一个可以接受的范围之内，绝大部分系统根本不会在乎这点性能差距。Java平台的优势是类库数量，如果IKVM可以仅靠这点性能损失换来.NET对Java类库的使用能力，天下没有更合算的事情了。&lt;/p&gt;
&lt;p&gt;不过让我更加感兴趣的是Java Server VM + Lucene 2.9.0和.NET + Lucene .Net 2.3.2的比较结果，我承认这个差距让我始料未及，因为就我过去的经验，相同的.NET和Java应用程序，.NET的性能会领先Java。在简单思考过后，我猜想有以下的几点可能：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Lucene 2.9.0的算法本身比Lucene 2.3.2效率高。&lt;/li&gt;
&lt;li&gt;JVM的Memory Consistency Model比CLR来的宽松，因而高效。&lt;/li&gt;
&lt;li&gt;JVM的JIT优化比CLR做的好。&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;据&lt;a href="http://java.sun.com/products/hotspot/whitepaper.html"&gt;HotSpot的白皮书&lt;/a&gt;称，Server VM与Client VM的除了Heap大小，GC等参数方面不同以外，最大的区别在于Server的JIT会尝试更多的优化手段，这会导致较多的启动时间，以此换来更好的执行效率：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The Client VM compiler does not try to execute many of the more complex optimizations performed by the compiler in the Server VM, but in exchange, it requires less time to analyze and compile a piece of code. This means the Client VM can start up faster and requires a smaller memory footprint. 
&lt;p&gt;The Server VM contains an advanced adaptive compiler that supports many of the same types of optimizations performed by optimizing C++ compilers, as well as some optimizations that cannot be done by traditional compilers, such as aggressive inlining across virtual method invocations. This is a competitive and performance advantage over static compilers. Adaptive optimization technology is very flexible in its approach, and typically outperforms even advanced static analysis and compilation techniques. &lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;而编译器及虚拟机大牛&lt;a href="http://www.cnblogs.com/RednaxelaFX/"&gt;RednaxelaFX&lt;/a&gt;在推特上也告诉我：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;话说GC方面CLR或许非常先进，但JIT方面就还是HotSpot强（和复杂）一些了。CLR没办法inline虚方法或者接口上的方法的调用，HotSpot却可以……总之这种对比的结果要看你测试的代码的性质&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;至于具体的情况，RednaxelaFX建议查看HotSpot和CLR在JIT之后的Native Code，这并非我所擅长的东西，于是就希望R大可以给出更详细的结果了。:)&lt;/p&gt;
&lt;p&gt;最后，便是本文的目的了：目前的测试缺少实际价值，那么您有兴趣和我一起做一个更接近生产环境的实验吗？或者说，您在生产环境中是如何使用Lucene的呢？&lt;/p&gt;</description>
      <comments>http://blog.zhaojie.me/2009/10/ikvm-simple-lucene-benchmark.html#comments</comments>
      <pubDate>Fri, 09 Oct 2009 07:26:00 GMT</pubDate>
      <lastBuildDate>Fri, 09 Oct 2009 07:26:00 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/extension/">项目扩展</category>
      <category domain="http://blog.zhaojie.me/cutting-edge/">技术尝鲜</category>
      <title>将Windows Live Writer打造为“所见即所得”编辑器</title>
      <link>http://blog.zhaojie.me/2009/08/windows-live-writer-wysiwyg.html</link>
      <guid>http://blog.zhaojie.me/2009/08/windows-live-writer-wysiwyg.html</guid>
      <description>&lt;h1&gt;前言&lt;/h1&gt; &lt;p&gt;&lt;a href="http://download.live.com/"&gt;Windows Live Writer&lt;/a&gt;（下称WLW）是博客写作利器，自从它发布之后，我几乎再也不使用博客园的在线编辑器写博客了。WLW的最大优势之一，便是可以自动获取目标博客的样式，然后让用户在特定的样式环境下编写文章。不过平心而论，WLW的“自动获取样式”功能并不怎么实用，因为在很多时候它都无法正确地获取到适合编辑的样式。这并不是WLW的错，因为不同网页的样式各有不同，我们有时候很难单独“取出”页面的一部分，同时保持着良好的样式——甚至有些样式还会牵涉到JavaScript。事实上，您目前看到的博客样式便无法由WLW自动得到，但是经过一定“手工打造”，我们还是可以在一个良好的样式环境中编写博客的。例如，以下便是我编写博客时的状态：&lt;/p&gt;&lt;a href="http://img.zhaojie.me/blog/168980/o_jeffz-wlw-edit.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/168980/r_jeffz-wlw-edit.png" width="450"&gt;&lt;/a&gt;  &lt;p&gt;它和您目前所看到样式是不是几乎一模一样？&lt;/p&gt; &lt;p&gt;事实上，我最近才忽然意识到，我们其实可以将其作为一个“HTML编辑器”，而不是一个“博客编辑器”使用。也就是说，我们可以利用它在特定样式环境下编写HTML内容。由于WLW已经具备了比较常用的功能，且生成出来的HTML代码非常干净，因此它的还是一个比较合适的HTML编辑器。事实上，我正打算以后就用WLW为&lt;a href="http://www.infoq.com/cn"&gt;InfoQ中文站&lt;/a&gt;写稿。因此目前这篇文章将会提供一个指南，希望可以帮助您打造一个合适的编辑环境。&lt;/p&gt; &lt;p&gt;补充一点：在这篇文章中，我们会多次提及“所见即所得”编辑方式，它在这里表示了“带有丰富样式”的编辑方式，而不是指最基础的编辑功能。&lt;/p&gt; &lt;h1&gt;为InfoQ中文站打造合适的编辑器&lt;/h1&gt; &lt;p&gt;首先，您需要&lt;a href="http://download.live.com/"&gt;下载&lt;/a&gt;并安装Windows Live Writer。在进行下一步之前，最好再&lt;a href="http://space.cnblogs.com/forum/topic/8550/"&gt;创建一个博客&lt;/a&gt;。因为我并没有在“全新”的环境下进行过尝试，因此严格来说，我无法百分之一百保证全新环境下进行操作不会出现问题。&lt;/p&gt; &lt;p&gt;完成了第一步之后，您可以&lt;a href="http://files.cnblogs.com/JeffreyZhao/WLW-InfoQ-Edit.zip"&gt;点此下载&lt;/a&gt;一个补丁包，您会发现其中包含两个文件：&lt;/p&gt; &lt;ul&gt; &lt;li&gt;InfoQ-Edit.reg注册表文件  &lt;li&gt;BlogTemplates目录 &lt;/li&gt;&lt;/ul&gt; &lt;p&gt;然后，依次进行以下几个步骤：&lt;/p&gt; &lt;ol&gt; &lt;li&gt;打开注册表编辑器（regedit.exe），备份HKEY_CURRENT_USER\Software\Microsoft\Windows Live\Writer\Weblogs节点下的内容。  &lt;li&gt;将InfoQ-Edit.reg文件中的内容倒入注册表。  &lt;li&gt;将BlogTemplates目录复制到C:\Users\%your_account%\AppData\Roaming\Windows Live Writer中去（可能会随着您的系统有所不同，请注意AppData可能是隐藏文件夹）。如果已经存在了BlogTemplates目录，直接覆盖即可。 &lt;/li&gt;&lt;/ol&gt; &lt;p&gt;打开Windows Live Writer，您会发现目前处在一个名为“InfoQ中文站”的博客中（如果没有，请在Blogs菜单中选择“InfoQ中文站”），但还是处于普通编辑模式下。现在，请选择View菜单下的Edit using theme选项（或使用Ctrl + F11），稍等片刻（正在下载样式文件），大公告成！如果没有意外的话，效果应该是这样的：&lt;/p&gt;&lt;a href="http://img.zhaojie.me/blog/168980/o_infoq-wlw-edit.png" target="_blank"&gt;&lt;img src="http://img.zhaojie.me/blog/168980/r_infoq-wlw-edit.png" width="450"&gt;&lt;/a&gt;  &lt;p&gt;尝试着修改标题和内容吧。自然，您是无法发布文章的，您可以将编辑模式切换至HTML，并将这些HTML复制到线上的编辑器里再发布。&lt;/p&gt; &lt;p&gt;接下来，我们就来进行一些简单分析。希望分析过后，您可以自由地将WLW打造成自己想要的样子——至少可以自定义编辑模板吧。另外，如果您在以上那些操作之后没有得到预期效果，也可以检查一下到底出了什么问题。&lt;/p&gt; &lt;h1&gt;注册表信息&lt;/h1&gt; &lt;p&gt;很明显，WLW是由注册表配合文件进行定制的，我们先从注册表这边入手。简单地说，注册表保存了您在WLW中定义的帐户信息。&lt;/p&gt; &lt;p&gt;InfoQ-Edit.reg文件向注册表内倒入多个数据。首先，它在HKCU\Software\Microsoft\Windows Live\Writer\Weblogs节点下定义了一个名为DefaultWeblog的字符串值，其中包含了默认帐户的GUID。默认帐户即您打开WLW之后所在的博客帐户。每个博客帐户都会在Weblogs节点下出现一个新的节点，节点的名称便是这个帐户的GUID。因此，我们下面关注的便是Weblogs节点下的db500b71-6eda-40d1-a6e3-9c196c68225f节点，它便表示了刚导入的“InfoQ中文站”这个帐户。&lt;/p&gt; &lt;p&gt;在这里我们也不会关注这个节点下的太多内容，您可以自行进行分析，大部分的数据我想还是比较容易猜到是什么作用的。因此，现在请将注意力放在EditorTemplate节点中，其中包含三个值：&lt;/p&gt; &lt;ul&gt; &lt;li&gt;&lt;strong&gt;DisplayWebLayoutWarning：&lt;/strong&gt;1则表示在切换到“所见即所得”编辑方式时是否出现警告文字。我已经将其设为0，即不进行提示。  &lt;li&gt;&lt;strong&gt;EditUsingStyles：&lt;/strong&gt;1则表示使用“所见即所得”进行编辑，它反映的便是WLW菜单View中Edit using theme的状态。  &lt;li&gt;&lt;strong&gt;LastEditView：&lt;/strong&gt;表示上次关闭博客帐号时所处的状态，如Normal表示“普通编辑方式”，WebLayout则表示“所见即所得”编辑方式。&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;EditorTemplate节点还包含了子节点，其中包含两个值：&lt;/p&gt; &lt;ul&gt; &lt;li&gt;&lt;strong&gt;Framed：&lt;/strong&gt;处于“所见即所得”编辑状态时所使用的模板文件名（目前是Edit.htm）。  &lt;li&gt;&lt;strong&gt;Webpage：&lt;/strong&gt;处于Preview状态时所使用的模板文件名（目前是Preview.htm）。&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Framed和Webpage的区别在于，前者可能只提供了一个“编辑区”样式（如第一张图片中，我使用的博客编辑样式），而后者用于预览编辑效果，因此则可能是个完整页面。不过在您刚才安装的补丁中，您会发现Edit.htm和Preview.htm的内容完全相同。所以您会发现，即时是在编辑的时候，我们也可以看到InfoQ页面上几乎完整的内容。&lt;/p&gt; &lt;h1&gt;模板内容&lt;/h1&gt; &lt;p&gt;在注册表中定义的只是模板的“文件名”，而真正的模板是存放在硬盘上的。没错，就是在C:\Users\%your_account%\AppData\Roaming\Windows Live Writer\BlogTemplates中（可能随着系统有所不同），其中应该已经包含了用博客帐户的GUID为名称的文件夹。进入，您就会发现Edit.htm和Preview.htm两个文件。&lt;/p&gt; &lt;p&gt;这两个文件其实都是普通的文件夹，只不过包含了两个站位符{post-title}和{post-body}，作用不言自明。如之前所说那样，Edit.htm可能只包含了简单的输入区域，因此对于我的博客其中就包含了这样的代码：&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: maroon"&gt;div &lt;/span&gt;&lt;span style="color: red"&gt;id&lt;/span&gt;&lt;span style="color: blue"&gt;="container"&amp;gt;
    &amp;lt;&lt;/span&gt;&lt;span style="color: maroon"&gt;div &lt;/span&gt;&lt;span style="color: red"&gt;id&lt;/span&gt;&lt;span style="color: blue"&gt;="wrapper"&amp;gt;
        &amp;lt;&lt;/span&gt;&lt;span style="color: maroon"&gt;div &lt;/span&gt;&lt;span style="color: red"&gt;id&lt;/span&gt;&lt;span style="color: blue"&gt;="content"&amp;gt;
            &amp;lt;&lt;/span&gt;&lt;span style="color: maroon"&gt;div &lt;/span&gt;&lt;span style="color: red"&gt;id&lt;/span&gt;&lt;span style="color: blue"&gt;="post" &lt;/span&gt;&lt;span style="color: red"&gt;class&lt;/span&gt;&lt;span style="color: blue"&gt;="post"&amp;gt;
                &amp;lt;&lt;/span&gt;&lt;span style="color: maroon"&gt;h2&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;{post-title}&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: maroon"&gt;h2&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                &amp;lt;&lt;/span&gt;&lt;span style="color: maroon"&gt;div &lt;/span&gt;&lt;span style="color: red"&gt;class&lt;/span&gt;&lt;span style="color: blue"&gt;="entry"&amp;gt;&lt;/span&gt;{post-body}&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: maroon"&gt;div&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
            &amp;lt;/&lt;/span&gt;&lt;span style="color: maroon"&gt;div&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
        &amp;lt;/&lt;/span&gt;&lt;span style="color: maroon"&gt;div&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
    &amp;lt;/&lt;/span&gt;&lt;span style="color: maroon"&gt;div&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
&amp;lt;/&lt;/span&gt;&lt;span style="color: maroon"&gt;div&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;
&lt;p&gt;那么样式呢？与普通网页一样，样式是也是通过模板文件中的&amp;lt;link /&amp;gt;节点引入，或直接写在HTML的&amp;lt;style /&amp;gt;节点中的。至于引入的CSS文件的位置，可以是远端，也可以是本地。不过如果您选择引入本地的CSS，则需要提供一个绝对路径，例如：&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: maroon"&gt;link &lt;/span&gt;&lt;span style="color: red"&gt;rel&lt;/span&gt;&lt;span style="color: blue"&gt;="stylesheet" &lt;/span&gt;&lt;span style="color: red"&gt;type&lt;/span&gt;&lt;span style="color: blue"&gt;="text/css" &lt;/span&gt;&lt;span style="color: red"&gt;href&lt;/span&gt;&lt;span style="color: blue"&gt;="file:///C:/Users/.../common.css" /&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;
&lt;p&gt;不过在目前的InfoQ的模板中，我在页面上直接引入了在线的CSS。因此，在切换至“所见即所得”编辑模式时可能需要等待一段时间，此时WLW正在下载CSS文件。如果您需要提高访问速度，则不妨将所有的CSS文件下载至本地，再修改Edit.htm中&amp;lt;link /&amp;gt;节点中引入的地址即可。&lt;/p&gt;
&lt;h1&gt;总结&lt;/h1&gt;
&lt;p&gt;还有什么需要总结的呢？把工具进行合适的定制可以大幅提高我们的工作效率。例如，现在我们可以直接在写文章时看到样式（包括代码，图片浮动等等），而不用发表为“草稿”再去页面上浏览了，对于我这种博客样式的完美主义者非常有帮助。&lt;/p&gt;
&lt;p&gt;再说，定制工具难道不也是程序员的乐趣之一吗？&lt;/p&gt;</description>
      <comments>http://blog.zhaojie.me/2009/08/windows-live-writer-wysiwyg.html#comments</comments>
      <pubDate>Mon, 17 Aug 2009 16:14:00 GMT</pubDate>
      <lastBuildDate>Mon, 17 Aug 2009 16:14:00 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/cutting-edge/">技术尝鲜</category>
      <category domain="http://blog.zhaojie.me/front-end/">前端表现</category>
      <title>在网页里添加Web Live Messenger对话框</title>
      <link>http://blog.zhaojie.me/2007/11/add-web-live-messenger-to-your-page.html</link>
      <guid>http://blog.zhaojie.me/2007/11/add-web-live-messenger-to-your-page.html</guid>
      <description>&lt;H2&gt;&lt;B&gt;Live Messenger对话框&lt;/B&gt;&lt;/H2&gt;
&lt;P&gt;时常在某些朋友的blog中看到一个可供聊天的对话框，它能让正在浏览这个站点的用户进行聊天。不过在我看来，这个功能形同鸡肋——谁会知道哪些人正在浏览，又有哪些人可以聊天呢？不过今天在浏览&lt;A href="http://lovecherry.cnblogs.com/" target=_blank mce_href="http://lovecherry.cnblogs.com/"&gt;LoveCherry&lt;/A&gt;的blog时发现在左侧边栏里出现了一个可供聊天的Live Messenger对话框，顿时让我产生了兴趣。不过知道这个东东的人似乎还不多，因此只能动用搜索引擎了（在这里想再说一句多余的话，因为我时常会收到一些类似于“ASP.NET AJAX框架哪里可以下载”之类的问题，所以我建议那些朋友一定要养成先搜再问的习惯）。那么我们就先来看看这个东西具体是什么样的吧。&lt;/P&gt;
&lt;P&gt;首先，我们可以访问这个页面（&lt;A title=http://settings.messenger.live.com/applications/CreateHtml.aspx href="http://settings.messenger.live.com/applications/CreateHtml.aspx" mce_href="http://settings.messenger.live.com/applications/CreateHtml.aspx"&gt;http://settings.messenger.live.com/applications/CreateHtml.aspx&lt;/A&gt;），从中可以看出微软提供了两种方式供用户使用Live Messenger的Web聊天功能。&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;提供一个链接（&lt;A href="http://settings.messenger.live.com/Conversation/IMMe.aspx?invitee=fba4447598b1d752%40apps.messenger.live.com&amp;amp;mkt=zh-cn" target=_blank mce_href="http://settings.messenger.live.com/Conversation/IMMe.aspx?invitee=fba4447598b1d752%40apps.messenger.live.com&amp;amp;mkt=zh-cn"&gt;&lt;IMG style="BORDER-TOP-STYLE: none; BORDER-RIGHT-STYLE: none; BORDER-LEFT-STYLE: none; BORDER-BOTTOM-STYLE: none" height=16 src="http://messenger.services.live.com/users/fba4447598b1d752%40apps.messenger.live.com/presenceimage?mkt=zh-cn" width=16 mce_src="http://messenger.services.live.com/users/fba4447598b1d752%40apps.messenger.live.com/presenceimage?mkt=zh-cn"&gt;&lt;/A&gt;），点击它则会弹出一个页面可供聊天——于是别人就可以通过这个页面与您联系了。值得一提的是，图标也会根据用户当时的状态不同而改变。 
&lt;LI&gt;提供了一段代码，在页面上直接放入一块较小的区域显示聊天页面。很显然，这是一个iframe。&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;在进行了简单的试验（使用Web Live Messenger和自己的Live Messenger聊天）之后，发现这个小玩意儿的功能还是比较可圈可点的。&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;可以选择是否允许匿名用户使用Web Live Messenger（&lt;A title=http://settings.messenger.live.com/applications/WebSettings.aspx href="http://settings.messenger.live.com/applications/WebSettings.aspx" mce_href="http://settings.messenger.live.com/applications/WebSettings.aspx"&gt;http://settings.messenger.live.com/applications/WebSettings.aspx&lt;/A&gt;）。 
&lt;LI&gt;性能很不错，基本上没有明显延迟，当然这可能和用户本身的网络条件有关。 
&lt;LI&gt;聊天的体验比想象中高很多，我们可以在Web Live Messenger的界面上发现“最近一条信息收于XXXX年X月X日 XX:XX:XX”以及“XXXX正在输入消息”的字样。此外，我们聊天中使用的特殊字体和表情符号也能正确显示。 
&lt;LI&gt;我尝试通过Web Live Messenger找出对方的IM帐号，但似乎它对于这点有着很好的保护，这意味着如果用户将Web Live Messenger放在blog上，可以避免因为泄露Email地址而遭受垃圾邮件地攻击。&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;试验了之后，我决定将其放在我的blog中，不过到底该怎么放呢？&lt;/P&gt;
&lt;H2&gt;&lt;STRONG&gt;Live Demo&lt;/STRONG&gt;&lt;/H2&gt;
&lt;P&gt;现在访问&lt;A href="http://lovecherry.cnblogs.com/" target=_blank mce_href="http://lovecherry.cnblogs.com/"&gt;LoveCherry&lt;/A&gt;的blog会发现他已经将Web Live Messenger从边栏撤下了。边栏实在太窄，如果使用一个稍微长一些的Nick就会被顶的很高，而且由于一行能显示的文字太少，用户体验也很差。最后，我使用了“传统”网页内嵌聊天对话框的做法。如果您现在正在浏览我的blog，就会发现页面的右下角出现了一个矩形的Windows Live Messenger的图片，点击它则会显示出一个300*400的Web Live Messenger聊天对话框。如果您觉得这个对话框挡着页面上的内容了，就可以点击对话框左上角的关闭按钮，这样页面上又只剩下了右下角的矩形图片了。同时，我选择了淡入淡出的效果来显示/隐藏Web Live Messenger聊天对话框。这么做的目的只有一个，那就是让用户体验更酷一些。:)&lt;/P&gt;
&lt;P&gt;现在大家可以试验一下Web Live Messenger的聊天功能了。不过请大家能够访问&lt;A title=http://settings.messenger.live.com/applications/CreateHtml.aspx href="http://settings.messenger.live.com/applications/CreateHtml.aspx" mce_href="http://settings.messenger.live.com/applications/CreateHtml.aspx"&gt;http://settings.messenger.live.com/applications/CreateHtml.aspx&lt;/A&gt;，在页面中和自己的Live Messenger进行聊天。如果您直接在我的blog上测试Web Live Messenger，我实在会忙不过来。:(&lt;/P&gt;
&lt;H2&gt;&lt;STRONG&gt;实现&lt;/STRONG&gt;&lt;/H2&gt;
&lt;P&gt;实现并不复杂，我总共用了大约2个小时，其中还包括学习了一些jQuery的功能所花的时间。唉，没想到我居然到现在才第一次使用这个如此了得的JavaScript框架。不得不说，如果您正在寻找一款方便您开发前端应用程序的JavaScript框架，并且希望它足够的小，那么jQuery很可能就是您需要的。与它强大的功能不相称的是迷你的体积。一个经过混淆，还没有Gzip压缩的jQuery脚本文件才26K大小，但是它带给你的便利可以帮您节省大量的工作。&lt;/P&gt;
&lt;P&gt;那么我们现在就开始吧，首先，我们需要让Web Live Messenger的聊天对话框能够永远显示在页面的可视范围之内。要实现这个功能，关键还是在于对页面中元素尺寸的计算。请看如下代码：&lt;/P&gt;
&lt;P style="BORDER-RIGHT: #c0c0c0 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #c0c0c0 1px solid; PADDING-LEFT: 5px; FONT-SIZE: 10pt; PADDING-BOTTOM: 5px; MARGIN-LEFT: 20px; BORDER-LEFT: #c0c0c0 1px solid; MARGIN-RIGHT: 20px; PADDING-TOP: 5px; BORDER-BOTTOM: #c0c0c0 1px solid; FONT-FAMILY: 'Lucida Sans Typewriter', 'Courier New'"&gt;&lt;SPAN style="COLOR: blue"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;script&lt;/SPAN&gt; &lt;SPAN style="COLOR: red"&gt;language&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;="javascript"&lt;/SPAN&gt; &lt;SPAN style="COLOR: red"&gt;type&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;="text/javascript"&amp;gt;&lt;/SPAN&gt;&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;function&lt;/SPAN&gt; getClientBounds()&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;{&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;var&lt;/SPAN&gt; clientWidth;&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;var&lt;/SPAN&gt; clientHeight;&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;if&lt;/SPAN&gt; ($.browser.msie)&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;{&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;clientWidth = document.body.clientWidth;&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;clientHeight = document.body.clientHeight;&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;}&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;else&lt;/SPAN&gt; &lt;SPAN style="COLOR: blue"&gt;if&lt;/SPAN&gt; ($.browser.safari)&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;{&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;clientWidth = window.innerWidth;&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;clientHeight = window.innerHeight;&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;}&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;else&lt;/SPAN&gt; &lt;SPAN style="COLOR: blue"&gt;if&lt;/SPAN&gt; ($.browser.opera)&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;{&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;clientWidth = Math.min(window.innerWidth,&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;document.body.clientWidth);&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;clientHeight = Math.min(window.innerHeight,&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;document.body.clientHeight);&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;}&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;else&lt;/SPAN&gt;&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;{&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;clientWidth = Math.min(window.innerWidth,&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;document.documentElement.clientWidth);&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;clientHeight = Math.min(window.innerHeight,&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;document.documentElement.clientHeight);&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;}&lt;BR&gt;&amp;nbsp;&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;return&lt;/SPAN&gt; { width : clientWidth, height : clientHeight };&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;}&lt;BR&gt;&amp;nbsp;&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;function&lt;/SPAN&gt; resetLiveMessengerPosition()&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;{&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;var&lt;/SPAN&gt; clientBounds = getClientBounds();&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;var&lt;/SPAN&gt; container = document.getElementById(&lt;SPAN style="COLOR: #a31515"&gt;"liveMessengerContainer"&lt;/SPAN&gt;);&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;var&lt;/SPAN&gt; scrollLeft = (document.documentElement.scrollLeft ?&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;document.documentElement.scrollLeft : document.body.scrollLeft);&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;var&lt;/SPAN&gt; scrollTop = (document.documentElement.scrollTop ?&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;document.documentElement.scrollTop : document.body.scrollTop);&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;var&lt;/SPAN&gt; containerLeft = scrollLeft + clientBounds.width - &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; container.clientWidth – 5;&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN&gt;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;var&lt;/SPAN&gt; containerTop = scrollTop + clientBounds.height - &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; container.clientHeight;&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;$(&lt;SPAN style="COLOR: #a31515"&gt;"#liveMessengerContainer"&lt;/SPAN&gt;).css(&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;{top : containerTop + &lt;SPAN style="COLOR: #a31515"&gt;"px"&lt;/SPAN&gt;, left : containerLeft + &lt;SPAN style="COLOR: #a31515"&gt;"px"&lt;/SPAN&gt;});&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;}&lt;BR&gt;&lt;SPAN style="COLOR: blue"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;script&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;&amp;gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;以上getClientBounds方法通过判断浏览器类型来得到页面显示区域的精确尺寸，而resetLiveMessengerPosition方法根据liveMessengerContainer元素的尺寸重设该容器在浏览器中的位置。这两个方法谈不上“技术”，而更像是一种“经验”，它们都是我属于所收藏的JavaScript代码，如果大家需要的话也可以保留，或者需要时再来我的blog查找（其实我以前也有文章用到过这些方法）。需要注意的是，如果您使用了的是IE浏览器，在某些的页面上可能会需要通过document.documentElement.clientWidth来获得代码（clientHeight也一样），具体原因我正在调查，大家在使用时也请注意这点。&lt;/P&gt;
&lt;P&gt;哎？那么resetLiveMessengerPosition方法该在什么时候调用呢？先不着急，我们再来实现Web Live Messenger的显示/隐藏，以及淡入淡出效果——为什么放在一起实现了？因为我们用到了jQuery框架。请看如下代码：&lt;/P&gt;
&lt;P style="BORDER-RIGHT: #c0c0c0 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #c0c0c0 1px solid; PADDING-LEFT: 5px; FONT-SIZE: 10pt; PADDING-BOTTOM: 5px; MARGIN-LEFT: 20px; BORDER-LEFT: #c0c0c0 1px solid; MARGIN-RIGHT: 20px; PADDING-TOP: 5px; BORDER-BOTTOM: #c0c0c0 1px solid; FONT-FAMILY: 'Lucida Sans Typewriter', 'Courier New'"&gt;&lt;SPAN style="COLOR: blue"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;div&lt;/SPAN&gt;&lt;SPAN&gt; &lt;SPAN style="COLOR: red"&gt;id&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;="liveMessengerContainer"&lt;/SPAN&gt; &lt;SPAN style="COLOR: red"&gt;style&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;="&lt;/SPAN&gt;&lt;SPAN style="COLOR: red"&gt;position&lt;/SPAN&gt;:&lt;SPAN style="COLOR: blue"&gt;absolute&lt;/SPAN&gt;;&lt;SPAN style="COLOR: blue"&gt;"&amp;gt;&lt;/SPAN&gt;&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;div&lt;/SPAN&gt; &lt;SPAN style="COLOR: red"&gt;style&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;="&lt;/SPAN&gt;&lt;SPAN style="COLOR: red"&gt;border&lt;/SPAN&gt;: &lt;SPAN style="COLOR: blue"&gt;solid&lt;/SPAN&gt; &lt;SPAN style="COLOR: blue"&gt;1px&lt;/SPAN&gt; &lt;SPAN style="COLOR: blue"&gt;black&lt;/SPAN&gt;; &lt;SPAN style="COLOR: red"&gt;width&lt;/SPAN&gt;:&lt;SPAN style="COLOR: blue"&gt;160&lt;/SPAN&gt;;&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: red"&gt;height&lt;/SPAN&gt;: &lt;SPAN style="COLOR: blue"&gt;39px&lt;/SPAN&gt;; &lt;SPAN style="COLOR: red"&gt;cursor&lt;/SPAN&gt;:&lt;SPAN style="COLOR: blue"&gt;pointer&lt;/SPAN&gt;;&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: red"&gt;background-image&lt;/SPAN&gt;:&lt;SPAN style="COLOR: blue"&gt;url(Messenger_Header_bg.gif)"&lt;/SPAN&gt;&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: red"&gt;id&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;="liveMessengerThumb"&amp;gt;&lt;/SPAN&gt;&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;img&lt;/SPAN&gt; &lt;SPAN style="COLOR: red"&gt;src&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;="Messenger_logo_beta.gif"&lt;/SPAN&gt;&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: red"&gt;alt&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;="&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;使用&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;Live Messenger&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;联系我&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;"&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: red"&gt;style&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;="&lt;/SPAN&gt;&lt;SPAN style="COLOR: red"&gt;margin&lt;/SPAN&gt;: &lt;SPAN style="COLOR: blue"&gt;10px&lt;/SPAN&gt; &lt;SPAN style="COLOR: blue"&gt;10px&lt;/SPAN&gt; &lt;SPAN style="COLOR: blue"&gt;0px&lt;/SPAN&gt; &lt;SPAN style="COLOR: blue"&gt;9px&lt;/SPAN&gt;;&lt;SPAN style="COLOR: blue"&gt;"/&amp;gt;&lt;/SPAN&gt;&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;div&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;&amp;gt;&lt;/SPAN&gt;&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;table&lt;/SPAN&gt; &lt;SPAN style="COLOR: red"&gt;border&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;="0"&lt;/SPAN&gt; &lt;SPAN style="COLOR: red"&gt;cellpadding&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;="0"&lt;/SPAN&gt; &lt;SPAN style="COLOR: red"&gt;cellspacing&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;="0"&lt;/SPAN&gt;&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: red"&gt;id&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;="liveMessengerPanel"&amp;gt;&lt;/SPAN&gt;&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;tr&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;&amp;gt;&lt;/SPAN&gt;&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;td&lt;/SPAN&gt; &lt;SPAN style="COLOR: red"&gt;valign&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;="top"&amp;gt;&lt;/SPAN&gt;&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;img&lt;/SPAN&gt; &lt;SPAN style="COLOR: red"&gt;id&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;="hideLiveMessengerPanel"&lt;/SPAN&gt;&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: red"&gt;style&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;="&lt;/SPAN&gt;&lt;SPAN style="COLOR: red"&gt;cursor&lt;/SPAN&gt;:&lt;SPAN style="COLOR: blue"&gt;pointer&lt;/SPAN&gt;; &lt;SPAN style="COLOR: red"&gt;margin-right&lt;/SPAN&gt;: &lt;SPAN style="COLOR: blue"&gt;3px&lt;/SPAN&gt;;&lt;SPAN style="COLOR: blue"&gt;"&lt;/SPAN&gt;&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: red"&gt;src&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;="Messenger_close_sm.gif"&lt;/SPAN&gt; &lt;SPAN style="COLOR: red"&gt;alt&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;="&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;关闭&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;"&lt;/SPAN&gt; &lt;SPAN style="COLOR: blue"&gt;/&amp;gt;&lt;/SPAN&gt;&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;td&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;&amp;gt;&lt;/SPAN&gt;&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;td&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;&amp;gt;&lt;/SPAN&gt;&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;iframe&lt;/SPAN&gt;&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: red"&gt;src&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;="..."&lt;/SPAN&gt; &lt;SPAN style="COLOR: red"&gt;width&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;="300"&lt;/SPAN&gt; &lt;SPAN style="COLOR: red"&gt;frameborder&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;="0"&lt;/SPAN&gt;&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: red"&gt;style&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;="&lt;/SPAN&gt;&lt;SPAN style="COLOR: red"&gt;border&lt;/SPAN&gt;: &lt;SPAN style="COLOR: blue"&gt;solid&lt;/SPAN&gt; &lt;SPAN style="COLOR: blue"&gt;1px&lt;/SPAN&gt; &lt;SPAN style="COLOR: blue"&gt;black&lt;/SPAN&gt;; &lt;SPAN style="COLOR: red"&gt;width&lt;/SPAN&gt;: &lt;SPAN style="COLOR: blue"&gt;300px&lt;/SPAN&gt;;&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: red"&gt;height&lt;/SPAN&gt;: &lt;SPAN style="COLOR: blue"&gt;400px&lt;/SPAN&gt;;&lt;SPAN style="COLOR: blue"&gt;"&amp;gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;iframe&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;&amp;gt;&lt;/SPAN&gt;&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;td&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;&amp;gt;&lt;/SPAN&gt;&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;tr&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;&amp;gt;&lt;/SPAN&gt;&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;table&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;&amp;gt;&lt;/SPAN&gt;&lt;BR&gt;&lt;SPAN style="COLOR: blue"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;div&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;&amp;gt;&lt;/SPAN&gt;&lt;BR&gt;&lt;BR&gt;&lt;SPAN style="COLOR: blue"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;script&lt;/SPAN&gt; &lt;SPAN style="COLOR: red"&gt;language&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;="javascript"&lt;/SPAN&gt; &lt;SPAN style="COLOR: red"&gt;type&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;="text/javascript"&amp;gt;&lt;/SPAN&gt;&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;$(&lt;SPAN style="COLOR: #a31515"&gt;"#liveMessengerPanel"&lt;/SPAN&gt;).hide();&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;$(document).ready(&lt;SPAN style="COLOR: blue"&gt;function&lt;/SPAN&gt;(){&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;$(window).scroll(resetLiveMessengerPosition);&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;$(window).resize(resetLiveMessengerPosition);&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;resetLiveMessengerPosition();&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;$(&lt;SPAN style="COLOR: #a31515"&gt;"#liveMessengerThumb"&lt;/SPAN&gt;).click(&lt;SPAN style="COLOR: blue"&gt;function&lt;/SPAN&gt;(){&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;$(&lt;SPAN style="COLOR: #a31515"&gt;"#liveMessengerThumb"&lt;/SPAN&gt;).fadeOut(500, &lt;SPAN style="COLOR: blue"&gt;function&lt;/SPAN&gt;(){&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;$(&lt;SPAN style="COLOR: #a31515"&gt;"#liveMessengerPanel"&lt;/SPAN&gt;).fadeIn(500, &lt;SPAN style="COLOR: blue"&gt;function&lt;/SPAN&gt;(){&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;resetLiveMessengerPosition();&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;});&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;resetLiveMessengerPosition();&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;});&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;});&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;$(&lt;SPAN style="COLOR: #a31515"&gt;"#hideLiveMessengerPanel"&lt;/SPAN&gt;).click(&lt;SPAN style="COLOR: blue"&gt;function&lt;/SPAN&gt;(){&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;$(&lt;SPAN style="COLOR: #a31515"&gt;"#liveMessengerPanel"&lt;/SPAN&gt;).fadeOut(500, &lt;SPAN style="COLOR: blue"&gt;function&lt;/SPAN&gt;(){&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;$(&lt;SPAN style="COLOR: #a31515"&gt;"#liveMessengerThumb"&lt;/SPAN&gt;).fadeIn(500, &lt;SPAN style="COLOR: blue"&gt;function&lt;/SPAN&gt;(){&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;resetLiveMessengerPosition();&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;});&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;resetLiveMessengerPosition();&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;});&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;});&lt;BR&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;});&lt;BR&gt;&lt;SPAN style="COLOR: blue"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;script&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;&amp;gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;liveMessengerContainer容器中的内容我就不进行太多解释了。同样略过的还有jQuery的基本使用，不过相信有一定JavaScript基础的朋友也能比较轻松地看懂。以上JavaScript代码的第一句隐藏了聊天对话框，接着在jQuery中经典的$(document).ready事件中对以有的元素进行操作。首先，我们要求在用户移动了滚动条（scroll），或者改变了浏览器大小（resize）时重新设置容器的位置。需要注意的是，我们接着需要显式调用resetLiveMessengerPosition方法来对容器的位置进行初始化。然后jQuery开始展现了它的神奇之处，短短几行代码即完成了淡入淡出的切换功能，让人叹为观止。&lt;/P&gt;
&lt;P&gt;至此，在页面中嵌入一个Web Live Messenger的工作就完成了。欢迎大家提出意见和建议，帮助我改进这个功能。&lt;/P&gt;</description>
      <comments>http://blog.zhaojie.me/2007/11/add-web-live-messenger-to-your-page.html#comments</comments>
      <pubDate>Fri, 09 Nov 2007 16:37:00 GMT</pubDate>
      <lastBuildDate>Fri, 09 Nov 2007 16:37:00 GMT</lastBuildDate>
    </item>
    <item>
      <author>jeffz@live.com (老赵)</author>
      <category domain="http://blog.zhaojie.me/cutting-edge/">技术尝鲜</category>
      <title>Gadget，又见Gadget - 浅尝Windows Live Contacts Gadget</title>
      <link>http://blog.zhaojie.me/2006/10/windows-live-contacts-gadget.html</link>
      <guid>http://blog.zhaojie.me/2006/10/windows-live-contacts-gadget.html</guid>
      <description>&lt;span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana"&gt;&lt;span style="FONT-SIZE: 20px"&gt;&lt;strong style="FONT-SIZE: 14pt"&gt;前言&lt;/strong&gt;&lt;/span&gt;&lt;br&gt;&lt;br&gt;自从Windows&amp;nbsp;Live推出开始，微软就加大了对于开发人员的&amp;#8220;笼络&amp;#8221;。上到Windows Live Gadgets和Windows Live Search Macro，下到Windows Live Toolbar和Messenger，每个产品纷纷通过某种方式提供API，这似乎已经是Windows Live系列产品的一个mandatory feature。迎合Web 2.0的Mashup理念，将中心转移到用户/开发人员，微软在这点上可谓煞费苦心。&lt;br&gt;&lt;br&gt;这种做法似乎颇为有效，至少Gadgets在刚出现时将我&amp;#8220;一举击溃&amp;#8221;，让我&amp;#8220;义无反顾&amp;#8221;地投身到Gadgets开发队伍中去。不过随着不断地深入，我的热情也渐渐消退。如果说Gadget的一些不足还可以在以后弥补的话（事实上现在的确已经相当不错了），而一些&amp;#8220;硬伤&amp;#8221;则会很难有所改进。例如，Gadgets都会在一个iframe中执行，这个sandbox提供了强大的安全保证，却也对于Gagdet表现本身做了无比的限制。另外，例如Windows Live Spaces Gadgets取消了set/getPreference功能，也几乎让其存在的价值打了很大的折扣。因此&lt;a href="http://blog.zhaojie.me/2006/10/book-list-gadget-for-windows-live-spaces-usage-instructions.html" target=_blank&gt;Book List Gadget&amp;nbsp;for Windows Live Spaces&lt;/a&gt;（这是我为了弥补中国市场Windows Live Spaces开发的Gadget，使用了Amazon的API）也成为了我以&amp;#8220;个人身份&amp;#8221;开发的最后一个Gadget。&lt;br&gt;&lt;br&gt;说得有点远了，收回。近日在&lt;a href="http://dev.live.com/" target=_blank&gt;Windows Live Dev&lt;/a&gt;里发现了一个新的Feature（其实已经出现一个多月了）：Windows Live Contacts Gadget (Beta)，一试之下，颇为有趣。&lt;br&gt;&lt;br&gt;Windows Live Contacts Gadget可能是一个创举，它能够将Windows Live Account上的联系人信息提供给任意第三方使用。任意第三方的产品可以轻易地结合这些联系人信息进行开发（后面将会看到它与Windows Live Local结合的范例）。要做到这点，从技术上来讲，要解决的问题主要就是Cross Domain Data Transfer。Windows Live Contacts Gadget使用了一个它称之为channel的技术巧妙地解决了这一点，虽然我觉得还不完美。不过现在不讨论太多技术，我也只是做了一个尝试，所以先来看一个Quick Start吧。&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;span style="FONT-SIZE: 14pt"&gt;Quick Start&lt;/span&gt;&lt;br&gt;&lt;br&gt;要使用Windows Live Contacts很简单，按照一下几步即可：&lt;br&gt;&lt;br&gt;&lt;strong&gt;1、添加channel文件：&lt;/strong&gt;&lt;br&gt;&lt;br&gt;将&lt;a href="http://dev.live.com/scripts/AddressManager/channel.htm" target=_blank&gt;http://dev.live.com/scripts/AddressManager/channel.htm&lt;/a&gt;复制到网站的根目录下。例如网站Domain是&lt;a href="http://www.jeffzlive.net/"&gt;http://www.jeffzlive.net&lt;/a&gt;，则channel文件则是&lt;a href="http://www.jeffzlive.net/channel.htm"&gt;http://www.jeffzlive.net/channel.htm&lt;/a&gt;。&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;strong&gt;2、引入必须的Javascript：&lt;/strong&gt;&lt;br&gt;&lt;br&gt;在代码中添加如下的Javascript引用：&lt;br&gt;
&lt;div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #eeeeee"&gt;&lt;span style="COLOR: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="COLOR: #800000"&gt;script&amp;nbsp;&lt;/span&gt;&lt;span style="COLOR: #ff0000"&gt;type&lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;="text/javascript"&lt;/span&gt;&lt;span style="COLOR: #ff0000"&gt;&amp;nbsp;src&lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;="http://dev.live.com/scripts/AddressManager/ContactSelectorPartner.js"&lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="COLOR: #800000"&gt;script&lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;span style="COLOR: #000000"&gt;&lt;br&gt;&lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="COLOR: #800000"&gt;script&amp;nbsp;&lt;/span&gt;&lt;span style="COLOR: #ff0000"&gt;type&lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;="text/javascript"&lt;/span&gt;&lt;span style="COLOR: #ff0000"&gt;&amp;nbsp;src&lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;="http://dev.live.com/scripts/AddressManager/proxy.js"&lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="COLOR: #800000"&gt;script&lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;
&lt;br&gt;&lt;br&gt;&lt;strong&gt;3、构造一个所需的HTML元素，作为Windows Live Contacts Gadget的容器：&lt;/strong&gt;&lt;br&gt;&lt;br&gt;在代码里添加如下的的HTML元素：&lt;br&gt;
&lt;div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #eeeeee"&gt;&lt;span style="COLOR: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="COLOR: #800000"&gt;div&amp;nbsp;&lt;/span&gt;&lt;span style="COLOR: #ff0000"&gt;id&lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;="ContactsGadgetSite"&lt;/span&gt;&lt;span style="COLOR: #ff0000"&gt;&amp;nbsp;style&lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;="width:250px;height:350px"&lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="COLOR: #800000"&gt;div&lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;span style="COLOR: #000000"&gt;&lt;br&gt;&lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="COLOR: #800000"&gt;div&amp;nbsp;&lt;/span&gt;&lt;span style="COLOR: #ff0000"&gt;id&lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;="ContactsDisplay"&lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="COLOR: #800000"&gt;div&lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;
&lt;br&gt;第一个元素ContactsGadgetSite是做为Gadget的容器存在的，因此对于它的大小有一定要求，其最小宽度为172px，最小高度为232px。第二个元素ContactsDisplay则是用来显示信息，在这个Quick Start中会使用到。&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;strong&gt;4、添加调用代码：&lt;/strong&gt;&lt;br&gt;&lt;br&gt;在某处添加如下代码，执行这段代码将初始化Windows Live Contacts Gadget：&lt;br&gt;
&lt;div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #eeeeee"&gt;&lt;span style="COLOR: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="COLOR: #800000"&gt;script&amp;nbsp;&lt;/span&gt;&lt;span style="COLOR: #ff0000"&gt;type&lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;="text/javascript"&lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="COLOR: #0000ff; BACKGROUND-COLOR: #f5f5f5"&gt;var&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;&amp;nbsp;CP&amp;nbsp;&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;=&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="COLOR: #0000ff; BACKGROUND-COLOR: #f5f5f5"&gt;new&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;&amp;nbsp;Microsoft.Gadget.ContactSelectorPartner(&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;document.getElementById(&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;"&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;ContactsGadgetSite&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;"&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;),&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;"&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;http://www.jeffzlive.net/privacyStatement.html&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;",&amp;nbsp;&lt;/span&gt;&lt;span style="COLOR: #008000; BACKGROUND-COLOR: #f5f5f5"&gt;//&lt;/span&gt;&lt;span style="COLOR: #008000; BACKGROUND-COLOR: #f5f5f5"&gt;privacy&amp;nbsp;statement&amp;nbsp;URL&lt;/span&gt;&lt;span style="COLOR: #008000; BACKGROUND-COLOR: #f5f5f5"&gt;&lt;br&gt;&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;"&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;name,email&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;"&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style="COLOR: #008000; BACKGROUND-COLOR: #f5f5f5"&gt;//&lt;/span&gt;&lt;span style="COLOR: #008000; BACKGROUND-COLOR: #f5f5f5"&gt;comma&amp;nbsp;delimited&amp;nbsp;list&amp;nbsp;of&amp;nbsp;requested&amp;nbsp;columns&amp;nbsp;to&amp;nbsp;return&lt;/span&gt;&lt;span style="COLOR: #008000; BACKGROUND-COLOR: #f5f5f5"&gt;&lt;br&gt;&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;receiveData,&amp;nbsp;&lt;/span&gt;&lt;span style="COLOR: #008000; BACKGROUND-COLOR: #f5f5f5"&gt;//&lt;/span&gt;&lt;span style="COLOR: #008000; BACKGROUND-COLOR: #f5f5f5"&gt;callback&amp;nbsp;function&lt;/span&gt;&lt;span style="COLOR: #008000; BACKGROUND-COLOR: #f5f5f5"&gt;&lt;br&gt;&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;"&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;http://www.jeffzlive.net/channel.htm&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;"&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;);&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="COLOR: #008000; BACKGROUND-COLOR: #f5f5f5"&gt;//&lt;/span&gt;&lt;span style="COLOR: #008000; BACKGROUND-COLOR: #f5f5f5"&gt;&amp;nbsp;communication&amp;nbsp;endpoint&amp;nbsp;in&amp;nbsp;your&amp;nbsp;domain&lt;/span&gt;&lt;span style="COLOR: #008000; BACKGROUND-COLOR: #f5f5f5"&gt;&lt;br&gt;&lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="COLOR: #800000"&gt;script&lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;
&lt;br&gt;其中第三个参数所需要的联系人的信息，用逗号分割。可以使用的参数是：name（姓名或昵称，如果没有填写的话则使用passport account的E-mail。）、email（主要E-mail、如果没有填写，则使用个人E-mail或Business E-mail）、phone（主要电话号码）、firstname、 middlename、lastname、nickname、passportname(用户的Mirosoft Passport ID)、emailpersonal、emailbusiness、emailother、phonepersonal、phonebusiness、phonemobile、phonepager、phonefax、phoneother、personalstreet、personalcity、personalstate、personalcountry、personalpostalcode、businessname、businessstreet、businesscity、businessstate、businesscountry、businesspostalcode、websitepersonal、websitebusiness。&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;strong&gt;5、添加回调函数：&lt;/strong&gt;&lt;br&gt;&lt;br&gt;添加回调函数的定义，例如：&lt;br&gt;
&lt;div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #eeeeee"&gt;&lt;span style="COLOR: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="COLOR: #800000"&gt;script&amp;nbsp;&lt;/span&gt;&lt;span style="COLOR: #ff0000"&gt;language&lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;="javascript"&lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="COLOR: #0000ff; BACKGROUND-COLOR: #f5f5f5"&gt;function&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;&amp;nbsp;receiveData(p_command,&amp;nbsp;p_contacts)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="COLOR: #0000ff; BACKGROUND-COLOR: #f5f5f5"&gt;var&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;&amp;nbsp;msg;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="COLOR: #0000ff; BACKGROUND-COLOR: #f5f5f5"&gt;switch&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;&amp;nbsp;(p_command)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="COLOR: #0000ff; BACKGROUND-COLOR: #f5f5f5"&gt;case&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;"&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;SIGN_OUT&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;"&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;:&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;msg&amp;nbsp;&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;=&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;"&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;user&amp;nbsp;is&amp;nbsp;not&amp;nbsp;signed&amp;nbsp;in&amp;nbsp;to&amp;nbsp;live.com&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;"&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="COLOR: #0000ff; BACKGROUND-COLOR: #f5f5f5"&gt;break&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="COLOR: #0000ff; BACKGROUND-COLOR: #f5f5f5"&gt;case&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;"&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;SIGN_IN&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;"&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;:&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;msg&amp;nbsp;&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;=&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;"&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;user&amp;nbsp;is&amp;nbsp;signed&amp;nbsp;in&amp;nbsp;to&amp;nbsp;live.com&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;"&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="COLOR: #0000ff; BACKGROUND-COLOR: #f5f5f5"&gt;break&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;;&amp;nbsp;&lt;/span&gt;&lt;span style="COLOR: #008000; BACKGROUND-COLOR: #f5f5f5"&gt;//&lt;/span&gt;&lt;span style="COLOR: #008000; BACKGROUND-COLOR: #f5f5f5"&gt;&amp;nbsp;user&amp;nbsp;is&amp;nbsp;signed&amp;nbsp;in&lt;/span&gt;&lt;span style="COLOR: #008000; BACKGROUND-COLOR: #f5f5f5"&gt;&lt;br&gt;&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="COLOR: #0000ff; BACKGROUND-COLOR: #f5f5f5"&gt;case&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;"&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;DATA&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;"&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="COLOR: #008000; BACKGROUND-COLOR: #f5f5f5"&gt;//&lt;/span&gt;&lt;span style="COLOR: #008000; BACKGROUND-COLOR: #f5f5f5"&gt;&amp;nbsp;here&amp;nbsp;comes&amp;nbsp;the&amp;nbsp;data!&lt;/span&gt;&lt;span style="COLOR: #008000; BACKGROUND-COLOR: #f5f5f5"&gt;&lt;br&gt;&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="COLOR: #0000ff; BACKGROUND-COLOR: #f5f5f5"&gt;var&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;&amp;nbsp;msg&amp;nbsp;&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;=&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;"&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;Done!&amp;nbsp;&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;"&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;+&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;&amp;nbsp;p_contacts.length&amp;nbsp;&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;+&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;"&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;&amp;nbsp;records&amp;nbsp;received.&amp;nbsp;&amp;lt;br&amp;gt;&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;"&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="COLOR: #0000ff; BACKGROUND-COLOR: #f5f5f5"&gt;for&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;&amp;nbsp;(&lt;/span&gt;&lt;span style="COLOR: #0000ff; BACKGROUND-COLOR: #f5f5f5"&gt;var&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;&amp;nbsp;i&amp;nbsp;&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;=&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;0&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;;&amp;nbsp;i&amp;nbsp;&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;&amp;lt;&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;&amp;nbsp;p_contacts.length;&amp;nbsp;i&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;++&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;msg&amp;nbsp;&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;+=&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;"&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;"&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;msg&amp;nbsp;&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;+=&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;"&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;Name:&amp;nbsp;&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;"&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;+&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;&amp;nbsp;p_contacts[i].name&amp;nbsp;&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;+&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;"&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;&amp;lt;br&amp;gt;&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;"&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;msg&amp;nbsp;&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;+=&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;"&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;Email:&amp;nbsp;&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;"&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;+&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;&amp;nbsp;p_contacts[i].email;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;msg&amp;nbsp;&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;+=&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;"&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;"&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="COLOR: #0000ff; BACKGROUND-COLOR: #f5f5f5"&gt;break&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;document.getElementById(&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;"&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;ContactsDisplay&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;"&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;).innerHTML&amp;nbsp;&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;=&lt;/span&gt;&lt;span style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"&gt;&amp;nbsp;msg;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br&gt;&lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="COLOR: #800000"&gt;script&lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;
&lt;br&gt;p_contacts是请求的联系人数组。只有当p_command为&amp;#8220;DATA&amp;#8221;时，p_contacts才会有数据。&lt;br&gt;&lt;br&gt;&lt;br&gt;到这里，这个Quick Start就完成了。&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;span style="FONT-SIZE: 14pt"&gt;&lt;strong&gt;使用效果&lt;/strong&gt;&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;strong&gt;1、打开Quick Start，如果您没有登陆Windows Live，则会看到下面的提示。&lt;/strong&gt;&lt;br&gt;&lt;br&gt;&lt;img src="http://img.zhaojie.me/blog/WLCG_NotSignedIn.jpg" border=0&gt;&lt;br&gt;&lt;br&gt;请点击Sign in并在弹出窗口内登陆。&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;strong&gt;2、登陆Windows Live后出现的页面：&lt;/strong&gt;&lt;br&gt;&lt;br&gt;&lt;img src="http://img.zhaojie.me/blog/WLCG_Ready.jpg" border=0&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;strong&gt;3、选择一项或多项，并点击Send select contacts按钮，则会弹出窗口：&lt;/strong&gt;&lt;br&gt;&lt;br&gt;&lt;span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana"&gt;&lt;img src="http://img.zhaojie.me/blog/WLCG_PopupSend.jpg" border=0&gt;&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;strong&gt;4、点击Send按钮，则页面中的回调函数则会被执行，页面中会显示信息：&lt;/strong&gt;&lt;br&gt;&lt;br&gt;&lt;img src="http://img.zhaojie.me/blog/WLCG_End.jpg" border=0&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;从上面的例子里可以看出Windows Live Contacts Gadget的大致功能。我另外也部属了一个&lt;a href="http://www.jeffzlive.net/Samples/WLContactGadget/MapContacts.html" target=_blank&gt;Mapping your contacts&lt;/a&gt;在我的Web Host上，可以看出使用Windows Live Local与Windows Live Contacts Gadget进行Mashup有多么的简单。&lt;br&gt;&lt;br&gt;&lt;a href="http://www.jeffzlive.net/Samples/WLContactGadget/QuickStart.htm" target=_blank&gt;点击这里&lt;/a&gt;查看Quick Start。&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;span style="FONT-SIZE: 14pt"&gt;&lt;strong&gt;缺点&lt;/strong&gt;&lt;/span&gt;&lt;br&gt;&lt;br&gt;可是缺点依旧存在，而且其严重程度可能导致了Windows Live Contacts Gadget无法让人接受。目前我认为最严重的问题是：&lt;br&gt;&lt;br&gt;1、如果联系人多，浏览器会出现比较长时间的假死现象。&lt;br&gt;2、浏览器的&amp;#8220;历史&amp;#8221;被严重摧残。Windows Live Contacts Gadgets使用了iframe，因此这几乎是无法避免的缺陷。&lt;br&gt;&lt;br&gt;事实上问题不止这些，官方也提供了Known Issues的列表，详情请见：&lt;a href="http://dev.live.com/contactsgadget/knownissues.aspx" target=_blank&gt;http://dev.live.com/contactsgadget/knownissues.aspx&lt;/a&gt;&lt;br&gt;&lt;br&gt;Windows Live Contacts Gadget要真正成功的话，真可谓&amp;#8220;路漫漫其修远兮&amp;#8221;&amp;#8230;&amp;#8230;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;span style="FONT-SIZE: 14pt"&gt;&lt;strong&gt;参考&lt;/strong&gt;&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;strong&gt;Windows Live Dev - Windows Live Contacts Gadget (Beta)&lt;/strong&gt;&lt;br&gt;&lt;a href="http://dev.live.com/contactsgadget/" target=_blank&gt;http://dev.live.com/contactsgadget/&lt;/a&gt;&lt;br&gt;&lt;br&gt;&lt;strong&gt;Momentary Gouts of Reason&lt;/strong&gt;&lt;br&gt;&lt;a href="http://blogs.msdn.com/dthorpe/archive/2006/08/18/706422.aspx" target=_blank&gt;http://blogs.msdn.com/dthorpe/archive/2006/08/18/706422.aspx&lt;/a&gt;&lt;br&gt;&lt;br&gt;&lt;strong&gt;Building a Mashup with the Windows Live Contacts Gadget and Virtual Earth&lt;/strong&gt;&lt;br&gt;&lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnlive/html/mashupWLContacts.asp?_r=1" target=_blank&gt;http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnlive/html/mashupWLContacts.asp?_r=1&lt;/a&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;/span&gt;&lt;/span&gt;</description>
      <comments>http://blog.zhaojie.me/2006/10/windows-live-contacts-gadget.html#comments</comments>
      <pubDate>Sun, 08 Oct 2006 08:43:00 GMT</pubDate>
      <lastBuildDate>Sun, 08 Oct 2006 08:43:00 GMT</lastBuildDate>
    </item>
  </channel>
</rss>
