2005年11月24日

在 Adobe 发布 GoLive CS2 中文版时,笔者即指出 Adobe 将在网页制作方面扶持 GoLive(相关文章:GoLive CS2中文版发布,Dreamweaver将淡出?),很多读者感到这个观点没有道理,认为 Dreamweaver 拥有如此普遍的用户群,怎么会被 Adobe 所忽略?今天笔者就来分析一下理由。请大家摒除成见,互相交流,共同进步。

从LiveMotion 说起

  从这几年 Adobe 的举动来看,Adobe 先是发布了与 Flash 相抗争的 LiveMotion ,然后在版本2.0的时候突然宣布中止该项目。这可以理解为在推出后市场预期不佳,赶超 Flash 无望而做出的决断。

  这是很正常的,毕竟SWF的核心技术在 Macromedia 手中。笔者认为,Adobe 就是在那个时候决定收购竞争对手 Macromedia 的,并随之展开了历时几年的财务准备。于是中止了 LiveMotion 的计划,因为已经没有必要再为这个项目继续投入。原班的开发团队合并到 AfterEffects 项目中,实际上 LiveMotion 的核心开发成员原先就来自于该项目。

  Adobe 是一个软件巨人,因此虽然步履缓慢,但迈出每一步之前必经深谋远虑。如果 Adobe 打算扶持 Dreamweaver ,GoLive 一定也会是在同个时期被叫停。但结果 GoLive 不仅没有被中止,反而在之后加大了开发的力度,并加入了对 Dreamweaver 界面的兼容。

