Author: 菩提老王

China mobile

        昨晚打10086,里面说现在是23点以后,您确定要使用紧急服务吗?紧急服务只能停开机云云,难道他们赚的比以前少了,把值夜班的人都撤了?害的今天占用23点以前的宝贵时间继续打10086,就问个关于机器呼叫转移设置的问题,说了半天都不清楚,给人感觉打10086只能单向办理收费业务,就是只能办理,不能退办。果然,我说要取消短信业务,结果被告知只能拿身份证去营业厅办……办的时候怎么那么痛快啊,电话,网上,短信一不小心就办成功了,退的时候就只能去营业厅……我半年才给你们打一次电话,这点要求都不能满足,哎!
        移动去年营业额800亿人民币。前阵子3G的广告是挺好,但是和人一样啊,不能光穿衣服漂亮,主要还得心灵美。不得不让我觉得它跟学校网络中心一样恶心,就是只收钱不办该办的事。

Bright Star

        金棕榈奖唯一的女得主Jane Campion(获奖作品是反映女性细腻心理的《钢琴课》,是部好电影),携19世纪诗人John Keats的爱情诗《Bright Star》的同名电影又去戛纳了……还没看过电影,到是对这首诗比较感兴趣。
        写作背景就是电影情节,关键是作者只有25岁不到的年龄(就去世了)。找到了一个比较完整的注释版本,也有明喻暗喻之类的分析,估计是外国语文课上的内容。从深蓝夜空中的星星,到宗教隐士洗礼的流水,还有柔软飘落的新雾,山顶上的白雪,爱人的tender breath,仿佛一次优美的时空旅行……但最后还是没能避开永远的话题:永恒和死亡。

Bright star,would I were stedfast as thou art—
Not in love splendor hung aloft the night,
And watching,with eternal lids apart,
Like nature’s patient,sleepless eremite,

The moving waters at their priestlike task
Of pure ablution round earth’s human shores,
Or gazing on the new soft-fallen mask
Of snow upon the mountains and the moors;

No—yet still stedfast,still unchangeable,
Pillow’d upon my fair love’s ripening breast,
To feel for ever its soft swell and fall,
Awake for ever in a sweet unrest,

Still,still to hear her tender-taken breath,
And so live ever-or else swoon to death.

注释:
stedfast:永恒的,不变的
aloft:高高在上的,夜空中的
lids:眼皮
Eremite:有宗教背景的隐士
pure ablution:洗礼

        想起一首同样想象空间极大的情诗,作者是木子。《我纷纷的情欲》:

尤其静夜
我的情欲大
纷纷飘下
缀满树枝窗棂
唇涡,胸埠,股壑
平原远山,路和路
都覆盖我的情欲
因为第二天
又纷纷飘下
更静,更大
我的情欲

ArcGIS API for Silverlight开发入门(8):在程序中使用Virtual Earth的服务

        Silverlight API中还包括了一个ESRI.ArcGIS.VirtualEarth.dll类库,让我们可以方便的访问到老东家的VirtualEarth服务。目前Silverlight API中提供的VirtualEarth服务有三种:Map,Geocode和Routing,不过一看就知道后两种服务对于国内的数据来说又无缘了。
        直接看如何使用它的Map服务获取地图数据吧。同前,新建一个Silverlight工程,添加ESRI.ArcGIS.dll和ESRI.ArcGIS.VirtualEarth.dll的引用,引入xml命名空间,在xaml里面这样写:





        可以看出,和添加其他图层基本是一样的。SIlverlight API中针对VE地图的图层类型是TileLayer,LayerStyle有三种:Road,Aerial和AerialWithLabels,分别对应矢量图,影像图和带街道标注的影像图。ServerType就比较特殊了,有两种:Staging和Production,分别对应访问VE服务的账户类别,前者是免费的,后者是收费的。如果你此时运行程序的话,那是看不到地图的,因为TileLayer还有个关键的token属性没有设置。
        VE的服务那是相当安全,每次访问VE的服务,都要提供一个token(一个加密字符串)来进行身份验证,而这个token又是根据TokenService自动生成的,要通过TokenService生成一个token,又需要一个合法的Microsoft Virtual Earth Platform developer account……明白了这个过程,就来做我们的工作吧。
        首先,去申请一个Microsoft Virtual Earth Platform developer account,当然之前你还得有一个Windows Live账号。申请的这个账号是Evaluation版的,所以决定了以后我们只能使用Staging的服务,如果要把它变成Production版本,可以通过邮件联系微软,然后缴费;
        之后到注册时所填的邮箱去激活申请的Microsoft Virtual Earth Platform developer account账号,然后为其设置密码(必须是8-14为之间,包括大、小写字母,数字,且还要有非字母数字的字符,和windows server 2008是一样的),我们平常肯定不会这样设置密码,为了以防万一,建议赶紧把设置好的密码记录下来,
