tag:blogger.com,1999:blog-171996212024-03-14T00:58:45.712-07:00Andrei's Blog about Lotus Domino and other thingsAndrei Kouvchinnikovhttp://www.blogger.com/profile/02423321078595062935noreply@blogger.comBlogger114125tag:blogger.com,1999:blog-17199621.post-22352309852002024222009-03-31T12:30:00.000-07:002009-04-01T03:22:08.200-07:00April Fools' pranks and jokes from Sametime botFor the April Fools' Day I updated our Joke Bot with new funny jokes and pranks. <br />I like the one in which victims are tricked into calling the zoo to ask for Mr. Lyon :)<br /><br />Open <a href="http://www.botstation.com/sametime/april.html" target="_blank">April Fools' Sametime Bot</a><br />Type "april" to bot to see more joke suggestions.<br /><br /><br />Other Sametime bots:<br /><br />* <a href="http://www.botstation.com/sametime/stwidget_joke.php" target="_blank">The original jokes bot</a><br><br />* <a href="http://www.botstation.com/sametime/halloween.html" target="_blank">Halloween jokes</a><br><br />* <a href="http://www.botstation.com/sametime/bot_wisdom.html" target="_blank">Wisdom quotes from famous people</a><br><br />* <a href="http://www.botstation.com/sametime/bot_translate.html" target="_blank">Translation bot</a><br><br />* <a href="http://www.botstation.com/sametime/bot_currency.html" target="_blank">Currency exchange rates</a><br><br />* <a href="http://www.botstation.com/sametime/stwidget_lotusphere.html" target="_blank">Lotusphere RSS posts on Technorati</a><br><br />* <a href="http://www.botstation.com/sametime/bot_regex.html" target="_blank">Example of Bot processing regular expressions (regex)</a><br><br />* <a href="http://www.botstation.com/sametime/stwidget_morse.php" target="_blank">Morse code</a><br><br />* <a href="http://www.botstation.com/sametime/bot_bible.html" target="_blank">Random bible quote</a><br><br />* <a href="http://www.botstation.com/sametime/stwidget_zip.html" target="_blank">Get city names by zip codes (Sweden)</a><br /><br /><br /><br />Here is the HTML code needed to include Joke Bot on your own web page. Access to bot is implemented with help of <a href="http://www.stwidget.com" target="_blank">STWidget web client for Sametime</a> - the first web based Sametime client.<br /><br /><font color="green"><b><br /><iframe src="http://www.stwidget.com/ggljoke/stwidget.html" scrolling="no" frameborder="0" style="width:170; height:280;"></iframe></b></font><br /><br />Example of a bot emdedded using the code above:<br /><span style="WIDTH: 170px; HEIGHT: 280px"><br /><iframe src="http://www.stwidget.com/ggljoke/stwidget.html" scrolling="no" frameborder="0" style="width:170; height:280"></iframe><br /></span><br /><br />Tags: <a href="http://technorati.com/tag/sametime" rel="tag">sametime</a> <a href="http://technorati.com/tag/sametime+bot" rel="tag">sametime bot</a>Andrei Kouvchinnikovhttp://www.blogger.com/profile/02423321078595062935noreply@blogger.com12tag:blogger.com,1999:blog-17199621.post-19983863619689768412009-03-17T11:08:00.000-07:002009-03-17T11:30:08.232-07:00Testing blogging from iPhoneTesting how it works to create a blog post using iBlogger app on iPhone. Sitting right now in a community train on the way home.<br/> <br/>Today Apple releases news about iPhone version 3 update. I hope they will include MMS functionality, SMS forwarding and video recording. Possibility to run applications in background would also be nice, then I would consider porting <a href="http://www.stwidget.com">STWidget Sametime web chat</a> to a native iPhone app. The problem with current apps in iPhone is that they are automatically aborted as soon as phone goes into sleep mode. That saves of course battery life and frees up memory, but there should be a way to override this behaviour by asking user to allow to run in background. Windows PDA allow this, but I couldn't use them for more than 1.5 hours of continuous typing, iPhone lasts about 3 hours. I mean <u>lasted</u> 3 hours, but after version 2.2 update last month, battery life jumps up and down without obvious reason. <br/><div class="iblogger-footer"><br clear="all"/><p style="text-align:right;font-size:10px;">[Posted with <a href="http://illuminex.com/iBlogger/index.html">iBlogger</a> from my iPhone]</p><br/></div><br />Andrei Kouvchinnikovhttp://www.blogger.com/profile/02423321078595062935noreply@blogger.com5tag:blogger.com,1999:blog-17199621.post-53881872236070750612008-12-26T11:24:00.000-08:002008-12-27T01:26:13.208-08:00Lotusphere and USA travel authorizationI am finally ready with all my Lotusphere bookings. But as it is right now, I'll have to stay in 3 hotels. First 1 night in "Dolphin", then 4 nights in "Port Orleans Riverside" and then 1 night in "Swan". I am on the waiting list for "Port Orleans Riverside", hope that I'll get at least 1 hotel switch less.<br /><br />When booking the flight ticket, I noticed a warning that from 12 January travelers must electronically register at least 72 hours prior to travel. See below for more info.<br /><br />Link:<br />http://www.cbp.gov/linkhandler/cgov/travel/id_visa/esta/about_esta/esta_intro/esta_english.ctt/esta_english.pdf<br />Extract:<br />Effective January 12, 2009, all VWP travelers will be required to obtain an electronic travel authorization prior to boarding a carrier to travel by air or sea to the U.S. under the VWP.<br /><br />VWP=Visa Waiver Program<br /><br />Tag: <a href="http://technorati.com/blogs/tag/lotusphere" rel="tag">Lotusphere</a>Andrei Kouvchinnikovhttp://www.blogger.com/profile/02423321078595062935noreply@blogger.com4tag:blogger.com,1999:blog-17199621.post-59880583828470075752008-12-01T06:07:00.000-08:002008-12-01T07:18:35.370-08:00Strange behavior of DXL importWhile working with DXL123 freeware Domino app(beta released soon), I found a strange behavior of DXL importer in LotusScript: swedish letters (åäö) in imported stream are changed to garbled characters. But simple <strong>stream.ReadText</strong> before importing the stream fixes the problem.<br />I guess it has to do with wrong encoding, maybe with utf-16 being used instead of utf-8, but I don't see how I would change that or why it begins working after stream.ReadText <?xml version="1.0" encoding="utf-16"?><br /><br /><br /><br />Dim tmpstream As NotesStream<br />Dim importer As NotesDXLImporter<br />Dim fixencoding As String <br /><br />Set tmpstream = session.CreateStream<br />Call domParser.setOutput(tmpstream)<br />Call domParser.Serialize<br /><br /><strong>fixencoding=tmpstream.ReadText <em>'This makes the result OK</em></strong><br /><br />Set importer = session.CreateDXLImporter(tmpstream, sourcedoc.ParentDatabase)<br />importer.ReplaceDBProperties = False <br />importer.ReplicaRequiredForReplaceOrUpdate = False<br />importer.DocumentImportOption = DXLIMPORTOPTION_REPLACE_ELSE_IGNORE <br />Call importer.Process <em>'.Import gives same result</em><br /><br /><br /><strong>DXL123</strong> is a set of LotusScript API to easily perform different operations on inline images and on attachments without knowing anything about DXL.<br /><br /><strong>Function available in DXL123:</strong><br />Copy attachments between documents (without detaching to disk)<br />Convert inline image to attachment (without detaching to disk)<br />Change name of an attachment (without detaching to disk)<br />Remove inline images<br />Import disk file as an inline image<br />Place inline image in text after specified word/phrase<br />Place inline image inside a table<br />Replace inline picture to another picture<br />Replace attachment in richtext to URL link<br />Replace inline image to HTML image reference<br /><br />Example:<br />attachment_name=CopyInlineImageToDocAttachment(sourcedoc, targetdoc, "Body", 2, False, True)' make the second image in Body field to become an attachment and delete the original image<br /><br /><br />Tag: <a href="http://technorati.com/blogs/tag/dxl" rel="tag">dxl</a>Andrei Kouvchinnikovhttp://www.blogger.com/profile/02423321078595062935noreply@blogger.com9tag:blogger.com,1999:blog-17199621.post-72324589902219306472008-10-31T02:15:00.000-07:002008-11-01T02:36:34.835-07:00Halloween botOn this dark October evening, amuse yourself with Halloween Sametime Bot, which knows a lot of Halloween jokes about vampires, ghosts and other scary creatures:<br /><br /><a href="http://www.botstation.com/sametime/halloween.html" target="_blank">Halloween Sametime bot</a><br /><br />To see more scary jokes, type "scary" or "joke" to the bot.<br /><br /><a href="http://www.botstation.com/sametime/halloween.html" target="_blank"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhak6n8FIWGahQmOg58vg6DKbgQAAaapZXaS94q1b0va6g2YJAI-h_0ngscKod2qT1DG69Y-1HFTZuENmCylhYCLzbMk7dCEeRNPG9mG9hqjnDAJGPkXuA2rpLZoJudd03GnAK3XQ/s320/halloweenbot.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5263296903175252690" /></a><br /><br /><br />Tags: <a href="http://technorati.com/tag/sametime" rel="tag">sametime</a> <a href="http://technorati.com/tag/sametime+bot" rel="tag">sametime bot</a>Andrei Kouvchinnikovhttp://www.blogger.com/profile/02423321078595062935noreply@blogger.com0tag:blogger.com,1999:blog-17199621.post-48027916138904062332008-08-21T07:16:00.000-07:002008-08-21T07:18:18.498-07:00Sametime bot shows currency exchange ratesBased on <a href="http://dominounlimited.blogspot.com/2008/07/sametime-bot-for-text-translations.html" target="_blank">Translation Bot</a>, I created another multi-step function for our <a href="http://www.botstation.com/products/stbot/about.php" target="_blank" title="Sametime bot homepage">Sametime bot</a>. It shows current exchange rates between different currencies (from Yahoo Finance).<br />You can try it here:<br /><a href="http://www.botstation.com/sametime/bot_currency.html" target="_blank" title="Sametime Bot">Currency Exchange Sametime bot</a><br /><br />Instructions:<br />1) Type 1 and click "Say" button (or press Enter key).<br />2) Type 2 to set Euro as source currency and press Enter key.<br />3) Type 7 to set Swedish crown as target currency and press Enter key.<br />The result is the current exchange rate according to Yahoo finance.<br /><br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhe0K41B8PgB9EFVB6RbTY9UyTN4eHgALxwDlNtan0yyJbMx6pXFHKDbsGU5SdP_2ESkXcsKtThtVDbDfLehY2lVvZknDePMSvNr6_LvvB17-zxH1qHLbnk0NpRpFTlVo62ePy5UQ/s1600-h/ScreenShot001.jpg"><img style="cursor:pointer; cursor:hand;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhe0K41B8PgB9EFVB6RbTY9UyTN4eHgALxwDlNtan0yyJbMx6pXFHKDbsGU5SdP_2ESkXcsKtThtVDbDfLehY2lVvZknDePMSvNr6_LvvB17-zxH1qHLbnk0NpRpFTlVo62ePy5UQ/s200/ScreenShot001.jpg" border="0" id="BLOGGER_PHOTO_ID_5230721274723685154" /></a> <a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjvgApGq54VQrFW-UguZcvYcQIB6T3wmciASnGEtuAMEmH0VEOqWA-DL3QeGG3Vx1Sy-8ise8lntjJTBLCBMJkoaDv5HELCGxBaLZYr_pR76syS_F6APqBx9RLrv99USn8pJAJX5g/s1600-h/ScreenShot002.jpg"><img style="cursor:pointer; cursor:hand;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjvgApGq54VQrFW-UguZcvYcQIB6T3wmciASnGEtuAMEmH0VEOqWA-DL3QeGG3Vx1Sy-8ise8lntjJTBLCBMJkoaDv5HELCGxBaLZYr_pR76syS_F6APqBx9RLrv99USn8pJAJX5g/s200/ScreenShot002.jpg" border="0" id="BLOGGER_PHOTO_ID_5230721411436276594" /></a><br /><br /><br /><br /><br />Tags: <a href="http://technorati.com/tag/sametime" rel="tag">sametime</a> <a href="http://technorati.com/tag/sametime+bot" rel="tag">sametime bot</a>Andrei Kouvchinnikovhttp://www.blogger.com/profile/02423321078595062935noreply@blogger.com2tag:blogger.com,1999:blog-17199621.post-28510249611631728772008-08-17T02:50:00.000-07:002008-08-17T03:15:11.418-07:00Another Javascript featureJavascript uses pointers when assigning objects. This can lead to unexpected results for those who are used to work with LotusScript and Visual Basic, where data is copied to the new object and is no longer connected to the original object.<br /><br />In the example below note that date2 object was not deliberately changed after it was initially set, but still at the end of the script it gets a new value which is the same as the changed date1 object.<br /><br /><script><br />var date1=new Date();<br /><strong>var date2</strong>=date1;<br /><br /><font color="green">alert(date2);</font> //shows Sun <em>Aug 17 </em>11:46:50 UTC+0200 2008<br /><br /><font color="blue">date1.setMonth(5);<br />date1.setDate(9);</font><br /><br /><font color="red"><strong>alert(date2);</strong></font> //shows Mon <em>Jun 9</em> 11:46:50 UTC+0200 2008<br /></script><br /><br /><a href="javascript:var date1=new Date();var date2=date1;alert(date2);date1.setMonth(5);date1.setDate(9);alert(date2); ">run example</a><br /><br />It also works in the opposite direction: if you change date2, the date1 will also be changed.Andrei Kouvchinnikovhttp://www.blogger.com/profile/02423321078595062935noreply@blogger.com2tag:blogger.com,1999:blog-17199621.post-41230782096495969802008-08-04T11:23:00.000-07:002008-08-04T11:25:39.612-07:00Why javascript doesn't like August and September in date validationDo you like August and September months? Well, then bad news, because JavaScript doesn't like them. Using <strong>parseInt</strong> function without base parameter to convert from text to number when validating month number 08 gives 0. <br />This is true only for August(month "08") and September(month "09"), so it can take a while until the error is discovered. Why is that happening? Well, probably because genious developers of Javascript API thought that people use octal (base8) as default. Numbers until 08(August, put as "08" in dates) are converted correctly because they are same in octal as in base10, and numbers after 09 are recognized correctly because they(almost never) have a non-zero leading number. In between we have our poor "08" and "09".<br /><strong>Fortunately</strong>, there is a parameter you can add to parseInt function which specifies the base, e.g. parseInt("09", <strong>10</strong>). But was it really so smart to use base8 as default for numbers beginning with 0 instead of always using base10 and requiring user to explicitely enter parameter for <strong>other</strong> (less used) bases?<br /><br /><br /><br />Alternatives for parseInt are parseFloat and Number functions:<br /><br /><font color="red"><strong>Doesn't work correctly:</strong></font><br /><a href="javascript:alert(parseInt('09'))">javascript:alert(parseInt("09"))</a><br /><br /><font color="green"><strong>Works correctly:</strong></font><br /><a href="javascript:alert(parseInt('09', 10))">javascript:alert(parseInt("09", 10))</a><br /><a href="javascript:alert(Number('09'))">javascript:alert(Number("09"))</a><br /><a href="javascript:alert(parseFloat('09'))">javascript:alert(parseFloat("09"))</a><br /><br><br><br>Andrei Kouvchinnikovhttp://www.blogger.com/profile/02423321078595062935noreply@blogger.com3tag:blogger.com,1999:blog-17199621.post-86013276724837269382008-07-28T11:41:00.000-07:002008-07-28T07:59:53.483-07:00Sametime bot for text translationsAs I wrote in my previous blog post "<a href="http://dominounlimited.blogspot.com/2008/02/lotusscript-to-translate-text-between.html" target="_blank">LotusScript to translate text between languages</a>", I have created a function in <a href="http://www.botstation.com/products/stbot/about.html" target="_blank">Sametime bot</a> to translate text between languages using Google Translate. Now this bot functionality is available for everyone to test through STWidget-Sametime AJAX web client.<br /><br /><strong>Link to live demo</strong>: <a href="http://www.botstation.com/sametime/bot_translate.html" target="_blank" title="Sametime bot translation">Sametime translation bot</a><br /><br />Quick instructions: <br />1) type 1 (to choose "Translate between languages" option) and then press Enter or click "Say" button.<br />2) type 1 (to choose English language) and then press Enter.<br />3) then type 2 (to choose German language) and Enter.<br />4) then type text you want to get translated, e.g. "I love programming" and Enter.<br /><br />To fetch the translation result, Bot makes a web call to Google Translate service, using MSXML2 object in a slightly modified LotusScript code as in the old post. Here is an animated picture of the translation process:<br /><br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiie5qFwgxJGim0v4EFJUg9EhotKkgUGZENytoHJofgF2FUb_quVok0LQpgmRlXZE_oagE79hYYTzXiY2cznCvfvDlAgJsRrV7yWSfCMBQuRxXuNUDFfNaJBuEezB7YPNf856OkJw/s1600-h/sametime_bot_translate.gif" target="_blank" title="Sametime bot animation"><img style="cursor:pointer; cursor:hand;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiie5qFwgxJGim0v4EFJUg9EhotKkgUGZENytoHJofgF2FUb_quVok0LQpgmRlXZE_oagE79hYYTzXiY2cznCvfvDlAgJsRrV7yWSfCMBQuRxXuNUDFfNaJBuEezB7YPNf856OkJw/s200/sametime_bot_translate.gif" border="0" alt="Sametime translation bot animation" id="BLOGGER_PHOTO_ID_5227425573303537714" /></a><br><br /><font size="1">Click picture to see animation</font><br /><br /><br /><br /><br />Some other funny functions available through the same bot are "<a href="http://www.botstation.com/sametime/bot_joke.html" target="_blank">joke</a>", "<a href="http://www.botstation.com/sametime/bot_wisdom.html" target="_blank">wisdom</a>", "<a href="http://www.botstation.com/sametime/bot_morse.html" target="_blank">morse</a>" and "<a href="http://www.botstation.com/sametime/bot_bible.html" target="_blank">random bible quote</a>". The main difference between these small functions and Translation function is that Translation works in multi-step mode, prompting user with available choices, thus eliminating the need for user to remember the syntax of the commands. Another multi-step function is "<a href="http://www.botstation.com/products/stbot/stwidget_sametime_bot.php" target="_blank">Company info</a>" where user can get virtually any corporate info through Sametime bot. <br /><br />All of the example functions above are handled by the same bot instance, so users do not need to add a separate bot to their buddy list for each new function added by developer/admin to bot. <br /><br />In one of my next posts I will show a screencapture video how to develop a "whois username" function using @Formula language and how to create multi-step "Translation" function. <br /><br /><br />Tags: <a href="http://technorati.com/tag/sametime" rel="tag">sametime</a> <a href="http://technorati.com/tag/sametime+bot" rel="tag">sametime bot</a>Andrei Kouvchinnikovhttp://www.blogger.com/profile/02423321078595062935noreply@blogger.com1tag:blogger.com,1999:blog-17199621.post-88109870572971263522008-07-23T14:12:00.000-07:002008-07-23T23:36:02.837-07:00Automated login to Domino by HTTP POST requestIn a comment to Joachim Dagerot's blog post "<a href="http://www.dagerot.com/2008/02/13/login-in-with-just-url-arguments/" target="_blank">Login in with just url-arguments</a>" I mentioned that it's possible to login without exposing login credentials in the URL. It is done by making a POST request to Domino web server, instead of GET request. User still can see login credentials if he views page's HTML source, but they are at least not shown directly in the URL. Showing login details in URL makes it possible for bypassers to see your password, it's saved in the browser's URL history and it's also logged in the Domino log database, which is not so good as anyone with access to the log database can see them. Such URL might even get indexed by Google and show up in the search results.<br /><br />To additionally secure automated login, an extra redirect can be used, so the page itself does not contain the password. Or even better and without any password exposure is a page/form which calls an agent which makes login in background and then passes the session cookie back to the initial page. But that's a topic for another blog post. Here i will show the simplest solution.<br /><br /><font color="#660066"><br /><form action="/names.nsf?Login" method="POST" name="LogonForm"> <br /><input type="hidden" name="Username" value="myname"><br /><input type="hidden" name="Password" value="mypassword"><br /><input type="hidden" name="RedirectTo" value="/anotherdb.nsf/view?OpenView"><br /></form><br /><br /><script><br />document.forms[0].submit();<br /></script><br /></font><br /><br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEivrHp2lkdxbWmpoX7vTdTCRpZPiMcclMWOEAVR2Aa0momXEbW409v-ZfhFWEYv3LXasUpCcCD7R1r4QiRL8DH4VxSVl6T4-nvecTkPKrpU31EpY04uyqHDpE3bgsn2b5IgM11Kqw/s1600-h/loginpost.gif"><img style="cursor:pointer; cursor:hand;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEivrHp2lkdxbWmpoX7vTdTCRpZPiMcclMWOEAVR2Aa0momXEbW409v-ZfhFWEYv3LXasUpCcCD7R1r4QiRL8DH4VxSVl6T4-nvecTkPKrpU31EpY04uyqHDpE3bgsn2b5IgM11Kqw/s320/loginpost.gif" border="0" alt=""id="BLOGGER_PHOTO_ID_5226460625420500082" /></a><br /><br />When user opens this page, the first form gets automatically submitted to "<strong>/names.nsf?Login</strong>". User gets logged in to Domino with username and password specified in the form's fields and then redirected to another database according to the value in RedirectTo field.<br /><br />Tags: <a href="http://technorati.com/tag/Lotus+Domino" rel="tag">Lotus Domino</a>Andrei Kouvchinnikovhttp://www.blogger.com/profile/02423321078595062935noreply@blogger.com29tag:blogger.com,1999:blog-17199621.post-44012253376716009342008-06-01T09:39:00.000-07:002008-06-01T10:39:13.222-07:00LotusScript's List bug strikes againLast week i was working with a LotusScript agent which uses <strong>List data type</strong> for storing text values. The agent was not working properly as it could not find matching values in the second list(which was populated with the same listtags as the first list). I suspected it was something wrong with processing of List, but couldn't find what part of the code was wrong, as I got no error messages. The List was more than 1000 elements and in the debugger I could only see about 200 first elements, which was not very helpful. I have earlier experienced <strong>similar problem with IsNull(mylist("listtag"))</strong> function, but in this agent there were no such IsNull checks (use IsElement instead of IsNull). After 2 hours of commenting parts of the code out, I finally found what was wrong. The fact of calling <strong>tst</strong> procedure with nonexistant list value mylist("b") as parameter, creates "b" list element with value ""! It does not generate "List item does not exist" error message as one would expect!<br /><br />I have hard to think that it works "as designed", as a programmer clearly doesn't want to create a new list element by simply passing it to a procedure.<br />Using IsElement(mylist("b")) before calling the procedure/function helps to avoid the problem, but that shouldn't be necessary, as the programmer expects an error if the List element does not exist.<br /><br />Sub Initialize<br /> Dim mylist List As String<br /> mylist("a")="a"<br /> ' Msgbox mylist("b") 'properly results in error "List item does not exist"<br /> <br /> Call tst(mylist("b")) 'erroneously creates "b" list element<br /><br /> ' Msgbox Isnull(mylist("b")) 'erroneously creates "b" list element<br /><br /> Msgbox mylist("b") 'shows "" as list value for "b" instead of an error<br /><br />End Sub<br /><br />Sub tst(tmp)<br /> <br />End Sub<br /><br /><br /><br />Tags: <a href="http://technorati.com/tag/lotusscript" rel="tag">LotusScript</a>Andrei Kouvchinnikovhttp://www.blogger.com/profile/02423321078595062935noreply@blogger.com4tag:blogger.com,1999:blog-17199621.post-23260828166910838632008-03-02T03:30:00.000-08:002008-03-02T03:56:28.725-08:00Short tip: connect to remote Windows desktop console sessionJust a short tip which I discovered today. <br /> <br />When connecting to a remote Windows server using the standard "Remote Desktop" client program, you are connected to a user session and can not see what happens on the server's main console (the one which you get when you login physically on the server). You can not, for example, see the Domino server console.<br /><br />But there is a special parameter which can be used with Remote Desktop client to login into Windows console session instead of user session.<br />In Start/Run menu type:<br /><strong>mstsc /console</strong><br />use your regular username and password, and you will be logged in directly to Windows console. I guess that you must have some kind of admin privilegies to do that.Andrei Kouvchinnikovhttp://www.blogger.com/profile/02423321078595062935noreply@blogger.com19tag:blogger.com,1999:blog-17199621.post-13548088410934251012008-02-23T11:09:00.000-08:002008-02-23T12:24:40.950-08:00LotusScript to translate text between languagesI am currently working to update our <a href="http://www.botstation.com/products/stbot/about.php" target="_blank">Sametime Bot</a> with a new feature: translation of text. It will be a prompted flow where user is asked for input language, output language and text. The answer from the bot is the translated text. The translation is done by using a LotusScript agent which gets the translation from Google Translate page. LotusScript agent uses MSXML object for web communication with the Goggle server.<br />See below for an example of translation between English and German.<br />Pictures show the messagebox for German, Spanish, French and Russian translations. The translation is of course not perfect, but enough good to understand the general meaning. <br />The best automated translator I've seen so far is by the company "Prompt": http://www.e-promt.com/ It produces very correct translations and even sees the difference between "hello all Domino developers" and "hello to all Domino developers".<br /><br /><pre><br />Sub Initialize<br /> Dim xmlhttp, MySoap<br /> Dim StartTag As String,EndTag As String, FromLang As String, ToLang As String, TextToTranslate As String<br /> StartTag<font color="4444FF">=</font> <font color="4444FF">|</font><font color="4444FF"><</font>div id<font color="4444FF">=</font>result_box dir<font color="4444FF">=</font><font color="#008000">"ltr"</font><font color="4444FF">></font><font color="4444FF">|</font><br /> EndTag <font color="4444FF">=</font> <font color="#008000">"</div>"</font><br /> FromLang<font color="4444FF">=</font><font color="#008000">"en"</font><br /> ToLang<font color="4444FF">=</font><font color="#008000">"de"</font><br /> TextToTranslate<font color="4444FF">=</font><font color="#008000">"hello all Domino developers"</font><br /> TextToTranslate<font color="4444FF">=</font>Replace(TextToTranslate,<font color="#008000">" "</font>,<font color="#008000">"%20"</font>)<br /> <br /> WebServer<font color="4444FF">=</font><font color="#008000">"http://translate.google.com/translate_t?text="</font>+TextToTranslate+<font color="#008000">"&hl=en&langpair="</font>+FromLang+<font color="#008000">"|"</font>+ToLang+<font color="#008000">"&ie=utf-8"</font><br /> Set xmlhttp <font color="4444FF">=</font> CreateObject(<font color="#008000">"MSXML2.ServerXMLHTTP"</font>)<br /> Call xmlhttp.<font color="a52a2a"><strong>open</strong></font>(<font color="#008000">"GET"</font>, WebServer, False)<br /> Call xmlhttp.setRequestHeader(<font color="#008000">"Content-Type"</font>, <font color="#008000">"text/html; charset=utf-8"</font>)<br /> Call xmlhttp.setRequestHeader(<font color="#008000">"User-Agent"</font>,<font color="#008000">"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)"</font>)<br /> Call xmlhttp.setRequestHeader(<font color="#008000">"Accept"</font>,<font color="#008000">"image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*"</font>)<br /> Call xmlhttp.setRequestHeader(<font color="#008000">"Accept-Language"</font>,<font color="#008000">"sv"</font>)<br /> Call xmlhttp.setRequestHeader(<font color="#008000">"Content-Type"</font>,<font color="#008000">"application/x-www-form-urlencoded"</font>)<br /> Call xmlhttp.send(Null)<br /> <br /> strxml <font color="4444FF">=</font> xmlhttp.responseText<br /> <br /> Msgbox Strleft(Strright(strxml,StartTag),EndTag) <br /> <br />End Sub<br /></pre><br /><br /><br /><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjiohdTUjuiZWIDY-oWgD3X-pWZHk2re_lj8_EkPuTLzL0aGTz6H443KlSgYQz9sKq-R-RalP5tWL4iLaTrihwZN-aJl_JoVX_mmOiFHpCSWZcjEQaYM8r3UDsMNLRdaWNaOIHrWA/s1600/ScreenShot342.gif"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgyElEDK9ylQSFBC4AoUGULcXx9qYJbeoev0EnQuUMQhEFNUatunHS8Q8b0khb4o9ZWOT04WINDfUOCE0pA2YwyIeN1J6q3MLNcJqJ0ntCmzcgcrz5DGlbVAOajAm2YQ6GqyGmX9w/s1600/ScreenShot343.gif"><br /><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgCh9_eIm_kco41S20DbsJI5aUcfmVJKv3aQGCVRsFuQZCG4oOg5eZRJJSLVdKbH7DEq0lNZrjJWAreFHwa2aQ-qpy1ajJEEwgBXhMms86vZjEjssXZ9AHqsxQokXY1ybPUK_st4g/s1600/ScreenShot344.gif"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhVdkOeq03IDBXg35SWNZzQQ1_Xuc4a-R02PgiqhLvQRaSXe-P6iK_Q627PB2vl9b2XjELObM1iPKPL1hnYCDf0f57U3oPutP8cPSaRl1hkML1esy88X_ugvS0AA9te0vBzq8zj1A/s1600/ScreenShot345.gif"><br /><br /><br />Tags: <a href="http://technorati.com/tag/LotusScript" rel="tag">LotusScript</a>Andrei Kouvchinnikovhttp://www.blogger.com/profile/02423321078595062935noreply@blogger.com11tag:blogger.com,1999:blog-17199621.post-4285897813483946962008-02-03T09:02:00.000-08:002008-02-03T09:36:43.373-08:00Sametime bot to read Lotusphere RSS feeds is updatedHey folks! I am back from the long period of not blogging! And several more posts are in the pipeline, including DXL API for handling pictures/files, webcam API for spying on Notes users and Java agent to impersonate web users! :)<br /><br />Last week I've updated my Sametime bot which shows <a href="http://dominounlimited.blogspot.com/2007/01/sametime-bot-shows-latest.html" target="_blank">blog posts in <strong>Lotusphere2007</strong></a> category(on Technorati). Now it shows the last 20 posts for keyword <strong>Lotusphere2008</strong>.<br />You can try it here: <a href="http://www.botstation.com/sametime/stwidget_lotusphere.html" target="_blank">Sametime bot</a><br /><br />If you want to see <strong>another blog category </strong>available through STWidget and Sametime Bot, drop me a line and I'll create a new function and an appropriate STWidget link. Or do you have an idea for a cool Bot function not related to RSS? Drop me a line and I'll see what I can do :)<br /><br />For sample of LotusScript agent fetching the RSS data from Technorati, see the old post: <a href="http://dominounlimited.blogspot.com/2007/01/sametime-bot-shows-latest.html" target="_blank">Sametime bot shows latest Lotusphere2007 blogs</a> <br /><br />Tags: <a href="http://technorati.com/tag/Lotusphere2008" rel="tag">Lotusphere2008</a> <a href="http://technorati.com/tag/sametime" rel="tag">sametime</a> <a href="http://technorati.com/tag/sametime+bot" rel="tag">sametime bot</a>Andrei Kouvchinnikovhttp://www.blogger.com/profile/02423321078595062935noreply@blogger.com0tag:blogger.com,1999:blog-17199621.post-71425525783496151212007-10-11T09:21:00.000-07:002007-10-11T03:34:51.637-07:00Using regex for matching multiple words anywhere in the sentenceThis blog post is to save time for those developers who want to use Regular Expressions to determine whether ALL of the multiple words are located anywhere in the input string. It took me several hours to make it work right for 3 sets with 3 alternative words in each set. Google was not to much help, only a couple of pages contained useful examples. <br /><br />It began with me implementing regex (regular expressions) matching mechanism for our <a href="http://www.botstation.com/products/stbot/about.php" taget="_blank">Sametime Bot</a> to make a more flexible pattern-matching solution than current wildcard matching. So that instead of simply specifying *helpdesk* to match all incoming questions where word "helpdesk" is present, with regex it is possible to fine-tune the match and handle "what is phone number to helpdesk?" incoming question and "How can I contact helpdesk on weekends" question differently. Matching capabilities of regex are amazing, there are very little operations you can't do with it.<br /><br /><em><strong>Pattern "any one word is enough":</strong></em><br /><strong>helpdesk|assistance|support</strong><br><br />Matches for: Can I get some <strong>assistance</strong>? How can I contact <strong>support</strong>? Does <strong>helpdesk</strong> have an email address?<br />Not matches for: What's the time? Can you assist me?<br><br />-------------------------------------<br><br /><em><strong>Pattern "all words must be present":</strong></em><br /><strong>^(?=.*?(phone|fone|call|contact))(?=.*?(help|assistance|support)).*$</strong><br><br />Matches for: What is the <strong>phone</strong> number to <strong>helpdesk</strong>? Can I <strong>call</strong> to <strong>support</strong> department from my cell phone? How can I <strong>contact</strong> <strong>helpdesk</strong>?<br />Not matches for: I need help! I want to call my mom. My phone doesn't work. Charlie, Charlie, this is Bravo, send more air support!<br><br />-------------------------------------<br><br /><em><strong>Pattern "all words must be present, but NOT that one":</strong></em><br /><strong>^(?=.*?(phone|fone|call|contact))(?=.*?(help|assistance|support))((<font color="red">?!weekend|night</font>).)*$</strong><br><br />Matches for: I want to come in <b>contact</b> with <b>support</b> now. I need <b>phone</b> <b>assistance</b> to install ABC software today.<br />Not matches for: What number can i call on <b>weekends</b> to get help with this tool? What phone number can I call to contact helpdesk at <b>night</b>?<br /><br>-------------------------------------<br><br /><br />With a little help from <a href="http://lekkimworld.com/2005/09/25/1127661564236.html" target="_blank">blog post on lekkimworld</a>, I created this LotusScript testing module so the creator of the pattern can test the pattern functionality by providing a text string which is matched to the pre-defined regex expression. The result of the test is either Match or Not match.<br /><br />Sub Click(Source As Button)<br /> Dim workspace As New NotesUIWorkspace<br /> Dim uidoc As NotesUIDocument<br /> Dim doc As NotesDocument<br /> Set uidoc = workspace.CurrentDocument<br /> Set doc=uidoc.Document<br /> Dim regexp As Variant<br /> Dim result As Integer<br /> Set regexp = CreateObject("VBScript.RegExp")<br /> regexp.IgnoreCase = True<br /> uinput=Inputbox("Input text to test for pattern match:", "Regex tester", userinput)<br /> <br /> userinput=uinput<br /> regexp.Pattern = doc.RegmatchSubject(0)<br /> result= regexp.Test(userinput)<br /> If result = -1 Then<br /> Msgbox "Regex match found!"<br /> Else<br /> Msgbox "Regex match NOT found!"<br /> End If<br /> Set regexp=Nothing<br />End Sub<br /><br />Online demo of regex questions to Bot: <a href="http://www.botstation.com/sametime/bot_regex.html" target="_blank">http://www.botstation.com/sametime/bot_regex.html</a><br /><br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj3JBPSLzXDwQGKxAUA9tqjUdDtCSZqqqD98fLOM8td6ScYqUvMNpQgcmHB8Mz-DLDmPUEUDTmA3kYJ9yrgEW4k0R05IBnCLvPaKlIjdaIsLwOd4LXu0lKRh-2CiLr9fvjZblVdpg/s1600-h/regex.jpg"><img style="cursor:pointer; cursor:hand;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj3JBPSLzXDwQGKxAUA9tqjUdDtCSZqqqD98fLOM8td6ScYqUvMNpQgcmHB8Mz-DLDmPUEUDTmA3kYJ9yrgEW4k0R05IBnCLvPaKlIjdaIsLwOd4LXu0lKRh-2CiLr9fvjZblVdpg/s400/regex.jpg" border="0" alt="Sametime Bot regex" id="BLOGGER_PHOTO_ID_5113443942647485698" /></a><br /><br /><br />Tags: <a href="http://technorati.com/tag/sametime+bot" rel="tag">Sametime bot</a> <a href="http://technorati.com/tag/regex" rel="tag">regex</a>Andrei Kouvchinnikovhttp://www.blogger.com/profile/02423321078595062935noreply@blogger.com170tag:blogger.com,1999:blog-17199621.post-50806419646879063962007-09-12T13:11:00.000-07:002009-04-02T04:32:42.564-07:00Morse code in @Formula language and as a function in Sametime BotHere comes another post about using Lotus Notes' @Formula programming language for accomplishing different tasks. This time I'll show how to convert text to <a href="http://en.wikipedia.org/wiki/Morse_code" target="_blank">Morse code</a>. Morse code is a method for transmitting telegraphic information, using standardized sequences of short and long elements to represent the letters, numerals, punctuation and special characters of a message. <br /><br /><img src="http://upload.wikimedia.org/wikipedia/en/thumb/9/9c/J38TelegraphKey.jpg/250px-J38TelegraphKey.jpg"> <img src="http://upload.wikimedia.org/wikipedia/commons/thumb/9/92/Intcode.png/250px-Intcode.png"><br /><br /><br />The @Formula code is rather short. First we by specify 2 arrays: one with letters and another with corresponding morse code. Then we simply use @ReplaceSubstring function to replace the letters in the input text to corresponding elements in the morse array. As the number of elements in the 2 arrays are the same, @ReplaceSubstring function applies 1-to-1 element replacement.<br /><br /><strong>letters:=" ":"A":"B":"C":"D":"E":"F":"G":"H":"I":"J":"K":"L":"M":"N":"O":"P":"Q":"R":"S":"T":"U":"V":"W":"X":"Y":"Z":"1":"2":"3":"4":"5":"6":"7":"8":"9":"0";<br />morse:=" ":".-":"-...":"-.-.":"-..":".":"..-.":"--.":"....":"..":".---":"-.-":".-..":"--":"-.":"---":".--.":"--.-":".-.":"...":"-":"..-":"...-":".--":"-..-":"-.--":"--..":".----":"..---":"...--":"....-":".....":"-....":"--...":"---..":"----.":"-----";<br />plaintext:="Morse code";<br />encoded:=@ReplaceSubstring(@UpperCase(plaintext);letters;morse+" ");<br />encoded</strong><br /><br />To reverse the process and convert from morse code to plain text following code can be used:<br /><br /><strong>letters:="A":"B":"C":"D":"E":"F":"G":"H":"I":"J":"K":"L":"M":"N":"O":"P":"Q":"R":"S":"T":"U":"V":"W":"X":"Y":"Z":"1":"2":"3":"4":"5":"6":"7":"8":"9":"0";<br />morse:=".-":"-...":"-.-.":"-..":".":"..-.":"--.":"....":"..":".---":"-.-":".-..":"--":"-.":"---":".--.":"--.-":".-.":"...":"-":"..-":"...-":".--":"-..-":"-.--":"--..":".----":"..---":"...--":"....-":".....":"-....":"--...":"---..":"----.":"-----";<br />encoded:="-- --- .-. ... . -.-. --- -.. . ";<br />plain:=@ReplaceSubstring(@Implode(@Replace(@Explode(@ReplaceSubstring(encoded;" ";" _ ");" ");morse;letters);"");"_";" ");<br />plain</strong><br /><br /><br /><br />I also implemented same morse formula as a function in Botstation Bot Framework, where user passes a text string to <a href="http://www.botstation.com/products/stbot/about.php">Sametime bot</a> and receives the morse code as output. Here is a picture and a live example.<br />Bot command syntax: <br />morse HERE IS TEXT TO ENCODE<br />demorse .. .-.. --- ...- . ... .- -- . - .. -- .<br /><br />Morse Bot online example: <a href="http://www.botstation.com/sametime/stwidget_morse.php" target="morse">http://www.botstation.com/sametime/stwidget_morse.php</a><br /><br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZTRf_EJqC23sxkeLAXCMGUI2Yt5iqde-bU0tNyE-WhiSaNGiMT_GbpTt8ekvZT8lw8GgYR57uoSFKy9Il9aT3Uyjg20TpKNNAn57fUr2BV6r0vpakIyqcwMO-4N2pId2ZdjxMng/s1600-h/morse_sametime.gif"><img style="cursor:pointer; cursor:hand;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZTRf_EJqC23sxkeLAXCMGUI2Yt5iqde-bU0tNyE-WhiSaNGiMT_GbpTt8ekvZT8lw8GgYR57uoSFKy9Il9aT3Uyjg20TpKNNAn57fUr2BV6r0vpakIyqcwMO-4N2pId2ZdjxMng/s400/morse_sametime.gif" border="0" alt=""id="BLOGGER_PHOTO_ID_5109073008144974834" /></a><br /><br /><br /><br />Tags: <a href="http://technorati.com/tag/lotus+domino" rel="tag">Lotus Domino</a> <a href="http://technorati.com/tag/sametime" rel="tag">Sametime</a>Andrei Kouvchinnikovhttp://www.blogger.com/profile/02423321078595062935noreply@blogger.com4tag:blogger.com,1999:blog-17199621.post-49241359406772827892007-09-10T14:08:00.000-07:002009-04-30T04:28:00.155-07:00Remove HTML tags using one line of @FormulaWhen you need to remove HTML tags from HTML-formatted text, you can use following Domino @Formula: <br /><br /><strong>@ReplaceSubstring(@ReplaceSubstring(OriginalText;"<br>":"<li>":"<ul>":"</ul>";@NewLine:@NewLine:(@NewLine+@NewLine):(@NewLine+@NewLine));"<"+@Right(@Explode(OriginalText;">");"<")+">";"")</strong><br /><br />See attached picture for example of original HTML-formatted text and of resulting text where HTML tags are stripped out.<br /><br />The @Formula does following:<br />1) Splits the original text using "<" as separator, creating an array of strings<br />2) In each array element takes the text to the right of the ">" character, which gives us every HTML tag used in the original text, for example BR, B, U, LI, FONT<br />3) Adds "<" and ">" to the calculated tags, so the array now consists of <BR>, <B>, <U>, <LI>, <FONT> etc.<br />4) In the original text replaces the occurances of computed tags to empty string "", thus stripping HTML out of text.<br /><br />As we often want to keep line breaks to keep the original look, then before replacing the tags with empty string, we replace <BR>, <UL>, <LI> with a hard new line. Without handling line breaks the code is much shorter:<br /><br /><strong>@ReplaceSubstring(OriginalText;"<"+@Right(@Explode(OriginalText;">");"<")+">";"")</strong><br /><br /><br /><br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgLZXmoFq42zVG-JZYnbM8oWIHYZBb5z2a5zCipuG0dUnNuzIiwTEVskcKVib31GPqPQKcU24YozPqgG9SxT8xeD7vancRF4DLmpUxqcY_A0Y_J_AU50EExhn05rJWQG1IdBM-MwA/s1600-h/removetags.gif"><img style="cursor:pointer; cursor:hand;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgLZXmoFq42zVG-JZYnbM8oWIHYZBb5z2a5zCipuG0dUnNuzIiwTEVskcKVib31GPqPQKcU24YozPqgG9SxT8xeD7vancRF4DLmpUxqcY_A0Y_J_AU50EExhn05rJWQG1IdBM-MwA/s400/removetags.gif" border="0" alt=""id="BLOGGER_PHOTO_ID_5108687105333429218" /></a>Andrei Kouvchinnikovhttp://www.blogger.com/profile/02423321078595062935noreply@blogger.com7tag:blogger.com,1999:blog-17199621.post-2779125444401636952007-06-03T14:04:00.000-07:002007-06-03T14:13:30.487-07:00Prohibit users to trigger agents from webWhen developing agents, it's easy to forget that every agent can be triggered from web with agentname?OpenAgent URL. Such agent invocation can cause unpredictable results.<br />To avoid this, developer has these 2 options:<br />1) Hide agent from web using property "hide design element from: Web browsers"<br />2) Programmatically find out if the agent is triggered from web and exit<br /><br />Sub Initialize<br />ev=Evaluate("@ClientType")<br /><strong>If ev(0)="Web" Then Exit Sub </strong> 'Do not run agent if triggered from web<br />'here goes the rest of the code <br />'which will be executed in Notes client but not on web<br />End SubAndrei Kouvchinnikovhttp://www.blogger.com/profile/02423321078595062935noreply@blogger.com3tag:blogger.com,1999:blog-17199621.post-14348245965794613172007-05-20T09:11:00.000-07:002007-05-20T09:25:25.054-07:00Domino geek meeting in StockholmThere will be a meeting in Stockholm (Sweden) on May 24, for people working with Lotus Domino and related software. The meeting is hosted by company Ekakan. <br />Read more here: http://www.ekakan.com/g33k<br /><br />Technorati tags:<br /><a href="http://technorati.com/tag/g33k+date" rel="tag">g33k date</a>, <a href="http://technorati.com/tag/g33k+meet" work="" rel="tag">g33k meet</a>Andrei Kouvchinnikovhttp://www.blogger.com/profile/02423321078595062935noreply@blogger.com3tag:blogger.com,1999:blog-17199621.post-77081350972137795132007-05-18T10:37:00.000-07:002007-05-20T09:11:17.753-07:00You've got a message... from the Second LifeNicholas Chase has published an interesting <a href="http://www-128.ibm.com/developerworks/edu/ls-dw-ls-stsl.html" target="_blank">article</a> on IBM Developerworks. It's about making it possible to chat with people in <a href="http://secondlife.com/" target="_blank">Second Life</a> (SL), without opening SL program. That's a rather innovative solution and I think that many SL users would appreciate such possibility.<br /><br />It works like this:<br />1) SL person clicks an object (a picture, a cube) which says "Type message now and it will be send to John Doe"<br />2)SL person types the message, like "Hi John, can you hear me?", while being near the object.<br />3)The object can "see" the typed text and sends it to a web servlet using HTTP call. Web server has a connection to Sametime server through Sametime bot.<br />4) Sametime bot forwards the message to John Doe, who is logged in on Sametime network.<br />5) John Doe has his Sametime client started and receives a message from Sametime Bot, saying "Hi John, can you hear me?".<br />6) John Doe types "Yes, how can I help you?" as the response to bot in the Sametime client chat window.<br />7) Bot outputs the answer to the servlet and the servlet outputs it back to the requesting SL object. <br />8) The object shows message "Yes, how can I help you?" in SL. Anyone near the object can see the message. So you actually do not chat with the person, but with the object itself, which "broadcasts" your message to all people nearby. I think your response message can in theory also be a private message send only to that person, but the person's request message is always visible to others.<br /><br /><a href="http://www-128.ibm.com/developerworks/edu/ls-dw-ls-stsl.html" target="_blank">http://www-128.ibm.com/developerworks/edu/ls-dw-ls-stsl.html</a><br /><br />I will try to implement the suggested solution and see if it can be used for something more useful than spam-chatting with people near chatboxes :)<br />Like having a "chat conference meeting" where people do not need to be logged in to SL, and actually do not even need an SL account. Can be interesting solution for chat-only SL meetings hold by companies like IBM. It should be possible to sort away chats from people other than the meeting's chairman. Just imagine an online conference where instead of people's avatars you see a lot of chatting cubes :)<br /><br />I will also try to connect the solution to my company's <a href="http://www.botstation.com/products/stbot/about.php" target="_blank">Sametime Bot</a>and use STWidget as a chat client. Having <a href="http://www.botstation.com/products/stweb/about.php"´target="_blank">AJAX/Flash-based STWidget </a>web client as chat interface would eliminate the need to download and install Sametime client.<br /><br />There are thousands of virtual shops in SL selling virual clothes, virtual furniture and stuff, and some shop owners would probably like to have an option to chat with customers even when they are not logged in to SL. Not sure if there is already some software for this <a href="http://www.babasucks.com/2006/133/wii-secondlife/" target="_blank">#</a>.<br /><br />Following things are to consider when developing SL-to-Sametime chat solution for more than 1 user:<br />* Noone in SL knows what Sametime is and don't care much either. A Sametime-less option would be great (Apache+MySQL+PHP).<br />* Sametime bot must be hosted somewhere. <br />* Same Sametime bot should be able to handle tens of thousands of objects and hundreds of simultaneous chats. I guess our <a href="http://www.botstation.com/products/stbot/about.php" target="_blank">Sametime bot</a> can be extended for this purpose, but it's still a difficult task. Probably several bots at several locations would be needed.<br />* People do not have Sametime client and don't want one. Can be solved with <a href="http://www.botstation.com/products/stweb/about.php" target="_blank">STWidget</a> though.<br />* People do not have access to Sametime servers. Can be temporary solved by using IBM's demo server.<br />* The biggest question: will Sametime add too much overhead to the solution, without actually making it easier to develop and maintain? Theoretically a message can be sent directly to STWidget chat client without going through Sametime network.<br /><br /><br />I'll publish the results of my tests.<br /><br />Tags: <a href="http://technorati.com/tag/sametime" rel="tag">sametime</a> <a href="http://technorati.com/tag/sametime+bot" rel="tag">sametime bot</a>Andrei Kouvchinnikovhttp://www.blogger.com/profile/02423321078595062935noreply@blogger.comtag:blogger.com,1999:blog-17199621.post-23146589361442212992007-04-23T22:59:00.000-07:002007-04-23T14:01:59.572-07:00Run scheduled agent every 60 secondsThe shortest time between executions of a scheduled agent is 5 minutes. But very often you want to run some important function with only 1 minute interval. Your function takes maybe only 2 seconds to run, but you still are required to wait 5 minutes before it can be started again at the next agent invocation.<br /><br />The agent I created makes it possible to simulate running agent every 60 seconds, or even every 2 seconds if you wish so. Some restrictions apply :) <br /><br />It uses the fact that Notes counts 5 minutes from the START of the previous instance, not from the END. So if your agent takes 4 minutes 50 seconds to run, the next execution of the agent (assuming perfect conditions) will be just 10 seconds after the previous execution is finished. Delays caused by server load and other unforeseen delays can cause the agent to wait from 30 seconds to 2 minutes until the next execution. During many tests, I havent's observed execution delay longer than 2 minutes. <br /><br /><br />Even with the worst case 2 minutes delay, it's much better than standard 5 minutes delay. Note that this delay is only for the time between agent executions, within the started agent you can call the function every 2 seconds if you wish.<br /><br />What if the function takes more than 5 minutes to run? Well, the next instance of the agent will wait until the current instance is finished and then start after a certain delay. In my tests the delay was almost always 2 minutes. The delay if the agent ends 15 seconds BEFORE the 5-minutes period (4m 45s) was according to my tests <b>always</b> 1 minute 5 seconds. These numbers will most certainly be somewhat different on your server. <br /><br /><br />The main disadvantage of this method is that one of the Agent Manager's threads will be constantly busy, so you would need to increase the number of agent threads to make it possible for other scheduled agents to run too.<br /><br />To enable your agent to run every 60 seconds, do following:<br />1) In your existing agent, move the code from Initialize method to MainAction method.<br />2) Paste the code from the agent below into the Initialize method of your agent.<br />3) Change variable values as needed.<br /><br />Agent is configured to execute the MainAction() function every <span style="font-weight: bold;">60 seconds</span>s (runinterval), max <span style="font-weight: bold;">100 times</span> (runmaxtimes), during the 5 minute period (agentschedinterval).<br /><br /><div style="FONT-SIZE: 8pt;COLOR: black;FONT-FAMILY: Verdana">Agent execution flow. Click to enlarge.<br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh43mYbzB-_SjfDegcv4X4615ndhEgZPfBmZfKwU-pX7i0gtvkC5ZiWGBZTQ95kY39cSH0nAZTgsVGvyB3Hf1jDhM7LLhEMwvhWEYfmeLH1YszwsGTyWMbLeZjaPbOHO3K09EImJw/s1600-h/ScreenShot114.jpg"><img style="cursor:pointer; cursor:hand;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh43mYbzB-_SjfDegcv4X4615ndhEgZPfBmZfKwU-pX7i0gtvkC5ZiWGBZTQ95kY39cSH0nAZTgsVGvyB3Hf1jDhM7LLhEMwvhWEYfmeLH1YszwsGTyWMbLeZjaPbOHO3K09EImJw/s400/ScreenShot114.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5056730248182860770" /></a></div><br /><br />"Gone in 60 seconds" agent:<br /><br /><br /><pre><div style="font-family: sans-serif; font-size: 9pt; color: black;"><br /><font style="color: blue;">Sub</font> <font style="color: blue;">Initialize</font><br /> <font style="color: green;">'Created by Andrei Kouvchinnikov, www.botstation.com</font><br /> <br /> <font style="color: blue;">Print</font> <font style="color: black;">"******************* Agent started *******************"</font><br /> <br /> <font style="color: blue;">Dim</font> session <font style="color: blue;">As</font> <font style="color: blue;">New</font> <font style="color: black;">NotesSession</font><br /> <font style="color: blue;">Dim</font> db <font style="color: blue;">As</font> <font style="color: black;">NotesDatabase</font><br /> <font style="color: blue;">Dim</font> expectedruntime <font style="color: blue;">As</font> <font style="color: blue;">Integer</font> <font style="color: green;">'time which take to run the function. required only for deciding about ending the loop.</font><br /> <font style="color: blue;">Dim</font> runinterval <font style="color: blue;">As</font> <font style="color: blue;">Integer</font> <font style="color: green;">'interval (sec) between runs</font><br /> <font style="color: blue;">Dim</font> runmaxtimes <font style="color: blue;">As</font> <font style="color: blue;">Integer</font> <font style="color: green;">' max number of times the function will run</font><br /> <font style="color: blue;">Dim</font> runcounter <font style="color: blue;">As</font> <font style="color: blue;">Integer</font> <font style="color: green;">'counter of number of times the function run</font><br /> <font style="color: blue;">Dim</font> runstart <font style="color: blue;">As</font> <font style="color: blue;">Long</font><font style="color: blue;">,</font> runend <font style="color: blue;">As</font> <font style="color: blue;">Long</font><font style="color: blue;">,</font> rundiff <font style="color: blue;">As</font> <font style="color: blue;">Long</font><br /> <font style="color: blue;">Dim</font> notimeleft <font style="color: green;">' loop must be closed now, no time left to run another round</font><br /> <font style="color: blue;">Dim</font> agentstart <font style="color: blue;">As</font> <font style="color: blue;">Long</font> <font style="color: green;">'initial time when agent started. required only for deciding about ending the loop.</font><br /> <font style="color: blue;">Dim</font> agentschedule <font style="color: blue;">As</font> <font style="color: blue;">Integer</font> <font style="color: green;">'nr of minutes this agent is scheduled to run. required only for deciding about ending the loop.</font><br /> <font style="color: blue;">Dim</font> dynadjust <font style="color: green;">'instead of hardcoded runtime value, use last run period for calculation of next period</font><br /> <font style="color: blue;">Dim</font> uselongestperiod <font style="color: green;">'instead of the last run period, use the longest period the function took to run </font><br /> <br /> expectedruntime<font style="color: blue;">=</font>10 <font style="color: green;">' function is initially expected to take max 10 seconds</font><br /> runinterval<font style="color: blue;">=</font>60 <font style="color: green;">' function is called with interval of X seconds</font><br /> runmaxtimes<font style="color: blue;">=</font>100 <font style="color: green;">'if function's run time variates, you can limit max number of times function runs</font><br /> agentschedinterval<font style="color: blue;">=</font>5 <font style="color: green;">'agent is scheduled to run every X minutes. From the agent properties.</font><br /> margininterval<font style="color: blue;">=</font>5 <font style="color: green;">'nr of seconds to add to the final round. used for situations when function's execution time is 0.</font><br /> runcounter<font style="color: blue;">=</font>0<br /> dynadjust<font style="color: blue;">=</font><font style="color: purple;">True</font><br /> uselongestperiod<font style="color: blue;">=</font><font style="color: purple;">True</font><br /> <br /> agentstart<font style="color: blue;">=</font><font style="color: blue;">Timer</font><br /> <br /> <font style="color: blue;">While</font> runcounter<font style="color: blue;"><</font>runmaxtimes <font style="color: blue;">And</font> notimeleft<font style="color: blue;">=</font><font style="color: purple;">False</font><br /> runstart<font style="color: blue;">=</font><font style="color: blue;">Timer</font><br /> <br /> <font style="color: blue;">Call</font> MainAction<font style="color: blue;">(</font><font style="color: blue;">)</font><br /> <br /> runend<font style="color: blue;">=</font><font style="color: blue;">Timer</font><br /> <font style="color: blue;">If</font> dynadjust<font style="color: blue;">=</font><font style="color: purple;">True</font> <font style="color: blue;">Then</font> expectedruntime<font style="color: blue;">=</font><font style="color: blue;">Int</font><font style="color: blue;">(</font>runend<font style="color: blue;">-</font>runstart<font style="color: blue;">)</font> <font style="color: green;">'dynamically adjust expected time to actual time it take to run the function</font><br /> <font style="color: blue;">If</font> uselongestperiod <font style="color: blue;">Then</font><br /> <font style="color: blue;">If</font> expectedruntime<font style="color: blue;"><</font><font style="color: blue;">Int</font><font style="color: blue;">(</font>runend<font style="color: blue;">-</font>runstart<font style="color: blue;">)</font> <font style="color: blue;">Then</font> expectedruntime<font style="color: blue;">=</font><font style="color: blue;">Int</font><font style="color: blue;">(</font>runend<font style="color: blue;">-</font>runstart<font style="color: blue;">)</font><br /> <font style="color: blue;">End</font> <font style="color: blue;">If</font><br /> timeleft<font style="color: blue;">=</font>runinterval<font style="color: blue;">-</font>expectedruntime<br /> <br /> <font style="color: blue;">If</font> <font style="color: blue;">Int</font><font style="color: blue;">(</font><font style="color: blue;">(</font>agentschedinterval<font style="color: blue;">*</font>60<font style="color: blue;">)</font><font style="color: blue;">-</font><font style="color: blue;">Int</font><font style="color: blue;">(</font><font style="color: blue;">Timer</font><font style="color: blue;">-</font>agentstart<font style="color: blue;">)</font><font style="color: blue;">)</font><font style="color: blue;"><</font>timeleft<font style="color: blue;">+</font><font style="color: blue;">(</font>expectedruntime<font style="color: blue;">+</font><font style="color: blue;">Int</font><font style="color: blue;">(</font>expectedruntime<font style="color: blue;">/</font>100<font style="color: blue;">*</font>30<font style="color: blue;">)</font><font style="color: blue;">+</font>margininterval<font style="color: blue;">)</font> <font style="color: blue;">Then</font> <font style="color: green;">'assumes that function can take 30% longer time to run than the last time</font><br /> notimeleft<font style="color: blue;">=</font><font style="color: purple;">True</font><br /> <font style="color: blue;">Print</font> <font style="color: black;">"Exit. Function will not manage to finish one more run. Computed time: "</font><font style="color: blue;">+</font><font style="color: blue;">Cstr</font><font style="color: blue;">(</font><font style="color: blue;">Now</font><font style="color: blue;">)</font><font style="color: blue;">+</font><font style="color: black;">" + "</font><font style="color: blue;">+</font><font style="color: blue;">Cstr</font><font style="color: blue;">(</font><font style="color: blue;">(</font>expectedruntime<font style="color: blue;">+</font><font style="color: blue;">Int</font><font style="color: blue;">(</font>expectedruntime<font style="color: blue;">/</font>100<font style="color: blue;">*</font>30<font style="color: blue;">)</font><font style="color: blue;">)</font><font style="color: blue;">)</font><br /> <font style="color: blue;">End</font> <font style="color: blue;">If</font><br /> <br /> <font style="color: blue;">If</font> timeleft<font style="color: blue;">></font>0 <font style="color: blue;">And</font> notimeleft<font style="color: blue;">=</font><font style="color: purple;">False</font> <font style="color: blue;">Then</font> <br /> <font style="color: blue;">Sleep</font> timeleft <font style="color: green;">'finished before the expected time. sleep until next execution.</font><br /> <font style="color: blue;">Else</font><br /> <font style="color: blue;">Sleep</font> <font style="color: blue;">Int</font><font style="color: blue;">(</font><font style="color: blue;">(</font>agentschedinterval<font style="color: blue;">*</font>60<font style="color: blue;">)</font><font style="color: blue;">-</font><font style="color: blue;">Int</font><font style="color: blue;">(</font><font style="color: blue;">Timer</font><font style="color: blue;">-</font>agentstart<font style="color: blue;">)</font><font style="color: blue;">)</font><font style="color: blue;">-</font>margininterval <font style="color: green;">'sleep X seconds-margin</font><br /> <font style="color: blue;">End</font> <font style="color: blue;">If</font><br /> runcounter<font style="color: blue;">=</font>runcounter<font style="color: blue;">+</font>1<br /> <font style="color: blue;">Wend</font> <br /> <font style="color: blue;">Print</font> <font style="color: black;">"******************* Agent finished *******************"</font><br /><font style="color: blue;">End</font> <font style="color: blue;">Sub</font><br /><br /><br /><font style="color: blue;">Sub</font> MainAction<font style="color: blue;">(</font><font style="color: blue;">)</font><br /> <font style="color: blue;">Print</font> <font style="color: black;">"Triggered "</font><font style="color: blue;">+</font><font style="color: blue;">Cstr</font><font style="color: blue;">(</font><font style="color: blue;">Now</font><font style="color: blue;">)</font><br /> <br /><font style="color: green;">%REM<br />Here goes your code<br />Delete demo code below.<br />%END REM</font><br /> <br /> <font style="color: blue;">Randomize</font><br /> sleeprand<font style="color: blue;">=</font><font style="color: blue;">Int</font><font style="color: blue;">(</font><font style="color: blue;">Rnd</font><font style="color: blue;">(</font><font style="color: blue;">)</font><font style="color: blue;">*</font>10<font style="color: blue;">)</font> <br /> <font style="color: blue;">Sleep</font> sleeprand <font style="color: green;">'Simulates time taken by the function's operations by sleeping X seconds</font><br /> <br /><font style="color: blue;">End</font> <font style="color: blue;">Sub</font><br /></div></pre><br/> <br/> <br/><br /><br /><div style="FONT-SIZE: 8pt; COLOR: gray; FONT-FAMILY: sans-serif; BORDER: 1 solid Grey; margin : 0px 0px 0px 0px;">This LotusScript was converted to HTML using the <b><i>ls2html</i></b> routine,<br>provided by Julian Robichaux at <a href="http://www.nsftools.com" target="_blank">nsftools.com</a>.</div><br /><br /><div style="FONT-SIZE: 8pt;COLOR: black;FONT-FAMILY: Verdana">Output from the agent. Note the 1m 5s delay between instances.<br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhwkCzz6Z9f1zULUEv3T-tmcrHIxG_zd0nH9UCdgdFa-dJ_2AbJpBYRC90nb9NnoAUViplVd34JahPzSJCGiBTihGwU1m3mdRZ8CjiPouCknGAwFDK5bjMTkcWppvreCqx_ncAutg/s1600-h/ScreenShot117.jpg"><img style="cursor:pointer; cursor:hand;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhwkCzz6Z9f1zULUEv3T-tmcrHIxG_zd0nH9UCdgdFa-dJ_2AbJpBYRC90nb9NnoAUViplVd34JahPzSJCGiBTihGwU1m3mdRZ8CjiPouCknGAwFDK5bjMTkcWppvreCqx_ncAutg/s400/ScreenShot117.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5056727727037057986" /></a></div><br /><br /><br />Technorati: <a href="http://technorati.com/tag/Lotus+Notes" rel="tag">Lotus Notes</a>Andrei Kouvchinnikovhttp://www.blogger.com/profile/02423321078595062935noreply@blogger.com10tag:blogger.com,1999:blog-17199621.post-85585620377276969522007-04-05T10:19:00.000-07:002007-04-06T15:42:21.117-07:00Happy Easter!Happy Easter everyone!<br /><br /><br />Bible reading for the 21st century: let Sametime bot to choose a random quote from the Bible, and then find that chapter in the book and continue reading from there!<br /><br />Link to online bot: <a href="http://www.botstation.com/products/stweb/stwidget_bible.php" target="_blank">Random Bible Quote</a>Andrei Kouvchinnikovhttp://www.blogger.com/profile/02423321078595062935noreply@blogger.com1tag:blogger.com,1999:blog-17199621.post-1311386929382804502007-02-05T12:36:00.000-08:002007-02-05T15:10:41.340-08:00The fastest way to programmatically import data from Excel to Lotus NotesThere are several ways to import data from Excel to Lotus Notes/Domino. One of the most popular is the built-in Import menu option, which can be used manually and works fine in most cases.<br /><br />But if you want to import Excel data programmatically, the easiest way is to use Excel's OLE Automation Objects. There are several ways to read data from Excel using OLE, and the one most often mentioned is reading data cell-by-cell. This is a very slow method, and should only be used if you want to read/write special cell properties such color, fonts, etc.<br /><br />The <strong>fastest method</strong> I found so far is to read and write Excel data using blocks of data with <span style="FONT-WEIGHT: bold">ExcelSheet.Range</span> method. You can with a single operation read the whole Excel sheet into an array, which extremely efficient, especially if there are many columns.<br /><br />I have created an example which can be used to <span style="color:#ff6600;"><strong>import people from Excel to Notes</strong></span>. Sample Excel file can be downloaded <a href="http://www.botstation.com/code/people.xls" target="_blank">here</a>.<br /><br />Depending on the type of data and number of columns, the speed of this method can be up to 100 times faster than reading cell-by-cell. It imports <strong>100 person documents per second</strong>, and the most of this time is used on creating new Notes documents, not on getting data from Excel.<br /><pre><div style="font-family:sans-serif;font-size:9pt;color:black;"><br /><span style="color:blue;">Sub</span> <span style="color:blue;">Initialize</span><br /><span style="color:green;">'This agent imports person records from Excel to Notes. It uses Range method which makes it very fast. </span><br /><span style="color:green;">'Created by Botstation Technologies (www.botstation.com) </span><br /><br /><span style="color:blue;">Dim</span> session <span style="color:blue;">As</span> <span style="color:blue;">New</span> <span style="color:black;">NotesSession</span><br /><span style="color:blue;">Dim</span> db <span style="color:blue;">As</span> <span style="color:black;">NotesDatabase</span><br /><span style="color:blue;">Dim</span> doc <span style="color:blue;">As</span> <span style="color:black;">NotesDocument</span><br /><span style="color:blue;">Dim</span> xlApp <span style="color:blue;">As</span> <span style="color:blue;">Variant</span><span style="color:blue;">,</span> xlsheet <span style="color:blue;">As</span> <span style="color:blue;">Variant</span><span style="color:blue;">,</span> xlwb <span style="color:blue;">As</span> <span style="color:blue;">Variant</span><span style="color:blue;">,</span> xlrange <span style="color:blue;">As</span> <span style="color:blue;">Variant</span><br /><span style="color:blue;">Dim</span> filename <span style="color:blue;">As</span> <span style="color:blue;">String</span><span style="color:blue;">,</span> currentvalue <span style="color:blue;">As</span> <span style="color:blue;">String</span><br /><span style="color:blue;">Dim</span> batchRows <span style="color:blue;">As</span> <span style="color:blue;">Integer</span><span style="color:blue;">,</span> batchColumns <span style="color:blue;">As</span> <span style="color:blue;">Integer</span><span style="color:blue;">,</span> totalColumns <span style="color:blue;">As</span> <span style="color:blue;">Integer</span><br /><span style="color:blue;">Dim</span> x <span style="color:blue;">As</span> <span style="color:blue;">Integer</span><span style="color:blue;">,</span> y <span style="color:blue;">As</span> <span style="color:blue;">Integer</span><span style="color:blue;">,</span> startrow <span style="color:blue;">As</span> <span style="color:blue;">Integer</span><br /><span style="color:blue;">Dim</span> curRow <span style="color:blue;">As</span> <span style="color:blue;">Long</span><span style="color:blue;">,</span> timer1 <span style="color:blue;">As</span> <span style="color:blue;">Long</span><span style="color:blue;">,</span> timer2 <span style="color:blue;">As</span> <span style="color:blue;">Long</span><br /><span style="color:blue;">Dim</span> DataArray<span style="color:blue;">,</span> fieldNames<span style="color:blue;">,</span> hasData<br /><br />timer1<span style="color:blue;">=</span><span style="color:blue;">Timer</span><br />filename<span style="color:blue;">=</span><span style="color:black;">"C:\people.xls"</span><br />batchRows<span style="color:blue;">=</span>200 <span style="color:green;">'process 200 rows at a time </span><br /><br /><span style="color:blue;">Set</span> db<span style="color:blue;">=</span>session<span style="color:blue;">.</span>CurrentDatabase<br /><span style="color:blue;">Set</span> xlApp <span style="color:blue;">=</span> <span style="color:blue;">CreateObject</span><span style="color:blue;">(</span><span style="color:black;">"Excel.Application"</span><span style="color:blue;">)</span><br />xlApp<span style="color:blue;">.</span>Visible <span style="color:blue;">=</span> <span style="color:purple;">True</span> <span style="color:green;">'set Excel program to run in foreground to see what is happening </span><br /><span style="color:blue;">Set</span> xlwb<span style="color:blue;">=</span>xlApp<span style="color:blue;">.</span>Workbooks<span style="color:blue;">.</span><span style="color:blue;">Open</span><span style="color:blue;">(</span>filename<span style="color:blue;">)</span><br /><span style="color:blue;">Set</span> xlsheet <span style="color:blue;">=</span>xlwb<span style="color:blue;">.</span>Worksheets<span style="color:blue;">(</span>1<span style="color:blue;">)</span><br /><br /><span style="color:blue;">Redim</span> fieldNames<span style="color:blue;">(</span>1 <span style="color:blue;">To</span> 250<span style="color:blue;">)</span> <span style="color:blue;">As</span> <span style="color:blue;">String</span><br /><br />DataArray<span style="color:blue;">=</span>xlsheet<span style="color:blue;">.</span>Range<span style="color:blue;">(</span><span style="color:black;">"A1"</span><span style="color:blue;">)</span><span style="color:blue;">.</span>Resize<span style="color:blue;">(</span>batchRows<span style="color:blue;">,</span> 250<span style="color:blue;">)</span><span style="color:blue;">.</span>Value <span style="color:green;">'get worksheet area of specified size </span><br /><br /><span style="color:blue;">For</span> y<span style="color:blue;">=</span>1 <span style="color:blue;">To</span> 250 <span style="color:green;">'we assume max 250 columns in the sheet </span><br />currentvalue<span style="color:blue;">=</span><span style="color:blue;">Cstr</span><span style="color:blue;">(</span>DataArray<span style="color:blue;">(</span>1<span style="color:blue;">,</span>y<span style="color:blue;">)</span><span style="color:blue;">)</span><br /><span style="color:blue;">If</span> currentvalue<span style="color:blue;"><</span><span style="color:blue;">></span><span style="color:black;">""</span> <span style="color:blue;">Then</span> <span style="color:green;">'abort counting on empty column </span><br />fieldNames<span style="color:blue;">(</span>y<span style="color:blue;">)</span><span style="color:blue;">=</span>currentvalue <span style="color:green;">'collect field names from the first row </span><br />totalColumns<span style="color:blue;">=</span>y<br /><span style="color:blue;">Else</span><br />y<span style="color:blue;">=</span>250<br /><span style="color:blue;">End</span> <span style="color:blue;">If</span><br /><span style="color:blue;">Next</span><br /><br /><span style="color:blue;">Redim</span> <span style="color:blue;">Preserve</span> fieldNames<span style="color:blue;">(</span>1 <span style="color:blue;">To</span> totalColumns<span style="color:blue;">)</span> <span style="color:blue;">As</span> <span style="color:blue;">String</span><br /><br />curRow<span style="color:blue;">=</span>2<br />hasData<span style="color:blue;">=</span><span style="color:purple;">True</span><br /><span style="color:blue;">While</span> hasData<span style="color:blue;">=</span><span style="color:purple;">True</span> <span style="color:green;">'loop until we get to the end of Excel rows </span><br /><span style="color:blue;">If</span> curRow<span style="color:blue;">=</span>2 <span style="color:blue;">Then</span> startrow<span style="color:blue;">=</span>2 <span style="color:blue;">Else</span> startrow<span style="color:blue;">=</span>1<br /><span style="color:blue;">For</span> x<span style="color:blue;">=</span>startrow <span style="color:blue;">To</span> batchRows<br />curRow<span style="color:blue;">=</span>curRow<span style="color:blue;">+</span>1<br /><span style="color:blue;">If</span> <span style="color:blue;">Cstr</span><span style="color:blue;">(</span>DataArray<span style="color:blue;">(</span>x<span style="color:blue;">,</span>1<span style="color:blue;">)</span><span style="color:blue;">)</span><span style="color:blue;">+</span><span style="color:blue;">Cstr</span><span style="color:blue;">(</span>DataArray<span style="color:blue;">(</span>x<span style="color:blue;">,</span>2<span style="color:blue;">)</span><span style="color:blue;">)</span><span style="color:blue;"><</span><span style="color:blue;">></span><span style="color:black;">""</span> <span style="color:blue;">Then</span> <span style="color:green;">'when 2 first columns are empty, we assume that it's the end of data </span><br /><span style="color:blue;">Print</span> <span style="color:blue;">Cstr</span><span style="color:blue;">(</span>curRow<span style="color:blue;">-</span>2<span style="color:blue;">)</span><br /><span style="color:blue;">Set</span> doc<span style="color:blue;">=</span><span style="color:blue;">New</span> <span style="color:black;">NotesDocument</span><span style="color:blue;">(</span>db<span style="color:blue;">)</span><br />doc<span style="color:blue;">.</span>Form<span style="color:blue;">=</span><span style="color:black;">"Person"</span><br />doc<span style="color:blue;">.</span><span style="color:blue;">Type</span> <span style="color:blue;">=</span> <span style="color:black;">"Person"</span><br /><span style="color:blue;">For</span> y<span style="color:blue;">=</span>1 <span style="color:blue;">To</span> totalColumns<br />currentvalue<span style="color:blue;">=</span><span style="color:blue;">Cstr</span><span style="color:blue;">(</span>DataArray<span style="color:blue;">(</span>x<span style="color:blue;">,</span>y<span style="color:blue;">)</span><span style="color:blue;">)</span><br /><span style="color:blue;">Call</span> doc<span style="color:blue;">.</span>ReplaceItemValue<span style="color:blue;">(</span>fieldNames<span style="color:blue;">(</span>y<span style="color:blue;">)</span><span style="color:blue;">,</span> currentvalue<span style="color:blue;">)</span><br /><span style="color:blue;">Next</span><br />doc<span style="color:blue;">.</span>ShortName<span style="color:blue;">=</span>doc<span style="color:blue;">.</span>FirstName<span style="color:blue;">(</span>0<span style="color:blue;">)</span><span style="color:blue;">+</span><span style="color:black;">" "</span><span style="color:blue;">+</span>doc<span style="color:blue;">.</span>LastName<span style="color:blue;">(</span>0<span style="color:blue;">)</span><br /><span style="color:blue;">Call</span> doc<span style="color:blue;">.</span>save<span style="color:blue;">(</span><span style="color:purple;">True</span><span style="color:blue;">,</span> <span style="color:purple;">False</span><span style="color:blue;">)</span><br /><span style="color:blue;">Else</span><br />hasData<span style="color:blue;">=</span><span style="color:purple;">False</span><br />x<span style="color:blue;">=</span>batchRows<br /><span style="color:blue;">End</span> <span style="color:blue;">If</span><br /><span style="color:blue;">Next</span><br /><span style="color:blue;">If</span> hasData<span style="color:blue;">=</span><span style="color:purple;">True</span> <span style="color:blue;">Then</span> DataArray<span style="color:blue;">=</span>xlsheet<span style="color:blue;">.</span>Range<span style="color:blue;">(</span><span style="color:black;">"A"</span><span style="color:blue;">+</span><span style="color:blue;">Cstr</span><span style="color:blue;">(</span>curRow<span style="color:blue;">)</span><span style="color:blue;">)</span><span style="color:blue;">.</span>Resize<span style="color:blue;">(</span>batchRows<span style="color:blue;">,</span> totalColumns<span style="color:blue;">)</span><span style="color:blue;">.</span>Value <span style="color:green;">'get worksheet area </span><br /><span style="color:blue;">Wend</span><br />timer2<span style="color:blue;">=</span><span style="color:blue;">Timer</span><br /><span style="color:blue;">Call</span> xlApp<span style="color:blue;">.</span>Quit<span style="color:blue;">(</span><span style="color:blue;">)</span> <span style="color:green;">'close Excel program </span><br /><br /><span style="color:blue;">Msgbox</span> <span style="color:black;">"Done in "</span><span style="color:blue;">+</span><span style="color:blue;">Cstr</span><span style="color:blue;">(</span>timer2<span style="color:blue;">-</span>timer1<span style="color:blue;">)</span><span style="color:blue;">+</span><span style="color:black;">" seconds"</span><br /><span style="color:blue;">End</span> <span style="color:blue;">Sub</span><br /></div></pre><br /><br /><div style="BORDER-RIGHT: 1px solid; BORDER-TOP: 1px solid; FONT-SIZE: 8pt; MARGIN: 5px 50px; BORDER-LEFT: 1px solid; COLOR: gray; BORDER-BOTTOM: 1px solid; FONT-FAMILY: sans-serif"><center>This LotusScript was converted to HTML using the <b><i>ls2html</i></b> routine,<br />provided by Julian Robichaux at <a href="http://www.nsftools.com" target="_blank">nsftools.com</a>.</center></div><br /><br />The Excel sample file was generated using this online tool: <a href="http://www.benjaminkeen.com/software/data_generator/" target="_blank">data generator</a><br /><br />Tags: <a href="http://technorati.com/tag/Lotus+Domino" rel="tag">Lotus Domino</a> <a href="http://technorati.com/tag/Excel" rel="tag">Excel</a> <a href="http://technorati.com/tag/LotusScript" rel="tag">LotusScript</a>Andrei Kouvchinnikovhttp://www.blogger.com/profile/02423321078595062935noreply@blogger.com17tag:blogger.com,1999:blog-17199621.post-2583964023736183602007-01-30T22:24:00.000-08:002007-01-30T14:38:59.218-08:00Programmatically change user's Notes passwordTo programmatically change user's password, Domino developers can use API function W32_SECKFMChangePassword. The function accepts 3 parameters: path to ID file. <strong>old password</strong> and new password.<br />Based on the <a href="http://www.experts-exchange.com/Applications/Email/Lotus_Notes_Domino/Q_20881381.html" target="_blank">article on experts-exchange</a> web síte, I have created a LotusScript agent which prompts user for his old password, prompts for the new password, automatically reads the path to current ID file and changes the password for that ID file. <br />Same code can be used in a LotusScript button mailed to users with instructions to click the button in order to change their current password.<br /><br />At the end of the script developer might also want to add functionality to send an email to the administrator notifying about successfull or failed password change.<br /><br /><br />Const NOERROR = &H0<br />Const ERR_MASK = &H3FFF<br />Const NULLHANDLE = &H0<br /><br />'// Lotus Notes/Domino C API (Windows/Intel 32-bit)<br />Declare Function W32_SECKFMChangePassword Lib {nnotes.dll} Alias {SECKFMChangePassword} ( Byval pIDFile As String , Byval pOldPassword As String , Byval pNewPassword As String ) As Integer<br />Declare Function W32_OSLoadString Lib {nnotes.dll} Alias {OSLoadString} ( Byval hModule As Long , Byval StringCode As Integer , Byval retBuffer As String , Byval BufferLength As Integer ) As Integer<br /><br />Sub Initialize<br /> Dim session As New NotesSession<br /> Dim IDFile As String, oldpassword As String, newpassword As String<br /> IDFile=session.GetEnvironmentString( "KeyFilename", True )<br /> oldpassword=Inputbox("Enter old password", "Old Password") <br /> If oldpassword="" Then <br /> Msgbox "No password entered"<br /> Exit Sub<br /> End If<br /> newpassword=Inputbox("Enter new password", "New Password") <br /> If newpassword="" Then <br /> Msgbox "No password entered"<br /> Exit Sub<br /> End If<br /> <br /> Call ChangePassword(IDFile,oldpassword,newpassword)<br />End Sub<br /><br />Sub ChangePassword( id As String, oldp As String, newp As String)<br /> Dim intAPIResult As Integer<br /> Dim szErrorText As String<br /> Dim szBuffer As String * 1024<br /> <br /> intAPIResult = W32_SECKFMChangePassword ( id, oldp, newp )<br /> Stop<br /> If Not ( ( intAPIResult And ERR_MASK ) = NOERROR ) Then<br /> szBuffer = String$ ( Lenb ( szBuffer ) , 0 )<br /> Call W32_OSLoadString ( NULLHANDLE , intAPIResult , szBuffer , Lenb ( szBuffer ) - 1 )<br /> If Instr ( 1 , szBuffer , Chr$ ( 0 ) , 5 ) > 1 Then<br /> szErrorText = Left$ ( szBuffer , Instr ( 1 , szBuffer , Chr$ ( 0 ) , 5 ) - 1 )<br /> Elseif Instr ( 1 , szBuffer , Chr$ ( 0 ) , 5 ) = 0 Then<br /> szErrorText = {}<br /> Else<br /> szErrorText = szBuffer<br /> End If<br /> Messagebox szErrorText , 16 , {C API ERROR CODE: } & Cstr ( intAPIResult )<br /> Else<br /> Msgbox "Successfully changed"<br /> End If<br />End Sub<br /><br /><br /><br />Tags: <a href="http://technorati.com/tag/Lotus+Domino" rel="tag">Lotus Domino</a>Andrei Kouvchinnikovhttp://www.blogger.com/profile/02423321078595062935noreply@blogger.com6tag:blogger.com,1999:blog-17199621.post-61130136095486103692007-01-27T07:03:00.000-08:002007-01-27T09:22:29.803-08:00See Lotusphere Opening Session video recording on Second LifeYou can now see the recording of Lotusphere 2007 Opening Session (with guest speaker Neil Armstrong) available on 3-D chat <a href="http://secondlife.com/" target="_blank">Second Life</a> and on IBM's web site. It's 2 hours 13 minutes long, so it's probably a good idea to watch it at home instead of dong it at work. To see the recording in Second Life, go to IBM Theater on IBM Island and click on the big TV screen. In a couple of seconds you'll see the video on 4 TV screens. Below is a screenshot of me watching Mike Rhodin's opening speech. In the middle right corner of the screenshot you can see Virtual Lotusphere building where you can (if you are lucky) meet other Lotusphere interested people. I hope that more IBM employees and business partners discover the Second Life program and IBM island. <br /><br />Click to enlarge<br><br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEigFZjicwW5RQvOSUTI9DpIXDVHhbHJkK0jBYKOoudP6tgIR9SIlBFBz-y6DSQDytvNNetQCx3Gsvj3L49gMYfuxaTrXUjTtdeF5tfa0_ZWauYdGu_0b66uEd0OPXJTVxzL1ORXgg/s1600-h/ScreenShot085.jpg"><img style="cursor:pointer; cursor:hand;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEigFZjicwW5RQvOSUTI9DpIXDVHhbHJkK0jBYKOoudP6tgIR9SIlBFBz-y6DSQDytvNNetQCx3Gsvj3L49gMYfuxaTrXUjTtdeF5tfa0_ZWauYdGu_0b66uEd0OPXJTVxzL1ORXgg/s320/ScreenShot085.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5024730572832628178" /></a><br /><br /><br /><br />Opening session webcast on IBM's web site:<br /><a href="https://www14.software.ibm.com/webapp/iwm/web/preLogin.do?lang=en_US&source=sw-pprod05&S_PKG=SW-lotusphere2007webcast" target="_blank">https://www14.software.ibm.com/webapp/iwm/web/preLogin.do?lang=en_US&source=sw-pprod05&S_PKG=SW-lotusphere2007webcast</a><br /><br />Tags: <a href="http://technorati.com/tag/Lotusphere2007" rel="tag">Lotusphere2007</a>Andrei Kouvchinnikovhttp://www.blogger.com/profile/02423321078595062935noreply@blogger.com0