GoLive生存的原因:

  那 GoLive 为何没有被叫停呢?笔者认为有如下几个理由:

  一是 GoLive 的版本已经很高,达到了 6.0 (CS2 相当于8.0),一个软件在如此高版本的时候,内核都已经非常成熟。就如同 Photoshop 内核在 4.0 时候就已定性,随后的各个新版本,都只是在周边操作上做文章。GoLive 也是如此,其内核在3.0时代(即被 Adobe 收购之时)已经很完善,否则不可能在当时的MAC平台处于垄断地位。

  放弃一个已经成熟的软件是不明智的。此其一也。

  第二个理由是决定性因素,这个理由决定了 Adobe 必须扶持 GoLive 而不是 Dreamweaver,那就是 Creative Suite 套件的发行。

  Adobe 近些年的开发理念发生了转变,即不再只看重于单个软件的功能,而是努力营造一种多软件综合使用的新概念。就是以拳头产品 Photoshop、Illustrator 作为龙头,将原先应用于其他领域的软件(如排版的 PageMaker )都与之进行功能上的组合。

  这个概念从经营策略上来看很有远见的,通过套件方式可以综合应用到各个领域,甚至那些并不是处于优势地位的领域。

  这个概念其实并不新鲜,Microsoft 就发布了 Office 套件,将文档编辑 Word 等软件综合发布,最终打败了原先在文本编辑、日程管理等方面占绝对优势的莲花公司。

  套件成功的原因在于用户对套件的青睐,套件各软件之间都有很好的继承性,比如 Word 文档可以很容易进入到 FrontPage 做成网页,或进入到 PowerPoint 做成幻灯片。

  套件各软件的操作相似性也令用户省去了重复学习的时间,无形之间就是提高了工作的效率。或许这对于熟练的操作者来说无足轻重,但对于新手来说无疑是方便的。

  并且,大家必须明白,新手永远比老手要多得多。虽然 Adobe 已经拥有许多老用户,但它也更明白新手市场的庞大,况且设计的老手也可能成为排版的新手。

  这也就是为什么笔者写的《大师之路》系列教程主要针对新手的原因。

  发行套件看似简单,实则非常复杂。因为各软件各自为政的时候,只要做好本职工作就好了。而如果作为套件的一部分,它就必须具有良好的兼容性和可共享性。其实 Photoshop 和 Illustrator 在很早的时候就开始彼此兼容的尝试。

  笔者认为兼容体现在三个层次:

  最低级的,是文件格式兼容,即一个软件可以打开另外一个软件所保存的文档,并转换为自己的格式。而文件编辑性必须把握尺度,否则容易造成软件功能的彼此冲突。设想一下,如果 Photoshop 可以完美地操作矢量图象,可以完整地编辑 *.ai 格式,那还有谁会去用 Illustrator ?正是出于这个原因,因此文件兼容方面始终不可能完全到位。

  其次是剪贴板兼容,即多个软件同时运行,共享剪贴板。最显著的例子就是在 Illustrator 中绘制复杂的路径,然后通过剪贴板导入到 Photoshop 中。

  此种兼容方式在技术层面上难度极高,因为需要转换不同软件中完全不同的处理方式,因此范围非常有限,实际上很多软件之间的剪贴板兼容,仅仅相当于免去在第一个软件中导出和在第二个软件中导入这两个步骤。

  最高级的兼容,是流程兼容,也可称为协作式兼容,即多个软件同时或先后运行,完成流程中所需文档的建立或更新。这种兼容主要体现在不同领域的软件之间,比如在出版软件和图像处理类软件之间。这种兼容方式,正是 Adobe Creative Suite 套件所倡导的方式。

  那我们来说一下什么叫流程兼容,举个简单的例子,我们使用Photoshop制作并以GIF或JPG等通用图像格式输出了一个按钮图像,通过DreamWeaver放置到网页中。如果以后需要修改,哪怕是最小的改动都必须再次开启Photoshop,然后再次输出GIF或JPG图像,而在Dreamweaver中也有可能需要再次设定该图像的参数。

  如果我们使用 GoLive 来放置该按钮图像,则能够不再以 GIF 或 JPG 等通用图像格式,而是直接以 Photoshop 专属的 PSD 格式放入网页,GoLive 会将其保存为 JPG 或 GIF。以后如果在 Photoshop 中修改了这个 PSD 文件,GoLive 则会检测到改动,并自动更新相应的 JPG 或 GIF。

  用户可以在关闭 GoLive 的情况下在 Photoshop 中修改该PSD文件并保存。再次开启 GoLive 并打开相应站点或网页的时候,图像更新就会自动进行。更新时 Photoshop 并不需要同时运行。此外,GoLive 甚至可以直接更改 PSD 文件中的文本内容而不需通过 Photoshop。(具体操作演示见http://www.99ut.com/tutorial/photo … atpsd001/index.html)此类方式还可应用于与 InDesign 和  Acrobat  配合的制作中。

  可以看出,这种流程兼容无论是对于个人或是团队,都是非常高效的。这也是 Adobe 几年以来一直努力的方向。曾占霸主地位的排版软件 PageMaker 被叫停(暂未下线),改由全新的 InDesign 代替,就是因为 PageMaker 的程序老旧功能单一,无法满足流程兼容的需要。

  因此 Adobe 扶持 GoLive 的主要原因就它是 Creative Suite 套件不可或缺的一个环节,没有它,Creative Suite 在网页出版上就会出现空白。而这个空白无疑又将给自己制造一个未来的竞争对手。Adobe 在很早也就开始尝试让 GoLive 加入到流程兼容中并取得了成功,而新近收购而来的 Dreamweaver 显然不具备融入流程的能力。GoLive 因为多了些 Adobe 血统和习性,注定被 Adobe 推到第一线。


Dreamweaver为什么不能替代GoLive

  那么在以后,Dreamweaver是否有可能代替 GoLive 呢?

  一般来说,Creative Suite 套件既然发布,并且目前为止已经发布到了版本2,那么更改其中成员的可能性就极小极小,因为更改成员软件将引发一系列的麻烦,包括产品支持,软件教学,以及新旧文件版本兼容。

  尤其是新旧文件兼容,是非常具有难度的,因为一个软件所保存的文件格式,通常都与之内核流程息息相关,而如果要令 Dreamweaver 兼容 GoLive 的站点管理模式,几乎相当于重写内核代码。而如果 Dreamweaver 作为新成员无法完全接管以前 GoLive 创建的站点,Adobe 则可能面临被起诉的危险。原因很简单:产品的升级令用户损失了数据。

Dreamweaver何去何从?

  Dreamweaver 最可能的去向是转向专业编程及数据库开发。并可能以 GoLive 插件形式发布。这里再告诉大家一则历史: GoLive 在发行 6.0 版本的时候是带有数据库编程模块的,支持 asp、php、jsp 等语言。当时是购买了第三方的代码以插件形式加入。但是在发布 CS (即7.0)版本的时候(即 LiveMotion 下线之时)突然取消了数据库编程模块。现在看来,原来是想在今后利用 DreamWeaver 的成熟技术。既然这样,就没有必要继续付钱给第三方了。

  因此大家千万不要小看了 Creative Suite 套件,不要认为那只是单纯的名称改换。在它之前, Adobe 的各软件都像彼此分离的大树,而现在这些大树不再注重高度,转为注重枝叶的互相交连,他日必遮天蔽日,这种联合的强大是超乎想象的。只是如果你并未涉足多个领域可能体会不到而已。可以说,除 非Adobe 财政崩溃或再出现一个软件业黑马加天才的角色,否则 Adobe 的霸主地位很难被动摇了。

Problem Statement
    
When editing a single line of text, there are four keys that can be used to move the cursor: end, home, left-arrow and right-arrow. As you would expect, left-arrow and right-arrow move the cursor one character left or one character right, unless the cursor is at the beginning of the line or the end of the line, respectively, in which case the keystrokes do nothing (the cursor does not wrap to the previous or next line). The home key moves the cursor to the beginning of the line, and the end key moves the cursor to the end of the line.  You will be given a int, N, representing the number of character in a line of text. The cursor is always between two adjacent characters, at the beginning of the line, or at the end of the line. It starts before the first character, at position 0. The position after the last character on the line is position N. You should simulate a series of keystrokes and return the final position of the cursor. You will be given a string where characters of the string represent the keystrokes made, in order. ‘L’ and ‘R’ represent left and right, while ‘H’ and ‘E’ represent home and end.
Definition
    
Class:
CursorPosition
Method:
getPosition
Parameters:
string, int
Returns:
int
Method signature:
int getPosition(string keystrokes, int N)
(be sure your method is public)
    

Constraints
-
keystrokes will be contain between 1 and 50 ‘L’, ‘R’, ‘H’, and ‘E’ characters, inclusive.
-
N will be between 1 and 100, inclusive.
Examples
0)

    
"ERLLL"
10
Returns: 7
First, we go to the end of the line at position 10. Then, the right-arrow does nothing because we are already at the end of the line. Finally, three left-arrows brings us to position 7.
1)

    
"EHHEEHLLLLRRRRRR"
2
Returns: 2
All the right-arrows at the end ensure that we end up at the end of the line.
2)

    
"ELLLELLRRRRLRLRLLLRLLLRLLLLRLLRRRL"
10
Returns: 3

