Saturday, December 22, 2007

I'm working on a ASP.NET web app that will allow administration of a new product feature and some of that content can be several paragraphs long. I'm using TinyMCE for those longer pieces and the ASP.NET AJAX Timer control to auto-save the form.

What I noticed is that any field connected to TinyMCE wouldn't be saved on auto-save, but would be saved just fine with a full Save button click and PostBack -- even though the same method was being used.

The details are a little hazy, but there's a layer in TinyMCE that disconnects what you see in your browser as you're typing from the actual textarea. On PostBack, the two were reconnected, but only then. After some searching I found references to TinyMCE's triggerSave() method. So, my hack to deal with this was to add the following immediately after tinyMCE.init():

setInterval("tinyMCE.triggerSave()", 30000);

This will call triggerSave() every 30 seconds. If I find a better way to handle this with the Timer control I'll update this post.

Friday, December 21, 2007

I had a very good conversation yesterday with John Kreisa the Director of Product Marketing for Mark Logic where we talked about the differences between Textml and MarkLogic Server -- the issues I raised in a previous post, plus a few others. One of the other topics that I forgot to mention there and is a huge plus for MarkLogic is the ability to influence relevancy ranking.

The best part of this conversation was that John initiated it. Now, I know it's a minor detail, and maybe even a little silly, but it's nice to know that they're being so proactive. None of the features we talked about may ever be added to the product, but at least I know my voice was heard.

I'm most hopeful that they add a document-focused admin console to the product. So far, it's the one thing I really miss (well, at least since I was able to build my own query parser).

UPDATE: MarkLogic recently released a new, very powerful search library. If you're reading this, you have to check out lib-search.

Thursday, December 20, 2007

I bumped into something interesting today while working on a TreeView control to be used to represent a book's table of contents on a website. The control had 3 levels: the root, the chapter level, and each major section within each chapter, which we call the "a-head level."

If the user is viewing a piece of content from the a-head level, I was asked to NOT expand the chapter level TreeNode, to apply a different background color to the selected node (the a-head leaf TreeNode), and to apply the same background color to the parent chapter level TreeNode. "Should be fine," I said.

Right. In a Windows form, a TreeNode has a property called BackColor that can be set, but in a Web form, this property is not available. I'm sure there's a good reason for this, but it caught me a bit off-guard ... and much swearing ensued when I realized it.

His post goes into much more detail on what you can do, but my needs were fairly simple. I did take advantage of the lesson to actually set a CSS class rather than just change the background color. Here's the custom TreeNode class I created to set the CSS class for the parent node of the selected node (documentation comments removed for brevity):

Knead/mix together with a little warm water as needed. When done, let the dough rest for 20-30 minutes. I usually cover it with the same mixing bowl. If it's cold out, give this more time.

Preheat the oven to 425. Bring a large pot of water 3/4 of the way full to a gentle boil.

Cut off pieces of the dough and roll it out like a bread stick. Then connect the ends to form a circle. Be sure this connection is tight. Drop a group of the biscuits into the boiling water. Don't let them stick to the bottom. When they float to the top (this will take only a few seconds), remove them and place them in the oven. I normally place them directly on the racks. As you grab them out of the boiling water, aim for either the connection point or 1/3 of the way passed it because they fall apart easily.

Bake until light brown.

This recipe makes a fair number. I usually place half in a freezer bag in the freezer.

There are some interesting variations of this recipe I've seen over the years.

If there's a set of controls on the page that requires validation, but some other action that may happen that does not require validation (perhaps there's a search box that's part of a MasterPage, but that exists on a page with an email form that should have some validation), set the ValidationGroup property on the validation controls and the button that should fire them to the same value.

Thanks to a co-worker for pointing this out to me before I had to think too hard about it!

you'll get "March" for the value instead of what you probably want, which is "February." The good people on php.net have lots to say about this. (I think the other condition is that "skipping" Feburary happens only on the 30th or 31st of the current month.)

I'm working on a simple way in an ASP.NET 2.0 website to 1) catch all application errors that are otherwise uncaught, 2) log these errors in the Event Viewer, and 3) display a friendly error message to the user when these errors occur, while trying to keep this code all in as few places as possible. Here's what I'm doing now. I'll modify this post if I change.