没准哪天就忘了。现在就可以用这个账户和密码来访问TokenService,通过它生成token,交给TileLayer的token属性。
        为了安全目的考虑,token是不建议也不能直接在Silverlight程序中进行设置的。那么怎么办呢?这样办:1、通过装载Silverlight的aspx页面的Page_Load方法,来申请我们的token,并把它添加到Silverlight的初始参数中,2、然后当Silverlight插件载入的时候,把token读出来,3、在Map_Loaded事件中,赋给TileLayer。
1、通过TokenService申请token:
在web app中add web reference,url用https://staging.common.virtualearth.net/find-30/common.asmx?wsdl,起个名字叫VirtualEarthService.TokenService。

其中Xaml1是Silverlight插件的ID:
2、Silverlight插件载入时读出这个token。在App.xaml.cs中:
private void Application_Startup(object sender, StartupEventArgs e)
{
VEtoken = e.InitParams["token"];
this.RootVisual = new Page();
}

3、最后在加载地图控件后,交付token:
private void Map1_Loaded(object sender, RoutedEventArgs e)
{
foreach (Layer layer in Map1.Layers)
if (layer is TileLayer)
(layer as TileLayer).Token = (Application.Current as App).VEtoken;
}

        终于能看见VE的图了。当然,我们的开发账户是免费的,所以地图上有很多“Staging”麻点(每个tile一个):

        至此,ArcGIS API for Silverlight的开发入门已经讲完了,我和大家一样也是边学边写的,刚好这两天SIlverlight API又升级了第二个Beta版。其实Silverlight和Flex一样,能使传统的WebGIS散发出全新的魅力,从而使我们的程序在RIA的道路上大踏步前进,能够做出什么样的效果也基本只受想象力的制约了。随着Silverlight 3的推出,我们也有理由相信Silverlight的明天会更好。

Last Chance Harvey

        《哈维最后的机会》,看着看着我就觉得像是老年温馨版的《日出之前》,最后的结局又比《幸福终点站》来的要舒服。

        Harvey Shine,笑容就和他的last name一样,辛勤工作的他为了去伦敦参加女儿的婚礼,丢了工作,到了伦敦后先被前妻数落一番,后被女儿告知决定让继父代替他参加婚礼……事实证明,不是老哈维人不好,只是别人比他更适合那个家庭。Kate Walker伤心哭诉的时候,老哈维也没有去给一个可靠男人的拥抱,还是让她自己做出了决定。
        “我能把这当做是还有希望吗?
        如果是的话,给我个明确的微笑。”
        musicman说,青春还没有掏出手枪我们就倒下了,永远的倒下。但这不也是在生活之路上的重生吗?没有了青春,但我们的生命还在继续。
        和《日出》《日落》一样,这种片子好像只适合在欧洲拍摄,不管是欧洲小镇还是大城,阳光总是显得特别充足,即使是在一天中最冷的日出前后,也感觉不到一点寒意。整个城市都非常干净,路边的落叶也只会让画面显得更加清新,看了就让人直想去哪里呆一段时间。
        另插一句,在L world里头也看见人家老外掏钱上作文课。我觉得一个小孩,要是不要让他在中小学写12年的作文,把娃一直憋着,等他长大了,抛开他掏钱去上writing class不说,肯定会写一篇丰富感情自然流露的好文章出来,为啥?憋的慌么,就跟那啥道理是一样的,至少也会保有对写作这一美好事物的兴趣。
        其实看到这个片子的介绍是去年冬天一个早晨,最近发现它的时候才想起来还有这么一茬事,又让我想起了当时的情景,挺有意思。