3)

    
"RRLEERLLLLRLLRLRRRLRLRLRLRLLLLL"
19
Returns: 12

This problem statement is the exclusive and proprietary property of TopCoder, Inc. Any unauthorized use or reproduction of this information without the prior written consent of TopCoder, Inc. is strictly prohibited. (c)2003, TopCoder, Inc. All rights reserved.

我的程序:

#include <string>
#include <iostream>

using namespace std;

class CursorPosition
{
public:
 int getPosition(string keystrokes, int N)
 {
  int result = 0;
  size_t len = keystrokes.length();
  if (len>50 || N<1 || N>100)
  {
   return result;
  }
  for (unsigned int i=0; i<len; ++i)
  {
   switch(keystrokes.at(i))
   {
   case ‘L’:
    result = result==0 ? 0 : result-1;
    break;
   case ‘R’:
    result = result==N ? N : result+1;
    break;
   case ‘H’:
    result = 0;
    break;
   case ‘E’:
    result = N;
    break;
   }
  }
  return result;
 }
};

Problem Statement
    
A square matrix is a grid of NxN numbers. For example, the following is a 3×3 matrix:
 4 3 5
 2 4 5
 0 1 9
One way to represent a matrix of numbers, each of which is between 0 and 9 inclusive, is as a row-major string. To generate the string, simply concatenate all of the elements from the first row followed by the second row and so on, without any spaces. For example, the above matrix would be represented as "435245019".  You will be given a square matrix as a row-major string. Your task is to convert it into a vector <string>, where each element represents one row of the original matrix. Element i of the vector <string> represents row i of the matrix. You should not include any spaces in your return. Hence, for the above string, you would return {"435","245","019"}. If the input does not represent a square matrix because the number of characters is not a perfect square, return an empty vector <string>, {}.
Definition
    
