<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-5673962546196658582</id><updated>2011-11-18T06:34:43.280-08:00</updated><title type='text'>Lotus Notes internal stuffs</title><subtitle type='html'>Inside this blog you will find how Lotus Notes and Domino implement some features internally.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://doctorapi.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5673962546196658582/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://doctorapi.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Doctor API</name><uri>http://www.blogger.com/profile/01145456611165275970</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>11</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-5673962546196658582.post-3629223811307732414</id><published>2010-08-02T03:16:00.000-07:00</published><updated>2010-08-02T03:18:08.495-07:00</updated><title type='text'>Developing an antivirus for Domino vs. Exchange</title><content type='html'>If a development company needs to write an antivirus for Domino and for Exchange there will be significant differences that will be analyzed in this article.&lt;br /&gt;&lt;br /&gt;First the developers need to choose which technology should be used here. For Lotus Domino the only choice is Notes C API with Extension Managers. For Exchange 2000/2003 they should use store event sinks + CDO + ExOLEDB + ADO or WebDav. For Exchange 2007/2010 they should use transport agents.&lt;br /&gt;&lt;br /&gt;One important note here is that in the Domino case, although they should support multiple platforms (Microsoft, AIX, ...) the extension manager and Notes C API did not suffer important modifications since R4. So an antivirus written for R4 can be easily migrated to R8.5 (of course some modifications will be needed). However for Microsoft this is not the case, Exchange 2010 removed CDO, event sinks, ExOLEDB, ADO and WebDav leaving only Tansport agent so the antivirus should be rebuilt from scratch.&lt;br /&gt;&lt;br /&gt;Basically talking in Domino the antivirus is an extension manager (a library) that intercepts all messages updated in the mail.box and each msg is put in dead state so later this message will be scanned by a server task which will remove the dead state to let the router route it. It must be written using C/C++ that is a language that consumes less CPU and memory than scripting languages. The Notes C API is the native API (lower level) and it is the same API used to write Domino itself... so it has a very good performance. Here the antivirus is fully integrated to Domino and it is like a native component (like another addin task like the router, indexer, agent manager, ...)&lt;br /&gt;&lt;br /&gt;In Exchange there are two implementations:&lt;br /&gt;For Exchange 2000/2003 a wide store event sink must be written and it will intercept each email written in the store (notice that this is a kind of storage notifier and not a delivery notifier). The event sink is triggered for each action performed on each email of all the users. &lt;br /&gt;If you send an email to 10000 users then the antivirus will be triggered 10000 times... in practice you only scan the first email putting a flag and the remaining 9999 emails will not be scanned because the flag is already present... but analyzing 9999 emails for the flag existance takes time. CDO, Event sink, ADO, and WebDav are just wrappers... they are not the native API. You can still write C++ code but all the calls must pass through these wrappers so the performance is poor. You are called for each email and at the time you are called you must scan the email (no dead state approach can be used here). Comparing it with Domino, it is like if an extension manager analyzed each email modified in each user DB instead of intercepting emails directly in the mail.box (that is by far faster). &lt;br /&gt;&lt;br /&gt;For Exchange 2007/2010 transport agent should be used. A transport agent is a a piece of code that is called each time an email is routed / submitted by Exchange. It has better performance since is a delivery notifier rather than a store notifier. It must be written in managed language (.net framework). However in practice the real virus checking is done in C++ and the .net library communicates with the C++ library to see if a given attachment is a virus.&lt;br /&gt;&lt;br /&gt;So Micosoft did a good job in removing CDO, ExOLEDb, and all this stuff and introducing transport agent + EWS.&lt;br /&gt;&lt;br /&gt;Now, as a developer I see that IBM (in fact IRIS on its origin) did a very good job with the Notes C API since the core architecture is the same since R4... As a developer I feel more comfortable developing under Domino. The problem of Microsoft is that they never expose any native API but only wrappers and these wrappers gets improved version by version. They needed so many years to discover that the event sink were not working properly in Exchange and they introduced a new technology in a mature product. Even more, transport agent have significant improvements introduced in Exchange 2010.&lt;br /&gt;&lt;br /&gt;My feeling is that Microsoft is not really helping developers to do good components, while Domino does a better job by providing the native API (documenting some more stuffs would be great!).&lt;br /&gt;&lt;br /&gt;I don't really know the reason why Microsoft does not expose the native API exposing wrappers that are in theory easier to use but in practice have more limitations. Maybe because they suffer more cracker "attacks" and exposing the native API would be more dangerous, or maybe because they want to do all by themselves and not to let other vendors to do components.&lt;br /&gt;&lt;br /&gt;On the top of that they force you to use the .net framework that is a good framework but it is still a scripting language. I wonder whether they use .net in their own core components of Exchange... &lt;br /&gt;&lt;br /&gt;Administrators should not panic: Antirivus for Domino and Exchange are working just fine but when evaluating them they must see in Domino that no Lotus script code neither java code are used (due to internal limitations) because for some vendors it's easier to use Lotus script / java than C++. For Exchange any component that uses vbscript is not really serious (poor performance + very easy to attack).&lt;br /&gt;&lt;br /&gt;I think that Microsoft should evaluate providing a native access to the transport layer and to the database store too. If they still want to provide wrappers like EWS + transport agent then it's OK but for advanced components a native API access will really help.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5673962546196658582-3629223811307732414?l=doctorapi.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://doctorapi.blogspot.com/feeds/3629223811307732414/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://doctorapi.blogspot.com/2010/08/developing-antivirus-for-domino-vs.html#comment-form' title='11 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5673962546196658582/posts/default/3629223811307732414'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5673962546196658582/posts/default/3629223811307732414'/><link rel='alternate' type='text/html' href='http://doctorapi.blogspot.com/2010/08/developing-antivirus-for-domino-vs.html' title='Developing an antivirus for Domino vs. Exchange'/><author><name>Doctor API</name><uri>http://www.blogger.com/profile/01145456611165275970</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5673962546196658582.post-6455046906099135823</id><published>2010-02-02T02:30:00.000-08:00</published><updated>2010-02-02T03:03:34.013-08:00</updated><title type='text'>Lotus Traveler scalability</title><content type='html'>I had the opportunity to analyze Lotus Traveler internally.&lt;br /&gt;I saw how it basically works and it makes me think about scalability.&lt;br /&gt;What the traveler server task does is to periodically (some times per second) call an API that will return which databases were modified since the last polling time. So it obtains the list of databases where at least one document was modified by calling the undocumented function NSFGetChangedDBs. It then exports another function &lt;a href="mailto:_java_com_lotus_sync_dca_access_NativeAccess_jniGetChangedDbs@36"&gt;_java_com_lotus_sync_dca_access_NativeAccess_jniGetChangedDbs@36&lt;/a&gt; so this java native function is finally used by the server task (that seems to be coded in java).&lt;br /&gt;Once it calls NSFGetChangedDBs, it calls another API to retrieve the list of modified documents for each DB since the last polling time and it exports it in the java function &lt;a href="mailto:_java_com_lotus_sync_dca_access_NativeAccess_jniGetModifedDocList@48"&gt;_java_com_lotus_sync_dca_access_NativeAccess_jniGetModifedDocList@48&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The java server task pseudo-code would like something like&lt;br /&gt;while( StillMustRun() ) {&lt;br /&gt;&amp;nbsp;DBs = GetChangedDbs();&lt;br /&gt;&amp;nbsp;for each db in DBs do {&lt;br /&gt;&amp;nbsp;&amp;nbsp;DOCs = GetModifiedDocList(db);&lt;br /&gt;&amp;nbsp;&amp;nbsp;for each doc in DOCs do {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;ProcessDoc(doc)&lt;br /&gt;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;Sleep few milliseconds&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;In my opinion, it works just fine if you have few databases that are affected by Traveler, but if you have many users using traveler then all this mechanism will just consume memory and CPU to your server.&lt;br /&gt;&lt;br /&gt;I suggest using an approach where an Extension Manager calls a callback function when a new document is added to a database. So the extension manager itself can filter (in the callback function itself) the DB (the comparison is pretty fast since each DB has a GUID (number) and it would be just a matter of searching the current DB GUID in this sorted GUID list) and if the DB is a "traveler-aware-DB" then it would add the new created document in a global shared memory list, and the traveler server task would just poll this list periodically thus consuming by far less CPU. This approach has more scalability.&lt;br /&gt;Internally talking is also easy and the traveler server task can still use java... but the API dll would just use this shared memory table instead of calling the APIs periodically.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5673962546196658582-6455046906099135823?l=doctorapi.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://doctorapi.blogspot.com/feeds/6455046906099135823/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://doctorapi.blogspot.com/2010/02/lotus-traveler-scalability.html#comment-form' title='16 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5673962546196658582/posts/default/6455046906099135823'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5673962546196658582/posts/default/6455046906099135823'/><link rel='alternate' type='text/html' href='http://doctorapi.blogspot.com/2010/02/lotus-traveler-scalability.html' title='Lotus Traveler scalability'/><author><name>Doctor API</name><uri>http://www.blogger.com/profile/01145456611165275970</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>16</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5673962546196658582.post-8704388594511330860</id><published>2009-12-23T07:10:00.000-08:00</published><updated>2009-12-23T07:32:28.710-08:00</updated><title type='text'>Are Notes/Domino APIs good?</title><content type='html'>I've been programming with Notes since 1996 using the Notes C API. But I also had the possibility to use other APIs like the Exchange APIs, Windows API, and many others. I also programmed in other languages like Java, VB.&lt;br /&gt;People don't like programming in C++ because this language requires a large learning curve, but in fact once you learn C++, you can "come back" in ten years and this language will not change. I mean, it does not require (the language itself) you to keep updated with this language. VB or .net are different cases, each version of VB or .net requires programmers to buy new books and learn the differences (that's part the Microsoft market) to keep programmers up to date.&lt;br /&gt;&lt;br /&gt;The Notes C API itself did not suffer modifications since many years... some few new APIs were added year past year but nothing that you cannot learn in half a day.&lt;br /&gt;&lt;br /&gt;So being a C programmer using the C API is pretty comfortable once you have learnt it.&lt;br /&gt;&lt;br /&gt;The Notes C API is the lowest level API you can use... the Domino server tasks and the Lotus Notes workstation themselves are written upon this API. In the Exchange world there are several APIs... although most of them can be accessed in C++ they are not really low-level APIs but wrappers. You never have low level access to the internal services of Exchange. And the worst thing is that for example in Exchange 2010 some APIs that were supported in previous version don't work anymore!!!&lt;br /&gt;&lt;br /&gt;Developing under Exchange is by far more complex than under Domino. Let's suppose an antivirus programmer. This programmer develops the AV for Domino and for Exchange. This programmer will only have 1 version for Domino... but for Exchange they will need to have 1 ersion for Exchange 2003/2007 and another version for Exchange 2010!!!&lt;br /&gt;Events in exchange 2010 is a weird stuff. You need to use COM+ components and you will be called back for each email that is processed... you cannot control when this component is loaded, you don't have controls over threads, so you cannot implement a good load-balancing model.&lt;br /&gt;&lt;br /&gt;Even the Windows 32 API suffers more modifications than the Notes C API. Each new operating system provides new APIs (e.g. in Vista you need to learn about UAC, and the internet explorer protection mode and many other stuffs).&lt;br /&gt;&lt;br /&gt;Last thing I want to mention is that it's a pitty that the Notes C API lotusphere session is not longer available since 2008.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5673962546196658582-8704388594511330860?l=doctorapi.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://doctorapi.blogspot.com/feeds/8704388594511330860/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://doctorapi.blogspot.com/2009/12/are-notesdomino-apis-good.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5673962546196658582/posts/default/8704388594511330860'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5673962546196658582/posts/default/8704388594511330860'/><link rel='alternate' type='text/html' href='http://doctorapi.blogspot.com/2009/12/are-notesdomino-apis-good.html' title='Are Notes/Domino APIs good?'/><author><name>Doctor API</name><uri>http://www.blogger.com/profile/01145456611165275970</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5673962546196658582.post-48386965929576199</id><published>2009-12-02T03:05:00.000-08:00</published><updated>2009-12-02T03:23:42.005-08:00</updated><title type='text'>IBM should provide a better "Extension Manager" support for Domino server developers</title><content type='html'>There is a typical problem with Extension Managers and antivirus. As many of you may know, this is how a typical antivirus/antispam/disclaimer works in the Domino server:&lt;br /&gt;When an email arrives to the mail.box, the antivirus extension manager changes the RoutingState field to "DEAD" or "HOLD". Then the Extension Manager "tells" the main antivirus server task to process this DEAD email. The antivirus processes this email and then it removes the RoutingState field so the router can deliver it.&lt;br /&gt;&lt;br /&gt;The problem appears when you install two components doing the same approach. For example an antivirus and a disclaimer. Both will need to put the email in DEAD state and here if none of these products takes care of this situation (that is not easy to do so) then there will be emails that will not be scanned or will not have a disclaimer since there will be a synchronization problem.&lt;br /&gt;&lt;br /&gt;The solution would be to provide another notes.ini parameter like&lt;br /&gt;EmailExtMgr_Addins=antivir,disclaim&lt;br /&gt;So when an email arrives Domino will put the email in dead state, then it will first call "antivir" and after that it will call "disclaim" and after that Domino will remove the DEAD state so there will be no synchronization problem.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5673962546196658582-48386965929576199?l=doctorapi.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://doctorapi.blogspot.com/feeds/48386965929576199/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://doctorapi.blogspot.com/2009/12/ibm-should-provide-better-extension.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5673962546196658582/posts/default/48386965929576199'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5673962546196658582/posts/default/48386965929576199'/><link rel='alternate' type='text/html' href='http://doctorapi.blogspot.com/2009/12/ibm-should-provide-better-extension.html' title='IBM should provide a better &quot;Extension Manager&quot; support for Domino server developers'/><author><name>Doctor API</name><uri>http://www.blogger.com/profile/01145456611165275970</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5673962546196658582.post-5459407709073535414</id><published>2009-10-28T04:08:00.000-07:00</published><updated>2009-10-28T04:09:13.455-07:00</updated><title type='text'>How to recognize a good Notes component...</title><content type='html'>&lt;span style="font-size:85%;"&gt;&lt;span style="font-size:85%;"&gt; &lt;p&gt;I will discuss here how to recognize a good component. By component I mean an external software that is installed as a module and it extends Lotus Notes or Lotus Domino. For example an antivirus, or a disclaimer.&lt;/p&gt;&lt;p&gt;&lt;/span&gt;A good component will always meet the expectations without giving too much work to the administrator.&lt;/p&gt;&lt;p&gt;Here are some tips that are useful when you evaluate a Lotus Notes/Domino component:&lt;/p&gt;&lt;p&gt;* It must be built using the Lotus Notes C API: Many components uses Lotusscript or formula or java or the C++ API. Lotusscript has serious disadvantages for example agents in the server have a time limit and it consumes CPU. The java API or the C++ API are just wrappers of the Lotus Notes C API.... so it's just another layer that makes the development of the component easier. Developing a component in Lotusscript or Java or even the C++ API is by far easier than developing it in Lotus Notes C API. Again, for the vender it's easier (and cheapest) NOT to use the Notes C API since development is faster. The Lotus Notes client and the Lotus Domino server themselves are written using the Lotus Notes C API... the indexer, the replica task, the Notes client and all internal components uses this API. As you can see if the component uses this API then it will be at the same level than the Notes client or the Domino server. It's a native API. The C++ API for example will be discontinued (it is already discontinued) by IBM... they said it in Lotusphere 2009. The Notes C API is the lowest-level API so it provides with with full capabilities. If you as a customer wants your vendor to do an enhancement to a product, if your vendor uses the C API then it will for sure be able to implement this enhancement.&lt;/p&gt;&lt;p&gt;* The component should not modify any Lotus Notes DB template. It's easier for deployment purposes to modify the DB templates. However when it's time to do an upgrade or to modify the template then here problems start. Consider migrating from 8.0.2 to 8.5.1... templates will need to be also migrated so you will loose the vendor components, or you will need to do extra work to also migrate the vendor component. If you have two components from two different vendors that modifies the templates then you will be in serious problems. Uninstalling code from templates is a mess if you have modified the same template for other purposes...&lt;/p&gt;&lt;p&gt;* Ask to other customers to see if the component is well working. Usually in the site of the vendor you will find the customers... feel free to contact them to ask about post-sales services. If you go to notes.net you will find many questions from customers using antivirus from serious vendors where they don't answer their questions or they say "wait 6 months and in the next release it will be fixed".&lt;/p&gt;&lt;p&gt;* A recent version number with many nice features does not mean that it's more stable than a previous one. The more things they provide in new releases, the more complex the component. As you know, Domino 7.0.3 is more stable than R 8.0.1 for example.&lt;/p&gt;&lt;p&gt;* A crash during the testing phase is a REAL OPPORTUNITY!!! A crash does not mean that the component is really bad. All components crashes... even Domino itself crashes as you already know. So if you find a crash during testing phase then this is a opportunity since you will be able to ask the vendor for a solution and you will evaluate the support. Don't interpret a crash as a fatal bug, it's a bug that affected the memory and it caused a crash... the same bug could have affected other things than the memory. Again, take into account the time it takes to the vendor to solve the problem.&lt;/p&gt;&lt;p&gt;* Deployment. Deploying a server component is straightforward. But depoying a client component is harder. There are many ways to deploy a client component. Sending emails to the users to ask them to execute an attachment, sending an email to all users with a stored form that silently deploys the software, modifying the DB template, and so on... a good component's vendor is not the one that tell you "this deployment method is the best, bla bla bla". A good vendor will ask you "which deploying method from the following list do you prefer?". Again, a good vendor invest time and effort in software to make administrators happier.&lt;/p&gt;&lt;p&gt;* Compatibility with other components. Making one component compatible with another is not easy. There are things that cannot be always covered. For example if you have an antivirus and an antispam (usually they are joint but just for the example purpose) from different vendors then you will usually have a synchronization problem. The best component will provide you with a mechanism to configure itself in such a way that it can recognize the other component. For example an antispam can recognize that an antivirus is installed... so it will wait for the antivirus to do its job and then the antispam will do its own job. In this case the antispam is a "better component" than the antivirus since it implements all the synchronization mechanisms.&lt;/p&gt;&lt;p&gt;I hope it helps you to evaluate a component. Evaluating a third party solution is not an easy task...&lt;/p&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5673962546196658582-5459407709073535414?l=doctorapi.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://doctorapi.blogspot.com/feeds/5459407709073535414/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://doctorapi.blogspot.com/2009/10/how-to-recognize-good-notes-component.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5673962546196658582/posts/default/5459407709073535414'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5673962546196658582/posts/default/5459407709073535414'/><link rel='alternate' type='text/html' href='http://doctorapi.blogspot.com/2009/10/how-to-recognize-good-notes-component.html' title='How to recognize a good Notes component...'/><author><name>Doctor API</name><uri>http://www.blogger.com/profile/01145456611165275970</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5673962546196658582.post-3481861482120819099</id><published>2009-07-17T11:52:00.000-07:00</published><updated>2009-07-17T12:06:53.029-07:00</updated><title type='text'>Main Lotus Notes workstation dlls and their meanings</title><content type='html'>If you list the .dll files that are installed in the Lotus Notes workstation, you will see that for example in R8.5 there are more than 300 dlls.&lt;br /&gt;&lt;br /&gt;However the main (or most known) dlls are three:&lt;br /&gt;nnotes.dll&lt;br /&gt;nnotesws.dll&lt;br /&gt;nlsxbe.dll&lt;br /&gt;&lt;br /&gt;The more important is nnotes.dll that is the Lotus Notes engine. This dll is also present in the Lotus Domino server installation. This dll contains all backend functions that are used by Lotus Notes. This dll exports all NSF and other backend functions.&lt;br /&gt;In fact the Notes C API is in fact a documentation of some functions exported from this dll. This dll exports nearly 13.300 functions from all these functions only 1100 are documented in the Notes C API reference.&lt;br /&gt;The Lotus Notes workstation in fact is just a program that uses this dlls and provides services in a graphical way.&lt;br /&gt;The server tasks (update, amgr, ...) are just programs that uses functions from these dlls.&lt;br /&gt;&lt;br /&gt;Now the nnotesws.dll implements all visual aspects belonging to the Lotus Notes workstation. It renders the view, the forms, the workspace and so on... it is like the shell32.dll file in Windows. The nlnotes.exe program delegates most of the visual aspects to this dll. When you select files from a view and you drag them into another place all is managed by this nnotesws.dll. When you open an attachment, it is managed by this dll.&lt;br /&gt;To put a single example. Suppose that you copy part of the email you are viewing. In this case nnotesws.dll calls the OleSetclipboard API filling the information.&lt;br /&gt;&lt;br /&gt;nlsxbe.dll is all about programming in Lotus Script and formula.&lt;br /&gt;It is like a kind of wrapper that translates the Lotus script code (or formula code) into Notes C API calls.&lt;br /&gt;&lt;br /&gt;There are many other dlls, all of them are important... but these 3 dlls are known by many people but not all them know what they are related to.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5673962546196658582-3481861482120819099?l=doctorapi.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://doctorapi.blogspot.com/feeds/3481861482120819099/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://doctorapi.blogspot.com/2009/07/main-lotus-notes-workstation-dlls-and.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5673962546196658582/posts/default/3481861482120819099'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5673962546196658582/posts/default/3481861482120819099'/><link rel='alternate' type='text/html' href='http://doctorapi.blogspot.com/2009/07/main-lotus-notes-workstation-dlls-and.html' title='Main Lotus Notes workstation dlls and their meanings'/><author><name>Doctor API</name><uri>http://www.blogger.com/profile/01145456611165275970</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5673962546196658582.post-4283013593719239005</id><published>2009-06-01T04:54:00.000-07:00</published><updated>2009-06-01T05:10:15.732-07:00</updated><title type='text'>Copy-paste in Notes is sometimes "native"</title><content type='html'>When you copy something in an application, the application calls the OleSetClipboard or SetClipboardData APIs to really fill the clipboard content so other applications can use them when you do a paste operation.&lt;br /&gt;&lt;br /&gt;Usually you fill the clipboard using many formats and it's OK that the "more representative" format is a native format. For example in Notes when you select things from a RichText field and you copy them, the "Notes Editor Internal" or "Notes Private Data" formats are used.... thus when you paste it inside the same Notes application then Notes will really paste the real content without loosing information. But Notes also copies the "Rich Text Format" that is also known by Word or Notepad.&lt;br /&gt;&lt;br /&gt;This behaviour is typical and it's OK.&lt;br /&gt;&lt;br /&gt;Problem is when you copy a document from a view. Here the above APIs are not used... Notes fills an internal buffer and it does not use the clipboard. For example if you copy a text (e.g. from Notepad) into the clipboard, then you go to Notes and you select few docs and you copy them then if you go to Notepad again and you paste the content, the original content you copied from Notepad is still in the clipboard! And you can paste the documents in the view at the same time.&lt;br /&gt;The same if you first copy a document from a view, then you copy text from Notepad... you can paste text inside Notepad again and the document inside Notes again: It's like if Notes has a pararell clibpard.&lt;br /&gt;However if instead of Notepad as the source app, you use Notes and you copy text from a Notes rich text field then here the clipboard behaviour is like any other standard application and you loose the last clipboard content.&lt;br /&gt;&lt;br /&gt;I think Notes should use the clipboard and among than copying an internal reference (propietary format) that is OK, it should also copy an .ndl file, and the columns concatenated by "," as CF_TEXT.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5673962546196658582-4283013593719239005?l=doctorapi.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://doctorapi.blogspot.com/feeds/4283013593719239005/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://doctorapi.blogspot.com/2009/06/copy-paste-in-notes-is-sometimes-native.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5673962546196658582/posts/default/4283013593719239005'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5673962546196658582/posts/default/4283013593719239005'/><link rel='alternate' type='text/html' href='http://doctorapi.blogspot.com/2009/06/copy-paste-in-notes-is-sometimes-native.html' title='Copy-paste in Notes is sometimes &quot;native&quot;'/><author><name>Doctor API</name><uri>http://www.blogger.com/profile/01145456611165275970</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5673962546196658582.post-8891327364221893293</id><published>2009-05-29T20:04:00.000-07:00</published><updated>2009-05-29T20:34:12.221-07:00</updated><title type='text'>$KeepPrivate is worse in R8.5</title><content type='html'>It is known that the $keepPrivate is easy to crack. Remember that the $KeepPrivate flag is a field in a document and if this field is set then when a user sees this document, this user should not be allowed to "share" the content of the document. So the user will not be able to forward, print, copy doc/content, or export.&lt;br /&gt;&lt;br /&gt;The internal implementation of pretty basic. In fact the Notes client will give an error when the user tries to perform any of the forbidden operations.&lt;br /&gt;&lt;br /&gt;Now you can (as you may know) write a simple agent that removes this field and after that any user can do whatever he/she wants.&lt;br /&gt;&lt;br /&gt;Also you can make print-screen...&lt;br /&gt;&lt;br /&gt;You can also access the content using backend access (Lotus script, Notes API, COM classes, java, ...).&lt;br /&gt;&lt;br /&gt;But with R8.5 there is a &lt;strong&gt;clear bug&lt;/strong&gt; and you can do the following to extract information:&lt;br /&gt;* Open the document that is supposed to be protected (e.g. Doc A)&lt;br /&gt;* Select the content of this document&lt;br /&gt;* Create another document (e.g. Doc B)&lt;br /&gt;* Drag the selected information from Doc A to Doc B and the content will be copied!!!&lt;br /&gt;You can drag the content to Winword for example...&lt;br /&gt;&lt;br /&gt;So it seems the Notes client team missed this point.&lt;br /&gt;&lt;br /&gt;My opinion is that the $KeepPrivate should be reimplemented in a stronger way:&lt;br /&gt;+ Attachments should only be viewed and the content of the viewer should not be copied. It has no sense to only protect the content of the document and leaving users opening or saving attachments&lt;br /&gt;+ This described drag issue should be fixed&lt;br /&gt;+ Print screen should not be allowed. This is not an easy point but it can be implemented with some tricks.&lt;br /&gt;+ The $KeepPrivate internal implementation should be quite similar to the $UpdatedBy... so this field should be mantained in the Notes backend (nnotes.dll). When a document is updated, it should reset $KeepPrivate to 1 if when opening it it already had this value.&lt;br /&gt;+ Does it makes any sense to allow user to select part of the doc content if the user is viewing a document having the $KeepPrivate set to 1?&lt;br /&gt;+ To cover the case where extern process access the content, this content could be encrypted and be decrypted only by the following modules:&lt;br /&gt;  * Notes client (since it needs to show the content)&lt;br /&gt;  * Updater task (to full text index)&lt;br /&gt;  * http task (so DWA can keep showing it)&lt;br /&gt;&lt;br /&gt;My 2 cents on improving security in Notes.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5673962546196658582-8891327364221893293?l=doctorapi.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://doctorapi.blogspot.com/feeds/8891327364221893293/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://doctorapi.blogspot.com/2009/05/keepprivate-is-worse-in-r85.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5673962546196658582/posts/default/8891327364221893293'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5673962546196658582/posts/default/8891327364221893293'/><link rel='alternate' type='text/html' href='http://doctorapi.blogspot.com/2009/05/keepprivate-is-worse-in-r85.html' title='$KeepPrivate is worse in R8.5'/><author><name>Doctor API</name><uri>http://www.blogger.com/profile/01145456611165275970</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5673962546196658582.post-9072670314253729533</id><published>2009-05-21T20:31:00.000-07:00</published><updated>2009-05-27T08:27:44.833-07:00</updated><title type='text'>How the update task internally updates the Full text search index.</title><content type='html'>The update task (nupdate.exe in Windows) is a server task. The basic algorithm is quite easy. It first opens the DB: &lt;br /&gt;STATUS LNPUBLIC NSFDbOpen(&lt;br /&gt;             const char far *PathName,&lt;br /&gt;               DBHANDLE far *rethDB);&lt;br /&gt;&lt;br /&gt;Then it calls this API:&lt;br /&gt;STATUS LNPUBLIC FTGetLastIndexTime(&lt;br /&gt;               DBHANDLE  hDB,&lt;br /&gt;               TIMEDATE far *retTime);&lt;br /&gt;&lt;br /&gt;The first parameter is the database that was opened, and the second parameter (output parameter) returns the last time (TIMEDATE) the index was done before.&lt;br /&gt;&lt;br /&gt;Then it calls this API:&lt;br /&gt;STATUS LNPUBLIC NSFDbGetModifiedNoteTable(&lt;br /&gt;               DBHANDLE  hDB,&lt;br /&gt;               WORD  NoteClassMask,&lt;br /&gt;               TIMEDATE  Since,&lt;br /&gt;               TIMEDATE far *retUntil,&lt;br /&gt;               HANDLE far *rethTable);&lt;br /&gt;&lt;br /&gt;This API returns the documents that were modified after a given time.&lt;br /&gt;The first parameter is the DB, the second parameter is this constant: NOTE_CLASS_DATA and the third parameter (Since) is the TIMEDATE that&lt;br /&gt;FTGetLastIndexTime returned. The retUntil and rethTable parameters are output parameters.&lt;br /&gt;&lt;br /&gt;Once the server task calls NSFDbGetModifiedNoteTable it knows which are the new documents that were modified since the last time the index was done.&lt;br /&gt;&lt;br /&gt;After that it opens each document (obtained from the rethTable parameter) and it updates the local index based on the document data.&lt;br /&gt;&lt;br /&gt;Finally it updates the last index time (unfortunately this API is not documented) using the retUntil parameter that was filled by NSFDbGetModifiedNoteTable so next time nupdate is executed it restarts from this last time.&lt;br /&gt;&lt;br /&gt;I showed here a brief description of the nupdate task. As you can see most part of this task is documented.&lt;br /&gt;&lt;br /&gt;In this article I showed how to write your own indexing task (you can follow this procedure to detect which documents needs to be indexed and use a custom indexing algorithm). In a future article I will propose a custom search implementation that would use your custom index and it would reuse the full-text-search UI workstation capability so the indexing and the searching would be transparent to the end users.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5673962546196658582-9072670314253729533?l=doctorapi.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://doctorapi.blogspot.com/feeds/9072670314253729533/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://doctorapi.blogspot.com/2009/05/how-update-task-internally-updates-full.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5673962546196658582/posts/default/9072670314253729533'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5673962546196658582/posts/default/9072670314253729533'/><link rel='alternate' type='text/html' href='http://doctorapi.blogspot.com/2009/05/how-update-task-internally-updates-full.html' title='How the update task internally updates the Full text search index.'/><author><name>Doctor API</name><uri>http://www.blogger.com/profile/01145456611165275970</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5673962546196658582.post-6399820350129464997</id><published>2009-05-21T19:59:00.000-07:00</published><updated>2009-05-21T20:05:00.020-07:00</updated><title type='text'>NoteID, UNID, DBID, ORIGINATORID....</title><content type='html'>So it main sound obvious but these IDs have significant differences.&lt;br /&gt;NoteID and UNID are identifiers that apply to documents.&lt;br /&gt;The NoteID is a number that uniquely identifies a document. This number is frequently represented in hexadecimal. It is a DWORD and it is a 32-bit number (even in 64 bits systems) so it can hold up to 2^32 numbers. However when you create two consecutive documents, then this number is increased by 4. It means that if at time 0 you create a document then this document will hold (for example) the NoteId 100 and if you then create another document in the same DB then this new document will now have the number 104. If you delete this document having the number 104 and you inmediately create another document, this new document will be 108 and not 104, so the NoteIDs are never reused.&lt;br /&gt;NoteIDs and remaining IDs (UNIDs, DBID, ...) are always represented in hexadecimal.&lt;br /&gt;&lt;br /&gt;Now, the NoteID identifies a document in a DB but not across replicas. If you have two replicas then each document in each replica will have its own NoteID. So how can you know if a document is the same in two replicas? Using the UNID that is also known as UNIVERSALNOTEID.&lt;br /&gt;Internally talking, a UNID is composed with 2 components:&lt;br /&gt;The File component and the Note component.&lt;br /&gt;The File component is a DBID (see below) and the Note component is the date/time when the very first copy of the document was stored into the first NSF.&lt;br /&gt;The date/time in Notes is internally represented using two DWORDs. So the Note component is in fact 2 DWORD (32 bit each DWORD).&lt;br /&gt;The DBID is also a time... It means that the UNID internally occupies 4 DWORD that are 128 bits against the 32 bits of a NoteID.&lt;br /&gt;&lt;br /&gt;If you want to choose which ID to use to identify a document in your application, the UNID is better since it will work across replicas.&lt;br /&gt;&lt;br /&gt;Now it comes the ORIGINATORID... here things starts getting more complex.&lt;br /&gt;The Originator ID (OID) for a document identifies all replica copies of the same document and distinguishes between different revisions of that document. It is composed of two parts:&lt;br /&gt;- The UNID&lt;br /&gt;- The Sequence Number and Sequence Time.&lt;br /&gt;&lt;br /&gt;If one document in one database has the same UNID as another document in a replica of that database, then the two documents are replica copies of each other. The Sequence Number and the Sequence Time, taken together, distinguish different revisions of the same document from one another.&lt;br /&gt;&lt;br /&gt;The DBID uniquely identifies a DB. The DBID is different for each replica of the same DB.. Internally talking it is composed of 2 DWORD members that identifies the exact DB creation time (unit of time is 10 milliseconds so it's quite unlikely that two DBs are created in the exact same time).&lt;br /&gt;&lt;br /&gt;In this document I explained the main IDs... there are other IDs like for example the RRV which uniquely identifies attachments inside a DB, but I will explain them in future articles.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5673962546196658582-6399820350129464997?l=doctorapi.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://doctorapi.blogspot.com/feeds/6399820350129464997/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://doctorapi.blogspot.com/2009/05/noteid-unid-dbid-originatorid.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5673962546196658582/posts/default/6399820350129464997'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5673962546196658582/posts/default/6399820350129464997'/><link rel='alternate' type='text/html' href='http://doctorapi.blogspot.com/2009/05/noteid-unid-dbid-originatorid.html' title='NoteID, UNID, DBID, ORIGINATORID....'/><author><name>Doctor API</name><uri>http://www.blogger.com/profile/01145456611165275970</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5673962546196658582.post-2039124719347395240</id><published>2009-03-13T06:48:00.000-07:00</published><updated>2009-03-13T06:52:22.554-07:00</updated><title type='text'>How a Notes view is internally navigated</title><content type='html'>&lt;p&gt;A Lotus Notes view is a collection of documents. Internally talking (from the Notes API documenation) a view is also a "collection." &lt;/p&gt;&lt;p&gt;&lt;br /&gt;So what happens when the user opens a view in the Lotus Notes workstation? Does Lotus Domino server return the entire view to the Notes workstation? In fact when the user navigates a view, Domino only returns a "chunk" of documents to the Notes workstation. Else (if the entire view was read) it would take lot of time to read the view content.&lt;br /&gt;So when the user opens a view, Notes requests only some documents. For example let's suppose a plain view (without categories) and in one window Notes can show 20 documents. When the user is viewing a view Notes may request for example 100 documents: the 20 documents to fit the window plus 40 documents before the first shown document plus other 40 documents after the last document being seen in the window. By this way if the user navigates the view scrolling down then the information is already in the client side and Notes does not need to ask the server for these documents... when Notes is approaching the end (or the beginning) of a chunk, it queries another chunk.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;When you expand a category Notes needs to get another chunk, the same if you go to the end or beginning of a view, or if you go to a given position of the view by dragging the scrollbar control.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;As you can see this is a very efficient way to navigate a view. &lt;/p&gt;&lt;p&gt;&lt;br /&gt;Notes uses the Notes API functions to navigate a view. The main used function is NIFReadEntries. This function admits 12 parameters:&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;STATUS LNPUBLIC NIFReadEntries(&lt;br /&gt;     HCOLLECTION hCollection,&lt;br /&gt;     COLLECTIONPOSITION far *IndexPos,&lt;br /&gt;     WORD SkipNavigator,&lt;br /&gt;     DWORD SkipCount,&lt;br /&gt;     WORD ReturnNavigator,&lt;br /&gt;     DWORD ReturnCount,&lt;br /&gt;     DWORD ReturnMask,&lt;br /&gt;     HANDLE far *rethBuffer,&lt;br /&gt;     WORD far *retBufferLength,&lt;br /&gt;     DWORD far *retNumEntriesSkipped,&lt;br /&gt;     DWORD far *retNumEntriesReturned,&lt;br /&gt;     WORD far *retSignalFlags);&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;IndexPos is the exact position in the view from where the chunk needs to be read.&lt;br /&gt;ReturnCount indicates how many documents needs to be read (in the previous example it should be set to 100).&lt;br /&gt;The remaining parameters can be found in the documentation, but what I try to show you is how Notes uses this function to navigate the view.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;What does this function return? Does it return the NoteID or UNID and then Notes opens each document to retrieve the fields to be shown in the view? Not really. If Notes opened each document to retrieve, for example in an email database, the subject or the delivered date then it would loose performance. What it does is to retrieve only the information to be shown in the view (it is called Summary buffer, I will explain it later in another post). So Notes does not need to open any document to show the view content. For each row (or document) in the view, NIFReadEntries returns packed data with the subject, delivered date, size, ...&lt;/p&gt;&lt;p&gt;&lt;br /&gt;What about readers? When a document is not shown in the view (because it contains reader fields) the job is done by the server... and it is an intensive job! It moreless needs to sequentially skip each document that does not need to be shown. So suppose that you are browsing a view containing 1.000.000 of documents but you are only allowed to see the first and the last document from this view. The Notes client will simply call NIFReadEntries and the server is the one that will need to skip 999.998 documents. The CPU (and I/O) consumption will be done by the server and not by the workstation. As you can see, reading a view that is affected by reader fields causes serious performance issues.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;Is there an accurate way to know how many documents are in a view? It will sound strange but there is no accurate way to know how many documents a view contains! Only if your view is plain (that is, it does not contain response documents neither categories) then you can call this Notes API function: NIFGetCollectionData. The other alternative to get the total number of documents is to fully navigate the view.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;This is the reason why the scrollbar control does not have a good behaviour for views having categories (specially when they are expanded).&lt;/p&gt;&lt;p&gt;&lt;br /&gt;I will propose a new feature that could be useful and very easy to implement by the Lotus Notes client developers at IBM. Suppose you have a view that shows all the bids and this view is sorted by the bid date. Now suppose that you want to view only bids from a given date (e.g. 01/01/2008) to another given date (e.g. 12/01/2008). In this case the view object should expose a new method like "FilterView". And you can simply pass these two dates in this method. Then internally talking is pretty straighforward to implement it: It's just a matter of locating the first date by calling the NIFFindByKey API and then locating the last date by calling the same NIFFindByKey API. And here you will have the "initial" and "last" COLLECTIONPOSITIONs that will indicate the bounds of the view. The only requirement is that the view should be sorted by bid date.&lt;br /&gt;This is similar to the show-single category feature but more flexible.&lt;br /&gt;Suppose you have a view showing names... and the first sorted column is the surname. And you want to see all documents where the surname starts with S or T or U. In this case you can apply the same exact logic.&lt;br /&gt;So with this proposal the LotusScript and Formula developers will easily filter the view dinamically without causing extra costs (like creating views with different formulas).&lt;/p&gt;&lt;p&gt;&lt;br /&gt;Well, in this article I shown how views internally works and I proposed an enhancement.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5673962546196658582-2039124719347395240?l=doctorapi.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://doctorapi.blogspot.com/feeds/2039124719347395240/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://doctorapi.blogspot.com/2009/03/how-notes-view-is-internally-navigated.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5673962546196658582/posts/default/2039124719347395240'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5673962546196658582/posts/default/2039124719347395240'/><link rel='alternate' type='text/html' href='http://doctorapi.blogspot.com/2009/03/how-notes-view-is-internally-navigated.html' title='How a Notes view is internally navigated'/><author><name>Doctor API</name><uri>http://www.blogger.com/profile/01145456611165275970</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry></feed>