ArcGIS API for Silverlight updated

        Silverlight API升级了,但还在继续它的beta之旅(Build 209,之前是Build 160),看来要修正的地方真不少。
        除了新出一个OverviewMap的widget,改进了Magnifier widget(减轻使用时的服务器负担),还允许在Map控件初始化的时候根据Extent来动态投影地图,这与Flex API是一样了……具体的变化请看这里

ArcGIS API for Silverlight开发入门(7):使用非AGS数据源的图层

        通过上一节学习,可以看出在Silverlight API中不仅可以轻松使用ArcGIS Server 9.3发布的地图服务,也可以通过继承相应的图层,引入其他的数据源,比如ArcGIS Server 9.2发布的地图服务,WMS服务,或者其他免费的数据。本节就通过一个实例,来看看如何将Google Map作为底图数据。
        Google Map是经过缓存的数据,所以需要继承的是TiledMapServiceLayer。那么在扩展这个图层的时候需要做哪些工作呢?首先就要明白地图缓存的原理。可以看出我们继承的这个图层,需要收集到以下几个信息:
1、Tiling Scheme Origin;
2、切图的范围,也就是FullExtent;
3、SpatialReference;
4、TileInfo,包括切图的大小,级数,以及每级的Resolution;
5、最后就是重写GetTileUrl方法。
        这是为什么呢?可以想象,当地图控件的范围改变时,能够获取到当前范围的信息,那么只要把左上角和右下角之间的Tile全部按顺序显示出来就行了。由前面的文章可以看出,当图层获取了1、2、3、4四个信息后,图层完全可以自动计算出所需的Tile,最后根据GetTileUrl方法取回这些Tile显示出来即可。
        那么对于Google Map的前4个参数,如何取得呢?记得在Catalog中做缓存时,有一个Load Tiling Scheme from Google Map吗?按照这个Tiling Scheme将一个地图服务做缓存,然后查看它的conf.xml和Service Directory,便完全可以取得这几个参数了。另外关于如何获取Google Map的缓存,网上已经有非常多方法,这里就不再讨论了。


        代码如下:
