Tuesday, December 25, 2007

Еще одно правило для SpamAssassin'a

В продолжение темы предыдущей статьи. Еще один "популярный" в последние дни спам предлагает базы с частной информацией. Subject письма произвольный, и приходят эти письма с произвольных адресов. Пока все эти адреса не попали в блок-листы, SpamAssassin пропускает эти письма. К счастью, спаммеры снабдили свои письма весьма необычным заголовком X-Mailer:

X-Mailer: Sendmail 8.12.11/8.12.11

Прокол со стороны спаммеров! Благодаря такому уникальному заголовку, этот спам легко отсеять с помощью следующих правил для SpamAssassin'a:


header MAILER_SENDMAIL X-Mailer =~ /^Sendmail 8\.12\.11\/8\.12\.11/
describe MAILER_SENDMAIL Spammy X-Mailer header
score MAILER_SENDMAIL 2.5

P.S. 26.12.2007. Похоже, отправители этих писем уже попали в блок-лист SpamCop, и теперь в дополнительном правиле нет необходимости.

Friday, December 21, 2007

Спам на букву "i"

Последнее время мы часто получаем новую разновидность спама. Это сообщения на русском языке на такие темы как "защита конфиденциальной информации предприятия", "защита коммерческой тайны", "Тренинг по продажам" и проч., причем доставляются они как будто через легальный сервер Yahoo. Не знаю как спаммеры это делают, но в результате SpamAssassin пропускает эти сообщения, т.к. единственный тест, который на них срабатывает - BAYES_99. Хоть это и очень важный тест, все равно его одного не достаточно. (Иногда возникает желание поднять score этого теста до 5.4, как это было в SpamAssassin'e версии 2, но я все же думаю, разработчики выбрали score 3.5 не зря - false positives никому не нужны).

К счастью, этот спам можно отсеять благодаря его странной особенности - subject всех этих сообщений начинается с латинской буквы i. В нераскодированном виде начало subject'а всегда выглядит так:

=?Windows-1251?Q?i_=

Никто в здравом уме не будет делать такой subject. Поэтому достаточно добавить в конфигурационный файл SpamAssassin'a (обычно /etc/mail/spamassassin/local.cf) следующие строки (здесь должно быть 3 строки, начинающихся со слов header, describe и score, но ваш браузер может их разбить в неудачном месте):


header SUBJECT_STARTS_WITH_I Subject:raw =~ /^ *=\?Windows-1251\?Q\?i_=/
describe SUBJECT_STARTS_WITH_I Subject has a common spam pattern
score SUBJECT_STARTS_WITH_I 2.5

и спам на букву "i" будет успешно отфильтрован.

P.S. 26.12.2007. Похоже, отправитель этих сообщений уже попал в блок-лист SpamCop, и в дополнительном правиле теперь нет необходимости.

P.S. 06.02.2008. Этот тип спама возвращается, причем теперь subject может начинаться не только на i, но и на точку. Обновленное правило:


header SUBJECT_STARTS_WITH_I Subject:raw =~ /^\s*=\?Windows-1251\?Q\?[i\.]_=/
describe SUBJECT_STARTS_WITH_I Subject has a common spam pattern
score SUBJECT_STARTS_WITH_I 2.5

Tuesday, December 11, 2007

Delivery failure to Exchange public folder

I set up a new public folder in our Exchange server to receive emails from external SMTP server. The intent was to store emails from customers for management perusal. As the folder was going to contain sensitive business information, I allowed access to it to management group only. Unfortunately, the delivery to the folder failed - the email was returned to sender with no explanation. Exchange server's event log showed nothing, but when I increased Exchange logging level, the following cryptic message showed up in the log:

The following call : EcLocallyDeliverMsg2 to the store failed. Error code : 1238 (Message-ID <046e01c83c04$e24bbfd0$5101a8c0@csltd.intranet> will be NDR'd). MDB : 87b7cb4d-7e6b-47fa-be39-85b0d7995226. FID : . MID : . File : C:\Program Files\Exchsrvr\Mailroot\vsi 1\Queue\NTFS_e1be85a401c83c0400000024.EML.

Well, that didn't clarify much. A quick internet search turned up this Microsoft KB article: http://support.microsoft.com/kb/873393, but that definitely was not my case.

Giving the issue more thought, I realized that in attempt to secure the access to the folder as much as possible I went a little too far by disallowing any access to Anonymous users. Now, when an external SMTP server submits an email to Exchange server, this is anonymous access as far as Exchange server is concerned. Thus the attempt to submit a message to the public folder is denied! The solution was to allow "Contributor" access to the Anonymous user.

The bottom line is that if an Exchange public folder is to receive email from an external SMTP server, Anonymous users should be allowed "Contributor" access.

Saturday, November 03, 2007

Beautiful code

I've read "Beautiful Code", a collection of 33 essays by leading computer scientists, edited by Andy Oram and Greg Wilson. What follows is by no means a review, just my impressions.
  1. Chapter 1, A Regular Expression Matcher, by Brian Kernighan. An interesting insight into implementation of a simplified regular expression matcher. Shows off recursion-based elegant and compact C code.
  2. Chapter 2, Subversion's Delta Editor: Interface as Ontology, by Karl Fogel. Describes a piece of Subversion version control system, the Delta Editor, which is the data structure that expresses the difference between two source code trees. The data structure is really an interface (being implemented in C, a language that doesn't support interfaces natively, it's a structure of function pointers). Instead of representing the delta explicitly, it provides a standard interface for a delta producer to provide the delta data, and for the delta consumer to use it. This way it can handle deltas that can't fit in memory due to sheer size or that are not available all at once (e.g. are downloaded from network). Various advantages of this design are discussed. An interesting approach of representing data as an interface.
  3. Chapter 3, The Most Beautiful Code I Never Wrote, by Jon Bentley. Praises brevity and simplicity. Examines the code that analyses QuickSort algorithm (which itself is viewed as the most beautiful code by the author). The performance analysis code gets progressively smaller and smaller and simpler and simpler through careful mathematical analysis. An interesting example of algorithm development and optimization, though, perhaps, mostly of academic value.
  4. Chapter 4, Finding Things, by Tim Bray. Explores a few common, if somewhat disconnected, topics related to search. Interesting for a brief instroduction into Ruby language, and its comparison to Java in terms of performance (Java wins). Touches regular expressions, associative arrays, binary search and then quickly discusses web search. I find this chapter rather superficial and unfocused.
  5. Chapter 5, Correct, Beautiful, Fast (In That Order): Lessons From Designing XML Verifiers, by Elliotte Rusty Harold. Describes the author's quest to implement verification of XML names in an XML parser correctly, but without sacrificing performance. A few smart improvement eventually lead the author to a surprisingly simple and efficient solution. "If there's a moral to this story, it is this: do not let performance considerations stop you from doing what is right. You can always make the code faster with a little cleverness. You can rarely recover so easily from a bad design".
  6. Chapter 6, Framework for Integrated Test: Beauty through Fragility, by Michael Feathers. Describes the desing of Framework for Intergated Testing (FIT), an automated testing framework. Talks how this framework is different from most of other frameworks by being very open, flexible and extensible. This radical alternative to traditional framework design (with few well-defined points of extensibility) proves useful in its application domain (testing).
  7. Chapter 7, Beautiful Tests, by Alberto Savoia. Talks of the beauty of testing. Sets off by describing the infamous binary search implementation bug and continues to test the supposedly corrected implementation using JUnit testing framework. Demonstrates the concepts of smoke testing, boundary value testing, testing theories, mutation testing, performance testing. Conclusion:
    • Some tests are beautiful for their simplicity and efficiency
    • Other tests are beautiful because, in the process of writing them, they help you improve the code they are meant to test in subtle but important ways
    • Finally, some tests are beautiful for their breadth and thoroughness
  8. Chapter 8, On-the-Fly Code Generation for Image Processing. Demonstrates an unusual optimization technique, on-the-fly code generation for time-critical procedures. The trick is that some branching and calculations are performed at code-generation time (once) rather than at run time. The .NET-based example uses System.Reflection.Emit namespace classes to emit Intermediate Language instructions at run time. Interesting, if highly-specialized technique of limited general utility. Conclusion: "Now, you might regard FilterMethodIL as ugly, and I'd be willing to concede that it sure isn't the prettiest code I've ever seen. But when an algorithm clocks in at a quarter of the execution time of some earlier code, then the only word that I find appropriate is beautiful".
  9. Chapter 9, Top-Down Operator Precedence, by Douglas Crockford. The author creates a JavaScript language parser in JavaScript using "Top-Down Operator Precedence" technique. The chapter is beyond me; didn't understand much.
  10. Chapter 10, The Quest for an Accelerated Population Count, by Henry S. Warren, Jr. Describes the algorithm for "population count", i.e. counting the number of 1-bits in a byte or word. Employs interesting mathematical techniques to speed up the algorithm. The topic is a little outside of my expertise and interests.
  11. Chapter 11, Secure Communication: The Technology of Freedom, by Ashish Gulhati. Describes the evolution of Cryptonite, the author's web-based email system that emphasized PGP-based security. Interesting for describing the system's architecture and its evolution, as well as PGP overview. Ends with a philosophical pitch for secure communications as a basis for personal freedom.
  12. Chapter 12, Growing Beautiful Code in BioPerl, by Lincoln Stein. Describes the author's Perl module for graphics in DNA research. Interesting insight into framework design.
  13. Chapter 13, The Design of the Gene Sorter, by Jim Kent. Describes the Gene Sorter, a web-based gene display program (http://genome.ucsc.edu/cgi-bin/hgNear). While I have no doubt it is very useful, I don't share the author's opinion on its beauty. I don't think CGI scripts are beautiful at all, especially when written in C. Something that starts a new process on each page access and has to keep persistent state in a database doesn't apeal to me. The "cart" mechanism is a neat trick, but it just patches the inherent limitation of CGI architecture. The polymorphic column structure is also a neat trick, but why attempt object-oriented programming in C when there is C++? Text file-based configuration of columns doesn't look particularly beautiful to me either. Why filters are not SQL-based? Why read all data from the database and filter in memory when the database can return only relevant data? To summarize, I am not impressed. Tastes differ.
  14. Chapter 14, How Elegant Code Evolves With Hardware: The Case Of Gaussian Elimination, by Jack Dongarra and Piotr Luszczek. Describes the evolution of linear algebra libraries (LINPACK, LAPACK, ScaLAPACK) with the evolution of hardware. Informative how algorithms change with the hardware, but I fail to see the beauty of this arcane Fortran code.
  15. Chapter 15, The Long-Term Benefits of Beautiful Design, by Adam Kolawa. Describes the design of LAPACK linear algebra library and is related to the previous chapter. With all the due respect to this venerable library, it's hard to see the beauty in this highly specialized Fortran code.
  16. Chapter 16, The Linux Kernel Driver Model: The Benefits of Working Together, by Greg Kroah-Hartman. An interesting insight into how the Linux kernel represents hardware devices. Fine example of object-oriented programming in C. Stresses the typically Linuxish development approach "make it harder so people have to think very carefully" by explaining how no type checking is done on device structures. In author's words: "It keeps easy hacks from springing up within the kernel and forces everyone to be very exact in their logic". Also emphasizes the interative and collaborative nature of Linux development.
  17. Chapter 17, Another Level of Indirection, by Diomidis Spinellis. Explains the layering of FreeBSD I/O subsystem and how it achieves a very fine separation of concerns among the layers, with resulting flexibility and maintainability. Touches the subject of "domain-specific languages". Ends with a warning to not overuse layering approach, since "layers are for cakes, not for software".
  18. Chapter 18, Python's Dictionary Implementation: Being All Things to All People, by Andrew Kuchling. Explains the design of Dictionary type in Python. Based on general-purpose hash table, the type has several special cases for more efficient handling of common scenarios, such as small dictionaries (5 elements of fewer) and dictionaries with string-type keys. Discusses the approaches to collision handing (carefully tuned open addressing), resizing and iteration.
  19. Chapter 19, Multi-Dimensional Iterators in NumPy, by Travis E. Oliphant. Describes the design of iterators for multidimensional arrays in NumPy, a Python package. Implements clever tricks to iterate over arrays of arbitrary dimensions efficiently. Interesting, but I must admit I did not understand the feature the author calls "broadcasting".
  20. Chapter 20, A Highly Reliable Enterprise System for NASA's Mars Rover Mission, by Ronald Mak. Discusses the design of Collaborative Information Portal (CIP), a large web-based information sharing and management application used by NASA Mars Exploration Rover mission. Gives a good overview of Service-Oriented Architecture in Enterprise Java Beans based applications. Explains the details in a case study of the Streamer Service (CIP's component). Great article on enterprise application design. My favorite quote: "Martians have zero tolerance for ugly software".
  21. Chapter 21, ERP5: Designing for Maximum Adaptability, by Rogerio Atem de Carvalho and Rafael Monnerat. Describes the design of EPR5, an open source ERP application based on Zope platform. Very difficult to read, I didn't understand much.
  22. Chapter 22, A Spoonful of Sewage, by Bryan Cantrill. A very dynamic and well-narrated story of the author's hunt for an elusive bug in Solaris thread synchronization code. Explains the problem of priority inversion, its theoretical solution, and the bug in the code that was supposed to solve it. The resolution of the bug, although not utterly beautiful on the surface, is truly beautiful, the author argues, because "in the seven years ... no one has done better".
  23. Chapter 23, Distributed Programming with MapReduce, by Jeff Dean and Sanjay Ghemawat. An interesting explanation of how Google's MapReduce programming model works (break the task into subtasks, run them in parallel, combine results), mentioning some of the specific challenges it faces due to its sheer scale (e.g. failure of some computers).
  24. Chapter 24, Beautiful Concurrency, by Simon Peyton Jones. Now that the hardware evolution trend is to increase the number of CPU cores rather than clock speed, the article says, concurrency is very important. It is also hard. The article explans the numerous problems of lock-based concurrency management, concluding that "the fundamental shortcoming of lock-based programming is that locks and conditional variables do not support modular programming" (locking logic is hard to modularize and disentangle from application logic). The article then goes on to describe the concept of Software Transactional Memory (STM) and how it overcomes the shortcomings of locks. The concept is presented using Haskell programming language and a brief introduction to it is included. Interesting for the overview of concurrency problems, introduction to Haskell and STM. Whether STM can be practially implemented in more mainstream languages remains to be seen.
  25. Chapter 25, Syntactic Abstraction: The syntax-case Expander, by Kent Dybvig. Starts with a brief overview of syntactic abstraction in programming languages (ability to define custom syntax constructs, such as preprocessor macros in C). Goes on to describe a macro expansion algorithm in Scheme, which I fail to penetrate.
  26. Chapter 26, Labor-Saving Architecture: An Object-Oriented Framework for Networked Software, by William Otte and Douglas C. Schmidt. Talks about object-oriented framework design and explores the subject in detail by presenting an example of Logging Server Framework. A very useful and interesting practical case study of OO design.
  27. Chapter 27, Integrating Business Partners the RESTful Way, by Andrew Patzer. Describes an approach to Web Services that is more light-weight than the popular (if overhyped) SOAP architecture. This light-weight approach is based on exchange of XML-encoded requests and responses using simple GET or POST requests over HTTP. As the author puts it, "Although I didn't know it at the time, this architectural style is now commonly referred to as REST or Representational State Transfer". Interesting for introduction to REST. I would disagree with the author on some of the implementation choices, though, e.g. there must be a better way to determine the request type than looking for a specific long string within the request body (e.g. listing on page 454).
  28. Chapter 28, Beautiful Debugging, by Andreas Zeller. Talks about delta debugging, an approach aiming to isolate bugs automatically by isolating the source code change that caused a failure. The concept is then expanded to automatic debugging through isolation of program state change that caused a failure. Interesting, but I still have doubts if the approach can be practically useful.
  29. Chapter 29, Treating Code as an Essay, by Yukihiro Matsumoto. This is the shortest and the least practical essay in the book. In fact, it doesn't describe any real piece of code or any practical problem. Perhaps it is indicative that it is the only essay written by a Japanese author (the author of Ruby language). This concise article talks about the abstract nature of code beauty. The author defines code beauty as combination of brevity, familiarity, simplicity, flexibility and balance.
  30. Chapter 30, When a Button Is All That Connects You to the World, by Arun Mehta. Apparently, no book published in the US can be complete without touching the subject of persons with disabilities in some way. This article talks about the author's noble attempt to design a software system for professor Stephen Hawking, eminent theoretical physicist, who, due to a severe disability, can only press one button. This extreme limitation makes for tough design problems and smart solutions. This said, the code examples in Visual Basic do not seem very beautiful to me. The author seems to acknowledge this: "I might warn you that it [the code] bears some resemblance to a bowl of spaghetti".
  31. Chapter 31, Emacspeak: The Complete Audio Desktop, by TV Raman. Describes Emacspeak, a complete Emacs-based audio desktop for visually impaired users. It's interesting to rethink the UI fundamentals we take for granted. Among other things, the article is interesting for a brief introduction of Emacs Lisp "advice" facility and Aspect Oriented Programming. Another notable thing is how the choices the author made to make web content accessible "in an eyes-free environment" were later paralleled in mainstream to make the web accessible to automated processing (such as RSS feeds).
  32. Chapter 32, Code in Motion, by Laura Wingerd and Christopher Seiwald. The article talks about "Seven Pillars of Pretty Code", a set of rules for good code formatting, as practiced by the authors of Perforce software configuration management system.
  33. Chapter 33, Writing Programs for "The Book," by Brian Hayes. The chapter describes the author's quest for the perfect solution to a simple computational geometry problem: given three points in the plane, do all of the points lie along the same line? That's one of those problems that's easy to solve in a wrong or ugly way. After trying several approaches, the author finally finds the perfect algorithm. I can't help adding a personal comment: it's frustrating that many great programmers lack fundamental mathematical training. Had the author known a little more linear algebra, the solution would be obvious from the beginning.

Thursday, October 04, 2007

Errors sending emails from Outlook Express: 0x800C0131 and 0x800C013B

A user complained about the following problem. When sending emails from Outlook Express he got the following error: "An unknown error has occurred. Account: '...', Server: '...', Protocol: POP3, Port: 110, Secure(SSL): No, Error Number: 0x800C0131"

A solution was found at Microsoft KB article 233264

The result was a mixed success. The original error was gone, however, while the user's mail folders were intact, their hierarchy disappeared. This was a minor annoyance, as the user could easily recreate his folder hierarchy. However, a new error replaced the old one: "An unknown error has occurred. Account: '...', Server: '...', Protocol: POP3, Port: 110, Secure(SSL): No, Error Number: 0x800C013B

This was tracked down to Microsoft KB article 253795. The article advised to rename Sent Items.dbx file, which we were reluctant to do as we didn't want to loose the user's sent emails. Instead we created a new folder TempSentItems, temporarily moved all emails from Sent Items to it, then deleted Sent Items. When Outlook Express recreated Sent Items folder, we moved the saved emails from TempSentItems to it and deleted the temporary folder.

Friday, July 27, 2007

Disk space shortage wreaks havoc on a domain controller

One day our Windows 2003 domain controller ran out of disk space, and a slew of problems ensued. Apparently, Active Directory synchronization failed due to insifficient space, and the event log was full of messages like this:
Event Type: Warning
Event Source: NETLOGON
Event Category: None
Event ID: 5705
Description:
The change log cache maintained by the Netlogon service for  database changes is inconsistent. The Netlogon service is resetting the change log.

Event Type: Warning
Event Source: W32Time
Event ID: 26
Description:
Time Provider NtpClient: The response received from domain controller  has a bad signature. The response may have been tampered with and will be ignored.

Event Type: Error
Event Source: NETLOGON
Event ID: 5805
Description:
The session setup from the computer  failed to authenticate. The following error occurred: 
Access is denied. 

Event Type: Warning
Event Source: LSASRV
Event Category: SPNEGO (Negotiator) 
Event ID: 40960
Description:
The Security System detected an authentication error for the server cifs/.  The failure code from authentication protocol Kerberos was "The attempted logon is invalid. This is either due to a bad username or authentication information. (0xc000006d)".

Event Type: Error
Event Source: Kerberos
Event ID: 4
Description:
The kerberos client received a KRB_AP_ERR_MODIFIED error from the server host/.  The target name used was ldap//@. This indicates that the password used to encrypt the kerberos service ticket is different than that on the target server. Commonly, this is due to identically named  machine accounts in the target realm (), and the client realm.   Please contact your system administrator.

Event Type: Error
Event Source: NETLOGON
Event ID: 3210
Description:
This computer could not authenticate with \\, a Windows domain controller for domain , and therefore this computer might deny logon requests. This inability to authenticate might be caused by another computer on the same network using the same name or the password for this computer account is not recognized. If this message appears again, contact your system administrator.
Even after freeing some space, problems continued, since Active Directory database was damaged. The solution was to reset computer domain password using netdom, as documented in Microsoft KB article 260575

What does "localhost" mean in named.conf?

Configuring BIND 9, run across an interesting issue. What does the following excerpt from named.conf mean:
options {
        listen-on port 53 { localhost; };
        ...
};
I thought this tells BIND to listen only on loopback adress (127.0.0.1). After all, this what "localhost" usually resolves to. To my great surprise, I've found that BIND is listening on all network interfaces. As it turns out, in the context of BIND configuration, localhost "Matches the IPv4 and IPv6 addresses of all network interfaces on the system." Go figure! The correct configuration is as follows:
options {
        listen-on port 53 { 127.0.0.1; };
        ...
};

Sunday, July 15, 2007

Masquerading multiple IPSec connections on a Linux router

Our company network is set up in a rather standard way. We have a Linux router connected to an ISP with one network card, and to the local network with another one. The local network uses the reserved IP range 192.168.1.0-192.168.1.255. The router does Network Address Translation (NAT), also known as IP Masquerade, to allow the internal hosts transparent access to the Internet. This type of configuration is widely used and is well documented, in Linux 2.4 NAT HOWTO or Linux IP Masquerade HOWTO to name a few sources.

IP masquerade works well for TCP and UDP, but how about some more exotic IP protocols? Not that easy when it comes to IPsec VPNs. We need to connect to a customer's site that uses Contivity VPN from Nortel. This is an IPsec-based product. Unfortunately, masquerading several IPsec connection through one router is a non-trivial task that Linux is currently not capable of. IPsec connection involves a handshake over UDP, after which the data is transmitted over IP protocol 50 (Encapsulating Security Payload, ESP). Since there is no connection tracking support for IP protocol 50 in the Linux kernel, only one internal client can connect to a remote IPsec VPN server at any time, because the kernel cannot tell one connection from another. This was not acceptable to us, since we need several people to work with the customer's VPN simultaneously.

NAT Traversal feature of IPsec protocol is supposed to resolve this problem, however, for some reason, NAT Traversal didn't work with the customer's VPN server. Attempts to persuade the customer's IT personnel to look into the issue and enable NAT Traversal proved unsuccessful (they either didn't understand what the problem was, or didn't care, or both). We had to resolve the issue ourselves.

After some thought, the solution was found. First it involved getting several external IP addresses from our ISP, as many as many people we needed to work with the customer's VPN. Luckily, it wasn't many, just five. The idea then was to route the IPsec traffic from the five internal clients through separate external IP addresses. This will allow the kernel to keep track of each connection separately and not mix them up. Here's how I achieved this using iptables.

For the sake of example, I'll assume that our external IP numbers were 1.1.1.1, 1.1.1.2, 1.1.1.3, 1.1.1.4 and 1.1.1.5. All these numbers were bound to our external network interface as aliases. Assuming our external interface is called eth1, these new addresses were assigned to alias interfaces eth1:1, eth1:2, etc. up to eth1:5. Also for the sake of example, assume that the client computers that need to talk to the customer's VPN have internal IP addresses 192.168.1.1 - 192.168.1.5 and that the customer VPN server's address is 2.2.2.2.

With this setup, I added the following iptable rules to NAT table:

iptables -t nat -A POSTROUTING -s 192.168.1.1 -d 2.2.2.2 -j SNAT --to-source 1.1.1.1
iptables -t nat -A POSTROUTING -s 192.168.1.2 -d 2.2.2.2 -j SNAT --to-source 1.1.1.2
...
iptables -t nat -A POSTROUTING -s 192.168.1.5 -d 2.2.2.5 -j SNAT --to-source 1.1.1.5

This tells the kernel the following: right after routing (POSTROUTING chain), if the packet is coming from 192.168.1.x (a VPN client) to 2.2.2.2 (the VPN server), masquerade it using source address 1.1.1.x.

An important note is that these rules should precede the rules that masquerade the entire network. I have a rule like this:

iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth1 -j MASQEURADE
and it is added to the POSTROUTING change after the special rules above.

The above technique allows to masquerade multiple IPsec (or indeed any IP protocol) connections when NAT Traversal is not available. This said, I would much prefer if NAT Traversal worked and saved me the headache.

Tuesday, June 19, 2007

Эпос древних укров

История украинского народа уходит корнями в глубокую древность. Она не начинается с Оранжевой Революции, как наивно полагают некоторые на Западе. Она не начинается с Переяславской Рады, как хотели бы думать в Москве. Она не начинается даже с Кия, Щека и Хорива, как полагают некоторые ограниченные историки в Украине. Установлено, кто украинцы ведут свое происхождение от древнейшего народа укров, проживавшего на территории современной Украины уже в 4-м тысячелетии до н.э. К сожалению, в результате ряда катастроф как природно-геологического, так и социально-политического характера, литературные и культурные памятники укров были полностью утрачены. Однако нет на свете ничего, что было бы потеряно навеки (кроме Халезмийского собора - см. Д. Адамс, "Жизнь, Вселенная и все остальное", М., Аст, 2002, стр. 287). Достижения современной статистической историографии позволили буквально по крупице воссоздать и расшифровать фрагмент эпоса древних укров, публикуемый ниже. Работы по расшифровке продолжаются, и мы надеемся, что вскоре эпос будет полностью восстановлен.

Дальше...

Thursday, May 17, 2007

SharePoint Server: Audiences based on group membership problem

SharePoint Portal Server is a great tool. One of its powerful features is audiences. Audience is a group of SharePoint server users to which the publishers can target the server's content. That is, certain items are shown only to certain audience members. For example, the server's home page may contain links to Development and Support group sites. Members of Development group only see the link to the Development site, and members of Support group only see the link to the Support site.

One of the ways to define an audience membership is via Windows security group. One can say that an audience consists of all members of a security group. This is often very convenient, as security groups often already reflect the organization's structure. However, setting up audiences on our company's SharePoint server I found that this simply didn't work. I set up an audience to consist of members of a security group that had 7 members. I found that the audience had only 1 member. I tried it with other groups - the results were utterly inconsistent. With some groups it worked, with some a few members were missing, with some all members were missing, and no clear pattern was seen.

After a long investigation the pattern was revealed. A security group member wouldn't make it to the group-based audience if the group was his/her primary group. It is a bug in SharePoint server, described in this blog post by Craig Gemmill for SharePoint Server 2003. I am using SharePoint Server 2007 and the bug is still present.

Apparently, it has to do with the fact that the user's primary group is not listed in its memberOf Active Directory attribute. The primary group's members attribute does not include the members with Primary Group attribute either. There are valid reasons for this design, described in this Microsoft KB article, but SharePoint Server, apparently, doesn't take Primary Group into account.

Thus the only solution was to reset the Primary Group of all users to Domain Users.

Monday, April 23, 2007

Using deadlines to install Windows updates on unattended servers

WSUS is a great tool to distribute and install Microsoft Updates. As long as the administrator approves the updates, an "Updates are ready" notification will pop up on each user's screen, and the users will be prompted to proceed with installing the updates.

But what about unattended servers? No-one ever logs into their consoles and thus there's nobody to install the updates. Having an administrator log in to each server to install updates is just too tedious. Luckily, this isn't necessary. Using deadlines, one can have the updates install on unattended servers automatically. Here's how I do it:

  1. I've created a computer group in WSUS called "Servers" and added all servers to it.
  2. Whenever I approve an update, I make a separate approval for the "Server" group with a deadline.
  3. When the deadline expires, updates are installed automatically.
A thing to note here is that most of the time a server will reboot after the updates are installed. You don't want your servers to reboot in the middle of the day. Therefore, set the deadline to off-hours.

Always set the deadline more than 22 hours in the future. This is because Automatic Updates service is checking for new updates by default every 22 hours. Imagine what happens if during the day, say at 12am you set the deadline for 11pm today. By 11pm a server may not have checked for new updates yet, and it will not know a new update with a deadline is available. Next day, say at 10am it will check, find the update and see that the deadline is already past due. It will then immediately install the update and reboot right when your users are busy using it. To avoid such unfortunate scenario, allow sufficient time for Automatic Updates to find the update before the deadline expires.

Устанавливаем Lingvo 12

Наша компания приобрела электронный словарь Лингво 12. ABBYY Software предлагает для своего продукта удобную схему лицензирования - concurrent licenses. Покупая какое-то количество concurrent licenses, пользователь получает право запускать столько копий Лингво в сети одновременно, причем не имеет значения на каких компьютерах. Для нас это было очень удобно, т.е. из более ста сотрудников нашей компании, одновременно Лингво не понадобится больше, чем двадцати.

Технически работает эта схема лицензирования так. На сервере устанавливается Lingvo License Manager. В него вводятся и активируются все лицензии. Клиентские машины получают лицензию от сервера при запуске Лингво.

На бумаге все хорошо. На практике обнаружилось, что при запуске Лингво на одном компьютере License Manager показывает, что все concurrent лицензии заняты этим компьютером, и ни один другой компьютер запустить Лингво уже не может. Весьма неприятный сюрприз. В интернете обнаружили описание такой же проблемы (http://forum.lingvo.ru/actualthread.aspx?tid=72935) и совет обратиться в службу поддержки. Написали на support@abbyy.ua. Служба поддержки ответила, поинтересовалась номером нашей лицензии, и действительно прислала нам обновление на License Manager, исправляющее эту ошибку. Таким образом при доработке напильником система все-таки работает.

Несколько неприятной, однако, оказалась следующая новость в Лингво 12. В предыдущих версиях Lingvo был LvAgent, который сидел в System Tray и позволял вызвать Lingvo по Ctrl-Ins-Ins. При закрытии самого Lingvo LvAgent продолжал работать. Теперь все немного не так. По-прежнему LvAgent может запустить Lingvo, но теперь при закрытии Lingvo стандартными способами (кнопочка "x" или Alt-F4), сам Lingvo продолжает работать и, что особенно важно при concurrent лицензировании, занимать лицензию. Т.о. стоит запустить Lingvo, как он занимает лицензию даже после закрытия. Есть, правда, в меню пункт "Выход", который действительно закрывает Lingvo - но вместе с LvAgent.

В свете этого моя рекомендация такая - в настройках на вкладке "Общие" снять флажок "Отображать значок ABBYY Lingvo в области уведомлений на панели задач". В этом случае LvAgent не используется и закрытие Lingvo действительно его закрывает. Но вызов по Ctrl-Ins-Ins будет невозможен.

И наконец, странная история, приключившаяся с инсталляцией Лингво. После установки License Manager, по рекомендации производителя, инсталляция самого Лингво была помещена на сетевой диск. Вскоре несколько пользователей пожаловались, что они не могут установить Лингво себе на компьютер, используя эту сетевую инсталляцию: инсталлятор сообщает "Внутренняя ошибка 2349" и прекращает работать. Выяснилось, что по какой-то причине часть файлов из инсталляции получили дату изменения 01.01.1857 (как это произошло - загадка). При копировании этих файлов инсталлятор пытался дать установленным копиями такую же дату, что заканчивалось ошибкой. После исправления даты файлов проблема разрешилась.

Tuesday, April 10, 2007

Outlook 2003 update breaking Outlook 2007

I had Microsoft Office 2003 on my computer and decided to upgrade to Office 2007. Feeling a little wary about this upgrade, I decided to keep Office 2003 installed, since Office 2007 installer allowed for such option. However, as the installer informed me, Outlook 2007 could not coexist with Outlook 2003, so Outlook 2003 had to be removed. Alright, so I ended up having just one Outlook (2007) and two copies of Word and Excel (2003 and 2007).

A surprise came when I installed the next round of Microsoft updates (from our local WSUS server). An "Junk mail filter update for Outlook 2003" (KB931764) was offered to me, although I no longer had Outlook 2003. Not knowing what this means, I installed the update.

Right after that had an error in Outlook: "The File ExSec32.dll is incompatible with Microsoft Office Outlook. Install Outlook Again.", when opening any Outlook item. Apparently the "Junk mail filter update" reinstalled some of Outlook 2003 DLLs that were not compatible with Outlook 2007 (I guess this was the reason why they could not coexist in the first place).

I removed ExSec32.dll in Office11 folder, then get the same error about RTFHTML.dll. Removed it as well. Outlook items started to open, but after a few more errors, I resorted to reinstalling Outlook 2007.

Ever since then, each monthly update of Junk Mail Filter for Outlook 2003 was offered to me by Windows Updates, and I had to manually deselect it. Finally, when I uninstalled Office 2003, the problem stopped.

Sunday, April 08, 2007

GroupWise vs. Excel

A long time ago a had to install Novell GroupWise 7.0 on my computer. Right after that I faced a problem with Excel 2003. To my surprise, the Windows "Close" button in the top-right corner (aka the "x-button") became disabled. Furthermore, sometimes when I was closing a workbook with Ctrl-F4, Excel would show the "Save As" dialog, even though the document was already saved. I suspected all this was caused by GroupWise, but since the annoyance was minor I didn't feel like spending time to figure this out. The situation became worse when I upgraded to Excel 2007. Now, whenever I opened a Excel file by double-clicking on it, Excel would come up, but the document would not open in it. I had to wait a few seconds, sometimes up to a minute, before the document would open. Interestingly, if I started Excel and then opened a document from it, it would open immediately without the annoying delay. This time I could not ignore the problem. Investigation revealed an apparently GroupWise-related file in c:\Program Files\Microsoft Office\XLSTART\GWXL97.XLA. I don't know what GroupWise wanted to do with Excel, but whatever it is, it is incompatible with Excel 2007 (the filename suggests it was developed for Excel 97). Removing the file resolved the problem.

Thursday, March 22, 2007

Blogging from Word 2007

They say one can write blog posts directly from Word 2007. I am just curious. Let's see if it works.

Apparently it does! Although it's not as good as I thought it would be. I don't seem to be able to update a post once it is published. Instead, it publishes the modified document as a new post. Still, it's interesting and somewhat unusual for Microsoft

Tuesday, March 06, 2007

Trouble adding users to local groups

Had a problem today with a Windows 2000 computer. We needed to add a user to the local Administrators group, and could not. Just clicking the "Add" button in the group membership window resulted in error message "An error occurred attempting to create the Object Picker. An error with no description has occurred." Luckily a solution was described here in Hidev, Inc. Knowledge base. In our case, the key HKLM\LDAP\Clsid was missing. Thanks!

Sunday, March 04, 2007

More on lingering objects

A followup to a previous post. I've been thinking how lingering objects appeared in the DCA domain controller (the one that didn't have the time sync problem). I have two theories:

Theory 1. While DCB controller was in year 2000, some objects were deleted in its copy of the Active Directory database. If things were going normal, DCB would keep a copy of these deleted objects in a "tombstoned" state for the duration of "tombstone lifetime" (by default 60 days). Within this period it would synchronize with DCA and tell it about the deletions, so DCA would delete these objects from its copy of the Active Directory database. But things were not going normal. When time on DCB was corrected, it found that those deleted objects were deleted 7 years ago, i.e. way longer ago than "tombstone lifetime". Consequently, the "tombstones" were deleted and it no longer had any memory of the deleted objects. All along, DCA continued to have copies of these objects, unaware of them being deleted. So, when the time was corrected, DCA wanted to synchronize to DCB, those objects were found to be lignering in DCA.

If this theory is correct, then the solution to delete lingering objects was the right one.

Theory 2. Nothing was deleted in DCB, instead something was created in DCA. While time was broken on DCB these changes failed to replicate from DCA to DCB. When time was corrected, DCB incorrectly assumed those new objects on DCA were lingering.

If this theory is correct, then the lingering objects should not have been deleted. Instead, Strict Replication Consistency should have been disabled (as described, among other places in the Event ID 1388 or 1988: A lingering object is detected section of Active Directory Operations Guide at Microsoft Technet) and thus objects allowed to be recreated at DCB.

Somehow I feel that Theory 1 is correct, but I have no definite proof.

Wednesday, February 21, 2007

Wrong Time on a Domain Controller

Today we had to shut down all our servers for electricity maintenance, and while they were starting back up after the maintenance, clock was set incorrectly on one of our two domain controllers. I am not completely sure why this happened, but it seems to be the fault of Tardis Internet time service. One way or another, time was reset to Jan 1st, 2000. All the hell broke loose.

First, the wrong time was picked up by some other computers that suddenly shifted to year 2000. That was the least of all problems. Second, users started having problems logging in to the domain. The faulty domain controller denied access due to clock skew. These two problems were resolved once the time problem was noticed and time at the domain controller was reset to the correct value. But this was not the end.

Unfortunately, while the faulty domain controller (we'll call it DCB) was in year 2000 it replicated with the other controller (let's call it DCA) that had the correct time. Then DCA remembered that it last replicated with DCB in year 2000! As the result, when the time on DCB was corrected, DCA no longer wanted to replicate to DCB thinking that it was way too outdated to replicate again. Attempts to force replication in replmon utility (from Windows Support Tools) resulted in the error "The Active Directory cannot replicate with this server because the time since the last replication with this server has exceeded the tombstone lifetime." Directory Service Event log on DCA showed Event 2042 which read:

It has been too long since this machine last replicated with the named source machine. The time between replications with this source has exceeded the tombstone lifetime. Replication has been stopped with this source.

The reason that replication is not allowed to continue is that the two machine's views of deleted objects may now be different. The source machine may still have copies of objects that have been deleted (and garbage collected) on this machine. If they were allowed to replicate, the source machine might return objects which have already been deleted.

This problem soon had consequences. One user reported that her workstation could no longer connect to shared resources on the DCB controller, with error message "Target principal is incorrect". It was a strange situation, since it could connect to any other server in the network, plus all other workstations but this one could connect to DCB too. Although I still don't have a definite explanation to this, my best guess is that this workstation had the bad luck to automatically change its domain account password while the replication was broken. As the result, DCA had its new password, but DCB still had the old one, and thus could not authenticate the workstation.

To resolve the replication problem I followed the advice from the Event 2042 log entry and numerous sources on the internet, such as "Event ID 2042: It has been too long since this machine replicated" chapter from Windows Server 2003 Active Directory Operations guide on Microsoft TechNet. On DCB I went to the registry key HKLM\SYSTEM\CurrentControlSet\Services\NTDS\Parameters and created a DWORD value Allow Replication With Divergent and Corrupt Partner with value 1. Then forced replication from DCA to DCB in replmon. This time replication worked, and after that I reset the registry value to 0.

Still, replication in the other direction, from DCB to DCA didn't work. Directory Service Event log on DCB showed Event 1988 which read:

Active Directory Replication encountered the existence of objects in the following partition that have been deleted from the local domain controllers (DCs) Active Directory database. Not all direct or transitive replication partners replicated in the deletion before the tombstone lifetime number of days passed. Objects that have been deleted and garbage collected from an Active Directory partition but still exist in the writable partitions of other DCs in the same domain, or read-only partitions of global catalog servers in other domains in the forest are known as "lingering objects".

This event is being logged because the source DC contains a lingering object which does not exist on the local DCs Active Directory database. This replication attempt has been blocked.

The best solution to this problem is to identify and remove all lingering objects in the forest.

Additionally, the Application event log was flooded with Event 1053 that read "Windows cannot determine the user or computer name. (Access is denied.). Group Policy processing aborted."

At the edge of panic, I searched for suggestions to Event 1053 error. In retrospect, I'm not sure I did the right thing, but I followed the advice from the Microsoft KB article 288167 (or 260575) to reset DCB's computer acccount password with netdom utility. After the password was reset and computer rebooted, the problem of the workstation that could not connect to DCB's shared resources disappeared.

It remained to restore replication from DCB to DCA though. I followed "Event ID 1388 or 1988: A lingering object is detected" chapter from Windows Server 2003 Active Directory Operations guide on Microsoft TechNet (there's also a few KB articles that you can find if you search for "lingering objects" at support.microsoft.com). Using repladmin /removelingeringobjects on DCA, as described there, I removed the objects that stopped the replication, and the issue was finally resolved.

In retrospect, I don't fully understand how those lingering objects occurred and if it was safe to remove them or not. Perhaps I should have disabled Strict Replication Consistency as described at the same TechNet article or in the Event 1988 log entry.

To wrap up this post, don't mess with time, it's important.

Dangers of Group Policy

As any powerful tool, Group Policy may cause trouble if used inappropriately. Once I have set the following parameters in our domain's default policy: Computer Configuration - Administrative Templates - Network - DNS Client - DNS Servers and DNS Suffix Search List to the values appropriate to our LAN. I must admit that in doing so I didn't pursue any particular purpose, since these settings were configured on all client computers either manually or with DHCP. It just seemed a right thing to do. Wrong. Recently we started using a laptop computer to access the Internet wirelessly via GPRS while on the road. All went well until the laptop was joined to the domain. Suddenly GPRS connection no longer worked. Investigation revealed the following: once the laptop was joined to the domain, Group Policy applied to it, including our internal LAN DNS Server setting. Then, unexpectedly, the computer continued using this DNS Server even when disconnected from the LAN and connected via GRPS, which, of course, didn't work. To resolve the problem I simply removed these settings from the Group Policy, then connected the laptop to the LAN and ran gpupdate to update Group Policy settings. I guess if I did need these settings in the Group Policy I would have to move the laptop to another OU in the Active Directory so that this particular policy would not apply to it.

Friday, February 16, 2007

Новое слово английского языка

Отечественная журналистика сталкивается с трудностями перевода.

13 февраля The Wall Street Journal опубликовал статью под названием "Russian for Chutzpah" с критикой известного выступления Путина в Мюнхене. Я совершенно не хочу вдаваться в суть статьи, заинтересовали меня трудности перевода. На сайте WSJ статья доступна только подписчикам, но зато на сайте Royal Dutch Shell ее можно прочитать (очевидно, компания Royal Dutch Shell заинтересовалась этой статьей потому, что она там упоминается в связи с проектом Сахалин-2). Статья начинается фразой:

The nearest equivalent the Russian language has for the word chutzpah is naglost.
Трудно не согласиться с автором. Но вот появляется перевод этой статьи на русский язык на украинском сайте UK2Watch, который затем переречатывает популярный новостной сайт Korrespondent.net. В переводе фраза звучит так:
В английском языке есть очень выразительное слово chutzpah, которое по-русски лучше всего переводится как «наглость».
Переводчик, по-видимому, не в курсе, что "очень выразительное" английское слово chutzpah ("хуцпа") на самом деле является ивритским, и в английский сленг пришло через идиш (подобно словам "хохма" или "ксива" в русском языке).

Также забавно, что очень выразительное слово chutzpah о выступлении Путина (хотя и в другом контексте) первым употребил на WSJ, а украинская блоггер (как в женском роде? трудности перевода) Вероника Хохлова здесь.

Saturday, February 10, 2007

Неофициальные патчи для Digikam

Digikam - прекрасная программа для работы с цифровыми фотографиями в Linux, которой я активно пользуюсь и рекомендую всем пользователям Linux'а. В этой заметке я опишу одну небольшую проблему Digikam и предложу ее решение.

На моем компьютере установлен не только Linux, но конечно же и Windows, без которого пока обойтись тяжело. Для работы с фотографиями под Windows я использую не менее прекрасную программу Picasa. Конечно, мне хотелось бы, чтобы комментарии к фотографиям, которые я ввожу в Digikam, воспринимались также и Picasa (например, для загрузки в Picasa Web Albums). И Digikam позволяет это сделать, благодаря опции "Save image comments as embedded text". При включении этой опции Digikam сохраняет комментарии к фотографиям в самих файлах фотографий в виде JPEG-комментариев и тэгов EXIF и IPTC. Picasa же использует для сохранения комментарием именно тэги IPTC. Так что Digikam и Picasa могли бы прекрасно понимать комментарии друг друга, если бы не одно "но" - и это, конечно, русские кодировки. Комментарии латинскими буквами воспринимаются прекрасно. Но попробуйте ввести в Digikam комментарий на русском: Picasa увидит одни знаки вопроса. А комментарий, введенный в Picasa в Digikam превратится в "крокозябры".

Для решения этой проблемы я создал небольшой патч для Digikam. После установки патча и перекомпиляции в Digikam появится новая опция. Она находится в диалоге "Configure Digikam" на странице Metadata и называется "IPTC Encoding". Выберите значение "Cyrillic (cp1251)" и после этого Digikam будет сохранять комментарии в IPTC тэги в читаемом для Picasa виде (т.е. Windows-кодировке) и, соответственно, читать комментарии, сохраненные в Picasa. Если же также установить другой мой патч на расширения kipi-plugins, то расширение Metadataedit позволит вам свободно редактировать метаданные IPTC на русском.

Патч для исходников Digikam 0.9.0 находится здесь, патч для исходников kipi-plugins 0.1.3 здесь. Собранный пакет Digikam RPM для Fedora Core 5 с моим патчем здесь, kipi-plugins - здесь.

Обновление для Digikam 0.9.1. Для этого релиза патчить надо сам Digikam и пакет libkexiv2. Патч для Digikam здесь, для libkexiv2 - здесь. Kipi-plugins модифицировать не нужно. Собранный пакет Digikam RPM для Fedora Core 5 с моим патчем здесь, libkexiv2 - здесь.

Обновление для Digikam 0.9.2. Патч для Digikam здесь, для libkexiv2 - здесь. Собранный пакет Digikam RPM для Fedora Core 5 с моим патчем здесь, libkexiv2 - здесь.

Обновление для Digikam 0.9.3. Патч для Digikam здесь, для libkexiv2 - здесь. Собранный пакет Digikam RPM для Fedora Core 5 с моим патчем здесь, libkexiv2 - здесь.

Включение этих патчей в официальную версию Digikam сейчас обсуждается.

Friday, February 09, 2007

A Piece of American Humor

A farmer named Clyde had a car accident. In court, the trucking company's fancy lawyer was questioning Clyde .

"Didn't you say, at the scene of the accident, 'I'm fine,'?" asked the lawyer.

Clyde responded, "Well, I'll tell you what happened. I had just loaded my favourite mule, Bessie, into the..."

"I didn't ask for any details", the lawyer interrupted. "Just answer the question. Did you not say, at the scene of the accident, 'I'm fine!'?"

Clyde said, "Well, I had just got Bessie into the trailer and I was driving down the road...."

The lawyer interrupted again and said, "Judge, I am trying to establish the fact that, at the scene of the accident, this man told the Highway Patrolman on the scene that he was just fine. Now several weeks after the accident he is trying to sue my client. I believe he is a fraud. Please tell him to simply answer the question."

By this time, the Judge was fairly interested in Clyde 's answer and said to the lawyer, "I'd like to hear what he has to say about his favorite mule, Bessie". Clyde thanked the Judge and proceeded.

"Well as I was saying, I had just loaded Bessie, my favorite mule, into the trailer and was driving her down the highway when this huge semi-truck and trailer ran the stop sign and smacked my truck right in the side. I was thrown into one ditch and Bessie was thrown into the other. I was hurting, real bad and didn't want to move. However, I could hear ole Bessie moaning and groaning. I knew she was interrible shape just by her groans. Shortly after the accident a Highway Patrolman came on the scene. He could hear Bessie moaning and groaning so he went over to her. After he looked at her, and saw her fatal condition, he took out his gun and shot her between the eyes.

Then the Patrolman came across the road, gun still in hand, looked at me,and said, "How are you feeling?"

"Now what the Fuck would you say?

Sunday, February 04, 2007

Парадоксы теории множеств

Небольшое предисловие

Эта статья бала написана мной в качестве реферата по психологии (!) в аспирантуре в 1996 г. По замыслу, это план занимательной лекции по математике. Насколько она занимательна судить читателю.


Парадоксы теории множеств

Что такое множество? Слово это часто встречается в повседневной речи -- мы говорим о "множество дел" или "множестве людей", -- и фактически подспудно присутствовало в математике с момента ее возникновения. Однако, явным образом понятие множества подверглось систематическому изучению лишь во второй половине XIX века в работах немецкого математика Георга Кантора -- до этого в математике существовали "натуральные числа" или "целые числа", но не "множество натуральных чисел" и не "множество целых чисел". И вот когда "множество" как таковое стало предметом математического рассмотрения, в этом, на первый взгляд, простом и повседневном понятии выявились глубокие противоречия, подорвавшие традиционный взгляд на основания математики и научного знания вообще.

Строго определить, что же такое множество не так-то просто. Определения типа "произвольная совокупность объектов" сути дела не проясняют, и есть ни что иное, как замена слова "множество" словом "совокупность", которое, в свою очередь, нуждается в определении. Несмотря на такие трудности с определением абстрактного понятия множества, понятно как задать некое конкретное множество -- нужно указать какие объекты этому множеству принадлежат, а какие не принадлежат. Например, число 1 принадлежит множеству натуральных чисел, а число 1.5 -- не принадлежит, как не принадлежит ему и автомобиль моего соседа. Пример с автомобилем может показаться несколько неуместным -- в самом деле, ясно, что автомобили к натуральным числам отношения не имеют, т.е. очевидно, что соседский автомобиль не принадлежит множеству натуральных чисел. Однако, в других, менее тривиальных ситуациях все не так очевидно, и возникает законный вопрос -- а какие объекты вообще могут быть элементами множеств? Когда мы говорим "указать какие объекты этому множеству принадлежат" -- о каких объектах мы говорим? Только о числах или о, скажем, функциях, автомобилях, людях? На протяжении столетий развития математики, на этот вопрос неявно отвечали -- о всех объектах. Элементами множеств могло быть все. В этом наивном стремлении свести все к множествам и скрывалось внутренне противоречие, которое мы постараемся прояснить. Но вначале необходимо ближе познакомиться с классической канторовой теорией множеств.

Одним из основных понятий, введенных Кантором, является мощность множества. Мощность есть обобщение количества элементов множества. Количество элементов множества {1, 2, 3} равно 3, и, соответственно, это множество меньше, чем множество {3, 4, 5, 7, 8}, в котором 5 элементов. Но сколько элементов в множестве всех натуральных чисел N? Бесконечно много, скажем мы. А в множестве целых чисел Z или вещественных чисел R? Тоже бесконечно много! Нельзя ли как-то сравнить эти бесконечности и определить, какая из этих бесконечностей больше?

Рассмотрим такой пример. Пусть множество (мы намеренно употребляем это слово) людей нужно рассадить в кресла в зале. Мы хотим определить, чего в зале больше: людей или кресел. Можно посчитать всех людей и все кресла и определить, какое из чисел больше. Но можно поступить и иначе: попросить всех сесть! Если останутся свободные кресла, то кресел больше, если же некоторые люди останутся стоять, то больше людей. Наконец, если все люди рассядутся, а свободных кресел не останется, то мы скажем, что людей и кресел поровну.

Аналогично мы можем поступать с множествами. Хотя мы не можем пересчитать все элементы двух бесконечных множеств, но мы можем попытаться поставить их элементы во взаимно-однозначное соответствие, иными словами, рассадить людей в кресла. Если установить такое соответствие удастся, то мы скажем (следуя Кантору), что два рассматриваемых множества равномощны. Если же, как бы мы не устанавливали соответствие, всегда остаются "лишние" элементы из одного из множеств, то это множество имеет большую мощность, чем другое.

При таком определении, оказывается, что множество всех целых чисел равномощно своему подмножеству -- множеству натуральных чисел. Этот парадоксальный, на первый взгляд факт, легко доказать. Выпишем целые числа в таком порядке:

0, 1, -1, 2, -2, 3, -3, ...

Ясно, что так мы выпишем все целые числа. Однако, если теперь мы занумеруем их всех слева направо натуральными числами 1, 2, 3, ..., то все целые числа "рассядутся в кресла" натуральных чисел. Таким образом установлено взаимно-однозначное соответствие между множествами N и Z, и, таким образом, они равномощны. Пока, впрочем, никакого парадокса нет -- просто к бесконечным множествам не всегда применимы наглядные представления.

Ну, а множество вещественных чисел R? Неужели и оно равномощно множеству натуральных чисел? Оказывается, R действительно больше N. Даже множество чисел интервала (0; 1) больше, чем множество натуральных чисел. Покажем это. Допустим, что нам удалось занумеровать все вещественные числа интервала (0; 1) натуральными числами. Выпишем тогда все эти числа в порядке номеров в виде десятичных дробей. Получится что-то вроде

1: 0.5678345345...
2: 0.0928942346...
3: 0.5675454323...
4: 0.9875376780...
и т.д.

Теперь составим вещественное число x таким образом. Если в числе № n на n-м месте стоит цифра 5, запишем в нашем числе x на n-м месте цифру 6; если же в числе № n на n-м месте стоит не пятерка, то запишем в числе x на n-м месте пятерку. Ясно, что x не совпадает ни с одним из перенумерованных чисел -- ведь от n-го числа оно отличается в n-ном знаке! Но x -- тоже число из интервала (0; 1), и потому тоже должно было быть занумеровано! Полученное противоречие показывает, что занумеровать все числа интервала (0; 1) невозможно, т.е. интервал (0; 1) больше множества N.

Есть ли еще большие множества? Да, и сейчас мы это увидим. Пусть S -- какое-то множество. Рассмотрим множество M(S) всех его подмножеств. Т.е. элементами M(S) являются подмножества множества S. Это может показаться слегка экзотичным, но мы ведь договорились, что элементами множеств может быть все, что угодно. Легко посчитать, что если S -- конечное множество из n элементов, то M(S) содержит 2n элементов. Сейчас мы покажем, что M(S) всегда больше S, даже если S бесконечно.

В самом деле, предположим, что нам удалось установить взаимно-однозначное соответствие между элементами S и элементами M(S), т.е. подмножествами S. Т.е. каждому x из S соответствует некоторое подмножество Sx. Рассмотрим теперь множество A всех тех x, которые не принадлежат своим Sx. Это -- тоже некоторое подмножество множества S (может случиться, что оно пусто, а может, совпадает со всем S). Раз так, оно соответствует некоторому конкретному x из S, т.е. A = Sx. Это x не может принадлежать A, т.к. A есть множество тех x, которые не принадлежат своим Sx. Но тогда, поскольку A есть множество всех тех x, которые не принадлежат своим Sx, x должно принадлежать A. Т.е. x и принадлежит, и не принадлежит A, что, конечно же, невозможно. Таким образом, взаимно-однозначное соответствие между S и M(S) невозможно.

Итак, множество M(R) всех подмножеств множества вещественных чисел больше, чем R, далее M(M(R)) больше, чем M(R) и т.д. (Кстати, M(N) равномощно R).

Теперь мы рассмотрим знаменитый парадокс Рассела. Назовем множество экстраординарным, если оно содержит себя в качестве элемента (вопрос о том, существуют ли такие множества, мы пока оставим в стороне). Остальные множества назовем ординарными. Рассмотрим теперь множество O всех ординарных множеств. Весьма экстравагантное множество, но, повторимся, мы допускаем любые объекты в качестве элементов множеств. Само-то O ординарно или нет? Если O ординарно, то, будучи множеством всех ординарных множеств оно должно содержать себя в качестве элемента, т.е. быть экстраординарным. Если же оно экстраординарно, то будучи множеством только ординарных множеств, оно не содержит себя в качестве элемента, и потому ординарно. Итак, если O ординарно, то оно экстраординарно, а если оно экстраординарно, то оно ординарно. Абсурд! Вся эта игра словами напоминает известный старинный парадокс брадобрея: если брадобрей бреет всех тех, и только тех, кто не бреется сам, то бреет ли он сам себя? Здесь, аналогично, если он бреет себя, то он не бреет себя, а если бреет -- то не бреет. Парадокс брадобрея, впрочем, разрешается весьма просто -- такого брадобрея не существует. Ни один брадобрей, как бы он не старался, не может выполнить условия брить всех тех, и только тех, кто не бреется сам -- это условие противоречиво, и потому невыполнимо. В случае множества O нам ничего не остается, как признать, что множества всех ординарных множеств не существует. Однако, в отличие от хитроумного брадобрея, потеря этого множества, хотя едва ли представляет практическую проблему, для оснований математики фатальна. Оно означает конец "наивной теории множеств", где элементами множества позволялось быть всем, чем угодно. Такая вольность в обращении с множествами привела нас к множеству, существование которого внутренне противоречиво. Т.к. такая ситуация в математике недопустима, приходится признать, что не все можно называть множеством. Нашего "монстра" O назвать множеством нельзя. Но что же это тогда? Ведь до сих пор подразумевалось, что существует любое множество, достаточно только это множество описать. И вот, мы описали множество, а оно не существует. Подчеркнем, не пусто, а именно не существует как таковое.

Другой парадокс, связанный с понятием мощности, проясняет, что причина противоречий кроется в "слишком больших" множествах. Рассмотрим множество всех множеств M. (Оно, кстати, экстраординарно). М(M) -- множество всех его подмножеств. Элементы М(M) -- множества, а т.к. M есть множество всех множеств, то все элементы М(M) являются также элементами M. Иными словами, М(M) есть подмножество M. Но ведь мы доказали, что мощность М(M) строго больше мощности M! Мощность подмножества не может быть строго больше мощности объемлющего множества. Таким образом для "монстров" типа M, понятие мощности отказывает. Т.е. множество всех множеств -- не множество.

Эти и другие открытия, совершенные математиками в конце прошлого -- начале этого века, заставили математическое сообщество по-новому взглянуть на основания своей науки и привели к созданию новых поразительных теорий множеств и логики, открытию многих новых фактов, таких как знаменитая теорема Геделя о неполноте, -- но это уже тема для отдельной лекции.

Saturday, February 03, 2007

Cовременная компьютерная революция. Виртуальная реальность?

Небольшое предисловие

Этот текст был написан мной в качестве реферата по философии в аспирантуре в 1996 г. Теперь он представляется весьма наивным, но по-своему интересен до сих пор.

Современная компьютерная революция

Виртуальная реальность?

В 1945 году в Пенсильванском университете (США) было создано первое электронно-вычислительное устройство, получившие название ENIAC - Electronic Numerical Integrator And Computer. Последнее слово этого названия и дало имя одному из величайших изобретений нашего века - компьютеру. Сам ENIAC применялся для баллистических расчетов, предсказаний погоды и некоторых научных вычислений. Сегодня, 50 лет спустя, трудно найти область человеческой деятельности, где компьютер не нашел бы применения. Однако, не только скорость прогресса в области компьютерной техники достойна внимания. Едва ли найдется другое достижение технологии, которое вызывало бы столь обширный, настойчивый, иногда просто благоговейный интерес у рядового обывателя, далекого от знания глубин компьютерной науки. Хотя по сути своей компьютер - не более чем инструмент, лишь сложностью отличающийся от пишущей машинки, в глазах многих, чтобы не сказать - большинства, неспециалистов (в терминологии программистов - пользователей) компьютер скорее не средство, а цель. “Он работает на компьютере” представляется вполне адекватным ответом на вопрос о чьем-либо роде занятий, в то время как ответ “он работает на пишущей машинке” звучит по крайней мере странно. Более того, компьютер представляется чуть ли не одушевленным существом. “Он не хочет печатать!” - восклицает в отчаянии пользователь. Конечно, в нашей стране такое отношение к ЭВМ частично связано с тем, что это чудо техники для нас пока еще в новинку, и мы привыкли к нему куда меньше, чем к телевизору (тоже отнюдь не простое устройство). Но это не единственная причина, да и на Западе, где компьютер давно уже прижился на каждом канцелярском столе, подобное отношение существует. О компьютерной революции рассуждают журналисты, философы и политики. Практически все прогнозы будущего человечества, сделанные как писателями-фантастами, так и профессиональными футурологами, так или иначе подразумевают существенную роль компьютеров. Причем, хотя в одних прогнозах “отбившиеся от рук” злонамеренные ЭВМ захватывают власть над людьми, а в других добрые “умные помощники” превращают жизнь человеческую в рай, в обоих сценариях компьютеру приписывается какая-то собственная воля, злая или добрая. Поневоле задумаешься - почему тема компьютеров столь притягательна и почему мы склонны одушевлять компьютер (по сути - железку)?

Ответить на второй вопрос не так сложно. Как мы уже заметили, компьютер отличается от пишущей машинки сложностью. И здесь происходит пресловутый переход количества в качество. Компьютер так сложен, и функционирование его зависит от столь многих факторов, что пользователь не может охватить и учесть их все. Реакции компьютера представляются со стороны непредсказуемыми и как будто зависящими от его, компьютера, “желания” и “настроения”. Отсюда и одушевление. Но одной “одушевленности” недостаточно для объяснения феноменальной популярности компьютерного дела. Ведь и телевизор, в известной мере, “одушевлен”, а уж домашний кот не только представляется одушевленным, но и является таковым. Компьютер многофункционален - на нем можно проводить научные расчеты, воевать с монстрами в игре “DOOM” или, скажем, набирать этот текст. Но и авторучка многофункциональна. Компьютер важен для индустрии - но и токарный станок не менее (а то и более) важен. На компьютере можно производить сложные расчеты - но считать, в конце концов, можно и на счетах.

Но есть одна вещь, которую счеты, в отличие от компьютера сделать не могут (и в этом - принципиальное отличие этих двух приборов) - счеты не могут принимать логических решений. Компьютер же может, пускай и самые простые. Поэтому именно с изобретением компьютера впервые стала возможна автоматизация интеллектуального труда. Благодаря своим логическим возможностям, ЭВМ может не просто вычислять, но и перебирать варианты, причем делать это со скоростью немыслимой для человека. А ведь решение технических и многих научных задач есть не что иное, как перебор множества вариантов. Правда, человек способен интуитивно “чувствовать” наиболее перспективные варианты и исключать из рассмотрения варианты заведомо тупиковые. Компьютер интуицией не обладает и пока еще не силен в искусстве отличать перспективные ходы мысли от тупиковых. Компьютер перебирает все варианты, но делает это настолько быстро, что может справиться с задачей своим “лобовым” методом, там где эвристика человека пасует.

Эта способность ЭВМ и является истинно революционной. Можно говорить, что она привела к возникновению новой парадигмы решения научных задач. Вместо того, чтобы искать эвристические ходы, избавляющие от необходимости перебора (точнее сказать, сильно ограничивающие перебор), достаточно свести задачу к конечному - пусть даже очень большому - перебору и поручить ЭВМ разобрать все варианты. Перечислить все задачи решенные таким способом невозможно, но классическим примером является знаменитая математическая проблема четырех красок (любую ли карту можно раскрасить четырьмя красками так, чтобы примыкающие страны были окрашены в разные цвета?). Разумеется, полный перебор здесь невозможен - количество возможных карт бесконечно. Многие математические гении искали эвристическое решение этой задачи, но проблема не поддавалась и казалась неразрешимой. И лишь недавно удалось свести все бесконечное разнообразие карт к конечному (но очень большому) числу классов. В отсутствие компьютера это достижение было бы бесполезным, так как перебрать все эти классы было бы невозможно в течение человеческой жизни. ЭВМ же справилась с подсчетом за несколько часов. (Кстати ответ в проблеме четырех красок - да, любую).

Но революция, произведенная вычислительной техникой в инженерии и науке - все-таки недостаточная причина для объяснения столь тотального интереса к компьютеру. Ведь революция эта произошла в 60-70е годы, и касалась она в основном инженеров и ученых. Почему же теперь, в 90е годы, к развитию компьютерной техники приковано внимание столь широких кругов общества?

Совершив революционный скачок - изобретение компьютера - технология медленно но верно двинулась по пути сближения компьютера с его пользователем. Программирование ENIAC’a было под силу лишь его создателям, так как осуществлялось на уровне машинных кодов. С изобретением алгоритмических языков, таких как Фортран, Паскаль или Си, говорить с компьютером стало говорить гораздо больше людей. Ориентированные на пользователя “дружественные” среды, управляемые меню или “кнопочками” еще больше упростили общение с ЭВМ. Обратившись лицом к пользователю, компьютер уже был готов к выходу из лабораторий “в мир”. И тут произошла новая революция.

Поистине эпохальное изобретение (пожалуй, более эпохальное, чем создание самого компьютера) было сделано в 1969 году в лабораториях Агентства передовых исследовательских проектов (ARPA) Министерства обороны США, где была создана первая компьютерная сеть. И если один компьютер таит в себе весьма обширные возможности, то мощь многих компьютеров, объединенных сетью, просто неограниченна. Не случайно именно сетевые технологии - самая “горячая” тема дискуссий компьютерного мира. Не здесь ли секрет притягательности компьютера?

Выйдя из лабораторий ARPA, и превратившись из локальной ARPAnet в глобальную Internet, окрещенную средствами массовой информации “Информационным супер-хайвеем” и “Киберпространством”, всемирная компьютерная сеть придала новый смысл понятию телекоммуникаций. Вот когда компьютер по-настоящему превратился из чисто технического инструмента в своего рода бытовой прибор. Даже в нашей, к сожалению, технологически отсталой среде электронной почтой уже мало кого удивишь, а уж в более развитых странах сеть проникла в самые, казалось бы, далекие от компьютеров области жизни. На экране компьютера можно получить прогноз погоды, сводку положения дел на Уолл Стрит, заказать билет на самолет, поболтать с друзьями (автор делает это регулярно) и даже познакомиться с будущей женой (говорят - автор сам не пробовал). Таким образом компьютер, ранее в общественном сознании находившийся в одной компании со счетами, перешел скорее в разряд журналов и телевидения. Компании, предоставляющие услуги по рекламе и обмену информацией в сети, нарождаются как грибы и зарабатывают миллионы. Самые горячие баталии между фирмами-производителями программного обеспечения разворачиваются именно в области программ для работы в сети. Откройте любой компьютерный журнал - да что там журнал, любую захудалую околокомпьютерную газетенку - страницы пестрят похожими на заклинания названиями сетевых технологий: Internet! Java! World Wide Web! Virtual Reality!..

Reality? Вот оно, ключевое слово - реальность! Именно реальность - хотя и “виртуальная” - встает за экраном монитора. Это верно даже для “одиночного” компьютера и тем более верно для компьютера, подключенного к всемирной сети. И здесь, как мне кажется, кроется корень популярности и интереса к компьютеру. В небольшом ящике, стоящем у вас на столе - целая реальность, мир, который вы можете открывать, и которым вы можете управлять, который вы можете творить. Ведь возможность открывать и творить - безусловно, одна из самых привлекательных вещей для человека, во всяком случае человека образованного, к коим мы хотели бы себя причислить. В “реальной” реальности возможности эти ограничены расстояниями, материальными затратами, отсутствием времени, недостатком таланта и т.д. В виртуальной реальности компьютера, разумеется, есть свои ограничения, но рамки возможного неизмеримо шире. Несколько нажатий на клавиши - и события в вашем, казалось бы, “неуправляемом” и “своенравном” электронном ящике идут по созданному вами плану. Вы испытываете захватывающее чувство творца, доступное лишь художникам, композиторам, актерам - только Богом данного таланта не требуется, достаточно лишь немного логического мышления. Конечно, совсем без таланта не обойтись, и полный бездарь или лентяй ничего не добьется и в виртуальной реальности, но все-таки уже не нужно быть гением, чтобы творить. Причем, если вы подключены к сети, то весь мир сможет оценить ваше творчество. Например, этот опус едва ли бы опубликовали в научном журнале, а поместить его в сети и, тем самым, “виртуально” опубликовать, ничего не стоит.

Итак, реальность и необычайно расширенные возможности творить - вот, по-видимому, принципиальные привлекательные черты компьютерного дела сегодня. О виртуальной реальности уже можно говорить, как об особой субкультуре, со своими идеалами, принципами, жаргоном (до языка он пока не дотягивает) и стилем общения. Как соотносится творчество в виртуальном мире с миром реальным? Не следует думать, что плоды виртуальной деятельности имеют лишь виртуальную ценность. Не говоря уже о программистах-профессионалах, получающих за свои виртуальные творения вполне реальную зарплату, многое из созданного “на клавишах” эстетически ценно и шедевры компьютерных мастеров заставляют задуматься о возникновении нового вида искусства со своей эстетикой. Есть и своя компьютерная этика, возник уже и забавный термин для нее - английское слово “netiquette”, образованное слиянием слов “net” - сеть и “etiquette” - этикет.

Хотя, конечно, виртуальная реальность - неотъемлемая часть реального мира, все же многие адепты всемирной сети рассматривают ее именно как реальность альтернативную. Будучи делом рук увлеченных энтузиастов, сеть предоставляет зачастую примеры научного благородства и свободы, немыслимые в “заорганизованном” мире по эту сторону экрана. Яркий пример - многочисленные программные продукты и целые программные комплексы (такие как, например, операционная система Linux), созданные авторами в свободное от основной работы время и распространяемые совершенно бесплатно, исключительно из любви к братьям по компьютерному сообществу. Можно ли представить себе людей, производящих, скажем, телевизоры и раздающих их бесплатно? Доходит даже до экстремизма: некоторые сетевики воруют коммерческие программные продукты и начинают распространять их бесплатно, оставаясь, конечно, анонимными, т.к. такая деятельность противоречит законодательству (а называется она на слэнге сетевиков “Warez”).

Также сеть предлагает свою особую модель общения (для адептов “альтернативности” она - лучше и правильней, чем способ общения в реальном мире, для людей более умеренных - просто иная). Уже упоминавшаяся операционная система Linux интересна не только тем, что создали ее из некоммерческих интересов, но и тем, что многие создатели никогда не видели друг друга в лицо. Они живут в разных странах мира, разделены расстояниями, финансовым положением, возрастом, но это не мешает им работать (творить!) вместе, общаясь электронной почтой. Электронная почта - e-mail - удивительным образом сочетает в себе оперативность телефонного звонка с некоторой “обезличенностью” (и, добавим, существенно более низкой, по сравнению с телефоном, ценой) письма, создавая совсем особый, не существовавший ранее, вид корреспонденции. А ведь e-mail - это еще не все. Всемирная “доска объявлений” Usenet позволяет задать интересующий вас вопрос или предложить тему для дискуссии буквально всему (виртуальному) миру, а системы телеконференций типа Internet Relay Chat позволяют болтать в реальном масштабе времени (кстати, часто на совершенно незначительные темы) с коллегами из других стран, не отрываясь от монитора. Это приводит к интересному психологическому эффекту. Чувствуешь, что мир (уже не виртуальный, а настоящий!) стал теснее и ближе. Можно пообщаться с другом из, скажем, Австралии, совсем не ощущая расстояния, а какой-нибудь мэтр интересующей вас науки уже не абстрактная фигура - ему можно запросто послать письмо с вопросом.

Вместе с этой, безусловно положительной, функцией сближения и сплачивания можно усмотреть и некоторую опасность в стремительно развивающейся компьютерной сети. Увлекшись виртуальной реальностью, очень легко забыть о реальной. Подобно наркоману, погружающемуся в “виртуальный” мир своих видений, адепт телекоммуникаций ныряет в глубины сети, где интересно и приятно, а раз так - зачем из них выныривать? Не случайно увлеченного программиста так же трудно оторвать от монитора, как наркомана от его сигареты с “травкой”. Не грозит ли нам появление нового вида наркомании? Пока антисоциальные последствия “компьютеромании” невелики, но в самом ближайшем будущем взломы банковских, а то и военных компьютерных систем, совершенные забывшимися “хакерами” могут представлять серьезную опасность для всего человечества. Есть о чем подумать психологам и социологам. Да и правоохранительным органам…

Итак, виртуальная реальность, с ее свободным творчеством, непринужденным общением и опасностью превращения в наркотик - вот к чему привела компьютерная революция сегодня. Каковы перспективы этой революции? Станет ли сеть единым и единственным средством общения? Или (как пугают фантасты) зародившийся в сети вирус в один “прекрасный” день погубит цивилизацию? По-видимому ни то, ни другое не произойдет. Пафос любой революции мало-помалу сводится на нет рутиной эволюции. Уже сегодня промышленные гиганты находят в сети новый, небывалый по возможностям рынок. Дальнейшая коммерциализация компьютерных технологий, хотя и сулит стремительный технический прогресс, может оказаться гибельным для того “вольного духа” братьев-программистов, о котором мы говорили. Когда сеть окончательно превратится в электронный рынок “товаров народного потребления” и арену рекламной борьбы (а такая тенденция имеется; не у нас, конечно), места для бесплатных проектов может и не остаться. Да и “компьютеромания” будет взята под контроль. Рискну предположить, что аномальный интерес к компьютерам поутихнет, и сеть превратится в одну из привычных областей человеческой деятельности, каковой она, по большому счету, и является.

Изобретение компьютера и компьютерных сетей дало человеку в руки мощнейший инструмент для творчества. Пока человек еще не “наигрался” новым инструментом и не раскрыл всех его возможностей, революция продолжается. Когда же возможности эти будут хорошо изучены (и если хватит благоразумия не использовать мощь нового инструмента во вред), ЭВМ потеряет статус “любимой игрушки”, но не исчезнет, а займет свое достойное место в инструментарии цивилизации. Сетевые “заклинания” исчезнут с газетных полос. До следующей революции.