Class:
MatrixTool
Method:
convert
Parameters:
string
Returns:
vector <string>
Method signature:
vector <string> convert(string s)
(be sure your method is public)
    

Constraints
-
s will contain between 1 and 50 digits, inclusive.
Examples
0)

    
"435245019"
Returns: {"435", "245", "019" }
The example above.
1)

    
"9"
Returns: {"9" }

2)

    
"0123456789"
Returns: { }
This input has 10 digits, and 10 is not a perfect square.
3)

    
"3357002966366183191503444273807479559869883303524"
Returns: {"3357002", "9663661", "8319150", "3444273", "8074795", "5986988", "3303524" }

This problem statement is the exclusive and proprietary property of TopCoder, Inc. Any unauthorized use or reproduction of this information without the prior written consent of TopCoder, Inc. is strictly prohibited. (c)2003, TopCoder, Inc. All rights reserved.

我的程序:

#include <algorithm>
#include <string>
#include <vector>
#include <iostream>

using namespace std;

class MatrixTool
{
public:
 vector<string > convert(string s)
 {
  int sqt[7] = {1, 4, 9, 16, 25, 36, 49};
  vector<string > result;
  int* p = find(sqt, sqt + 7, s.length());
  if (p != sqt + 7)
  {
   unsigned int n = (unsigned int)(p – sqt) + 1;
   size_t len = s.length();
   for (unsigned int i=0; i<len; i+=n)
   {
    result.push_back(s.substr(i, n));
   }
  }
  return result;
 }
};

Problem Statement
    
A simple line drawing program uses a blank 20 x 20 pixel canvas and a directional cursor that starts at the upper left corner pointing straight down. The upper left corner of the canvas is at (0, 0) and the lower right corner is at (19, 19). You are given a vector <string>, commands, each element of which contains one of two possible commands. A command of the form "FORWARD x" means that the cursor should move forward by x pixels. Each pixel on its path, including the start and end points, is painted black. The only other command is "LEFT", which means that the cursor should change its direction by 90 degrees counterclockwise. So, if the cursor is initially pointing straight down and it receives a single "LEFT" command, it will end up pointing straight to the right. Execute all the commands in order and return the resulting 20 x 20 pixel canvas as a vector <string> where character j of element i represents the pixel at (i, j). Black pixels should be represented as uppercase ‘X’ characters and blank pixels should be represented as ‘.’ characters.
Definition
    
Class:
DrawLines
Method:
execute
Parameters:
vector <string>
Returns:
vector <string>
Method signature:
vector <string> execute(vector <string> commands)
(be sure your method is public)
    

Notes
-
The cursor only paints the canvas if it moves (see example 1).
Constraints
-
commands will contain between 1 and 50 elements, inclusive.
-
Each element of commands will be formatted as either "LEFT" or "FORWARD x" (quotes for clarity only), where x is an integer between 1 and 19, inclusive, with no extra leading zeros.
-
When executing the commands in order, the cursor will never leave the 20 x 20 pixel canvas.
Examples
0)

    
{"FORWARD 19", "LEFT", "FORWARD 19", "LEFT", "FORWARD 19", "LEFT", "FORWARD 19"}
Returns:
{"XXXXXXXXXXXXXXXXXXXX",
 "X………………X",
 "X………………X",
 "X………………X",
 "X………………X",
 "X………………X",
 "X………………X",
 "X………………X",
 "X………………X",
 "X………………X",
 "X………………X",
 "X………………X",
 "X………………X",
 "X………………X",
 "X………………X",
 "X………………X",
 "X………………X",
 "X………………X",
 "X………………X",
 "XXXXXXXXXXXXXXXXXXXX" }