public class GoogleMap:TiledMapServiceLayer
{
public override void Initialize()
{
this.FullExtent = new ESRI.ArcGIS.Geometry.Envelope(-20037508.342787,-20037508.342787,20037508.342787,20037508.342787);//(-180, -85.0511287798066,180, 85.0511287798066)
{
SpatialReference = new ESRI.ArcGIS.Geometry.SpatialReference(102113);
};
this.SpatialReference = new ESRI.ArcGIS.Geometry.SpatialReference(102113);
//this.InitialExtent = this.FullExtent;
this.TileInfo = new TileInfo()
{
Height = 256,
Width = 256,
Origin = new ESRI.ArcGIS.Geometry.MapPoint(-20037508.342787, 20037508.342787)//Origin = new ESRI.ArcGIS.Geometry.MapPoint(-180, 90)
{
SpatialReference = new ESRI.ArcGIS.Geometry.SpatialReference(102113)
},
Lods = new Lod[20]
};

double resolution = 156543.033928;
for (int i = 0; i < TileInfo.Lods.Length; i++)
{
TileInfo.Lods[i] = new Lod() { Resolution = resolution };
resolution /= 2;
}

base.Initialize();
}

public override string GetTileUrl(int level, int row, int col)
{
//google maps map
//string baseUrl = "http://mt0.google.com/mt/v=ap.92&hl;=zh-CN&x;=";
//string url = baseUrl + col.ToString() + "&y;=" + row.ToString() + "&z;=" + level.ToString() + "&s;=";
//return url;

////google maps satallite
string baseUrl = "http://khm2.google.com/kh/v=38&hl;=zh-CN&x;=";
string url = baseUrl + col.ToString() + "&y;=" + row.ToString() + "&z;=" + level.ToString() + "&s;=";
return url;
}

}
        需要注意一点,Google Map采用的是WGS 1984 Web Mercator投影,这个投影的wkid在REST API中查不到,但在Service Direcotry中可以找到,是102113。另外,重写DynamicMapServiceLayer也是基本相同的。
        之后也可以按照这个Tiling Scheme对自己的服务作缓存,自己的数据和Google Map便可以叠加在一起了。但是这样子使用Google Map的数据不仅担心会被封IP,而且更重要的是版权问题,毕竟不像JS API(有ArcGIS JavaScript Extension for the Google Maps API )或者Flex API(有Google Map API for Flex)。别忘了MS有自己的Virtual Earth,下一节中就来看看如何在我们的程序中名正言顺的使用VE的数据吧。

ArcGIS API for Silverlight开发入门(6):图层类型小结

        在用Silverlight API开发的过程中,不论是从客户端提交到服务器端的数据,还是从服务器端返回客户端的数据,都要表现在浏览器中,具体的来说是Map控件里。但根据各自类型的不同,比如数据源,地图服务的类型,是否缓存等,决定了它们将处于某个图层里,前面讲过的GraphicsLayer就是一种图层。清楚地认识这些图层类型,对于处理于服务器与客户端之间的地图数据来说是很重要的。
        所有的图层都是从Layer类型继承而来的,可以参考下载的API中的对象模型图。
Layer
  |–TiledMapServiceLayer
  |       |–ArcGISTiledMapServiceLayer
  |–DynamicLayer
  |       |–DynamicMapServiceLayer
  |                 |–ArcGISDynamicMapServiceLayer
  |                 |–ArcGISImageServiceLayer
  |                 |–GPResultImageLayer
  |–GraphicsLayer
  |       |–FeatureLayer
  |–ElementLayer
        下面就按顺序认识一下这些图层吧,也包括Silverlight API中独有的FeatureLayer。

1、Layer:
        继承自Silverlight中的DependencyObject,并实现了INotifyPropertyChanged接口,是Silverlight API中其他图层的基类。可以把它看成麦子,再好吃的凉皮,泡馍都是由它做出来的;

2、TiledMapServiceLayer:
        继承自Layer,是所有使用了缓存的地图服务的基类。通过它可以在程序中加入经过缓存的,来自不同数据源的地图服务。比如ArcGIS Server的地图服务,Google Map的地图,Virtual Earth的地图等;

3、ArcGISTiledMapServiceLayer:
        继承自TiledMapServiceLayer。像上面说的一样,这个图层扩展了TiledMapServiceLayer,于是支持由ArcGIS Server 9.3版本发布的经过缓存的地图服务;又比如ArcGIS Server 9.2版本发布的缓存地图服务不支持REST方式连接,如果要在93的客户端API中使用的话,就可以通过TiledMapServiceLayer扩展一个比如ArcGISTiledMapServiceLayer92,来支持92Server发布的缓存地图服务;

4、DynamicLayer:
        继承自Layer,是动态地图服务的基类;

5、DynamicMapServiceLayer:
        继承自DynamicLayer,对应于TiledMapServiceLayer,要使用未经过缓存的动态地图服务,就得通过扩展这个图层来实现;