If you want to run a Visual Studio.NET 2005 website as a root site when debugging or previewing, take a look at Scott Gutherie's post on this. Instead of having your site run as http://localhost:1234/myapp it will run as http://localhost:1234/. Makes life easier when doing relative paths.

By the way, if you're a .NET developer, you should be reading his blog regularly.

If you have page level tracing enabled on your site and you begin adding ASP.NET AJAX controls, you may see errors that say something along the lines of "Sys.WebForms.PageRequestManagerParseErrorException The message received from the server can not be parsed" when you preview or debug those pages. The ones I experienced appeared in a JavaScript alert popup.

If you have Trace="true" on the page in question, remove it. If you have your web.config file set for tracing, change it to: <trace enabled="true" localOnly="true" pageOutput="false" />

Browse or debug the page and then go to the root of your application's trace.axd file (http://yourapp/trace.axd) to get to the trace information.

Tuesday, August 28, 2007

I had a query I was using to generate a list of documents stored in a MarkLogic Server collection. The results were being passed to a web application for use as a title list. I was getting the results I wanted, but the query was taking about 20 seconds to complete and there were fewer than 200 book-length XML files to search. The key line in that query was:

for $i in cts:search(//book, cts:collection-query($myCollection))

I knew there had to be a better way to express this, but I couldn't find anything in the API that helped. Then someone suggested using the built-in XQuery function, collection(). I changed the query to...

for $i in collection($myCollection)/book

...and now the query runs in less than .05 seconds, including some trips down into the structure to grab metadata. That's what I was expecting.

Thanks to the people on the Mark Logic developer email list for helping with this.

We're using TortoiseSVN as a Subversion client for Windows and it's been great, but the icon overlays that appear in Windows Explorer have suddenly started to disappear. What's really strange is that they may appear at the top-most directory, but disappear when you drill down.

I haven't found the root cause yet, but here's how to get them back.

Open the Task Manager. Find TSVNCache.exe and click End Process.

Shutdown and then restart Windows Explorer. Go to Start > Shutdown. Hold down the Shift+Alt keys and then click the Cancel button. To bring up the Task Manager, hold down the Ctrl+Shift keys and then click Esc. Now, in the Task Manager, go to File > New Task and type in explorer.exe. Supposedly, this is the "proper" way to kill and restart the Windows Explorer process.

Monday, June 25, 2007

Scott Berkun has a funny post all of the different development methodologies out there. I'd say where I'm working now is somewhere between...

Development By Denial (DBD): Everybody pretends there is a method for what’s being done, and that things are going ok, when in reality, things are a mess and the process is on the floor. The worse things get, the more people depend on their denial of what’s really happening, or their isolation in their own small part of the project, to survive.

…and…

Shovel-Driven Development: Get it out the door as quickly as possible, cut-n-paste from anything that you find that works on Google, if it works it’s ready. Closely related to “Duct-tape Driven Design”

…with a healthy smattering of…

Decapitated Chicken Process: A time honored micromanagement technique where each day managers identify a drastic emergency and require developers drop what they are doing (and whatever process they are using) and immediately attend to the latest conflagration. Since this does the double duty of creating new bugs and making other tasks fall behind, fires become easier and easier for managers to spot and then freak out about. Practically a standard in the games industry.

<asp:CustomValidator ID="txtToCustom" runat="server" ControlToValidate="txtTo" Display="Dynamic" ErrorMessage="One of the &quot;To:&quot; email addresses you provided is not in the proper format or is not separated by a comma." OnServerValidate="txtToCustom_ServerValidate">*</asp:CustomValidator>

protected bool IsEmail(string address) { /* This regular expression is provided by the .NET Framework and is the same * as the one used to check the from address. If that changes for any reason * this should be updated to match. */ Regex emailRegEx = new Regex(@"\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*", RegexOptions.IgnoreCase); if (emailRegEx.IsMatch(address)) return true; return false; }

protected string[] Tokenize(string addresses) { /* This is pulled out as a separate function because I expect it to mature * and change over time, and it will probably to move into a class library * at some point. */ Regex separatorRegEx = new Regex(","); return separatorRegEx.Split(addresses); }

There is at least one very big assumption here: the domains provided by the user are correct. If you'd like to check these, there is a bit of code at http://www.codeproject.com/aspnet/Valid_Email_Addresses.asp that offers an approach.

Also, to do this, you need some sort of approach to string tokenization. Unlike Java, C# does not have any helper classes for this. There are basic approaches to this problem at http://en.csharp-online.net/CSharp_Regular_Expression_Recipes%E2%80%94A_Better_Tokenizer and http://www.dotnetwatch.com/page229.aspx.

-XSLTC (use XSLTC for transformation)-IN inputXMLURL-XSL XSLTransformationURL-OUT outputFileName-V (Version info)-EDUMP [optional filename] (Do stackdump on error.)-XML (Use XML formatter and add XML header.)-TEXT (Use simple Text formatter.)-HTML (Use HTML formatter.)-PARAM name expression (Set a stylesheet parameter)-MEDIA mediaType (use media attribute to find stylesheet associated with a document)-FLAVOR flavorName (Explicitly use s2s=SAX or d2d=DOM to do transform)-DIAG (Print overall milliseconds transform took)-URIRESOLVER full class name (URIResolver to be used to resolve URIs)-ENTITYRESOLVER full class name (EntityResolver to be used to resolve entities)-CONTENTHANDLER full class name (ContentHandler to be used to serialize output)

Options for Xalan-Java Interpretive

-QC (Quiet Pattern Conflicts Warnings)-TT (Trace the templates as they are being called)-TG (Trace each generation event)-TS (Trace each selection event)-TTC (Trace the template children as they are being processed)-TCLASS (TraceListener class for trace extensions)-L (use line numbers for source document)-INCREMENTAL (request incremental DTM construction by settinghttp://xml.apache.org/xalan/features/incremental to true)-NOOPTIMIMIZE (request no stylesheet optimization proccessing by settinghttp://xml.apache.org/xalan/features/optimize to false)-RL recursionlimit (assert numeric limit on stylesheet recursion depth)

This is a great list of Java Q & A from a JDJ article. I'm repeating it here because I can never find anything on their site after a month or so.

Q1. How could Java classes direct program messages to the system console, but error messages, say to a file?

A. The class System has a variable out that represents the standard output, and the variable err that represents the standard error device. By default, they both point at the system console. This how the standard output could be re-directed:

A. An abstract class may contain code in method bodies, which is not allowed in an interface. With abstract classes, you have to inherit your class from it and Java does not allow multiple inheritance. On the other hand, you can implement multiple interfaces in your class.

A. This keyword indicates that the value of this member variable does not have to be serialized with the object. When the class will be de-serialized, this variable will be initialized with a default value of its data type (i.e. zero for integers).

Q5. How can you force garbage collection?

A. You can't force GC, but could request it by calling System.gc(). JVM does not guarantee that GC will be started immediately.

Q6. How do you know if an explicit object casting is needed?

A. If you assign a superclass object to a variable of a subclass's data type, you need to do explicit casting. For example:

Object a; Customer b; b = (Customer) a;

When you assign a subclass to a variable having a supeclass type, the casting is performed automatically.

Q7. What's the difference between the methods sleep() and wait()

A. The code sleep(1000); puts thread aside for exactly one second. The code wait(1000), causes a wait of up to one second. A thread could stop waiting earlier if it receives the notify() or notifyAll() call. The method wait() is defined in the class Object and the method sleep() is defined in the class Thread.

Q8. Can you write a Java class that could be used both as an applet as well as an application?

A. Yes. Add a main() method to the applet.

Q9. What's the difference between constructors and other methods?

A. Constructors must have the same name as the class and can not return a value. They are only called once while regular methods could be called many times.

Q10. Can you call one constructor from another if a class has multiple constructors

A. Yes. Use this() syntax.

Q11. Explain the usage of Java packages.

A. This is a way to organize files when a project consists of multiple modules. It also helps resolve naming conflicts when different packages have classes with the same names. Packages access level also allows you to protect data from being used by the non-authorized classes.

Q12. If a class is located in a package, what do you need to change in the OS environment to be able to use it?

A. You need to add a directory or a jar file that contains the package directories to the CLASSPATH environment variable. Let's say a class Employee belongs to a package com.xyz.hr; and is located in the file c:\dev\com\xyz\hr\Employee.java. In this case, you'd need to add c:\dev to the variable CLASSPATH. If this class contains the method main(), you could test it from a command prompt window as follows:

c:\>java com.xyz.hr.Employee

Q13. What's the difference between J2SDK 1.5 and J2SDK 5.0?

A.There's no difference, Sun Microsystems just re-branded this version.

Q14. What would you use to compare two String variables - the operator == or the method equals()?

A. I'd use the method equals() to compare the values of the Strings and the == to check if two variables point at the same instance of a String object.

Q15. Does it matter in what order catch statements for FileNotFoundException and IOExceptipon are written?

A. Yes, it does. The FileNoFoundException is inherited from the IOException. Exception's subclasses have to be caught first.

Q16. Can an inner class declared inside of a method access local variables of this method?

A. It's possible if these variables are final.

Q17. What can go wrong if you replace && with & in the following code:

String a=null; if (a!=null && a.length()>10) {...}

A. A single ampersand here would lead to a NullPointerException.

Q18. What's the main difference between a Vector and an ArrayList

A. Java Vector class is internally synchronized and ArrayList is not.

Q19. When should the method invokeLater()be used?

A. This method is used to ensure that Swing components are updated through the event-dispatching thread.

Q20. How can a subclass call a method or a constructor defined in a superclass?

A. Use the following syntax: super.myMethod(); To call a constructor of the superclass, just write super(); in the first line of the subclass's constructor.

Q21. What's the difference between a queue and a stack?

A. Stacks works by last-in-first-out rule (LIFO), while queues use the FIFO rule

Q22. You can create an abstract class that contains only abstract methods. On the other hand, you can create an interface that declares the same methods. So can you use abstract classes instead of interfaces?

A. Sometimes. But your class may be a descendent of another class and in this case the interface is your only option.

Q23. What comes to mind when you hear about a young generation in Java?

A. Garbage collection.

Q24. What comes to mind when someone mentions a shallow copy in Java?

A. Object cloning.

Q25. If you're overriding the method equals() of an object, which other method you might also consider?

A. hashCode()

Q26. You are planning to do an indexed search in a list of objects. Which of the two Java collections should you use: ArrayList or LinkedList?

A. ArrayList

Q27. How would you make a copy of an entire Java object with its state?

A. Have this class implement Cloneable interface and call its method clone().

Q28. How can you minimize the need of garbage collection and make the memory use more effective?

A. Use object pooling and weak object references.

Q29. There are two classes: A and B. The class B need to inform a class A when some important event has happened. What Java technique would you use to implement it?

A. If these classes are threads I'd consider notify() or notifyAll(). For regular classes you can use the Observer interface.

Q30. What access level do you need to specify in the class declaration to ensure that only classes from the same directory can access it?

A. You do not need to specify any access level, and Java will use a default package access level.

Tuesday, June 5, 2007

If you have WordPress installed and running successfully on a Windows server, then you install the TortiseSVN client, and then you export a block of code from Subversion, you may notice that the WordPress admin UI can no longer save edited presentation files. I found that the TortiseSVN install removed the IIS guest user account I had allowed on the themes directory, changing the permissions on that directory back to what they were originally, so it had to be added back to allow access.

Monday, June 4, 2007

I had a hard time finding this information. Here's how you can get a count of the number of posts in your current loop and the index of the current post you're accessing. post_count starts at zero and current_post starts at 1. In this example, I'm outputting a horizontal rule after all posts except the last one in the loop.

Sunday, May 27, 2007

I have a situation where I need to use a web service in PHP 4. I found a piece of free PHP code call nusoap and in this site created /lib/nusoap for all of its code. Here are some helpful snippets to access the web service methods and data.

This is actually split across an application listener object and a JSP view page after a search result item is clicked on, which is why you'll see an Object being pulled from the session. You'll also see a reference to SearchUtilities, a search helper object.

// This section would be part of a loopIxiaDocument doc = rs.Item(i, "highlight"); // Hits marked with a span of the class "highlight"MemoryStream xmlStream = new MemoryStream();doc.Content.SaveTo(xmlStream);xmlStream.Position = 0;

Thursday, May 10, 2007

I've been working with Ixiasoft's Textml Server for several years now. Recently I've also started working with Mark Logic's MarkLogic Server and I'm starting to notice differences -- some in Textml's favor and some in Mark Logic's favor.

Some of my knocks on MarkLogic compared to Textml are:

MarkLogic lacks a query parser. A simple set of expressions should be defined and accepted by a parser -- AND, OR, NOT, a near operator, some sort of frequency and priority operators, would be fine. If you need something more complex then you have to build your own, but give me something. (Truth be told, the one in Textml is a little flaky.)

MarkLogic lacks a common way to not index or search stopwords. Add the ability to define a list of stop words on the forest or database level.

MarkLogic lacks a document-focused admin interface. Textml's version of this comes in quite handy.

MarkLogic lacks result set counts that are both fast and accurate. I should not need to worry about whether I should use xdmp:estimate(), cts:remainder(), or fn:count() to know how many items are in my cts:search(). Just tell me. A database can do it. Textml can do it. MarkLogic needs to as well.

Some of my knocks on Textml compared to MarkLogic are:

Textml lacks the ability to accept a large document and search/return only part of it as a result of a search. If I have a book to load, I have to figure out what my display unit in the application is going to be (an entire chapter, a smaller section of a chapter) and break up the file ahead of time. There are all sorts of reasons why that's a problem.

Sunday, May 6, 2007

Here's a query to get a document's properties from MarkLogic Server using an attribute value. The attribute name is "id" and it is on the node named "document." I used the cts:element-attribute-value-query() function because I can set the case sensitivity and other options. The entire <prop:properties> node is returned.

You can pass in a variable from an external app or you can define it in the query using let. You can also tack on some additional metadata, like the URI of the document and any collections it belongs to. Change the return block for this to something like:

Thursday, May 3, 2007

I had a relatively simple requirement for building a search application running against MarkLogic Server: search multiple levels of the XML hierarchy for all files in the repository and return each level as a document; the search must be case and diacritic insensitive. Here's beginnings of the query that did the trick:

I had to install PHP 4 under IIS on Windows Server 2003. The manual installation went fine, but PHP was looking for the php.ini file in C:\WINDOWS. I already added my install directory, C:\php, to the PATH environment variable and rebooted the machine, but this didn't seem to matter.

Buried on one of the many posts on php.net, I found a suggestion that worked. I had to add the following registry key (Start > Run > regedit)...

HKEY_LOCAL_MACHINE\SOFTWARE\PHP

...with the string value name IniFilePath and the value c:\php. After I did this, I did a hard stop of IIS and restarted it and the change took fine and saw the proper php.ini file.

I stopped all the SQL Server services and the Indexing Service, but the files were still locked. After a little Googling, I found Unlocker, a very handy tool. This told me that the Microsoft Search service had the lock. I used Unlocker to remove the locks, made my edits, and restared all the services (including Microsoft Search for good measure).

Monday, April 9, 2007

I've had two situtions recently where I needed to turn off DTD validation before processing an XML file in a .NET app. The ability to do so is in the class library, but there aren't a lot of examples. Here are two ways using two different objects:

Wednesday, March 21, 2007

This is a pretty simple example. There's a heck of a lot more that you can do.

SELECT Distinct(i.imageFile), i.caption, i.fileID, i.fragmentID, i.path, c.title FROM metadata_image AS m JOIN image AS i ON m.image_id=i.id LEFT JOIN fragments AS c ON i.fragmentID=c.cid WHERE Contains(i.*, '"some" or "word"') OR Contains(c.*, '"some" or "word"') OR Contains(m.*, '"some" or "word"') ORDER BY c.title, i.caption

Monday, March 12, 2007

After upgrading my Visual Studio.NET 2005 installation to SP1, none of my website applications would publish. Aggravating. I started getting the hideously vague error "Index was outside the bounds of the array." Here are some suggestions on how to handle this problem.

My solution was to go into my Projects/[project name]/ directory and rename the current directory, there from my last Publish run, and then to try and publish it again. This worked for all of my projects.

Visual Studio.NET 2005 needs to run in compatibility mode and as an administrator

UltraEdit 8.10 needs to run in compatibility mode and as an administrator

Windows Updates

After running a truck-load of updates and restarting, a driver compatibility warning comes up and even throws a blue screen of death for the Sonic Solutions DLA. Roxio says it's Dell's problem because it's a Dell machine with an OEM version. Dell says it's Roxio's problem. In any case, Roxio has a solution for it which seems to work.

XMLSpy 2006 Home Edition seems to run fine, although it did try to call home after registering and while I started it up the first time

To switch to a compatibility mode and/or run as an administrator, do the following.

After install, right-click on the app icon, switch to the Compatibility tab

Check the compat. mode checkbox and switch the drop-down to Windows 2000 (or whatever is appropriate for you)

Tuesday, February 20, 2007

I wasn't sure if I had an error in my code or if I uncovered a bug in Textml's QueryAnalyzer, so I wrote a little ASP.NET page where I could pass in a search string and see what QueryAnalyzer would do with it. This is how I found the bug with their .NET implementation of the choice operator.

Wednesday, February 14, 2007

Document searches in Textml are insensitive to case and ... in most cases ... special characters. For example, searches for "José Martí" and "jose marti" should return the same results set in the same order. But there is at least one exception to this, ñ. A search for "quinceañera" will return a different set of results when compared to "quinceanera." Ixiasoft has reported this is a feature based on requests from their Spanish-speaking partners and customers, which make sense because the two are different characters in the Spanish alphabet.

One solution is to add a hidden element to the document that contains the alternate spelling.

Another solution is to use the <oneof> element. To do this you would intercept each word at the application level and modify words with "ñ" or "n." That part of the query might look something like this:

If you have to support this particular feature, neither solution is very palatable.

UPDATE 1: If you try and pass the choice operator to the Textml QueryAnalyzer object in .NET, it will throw an exception. quincea[n,ñ]era as a search string will fail. I've submitted this bug to Ixiasoft and I'm waiting for a response.

UPDATE 2: Ixiasoft has responded that this is a bug and is due to be released in their newest package, 3.6.1.1542.

Sunday, February 11, 2007

In Visual Studio 2003, I needed a way to determine the encoding of an XML file. I found some information about reading the byte order mark (BOM) on a file, but I couldn't get it to work properly. The alternative approach below seems to be working. In this example, I needed the file to be UTF-8.

There are several ways to transform an XML document with XSL. This is one approach that includes passing parameters to the XSL and assumes the transformation is targeted for a <div> element. You'll need the following namespaces added, assuming this is an ASP.NET website: System.IO, System.Xml.Xsl, System.Xml.XPath. This should be wrapped in a try/catch block.

divXml.InnerHtml = xpathWriter.ToString(); /* divXml is a control on the ASPX page */

UPDATE: Why would you need this approach versus using the Xml control? I ran into a situation where some legacy XSL used the document() function and called a file on the network. I needed to 1) use impersonation and 2) set XmlSetting when I called Load().

Tuesday, February 6, 2007

Given an ASP.NET DropDownList control and a value, you can set the selected item in that list if the value exists. There are a couple of ways to do this, but this approach takes into consideration that the value may not be found in the list.

Sunday, February 4, 2007

This was a quick hack for a friend to get a random background image set for a table. You should be able to add this just about anywhere in the <body> tag. This would also work just for a table cell.

<script language="javascript"><!--onload = function() {/* If you change the directory, make sure you update it here. */var imageDirectory = "http://www.yourwebsite.com/images/";/* If you want to add more images on your own, put the the file name in the middleof the list here. Make sure there are quotes around it and a comma at the end. */var imageArray = new Array("image3.gif","image6.gif","image1.gif","image4.gif","image2.gif","image5.gif");var imageArrayLength = imageArray.length; // Leave these next few lines alonevar pseudoRandomNumber = ( Math.round( Math.random() * (imageArrayLength - 1) ) );document.getElementById("tableImage").style.backgroundImage="url('" +"imageDirectory + imageArray[pseudoRandomNumber] + "')";}//--></script><noscript><style type="text/css">#tableImage {background-image:url('http://www.yourwebsite.com/images/image3.gif');}</style></noscript>