This sequence of commands draws a 20 x 20 outline of a square. The cursor is initially at (0, 0) pointing straight down. It then travels to (0, 19) after the first FORWARD command, painting each pixel along its path with a ‘*’. It then rotates 90 degrees left, travels to (19, 19), rotates 90 degrees left, travels to (19, 0), rotates 90 degrees left, and finally travels back to (0, 0).
1)

    
{"LEFT", "LEFT", "LEFT", "LEFT", "LEFT", "LEFT", "LEFT", "LEFT"}
Returns:
{"………………..",
 "………………..",
 "………………..",
 "………………..",
 "………………..",
 "………………..",
 "………………..",
 "………………..",
 "………………..",
 "………………..",
 "………………..",
 "………………..",
 "………………..",
 "………………..",
 "………………..",
 "………………..",
 "………………..",
 "………………..",
 "………………..",
 "……………….." }
The cursor spins round and round, but never actually paints any pixels. The result is an empty canvas.
2)

    
{"FORWARD 1"}
Returns:
{"X……………….",
 "X……………….",
 "………………..",
 "………………..",
 "………………..",
 "………………..",
 "………………..",
 "………………..",
 "………………..",
 "………………..",
 "………………..",
 "………………..",
 "………………..",
 "………………..",
 "………………..",
 "………………..",
 "………………..",
 "………………..",
 "………………..",
 "……………….." }
Going forward by one pixel creates a line that is 2 pixels long because both the start and end points are painted.
3)

    
{"LEFT", "FORWARD 19", "LEFT", "LEFT", "LEFT",
 "FORWARD 18", "LEFT", "LEFT", "LEFT", "FORWARD 17",
 "LEFT", "LEFT", "LEFT", "FORWARD 16", "LEFT",
 "LEFT", "LEFT", "FORWARD 15", "LEFT", "LEFT", "LEFT",
 "FORWARD 14", "LEFT", "LEFT", "LEFT", "FORWARD 13",
 "LEFT", "LEFT", "LEFT", "FORWARD 12", "LEFT", "LEFT",
 "LEFT", "FORWARD 11", "LEFT", "LEFT", "LEFT", "FORWARD 10",
 "LEFT", "LEFT", "LEFT", "FORWARD 9", "LEFT", "LEFT",
 "LEFT", "FORWARD 8", "LEFT", "LEFT", "LEFT", "FORWARD 7"}
Returns:
{"XXXXXXXXXXXXXXXXXXXX",
 "……………….X",
 "..XXXXXXXXXXXXXXXX.X",
 "..X…………..X.X",
 "..X.XXXXXXXXXXXX.X.X",
 "..X.X……….X.X.X",
 "..X.X.XXXXXXXX.X.X.X",
 "..X.X.X……..X.X.X",
 "..X.X.X……..X.X.X",
 "..X.X.X……..X.X.X",
 "..X.X.X……..X.X.X",
 "..X.X.X……..X.X.X",
 "..X.X.X……..X.X.X",
 "..X.X.X……..X.X.X",
 "..X.X.XXXXXXXXXX.X.X",
 "..X.X…………X.X",
 "..X.XXXXXXXXXXXXXX.X",
 "..X…………….X",
 "..XXXXXXXXXXXXXXXXXX",
 "……………….." }

 
This problem statement is the exclusive and proprietary property of TopCoder, Inc. Any unauthorized use or reproduction of this information without the prior written consent of TopCoder, Inc. is strictly prohibited. (c)2003, TopCoder, Inc. All rights reserved.

我的程序:

#include <string>
#include <vector>
#include <iostream>

using namespace std;

class DrawLines
{
public:
 vector<string > execute(vector<string > commands)
 {
  vector<string > result;
  _init();
  vector<string >::iterator it = commands.begin();
  while (it != commands.end())
  {
   if (‘L’ == it->at(0))
   {
    ++_dir;
    if (_dir > LEFT)
    {
     _dir = DOWN;
    }
   }
   else if (‘F’ == it->at(0))
   {
    size_t p = it->find(‘ ‘, 0);
    unsigned int step = atoi(it->substr(p, it->size()-p).c_str());
    _line(step);
   }
   ++it;
  }
  for (unsigned int i=0; i<SIZE; ++i)
  {
   result.push_back(string(&_buff[i*SIZE], &_buff[(i+1)*SIZE]));
  }
  return result;
 }
private:
 enum
 {
  DOWN,
  RIGHT,
  UP,
  LEFT
 };