6、ArcGISDynamicMapServiceLayer:
        继承自DynamicMapServiceLayer,针对ArcGIS Server 9.3版本发布的动态地图服务。同理,如果要在客户端API中使用其他动态地图服务,比如OGC的WMS服务,则也需要像这个图层一样,扩展上面的DynamicMapServiceLayer来实现;

7、ArcGISImageServiceLayer:
        继承自DynamicMapServiceLayer,针对ArcGIS Server 9.3版本发布的Image Service,因为影像服务也属于动态的地图服务。在客户端API中,可以通过ArcGISImageServiceLayer的一些属性,方便通过浏览器来展示服务器端的影像数据,比如通过BandIds属性,可以快速调整影像数据显示波段的组合(RGB通道),提供不同结果供用户查看。点击这里,查看一个实例;

8、GPResultImageLayer:
        继承自DynamicMapServiceLayer,针对Geoprocessing服务所产生的结果。可以请求服务器端的GP服务将结果动态生成一张图片,将此图片作为GPResultImageLayer图层直接添加到Map控件中;

9、GraphicsLayer:
        继承自Layer,是图形数据集中展现的地方,在第四讲中已经详细讨论过了;

10、FeatureLayer:
        继承自GraphicsLayer,这也是Silverlight API中的亮点之一,通过它可以完成一个比较炫的功能:

        整个过程在xaml中就可以实现,只需要在Map的Layers中插入以下代码即可:
<esri:ArcGISTiledMapServiceLayer ID="StreetMapLayer" Url="http://server.arcgisonline.com/ArcGIS/rest/services/ESRI_StreetMap_World_2D/MapServer"/>
<esri:FeatureLayer ID="featurelayer"
Url="http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Specialty/ESRI_StatesCitiesRivers_USA/MapServer/0"
Where="POP1990 > 75000" ClusterFeatures="True" FlareBackground="#99FF0000" FlareForeground="White" MaximumFlareCount="9"
FeatureSymbol="{StaticResource markersymbol}">
<esri:FeatureLayer.OutFields>
<sys:String>CITY_NAME</sys:String>
<sys:String>POP1990</sys:String>
</esri:FeatureLayer.OutFields>
<esri:FeatureLayer.MapTip>
<Grid Background="LightYellow">
<StackPanel Margin="5">
<TextBlock Text="{Binding Converter={StaticResource MyDictionaryConverter},
ConverterParameter=CITY_NAME, Mode=OneWay}" FontWeight="Bold" />
<StackPanel Orientation="Horizontal">
<TextBlock Text="Population (1990): " />
<TextBlock Text="{Binding Converter={StaticResource MyDictionaryConverter},
ConverterParameter=POP1990, Mode=OneWay}" />
</StackPanel>
</StackPanel>
<Border BorderBrush="Black" BorderThickness="1" />
</Grid>
</esri:FeatureLayer.MapTip>
</esri:FeatureLayer>

        可以看出这个FeatureLayer其实是将一个Query查询封装到了一个GraphicsLayer中。通过url指定查询的图层,where指定查询条件(也可以输入geometry指定查询的图形),最关键的是ClusterFeatures=”True”,当一个范围内feature过多时,就将他们“聚合”在一起,以一个更大的符号表示出来,进一步放大时才将它们单独显示出来,如果聚合的目标不超过MaximumFlareCount设置的数目,那么就会出现那个flare动画。在MapTip(继承自GraphicsLayer)里面进行了简单的设置,一个背景为黄色的Grid里显示两行文字,用一个DictionaryConverter类将返回的Graphic.Attributes集合中的两个字段转换成String类型显示出来。顺便提一下,FeatureLayer也可以用于线或面层的查询,但如果继续使用ClusterFeatures的话就没什么意义了。虽然FeatureLayer封装的比较死,只能有此一种效果,但它提供给我们一种思路,可以结合SilverlightRIA的特性,充分发挥自己的想象力做出更炫的效果来;但是,对于需要展现海量(成百上千个)点数据的图层来说,ClusterFeatures是一个非常有用的特性,毕竟将这么多点同时呈现出来性能还是有问题的。如果不使用ClusterFeatures,看起来应该是这样的:

        不用FeatureLayer行吗?
        说到FeatureLayer,还有两个Renderer不得不提一下:UniqueValueRenderer和ClassBreakerRenderer。它们都是依托FeatureLayer的,用于单值专题图的渲染。具体的用法都比较简单,可以查看API中的Concepts。但Samples中的Thematic Rendering例子并没有采用这两种Renderer,而是人为地为每个Graphic设置了不同的Symbol。目前看来虽然这两个Renderer有点鸡肋,但毕竟是现在3种客户端API中提供的唯一现成的Renderer,可以猜想也许下个版本的Silverlight API中会有更加成熟的专题图Renderer直接供我们使用;

11、ElementLayer:
        继承自Layer,它可以用来专门呈现Silverlight中原生的FrameworkElement,比如视频,音频等。虽然在FillSymbol的Fill属性中也能利用Brush类来展现一段视频,但毕竟有些“小气”,在ElementLayer中可以大大方方的放置Silverlight元素。你可能会问,在Map控件之外,Grid等布局元素中不是也能放置Silverlight的东西吗,为什么要放在ElementLayer里呢?其实有个问题经常困扰GIS开发人员,就是想让一些非地理数据元素随着地图范围的变化(放大,缩小,平移)而变化,而无须自己在Extent变化后重新计算客户端坐标,手工改变这些元素的位置。瞧,ElementLayer正解决了这个问题。

        目前Beta版的API中暂时有这么多图层类型,以后也许会继续增加。但万变不离其宗,无非就是从那几个基类中派生出来的。所以,下一节我们就通过一个实例来看看如何扩展基类的MapServiceLayer,来达到使用非ArcGIS Server数据源的目的。

ArcGIS Server的切图原理深入

GoogleMap,Virtual Earth,YahooMap等,目前所有的WebGIS都使用了缓存机制以提高地图访问速度。原理都是将地图设定为多个比例尺,对于每个比例尺提前将地图分成若干小图片,存在服务器上,客户端访问时直接获取需要的小图片拼接成地图,而不是由服务器动态创建出一幅图片来送到客户端,极大程度的提高了反问速度。好比外面卖菠萝,和自己买一整个回家吃不同,提前把一个菠萝等分成四份(js可能会分成6份),你只需买一份来吃,体积小,方便吃,而不是对着整个菠萝咬下去,弄一脸菠萝汁。
本文中来详细了解一下ArcGIS Server目前为地图服务建立缓存(切图)的原理。先来了解一个概念:
Tiling Scheme:创建地图缓存时使用的一系列参数的总称。包括比例尺级别,图片格式,图片大小等等。
Tiling Scheme Origin:是tiling scheme grid的左上角。默认情况下就是由mxd文档使用的坐标系的原点。而切图的范围通常是mxd文档中full extent的范围,即从full extent的左上角(map origin)到右下角。注意区分map origin与tiling scheme origin。

对于不同的地图服务(mxd文档),如果使用相同的坐标系,那么就有相同的tiling scheme origin,即使他们的full extent不同(map origin不同),也能处于同一参考系中。如果full extent相同,则可以轻松地叠加在一起,这也是tiling scheme origin设计的初衷。默认情况下,切图的范围是mxd文档的full extent。如果手工设置了tiling scheme origin,那么切图的范围只能是地图范围中tiling scheme origin右下角的部分:如果tiling scheme origin在map origin的左上角,那么切图范围还是full extent;如果tiling scheme origin落在地图中,那么切图的范围就是从tiling scheme origin到full extent的右下角。这也就是为什么建议通过设置特定的矩形范围(92中)或直接使用featureclass(93中)来改变切图范围,而不是利用tiling scheme origin来限制切图范围的原因。
那么地图到底是怎么切出来的?切多少块呢?通过一个例子深入浅出吧。一个中国地图,采用了自定义的坐标系:

切图时设置如下:

看看切图完成后的文件夹结构:

在缓存目录中,首先是地图服务命名的文件夹china;之后是切图的DataFrame命名的文件夹Layers;由于采用的是fused方式,下来就是_alllayers,如果是multi-layer切图,那么就是每个图层的序号文件夹;下来就是切图设置的多个比例尺级别(Level of Detail,LOD),从小到大,对应前面设置的5个比例尺;一个比例尺文件夹下,是切图的“行”文件夹,命名规则是R加上8位行号(16进制),不足补0。比如图中的R0000000a,表示此比例尺中第10行(16进制中的a);每行文件夹下就是该行的所有tile文件了,命名规则是C加上8位列号(16进制),不足补0。为什么这个比例尺下(L01)中只有8,9,10,11行呢?前面说过切图的范围是full extent,说明在该比例尺下,从tiling scheme origin算起,中国地图的范围只占到了这几行,其余没有,不切。同理,对于上面的第九行文件夹中,只有7,8两列,其余的没有,不切。
再打开和_alllayers文件夹同级的conf.xml看看吧,里面保存了整个tiling scheme参数。

可以看出地图服务使用的坐标系信息,tile图片的DPI(96),每个tile的长度和宽度(512),以及tiling scheme origin。
现在来计算某个比例尺中,地图上一个点所在的tile图片的行列号了。比如计算L01中,乌鲁木齐市所在tile的行列号。需要收集三个信息:
1、获得乌市的地理坐标:在本地图中是x=-1341070,y=5343697;
2、获得tiling scheme:x=-35331700,y=46619300;
3、获得当前比例尺的resolution,即一个像素所占的地图单位长度:在L01比例尺上是8466.68360003387。

乌市所在的行号:(35331700-1341070)/(8466.6836*512)=7.84=8
乌市所在的列号:(46619300-5343697)/(8466.6836*512)=9.52=10
所以乌鲁木齐在切图的第二个比例尺中,处于第10行,第8列的tile。

Hallelujah: a song is not just a song