 enum
 {
  SIZE = 20
 };

 void _init(void)
 {
  _x = 0;
  _y = 0;
  _dir = DOWN;
  for (unsigned int i=0; i<SIZE*SIZE; ++i)
  {
   _buff[i] = ‘.’;
  }
 }

 void _line(unsigned int step)
 {
  switch(_dir)
  {
  case DOWN:
   for (unsigned int i=0; i<step; ++i)
   {
    _buff[_x+_y*SIZE] = ‘X’;
    ++_y;
   }
   break;
  case RIGHT:
   for (unsigned int i=0; i<step; ++i)
   {
    _buff[_x+_y*SIZE] = ‘X’;
    ++_x;
   }
   break;
  case UP:
   for (unsigned int i=0; i<step; ++i)
   {
    _buff[_x+_y*SIZE] = ‘X’;
    –_y;
   }
   break;
  case LEFT:
   for (unsigned int i=0; i<step; ++i)
   {
    _buff[_x+_y*SIZE] = ‘X’;
    –_x;
   }
   break;
  }
  _buff[_x+_y*SIZE] = ‘X’;
 }

 unsigned int _x;
 unsigned int _y;
 unsigned int _dir;
 char   _buff[SIZE*SIZE];
};

2005年11月21日

著名的ASCII动画。

观看方法:telnet towel.blinkenlights.nl

2005年11月12日

今晚北航发生一场车祸,我晚上10点左右,在出北门那条路上,路封了。
南边5、6个保安守着路口,拉上了警戒线,让绕行,我从西边打印店前面绕过去,看见一辆中型卡车和一个大概夏利撞了,夏利屁股

擦了卡车后面的 斗,没什么事,四周有10多个保安吧,用警戒线把现场围起来了,保卫处处长亲自上阵,指挥行动,特别紧张的样

子。撞车占了半条马路,另半条空着也不让过。

保安们终于盼到这一天了,可以向广大师生展示我校保安队这只威武之师,正义之师,日夜保卫者北航内数万人的生命和财产安全。

可能他们美国大片看多了,感觉自己也像个快速反应部队了。我觉得他们应该换成迷彩,再戴上黑面具,和无线电通讯设备,这样才

象,交警肯定高兴了,现场保护得多好啊,溅出的玻璃喳(如果溅出了的话)都保存完好,绝对第一现场,这对将来对这起交通事故

定性和判定责任都有重要意义,也对保险公司理赔及新闻记者采访保留第一手资料。

有这样一只强大的武装力量保卫我们,我感到特别安心,吃得香,睡得好,把精力集中到学习上,为四化做建设。

2005年11月08日

从九月份开始去张贝,已经两个月了,这两个月,去了不到20次吧,但是感觉效果还是不错的,每次都坚持一个流程,这段时间下来,感觉身上的肉明显硬了许多,而且也感觉精力更旺盛了。

虽然说晚上下班了去折腾,应该会更累,但是我一直没感觉影响我白天的精神,相反,感觉精神更好了,人就是这样,越待着,就会越没精神,累一点,反而充满活力了。

张贝比浩沙最大的好处,就是离家比较近,下班了,先去吃个饭,然后上上网消化消化,再慢悠悠骑车过去,感觉非常爽,如果下班直接去健身,会感觉非常累,休息这么一小会,感觉好多了。

每次去之前,都有点不想,因为懒得出去,但是如果挣扎过来,到了那里,就会很兴奋,不想回来了,每次都是这样,这就叫做坚持吧,只要坚持下去,就会获得好的回报。

坚持,还是坚持,天气慢慢冷了,我一定要坚持下去。争取半年后,让身上的赘肉滚蛋,有个比较不错的身材。嗯。

2005年11月07日

接着上篇文章继续说

http://www.vrforum.cn/viewthread.php?tid=10769

2005年11月04日

晓康写的,可以到下面地址下载:

http://www.vrdn.net/viewthread.php?fpage=1&tid=831