[youtube=http://www.youtube.com/watch?v=mmyQEdr_IVY]
        最近在newnaw.com上把背景音乐换成了《Hallelujah》,是Rufus Wainwright唱的,不少同学反映都好听,其实在这首歌背后还有不少的东西。
        最初听到这首歌是在《the L World》第一季里,于是乎就找到了Leonard Cohen。他是上世纪加拿大的一位诗人,小说家,词曲作者,歌手。30多岁才出版了第一张专辑,但在这之前他已经是小有名气的一位诗人了。豆瓣上有他的一本书,不过看起来读过的人不多。在google一下,结果上的第一张肖像让我想起了保罗莫里哀,不禁肃然起敬。尽管不及达芬奇,但我还是忍不住想说:哦,又是一位让人尊敬的多才多艺者。
        看看歌词的前两段:
I’ve heard there was a secret chord
That David played, and it pleased the Lord
But you don’t really care for music, do you?
It goes like this:
The fourth, the fifth, he minor fall, the major lift
The baffled king composing Hallelujah

Hallelujah, Hallelujah
Hallelujah, Hallelujah

Your faith was strong but you needed proof
You saw her bathing on the roof
Her beauty and the moonlight overthrew you
She tied you to a kitchen chair she broke your throne and she cut your hair
And from your lips she drew the Hallelujah

Hallelujah, Hallelujah
Hallelujah, Hallelujah
        没有读过圣经,有点不知所云(哈利路亚,赞美上帝的声音)。在一篇博客里找到了歌曲中的故事,很是吸引人:
        第一段歌词中提到的David。David,大卫,牧羊人出身,但容貌俊美,英勇善战,能赋能歌,战胜巨人哥利亚,被上帝选为以色列的国王。在大卫当国王的时候,一日傍晚,在阳台闲逛时偶然发现一貌美女子正在沐浴(Hallelujah 歌词中的 You saw her bathing on the roof / Her beauty and the moonlight overthrew you),娇媚性感的曲线加上柔和迷人的月光将大卫彻底吸引住。之后,大卫便派人四处打听此女子,想要知道她的芳名。原来,这个迷人的女子名叫 Bethsheba(拔示巴),是大卫的一位部将Uriah(乌利亚)的妻子。大卫忍受不住占有拔示巴的欲望,终于让人将拔示巴接入宫中,与其同房。不久,拔示巴怀上了大卫的孩子,大卫恐慌万分,急忙召回远在前线的乌利亚,借口让其休整一下,意图让乌利亚回到家中与妻子同房以掩盖拔示巴肚中孩子的亲缘归属。但是,乌利亚是一位忠于职守为国尽忠的勇士,他对大卫说:“国家处于危机,我怎有心思回家与妻子相欢,溺于安享。”乌利亚要求大卫将自己重新派回到战场上。大卫此时便顺水推舟,并写成密信一封,让乌利亚携信到大将军约亚那里;信中大卫指示约亚将乌利亚派往最为危险的战场。于是,乌利亚就在大卫的密谋和意愿下战死沙场,而大卫则将拔示巴迎进自己的后宫,名正言顺的占有了拔示巴。然而,占有拔示巴的大卫并不快乐,他白天对着众人强颜欢笑,夜晚就成为自己罪过的奴隶,受尽折磨。大卫认识到自己的罪行,写下五十一篇忏悔书,歌与上帝,祈求宽恕(Now I’ve heard there was a secret chord / That David played, and it pleased the Lord / But you don’t really care for music, do you?)。第二段中,She tied you To a kitchen chair / She broke your throne, and she cut your hair 这个场景虽然在大卫犯奸淫罪的过程中也有相似发生,但如果用 Samson(参孙)和 Delilah(达利拉)的故事来解释则更为贴切。以色列在被非力士人统治的时候,族中有个大力士,名叫参孙,上帝赐予他空手撕裂雄狮的神力,这使得非力士统治者颇为惧怕,但是,参孙有个弱点:上帝与其约定——不得剪发,如是,则神力尽失。参孙爱上了一位非力士族的姑娘,名叫达利拉。非力士统治者赐予达利拉许多钱财,命令她与参孙相好并套出他为何力大无穷的秘密。参孙在达利拉的三次诱惑下以编造的故事将其蒙混,但是最后参孙还是将自己的秘密告诉的达利拉。一日,达利拉趁安抚参孙熟睡于自己的膝上时,让人将参孙的头发剪掉了。参孙醒来,发现自己的头发被剪,神力也一并消失了。可怜的参孙在爱情的迷惑下,违背了与神定下的誓言,从一个英勇的大力士变成了一个人人欺辱的瞎子。
        但是Cohen说,写这首歌曲他花了两年的时间,像上面两段一样,最初歌词有80多个章节,写满了整整两个笔记本,正式出版时有15个章节,里面该有多少故事啊。“the fourth, the fifth, the minor fall, the major lift”,和弦就和歌词中一样在变换:F (“the fourth”, in the tonality of C major), G (“the fifth”), Am (“the minor fall”), F (“the major lift”),什么C大调,X和弦的,五线谱小强就不在这里乱解释了。
        此外百度这首歌的话,它的身份比较多的是《怪物史莱克》的插曲。动画中的Hallelujah是John Cale唱的,但是在原声碟中收录的却是Rufus Wainwright的版本。不过,本歌曲最成功的版本并不是由Cohen本人演唱,而是在Jeff Buckley的《Grace》专辑中……其实这首歌被n个歌手录制了n个版本,超过了180次,也被用作了多部电影或电视剧的插曲,其中包括看过的《the west wing》,没有看过的《Ugly Betty》等。