Thursday, December 31, 2009

Computer Upgrade

I upgraded my computer this holiday season and ran into some problems. Thought I'd document some of them here. I built my rig from parts; I spent a lot of time this month reading up on new technology. It had been a few years since I last built a higher end PC. In the end I basically went with newegg recommendations and I wasn't disappointed with their parts choices. It was easy to figure out compatibility too.

My first small problem was with my power supply. I had a CORSAIR CMPSU-750TX and I couldn't find the 4-PIN connector. Turns out that the 8 PIN connector could be separated into two 4 PIN connectors. I had to read the manual before I noticed. I don't know if this is standard in power supplies nowadays, but I had never encountered it before.

The second problem was with my motherboard. The screen stayed black after powering it on; I heard no beeps, it wasn't going through POST. I got a M4A79XTD EVO with a Phenom II X4 955 CPU through a newegg combo deal. I read a lot of reviews that said the combo was bad because the 955s being sent out were C3, which are incompatible with the BIOS shipped on the mobo (motherboard.) Furthermore, you couldn't update the BIOS without a compatible CPU. After googling, I found that C3 was the revision number of the processor. On ASUS's page, http://support.asus.com.tw/cpusupport/cpusupport.aspx?model=M4A79T%20Deluxe, I found the list of supported CPUs for the mobo. Each revision of AMD's CPUs has its own model number. Mine was HDX955FBK4DGIBOX. Took me a second to realize that the "BOX" could be ignored. It turned out my CPU was C2, which worked with bios on the motherboard. In the end, it turned out my RAM was bad on arrival. I'm glad I was able to figure out the CPU issue or else I would have probably tried to return the motherboard.

Lastly, I gave my wife most of my old parts, one of which was an ASUS A8V DELUXE motherboard. I was unable to install Windows, I kept getting a BSOD (blue screen of death) saying that "The bios in this system is not fully acpi compliant." However, the bios was ACPI compliant and I never had problems while I was using it. The bios even had an "Enable ACPI" option, which was on. I decided to reset the CMOS and see if that would fix it. Since I lost my manual and couldn't tell where the jumper was, I simply removed the motherboard's battery for 5 minutes (make sure all power to the computer is unplugged first.) That did the trick.

Those were the trickier errors I ran into, but I had lots of other issues such as bad drives, configuring jumpers correctly, making things reach... stuff that required opening the machine a lot, but nothing that wasn't obvious. So, I spent a lot of time building systems for my wife and I, but now that they're running, I'd say it was worth it. Hopefully, you can avoid the problems I ran into.

Monday, November 30, 2009

Javascript Effects

I've been busy this month, but I found a lost blog post from 11/2007. I think it's still relevant. At least the links are still alive. And Javascript is still really handy to know well:

Well, I've been doing web page mock-ups at work, and I've gotten some pretty cool effects down. It always amuses me how important the appearance is to a project. It makes sense, since rock solid systems can't really be demo'ed, but one cool transparency effect can knock an audience off their feet in a couple seconds. Not just anyone can comment when you describe how you brought your algorithm from O(n!) to O(log n), but everyone can say "Wow, that dragging and dropping is pretty nifty." So don't ever neglect the appearance of your project if you want normal people to use it. Luckily, effects are usually pretty easy to do on a web page, since someone else has probably done it before. I wanted to take this post to share some links that I had found really useful.

First of all, just in case you don't know css, read this. CSS is really important to making a web page. I'd suggest reading everything at that link for anyone who isn't an expert.

For transparency effects, this webpage was my guide: http://www.mandarindesign.com/opacity.html. It described everything needed to have mouseover transparency working in all the major browsers, using css and javascript. Very helpful.

For drag and drop, I referred to this website: http://www.walterzorn.com/dragdrop/dragdrop_e.htm. He did a really good job providing tons of examples and his own implementation. From simple dragging and dropping to resizing images and sliding bars, this was a great reference to me. He even provides javascript if you want to use his code directly.

By the way, if you're one of those people who puts javascript programming on the same level as html/css programming, then read Rediscovering Javascript. Hopefully, you'll change your mind. If you are new to programming, a great Javascript guide is "Eloquent Javascript." It has a nice interpreter, which means you can test javascript code quickly.

Saturday, October 31, 2009

Removing and Ejecting Disks

Requires: Windows XP Professional

So, you plug in a USB drive, do your stuff, and then you want to take it out. Pretty common today, right? So you've got to go to your taskbar, right click that "Safely Remove Drive" icon, and so on. I thought it was kind of annoying, so I looked for a way to do this without having to use the mouse (and that was free.) And I eventually found it at this site. His english isn't too great, but he's not a native speaker and it's not -that- hard to understand.

As he says, there are several tools that claim to do this. Don't use them because they don't work correctly. For example, in XP, DevEject fails to let you know if the operation failed. If you google "safely remove usb xp command line" you'll get articles talking about the devcon tool. Don't use that either because devcon causes the device in question to be uninstalled. This is not desired and does NOT cause the device to be "unplugged." So use the tools from http://www.uwe-sieber.de/usbstick_e.html.

So yay, now you can do usb stuff from command line. Sometimes you'll get a failure message. Unless you accidentally specified a non-removable drive, the most likely reason for this is that Windows has "locked" some of the files on the drive. So annoying, especially since you'll not know how to unlock them, since you probably already closed all he programs that were using it. If that's the case, use this program, "Unlocker", to free up those files. It works like a charm and appears in the right click menu for easy use. Download unlocker: http://ccollomb.free.fr/unlocker/

Wednesday, September 30, 2009

Web Screnshots

Making screenshots of web pages (whole long screenshots, from top of the page to the bottom) is pretty important, so it's pretty useful to have a good screenshot tool. The one I use is FireShot. It's a firefox extension, but it can also be installed on IE. It's nice, easy to use, and free. You can save in different image formats as well. It's a good tool.

Firefox
Internet Explorer

Thursday, August 27, 2009

Code Launcher

Requires: Windows (2000 and higher) and Ruby

When I first started playing with lots of languages two years ago, I built a simple extensible ruby script for myself that compiles/executes source code. I called it "Code Launcher." I was using Textpad mostly at that time, so I set up Textpad to run codeLauncher on the active file with the press of "ctrl-1". "Code Launcher" has a different effect depending on the extension of the currently opened file. For example, I have HTML files open in firefox, ruby code run through a batch file (so it can have a guaranteed pause), and java code compiled and then run through a batch file. It's a simple idea, but it was also a really useful idea that I still use for quick coding. Here's the code for it... the nicest thing about it is that you can add and take from it freely and quickly. Build in special cases for yourself and whatnot.

  1. # This program was created for use in TextPad, so that I could add this  
  2. # as a user tool which would do exactly what I wanted to the current open file.  
  3. # This way, I didn't need a different user tool (and different key shortcut)   
  4. # for every different kind of file.  I did this in Ruby because I had been learning   
  5. # it and liking it a lot at the time.  
  6. #  
  7. # The current problem with it is that there can not be more than one parameter.  
  8. #  
  9. # This program requires ruby 1.8 and AutoIt3 installed.  
  10. # 03/20/07  
  11.   
  12. require 'win32ole'  
  13.   
  14. class CodeLauncher  
  15.     def initialize( fileParam, promptForParams = false, browser = "C:\\Program Files\\Mozilla Firefox\\firefox.exe" )  
  16.         params = ""  
  17.         exit if( !fileParam )  
  18.   
  19.         #Get parameters if parameters are asked for  
  20.         if( promptForParams )   
  21.             require 'getParams.rb'  
  22.             app = FXApp.new("Get Parameters""FXRuby")  
  23.             gp = GetParams.new(app)  
  24.             app.create  
  25.             app.run  
  26.             params = gp.param  
  27.             params = "\" \""+params+"\""  
  28.         end  
  29.   
  30.         #parse out the file name  
  31.         if( fileParam =~ /(.*)\\(.*)\Z/ )  
  32.             fileDir = $1  
  33.             fileName = $2  
  34.         else  
  35.             exit  
  36.         end  
  37.         extension = $2 if( fileName =~ /(.*)\.(.*)\Z/ )  
  38.   
  39.         #Special Cases (if any, for quick parameter testing)  
  40.   
  41.         #Extension based general executions/compilations  
  42.   
  43.         # Ruby, simpy open using a batch file (for the pause effect)  
  44.         if( extension == "rb" || extension == "rbw")  
  45.             runInCmd( fileDir, fileName, params, true )  
  46.         end  
  47.   
  48.         # Java, compile the code an run in a batch file (for the pause effect)  
  49.         if( extension == "java" )  
  50.             runInCmd( fileDir, "javac\" \""+fileName, ""false )  
  51.             runInCmd( fileDir, "java\" \""+fileName.chomp(".java"), params, true )  
  52.         end  
  53.   
  54.         # HTML, open the page in the browser  
  55.         if( extension == "html" )  
  56.             openInBrowser( browser, fileDir+"\\"+fileName )  
  57.         end  
  58.   
  59.         # PHP, open the page in the browser  
  60.         if( extension == "php" )  
  61.             openInBrowser( browser, fileDir+"\\"+fileName )  
  62.         end  
  63.   
  64.         # JSP, open the page in the browser  
  65.         if( extension == "jsp" )  
  66.             openInBrowser( browser, fileDir+"\\"+fileName )  
  67.         end  
  68.   
  69.         # batch, simply open the batch file  
  70.         if( extension == "bat" )  
  71.             runInCmd( fileDir, fileName, params, false )  
  72.         end  
  73.     end  
  74.   
  75.     #Run the code  
  76.     def runAutoIT3( cmdString )  
  77.         au3 = WIN32OLE.new("AutoItX3.Control")  
  78.         au3.opt("WinTextMatchMode", 2)  
  79.         au3.RunWait( cmdString )  
  80.     end  
  81.   
  82.     def openInBrowser( browser, url )  
  83.         runAutoIT3( browser+" \""+url+"\"" )  
  84.     end  
  85.   
  86.     def runInCmd( fileDir, command, params, leaveOpen )  
  87.         cmdString = ""  
  88.         if( leaveOpen )  
  89.             cmdString = "cmd.exe /c \"codeLauncherPause.bat \"" + fileDir + "\" \""+ command + params + "\"\""  
  90.         else  
  91.             cmdString = "cmd.exe /c \"cd " + fileDir + " && \"" + command + params + "\"\""  
  92.         end  
  93.         runAutoIT3( cmdString )  
  94.     end  
  95. end  
  96.   
  97. if __FILE__ == $0  
  98.     #Get Parameters  
  99.       
  100.     filename = ARGV[0]  
  101.     exit if( !filename )  
  102.     browser = ARGV[1]  
  103.       
  104.     browser = "C:\\Program Files\\Mozilla Firefox\\firefox.exe" if( !browser )  
  105.       
  106.     #execute  
  107.     CodeLauncher.new( filename, false, browser )  
  108.     exit  
  109. end  
  1. cd %1  
  2. %2 %3  
  3. pause  
And setting CodeLauncher to be run through "ctrl-1" in Textpad is pretty easy. Go to configure, then select preferences, then select tools. Add a DOS Command, name it whatever you want. I called mine Code Launcher.

Click Apply, then expand Tools. For Parameters, type "codeLauncher.rb $File". For Initial Folder, enter the full path to the codeLauncher.rb script. Make sure "Close DOS window on exit" is checked. Then click OK. You're all set.



As a parting note, make sure whatever you're using to develop code with does code launching (maybe build/execute is a better term) and make sure you tailor fit it to your usage. Any decent development environment does... F5 is a common key to try. This is really basic funcitonality that makes a developer's life tons easier.

Monday, August 17, 2009

My Path to a Java/COM Bridge

Accurate as of July 2007.

A company my company was subcontracting to for a project told us that we could only use their hardware via COM objects. As a team, we didn't know very much about COM. Our application was entirely Java based. To us, their requirement implied that we needed to write JNI code, which frightened us because we've done -that- before.

Since we didn't know that much about COM, I was tasked to do a study on COM and a feasibility study for using COM objects from Java. I broke up the study into two parts. First, I figured out the basics of COM so that I could explain it to my team members. Second, I looked into and evaluated solutions to our problem. (SPOILER: We ended up going with J-Integra.)

The study was actually interesting and I think it's useful in general. Being able to use COM means that you have a lot of opportunity to interact with Windows applications. The ability to automate Microsoft Office applications is really convenient. So I'm going to share some of the results of my COM studies. First, I'll try to explain COM if you don't know much about it. Then I'll go into a comparison of Java/COM bridges.

I'm no expert on any of this, so don't let this be the end of your own studies. And I don't really go very deeply into either COM nor the Java-COM bridges. Also, I did quickly convert this from a private internal document to one for public use, so it might read funny in some places. So use this article more as a starting point.

If you want to learn, COM, listen

To teach COM, I'm going to reference the best of what I've read in an order I find very conducive to learning COM. I don't care too much about in-depthness to start off with: I build up to that when I feel I'm ready. This order will reflect that. So, let's start learning. Please note that I'm writing from the perspective of using Visual Studio 2005 and Windows XP Home:

1. http://www.codeproject.com/com/comintro.asp
This covers the COM interaction client side basics and is quite straightforward. This article (and the ones that will follow) reference ATL without describing what it is. The Active Template Library is simply a set of template-based C++ classes that simplify the programming of COM objects. ATL includes an object wizard that sets up the primary structure of COM Objects (including OLE Automation servers and ActiveX controls) very quickly with a minimum of hand coding. ATL allows creating smaller controls without support DLLs, so ATL is in a sense a lightweight alternative to Microsoft Foundation Classes (MFC) for the COM control environment.

2. http://www.codeproject.com/com/comintro2.asp
This covers making a COM server. Note that the client will not work unless you register the DLL you create/download. Do this by running "regsvr32 MsgBoxSvr.dll" in the command window.

3. http://www.microsoft.com/msj/1295/activex1295.aspx
COM distinguishes between three interface types: custom, dispatch, and dual interfaces. It's at least important to be familiar with the results of implementing the IDispatch interface. The IDispatch interface is the interface that exposes the OLE Automation protocol. The Automation (IDispatch) interface allows a client application to find out what properties and methods are supported by an object at run-time. It also provides the information necessary to invoke these properties and methods. Client applications do not need to be aware of the object members when they are compiled.

Those three are good enough on their own as a starter, but personally, I needed more reinforcement. And thus...

4. http://www.codeproject.com/com/rrcombasics.asp
Once again, COM basics. The grammar is bad, but it will help reinforce the basics.

5. http://www.codeproject.com/com/Inside_COM.asp
Another in-depth Introduction to COM (Server and Client). This one doesn't come with a code download.

6. http://www.codeproject.com/com/mmtopo_comid.asp
Some vocabulary definitions, once again meant to reinforce the basics.

An important aspect of my project at work was the need of being able to use callback methods (aka COM events) with COM. The next links go over this:

7. http://www.samspublishing.com/articles/article.asp?p=25922&seqNum=4&rl=1
This explains the concepts of COM events.

8. http://www.codeproject.com/com/connectionpoint.asp?df=100&forumid=14124&exp=0&select=1481687
An example/tutorial going over COM events. This code simply doesn't compile on Visual Studio 2005.

And since .Net is so important now, COM interoperability is an issue. These articles give some basics on that. A component available from .NET (written in C#) is a .NET component. It is different from a COM component because it requires a few of the DLLs from the .NET Framework in order to work.

9. http://www.codeproject.com/useritems/BuildCOMServersInDotNet.asp / http://www.codeproject.com/dotnet/cominterop.asp
General stuff

10. http://support.microsoft.com/kb/828736/en-us
More about writing a .NET component.

11. http://support.microsoft.com/kb/313891
How to sink managed C# events. I believe that this is the best way to providing callbacks for COM components in C#.

The above information should be enough knowledge to understand what's going on when I get to explaining the Java/COM bridges. I'm going to provide a few more links that go a little more in depth, but you can probably do without the extra information. If you really wanted to learn COM, even this won't be enough for you. You're going to have to buckle up and buy a book. But anyway...

12. http://www.codeproject.com/com/com_in_c1.asp
To understand how COM really works, you should do it from C. This is a series of 8 tutorials (com_in_c1 to com_in_c8) that will really let you know what's going on beyond all the Visual Studio gives you through its wizards and templates.

13. http://en.wikipedia.org/wiki/Component_Object_Model
Finally, for a refresher course, read the wikipedia page. The links are nice. You may want to wiki OLE Automation, ActiveX, ATL, and IDispatch while your out it. Reviewing by reading is always beneficial, even if not as beneficial as reviewing by doing.

14. http://www.microsoft.com/com/default.mspx
Lastly, the definitive source on COM. Good luck finding your way around there, lots of scattered information.

Java Couldn't Originally Make Connections Or Method Calls.... OM.

So, after all that reading, we're finally ready to see if we can figure out the problem. The goal is to use Java to work with COM objects. No matter how you look at it, this involves interacting with native code running outside the JVM. Web Services (Java to Soap/Soap to COM) is an option, but due to the poor performance and the limited COM interaction (no events and worse), it's not a very good option. It was possible to directly call COM objects using Microsoft's own JVM in Windows, but Microsoft dropped its Java support and who really wants to lock into a specific JVM anyways? Basically, the only real option there is right now is to use JNI, which is not very fun. Our best hope is that someone else has already written the JNI for us and wrapped it up in a not-as-unfun Java API. Fortunately, this need for COM interactions is common enough that people have done that, to varying extents.

There are open-source implementations and there are (costly) commercial solutions. I'm going to point out eleven solutions that I've come across. Please pay very close attention, these solutions are very different and support COM in different ways. Make sure the solution you choose will do what you want and that it's something you can bear to work in. I want to cover each of these solutions enough so that you know if it will work for you. I'll make some comments about using it (and it's pricing) so you can decide if you can work with it. When in doubt, don't take my word for it and go to a more reliable source, specifically the project's website. Things could have definitely changed since I wrote this.

BTW, I found this gem of a study. It was very helpful to me: http://www.mit.jyu.fi/minurmin/javacom/javacom_report.html

Comparisons

I hunted down as many solutions as I could find, but ended up only reviewing three of them. Feel free to do more research on your own.

Summaries

Hopeful #1
: Jacob, http://danadler.com/jacob/ -> http://sourceforge.net/projects/jacob-project/
The potentially big problems with Jacob are its difficult error prone syntax, the lack of vtable call support, and inconsistencies in being able to access all the COM objects it should. The benefits are the cost (open source) and the maturity of the project.

Jacob uses a lot of Reflection and does its mappings based on strings provided. That means that typos are deadly and very difficult to track down because everything will compile right... it just won't work. The Jacob API is very verbose: a Jacob call can easily be twice as many lines of code as opposed to a VBScript call. Just another thing that makes debugging difficult. There is no built in way to create wrappers, but I read about a technique of modifying Jacob to use wrappers. I don't think it's worth the effort though.

Jacob has a lack of vtable call support, which means that it can not support custom interfaces. The COM objects must support the IDispatch interface (meaning ActiveX/OLE objects).

Another problem that I've encountered seems to be an incompatibility with certain COM objects. The calls won't work with certain objects (I've had very inconsistent experience with COM objects supporting callbacks in particular.) I highly suspect that it's due to badly formed COM Objects, but as of yet, I haven't tracked down the specific problem. It's not just my COM objects either: Callbacks won't work with Microsoft Office 2000, but will work with Microsoft Office 2003.

The benefits of using this solution is that it's open source and it's the most mature open source solution. It has decently active forums for minor issues and plenty of people have reported success using it. A commercial solution would be much, much better, but a Jacob solution will probably be manageable.

Hopeful #2: Jsegue, http://jsegue.sourceforge.net/
This solution seems pretty good. Unlike Jacob, it supports vtable calls. However, its API is far worse and the wrapper solution is no good (requires C++ code.)

Hopeful #3: J-Integra, http://j-integra.intrinsyc.com/
This seems to be the overall best tool I've found so far. In addition, its API is easier to use than the other solutions. It is a commercial product with all the disadvantages (cost) and benefits (support) associated.

For Java to COM support, J-Integra basically works by using their comtojava tool to create a Java Wrapper for a specified COM object. The resulting wrapper class and a J-Integra jar are imported by the class that needs COM to Java interaction. All COM calls are called as method calls of the wrapping class. The comtojava tool is easy to use and doesn't require much more than specifiying the COM class to wrap.

COM events (callbacks) are implemented using Java's standard listener registration technique. J-Integra connects with .NET components as well as COM components.

J-Integra provides support for many more Java/COM bridge needs. It allows Java to be called from COM, it allows native interfaces to be used for speed (as opposed to a native COM implementation). Probably the best things about J-Integra are its documentation and technical support. Overall, J-Integra seems to be the best way to go for a Java/COM bridge, as long as you can afford it.

Hopeful #4: com4j, https://com4j.dev.java.net/

Hopeful #5: EXJCom, http://www.ezjcom.com/purchase.html

Hopeful #6: JCOM, http://sourceforge.net/projects/jcom/
Open source and abandoned (in all but name.)

Hopeful #7: JNIWrapper, http://weblog.janek.org/Archive/2004/06/27/JNIWrapper-JavaDesktopInt.html

Hopeful #8: JaWin, http://jawinproject.sourceforge.net/jawin.html

Hopeful #9: Java2Com, http://www.nevaobject.com/default.htm

Hopeful #10: Bridge2Java, http://www.alphaworks.ibm.com/tech/bridge2java

Hopeful #11: DTJCB, http://www.alphaworks.ibm.com/tech/dtjcb

Hopeful #12: http://sourceforge.net/project/showfiles.php?group_id=174727
Not mature yet, but maybe later. It might be worth looking into later.

Comclusion

And that's all I came up with for my own study. Hopefully, it will help you in whatever you're doing.

Friday, July 31, 2009

Replacing Explorer Navigation

Requires: Windows 2000/XP, AutoIt3, and PS Hot Launch.

In internet explorer, you can use either backspace or alt-left to go to the previous page; the state is saved so that all selected items are still selected and all text in forms is still entered. In windows explorer (y'know, what you Windows users use to traverse your systems) for XP the same thing seems to happen. However, this is not the case.

Backspace actually corresponds to "Move Up One Directory" and Alt-left corresponds to "Back." If you are used to using Backspace to go back on web pages, I would suggest getting used to Alt-Left. Alt-Forward will move you forward (so it makes more sense) and making backspace go back may lead to problems will filling out web forms. I mapped Alt-Up to move up a directory and Alt-Down to close the active window, using AutoIt scripts and PS Hot Key. It took a while to wean off using backspace, but Alt-[Direction] actually makes more sense, is more unlikely to cause errors, and works the same on all windows computers. And so it's the better alternative than remapping keys.

(Haha, I've lied. I ended up switching all my Alt-[Direction] shortcuts with Ctrl-[Direction], unless there's a program conflict. I used AutoIt scripts mapped to key combinations via PS Hot Keys. Ctrl instead of Alt made it a lot easier to use the commands one handed and I don't use other people's machines all that often anyway.)

Tuesday, June 30, 2009

Removing and Ejecting Disks

Requires: Windows XP Professional

So, you plug in a USB drive, do your stuff, and then you want to take it out. Pretty common today, right? So you've got to go to your taskbar, right click that "Safely Remove Drive" icon, and so on. I thought it was kind of annoying, so I looked for a way to do this without having to use the mouse (and that was free.) And I eventually found it at this site. http://www.uwe-sieber.de/usbstick_e.html His english isn't too great, but he's not a native speaker and it's not -that- hard to understand.

As he says, there are several tools that claim to do this. Don't use them because they don't work correctly. For example, in XP, DevEject fails to let you know if the operation failed. If you google "safely remove usb xp command line" you'll get articles talking about the devcon tool. Don't use that either because devcon causes the device in question to be uninstalled. This is not desired and does NOT cause the device to be "unplugged." So use the tools from http://www.uwe-sieber.de/usbstick_e.html.

So yay, now you can do usb stuff from command line. Sometimes you'll get a failure message. Unless you accidentally specified a non-removable drive, the most likely reason for this is that Windows has "locked" some of the files on the drive. So annoying, especially since you'll not know how to unlock them, since you probably already closed all he programs that were using it. If that's the case, use this program, "Unlocker", to free up those files. It works like a charm and appears in the right click menu for easy use. Download Unlocker: http://ccollomb.free.fr/unlocker/

Sunday, May 24, 2009

Remapping keys for closing windows

Requires: Windows 2000/XP, AutoIt3, and PS Hot Launch.

Really simple tweak today. In Windows, the shortcut to close a window is "Alt-f4." That annoys me. I mean, it takes two hands, the keys are far apart, blah blah blah... Really, this is one of those things that I probably should have just gotten used to, but... I didn't. Instead, I found a way to use "ctrl-down", which works well for me since I'm using "ctrl-(other arrow keys)" for navigating windows explorer. I find it easier and faster to use the right ctrl with the arrow keys for quick navigation. My solution uses an Auto It script and PS Hot Launch.

The AutoIt script is really simple:

      WinClose( "" )

It'll close the program that currently has focus. Simply save that code and map it (using PS Hot Launch) to "ctrl-down." You can use PS Hot Launch to to make up a lot of your own commands and tweak all your keyboard shortcuts without actually changing the keys. The only thing to be careful about is not ruining pre-existing shortcuts.

As I was writing this, I realized the title could be misread to mean closing the Windows Operating System. In case that mistake lead you to read this, I'll give you a tip to close that from Command Line. Simply type in:

      shutdown -s -f -t 0

This'll shut down the computer, not give you program warnings, and do it without a delay. Do "shutdown -?" for more options. Cinchy. You can put the code in a batch file and then map it to a key or put it on your desktop and click on it when you want to shutdown. I think it's a better method than the click through GUI.

Thursday, April 02, 2009

Sorting A Million Integers

Have you ever heard the popular programming interview question, "Show me how to sort one million 32 bit integers in 2MB of RAM?"

I've read about it, but have never actually been asked it in an interview. I think the correct response is that one million 32 bit integers would not fit in 2MB of RAM. But if you assume the problem implies you have an unlimited amount disk space, then the problem is actually solvable. I recently read a good article going over the solution to this problem, so I thought I'd share the links.

The article (and its follow up) assume you know about heaps and heapsort. In case you don't, a heap is a tree-like data structure and heapsort is a very fast sorting algorithm. You can read about them more on wikipedia, Heap here and Heapsort here. If you're unfamiliar with heapsort, I'd strongly suggest you read about Sorting Algorithms in general. Although you'll probably never need to program one for work, it's really nice topic to know about and will probably help you learn to judge your own algorithms better. By the way, here is a java implementation of Heapsort based on the pseudocode from its wikipedia article.
  1. public class Heap {  
  2.   
  3.   public static int[] swap( int[] a, int first, int last ) {  
  4.     int tmp = a[first];  
  5.     a[first] = a[last];  
  6.     a[last] = tmp;  
  7.     return a;  
  8.   }  
  9.   
  10.   public static int[] heapSort( int[] a, int count ) {  
  11.     a = heapify(a, count);  
  12.   
  13.     int end = count - 1;  
  14.     while( end > 0 ) {  
  15.       //swap the root (maximum value) of the heap with the last element of the heap  
  16.       a = swap( a, 0, end );  
  17.   
  18.       //decrease the size of the heap by one so that the previous  
  19.       //max value will stay in its proper placement  
  20.       end--;  
  21.   
  22.       //put the heap back in max-heap order  
  23.       a = siftDown(a, 0, end);  
  24.     }  
  25.   
  26.     return a;  
  27.   }  
  28.   
  29.   public static int[] heapify(int[]a, int count ) {  
  30.     //Start is a's index of the last parent node  
  31.     int start = (count-2)/2;  
  32.   
  33.     while( start >= 0 ) {  
  34.       //Sift down the node at index start to the proper place such that  
  35.       //all nodes below the start index are in heap order  
  36.       a = siftDown(a, start, count-1);  
  37.       start--;  
  38.     }  
  39.   
  40.     return a;  
  41.   }  
  42.   
  43.   public static int[] siftDown(int[] a, int start, int end) {  
  44.     int root = start;  
  45.   
  46.     //While the root has at least one child...  
  47.     while( root *2 + 1 <= end ) {  
  48.       //root*2 points to the left child  
  49.       int child = root * 2 + 1;  
  50.   
  51.       //If the child has a sibling and the child's value is less than its sibling's...  
  52.       if( child + 1 <= end && a[child] < a[child+1] ) {  
  53.         //Then point to the right child instead  
  54.         child = child+1;  
  55.       }  
  56.   
  57.       //If out of max heap order...  
  58.       if( a[root] < a[child] ) {  
  59.         //Then repeat to continue sifting down the child now  
  60.         a = swap(a, root, child);  
  61.         root = child;  
  62.       } else {  
  63.         return a;  
  64.       }  
  65.     }  
  66.   
  67.     return a;  
  68.   }  
  69. }  
With the Heapsort explanation out of the way, here is the article. It's very clear and well written by Guido van Rossum, the creator of Python. Here is the link.

In the comments, someone pointed out the link to a faster algorithm, which you can read about here.

Guido van Rossum replied with:

"That's a cool way of doing it, but not for Python, where an int takes 12 bytes and the list takes another 4 bytes per value. Given some other overhead you'd end up having to make a lot of passes over the full input (the same number as would be feasible with my version -- I used 100 but it could likely be less), which would probably be slower. It's interesting that a heap features in both algorithms. I'm not convinced that it's the fastest way to sort though, despite the O(N log N) complexity. Python's built-in sort is wicked."

By the way, if you like reading articles about problem solving using programming, I suggest you also read Solving Every Sudoku Puzzle and How to Write a Spelling Checker, both by Peter Norvig. They're very good articles. Does anyone know about any other very well written problem solving articles?

Tuesday, March 24, 2009

Manga Meeya


A while ago, I wrote a post about CDisplay, an awesome Comic Book Reading Tool. I had several problems with it (such as its non customizable shortcuts, full screen mode that didn't work with my dual screens, random crashes while opening certain archives, difficulty in dealing with archives within archives...), but I didn't think that anything better existed out there. I tried CDisplayEx, but that was way worse. I was even tempted to write my own manga viewer called "CDisplayEx+Alpha." But there's no need, because I found MangaMeeya, which is everything I ever wanted in a comic reader and more.

My favorite features about MangaMeeya are its ability to display two pages at once, its smart look ahead feature, its ability to view pages either left-to-right or right-to-left, its fit-to-page image resizing, its ability to automatically deal with compressed files, and its customizability. On top of all that, MangaMeeya is blazingly fast. In addition to comic reading, it works really well as a generic image viewer... you can even delete images using MangaMeeya and use it to organize your galleries. I really can't even imagine a better sequential image viewing tool.

I don't really know the history of MangaMeeya or where it came from. I don't even know its home page. I think that it's a Japanese commercial product, but that development has ended over some copyright dispute. At some point, some guy unofficially translated it into English. If anyone has more information about MangaMeeya, please let me know, since I would like to pay for the program.

Link to Download English MangaMeeya:  Download Here

Context Menu

Although its internal file browser is nice, you will definitely want to add MangaMeeya to your right click context menu. That'll allow you to right click on any file or folder and have it open in MangaMeeya. You can do this by going into the registry and adding new shell commands to the '*' and 'Folder' extensions. Or you can download this batch file I wrote and then run it in the directory where MangaMeeyaCE-English.exe is located. I've tested it on Windows XP SP2, Windows XP SP3, and Windows Vista. It will modify your registry, but I can't imagine how it could ruin anything. Still, I assume no responsibility if you somehow use it to wreck your system. The context item will be named CMangaMeeya, which should always put it near the top of your right click list.
  1. @echo off  
  2. if not exist MangaMeeyaCE-English.exe (  
  3.   echo MangaMeeyaCE-English.exe Not Found In Current Directory.  
  4.   echo Please run this file in the MangaMeeya Directory!  
  5.   echo.  
  6.   pause  
  7.   exit  
  8. )  
  9.   
  10. echo Creating Registry file...  
  11.   
  12. echo Windows Registry Editor Version 5.00 > mangameeya.reg  
  13. echo. >> mangameeya.reg  
  14. echo [HKEY_CLASSES_ROOT\Folder\shell] >> mangameeya.reg  
  15. echo [HKEY_CLASSES_ROOT\Folder\shell\CMangaMeeya] >> mangameeya.reg  
  16. echo [HKEY_CLASSES_ROOT\Folder\shell\CMangaMeeya\command] >> mangameeya.reg  
  17. echo @="\"%cd:\=\\%\\MangaMeeyaCE-English.exe\" \"%%1\"" >> mangameeya.reg  
  18. echo. >> mangameeya.reg  
  19. echo [HKEY_CLASSES_ROOT\*\shell] >> mangameeya.reg  
  20. echo [HKEY_CLASSES_ROOT\*\shell\CMangaMeeya] >> mangameeya.reg  
  21. echo [HKEY_CLASSES_ROOT\*\shell\CMangaMeeya\command] >> mangameeya.reg  
  22. echo @="\"%cd:\=\\%\\MangaMeeyaCE-English.exe\" \"%%1\"" >> mangameeya.reg  
  23.   
  24. regedit /s mangameeya.reg  
  25.   
  26. echo Successfully Added Manga Meeya to Context Menu as CMangaMeeya!  
  27.   
  28. pause  
My CDisplay Clone Set Up

Since I've used CDisplay for a few years, I've gotten used to many of its key shortcuts. Since MangaMeeya is so customizable, I switched many of the key shortcuts to be more CDisplay-like. If you're in the same boat as me, feel free to use my configuration settings. Simply download my file and swap it with the file in your MangaMeeya directory.

My Configuration Settings File:  Download Here

My Frequently Used Commands:

Right Arrow: Goes to the next section or page.
Left Arrow: Goes to the previous section or page.
Ctrl+l: Foes to the next directory or compressed file. It's a lowercase 'L', not the number one.
Ctrl+Shift+l: Goes to the preview directory or compressed file. It's a lowercase 'L', not the number one.
l: Allows you to select a folder to open. It's a lowercase 'L', not the number one.
o: Allows you to select a file to open. It's a lowercase 'O', not the number zero.
`: Exits the program
Ctrl+Return: Switches between full screen mode and Windowed mode.

Well, if you read comics on your computer, I hope that you give MangaMeeya a try. It's definitely worth it.

Thursday, March 12, 2009

Simple Anagrammer

While watching my family feverishly play word jumble one day, I decided to write a program to list anagrams. They're still addicted to that game, but I've long since finished up my program. Although it wasn't much effort, I thought I'd go over what I came up with. I wrote code to find single word anagrams, sub anagrams, and multi word anagrams. Since those may be my own nomenclature, I'll explain more clearly. What I'm calling a Single Word Anagram is a single word made up from all the letters of one or more words, such as "cat" to "act" and "resume" to "sure me." What I'm calling Sub Anagrams are possible shorter words made up from one or more words, such as "cat" to "catharsis" and "user" to "sure me." What I'm calling Multi Word anagrams are two or more words made up from all the letters of , such as "sure me" to "resume." Now let's get into my implementation. You should know that my implementation does assume you're more concerned about processing time than memory space.

Also, I originally wrote the code in java, but that language is not very suited for code snippets... it's so, so verbose. So all my code examples are going to be in ruby, with an emphasis of being as concise as possible. I left out all the optimizations I did for my java program, I'm only intending to give a general example of how the code works. So the code runs very, very slowly for long words. But, you'll get the idea of what's going on.

Word List

Before I get into my algorithms, I should go over obtaining a good word list, which is probably the most important step. A word list is exactly what it sounds like and it's what you'll use to determine if a word is real or not. There are lots of word lists out there and you should choose one depending on how thorough you want to be and what language you want to use. There's one in /usr/dict/words if you're using unix, but it isn't very good. I like the very flexible set I found at word list called scowl. It gives you a lot of different word lists you can pick and choose from. The word lists are found in "[scowl home]\final"; they're arranged by a description followed by their part number. A part number of 10 includes a small set of very common words, a part number of 95 contains a very large set of uncommon words. No two sets for a description contain the same word. For my word list, I used english-words.10, english-words.20, english-words.30, and english-words.40. You can trim down the word lists however you want.

By the way, I also found a word list at wordnet that you can also use as a dictionary for looking up definitions. It's free, which is nice.

Single Word Anagrams

After you have your word list, you need a good algorithm. Let's say you want to find all the anagrams of a word. The most straightforward solution is to find all the permutations of the letters in that word and then figure out which ones are real by comparing to your word list. Of course, this is horribly inefficient. I mean, for every n length word you're doing n! comparisons. It's doable on today's machines, just very, very slow.

A better solution is to create a special dictionary (/hash table) for yourself. The key will be the letters of a word arranged alphabetically, the value will be a list of words with that key. So, for example, the key "abt" will contain the word list "bat, tab". You'll have to iterate over your whole word list to create the dictionary, which will take a few seconds, but it is a one time thing. And once it's created, listing the anagram is as easy as arranging the letters of your target word alphabetically and looking it up in the dictionary you created. Make sure everything is lower case for your comparisons.

Here's my ruby code:
AnagrammerBySort.rb - Part 1
view plaincopy to clipboardprint?
  1. def words text  
  2.   text.downcase.scan(/['\w]+/)  
  3. end  
  4.   
  5. def getWordKey word  
  6.   return word.split("").sort!.to_s.strip  
  7. end  
  8.   
  9. def train features  
  10.   model = Hash.new{|hash,key| hash[key] = Array.new}  
  11.   features.each {|f| model[getWordKey(f)].push(f)}  
  12.   return model  
  13. end  
  14.   
  15. NWORDS = train(words(File.new("words.txt").read))  
  16.   
  17. def singleWordAnagram word  
  18.   return NWORDS[getWordKey(word)]  
  19. end  
Sub Anagrams

To find sub anagrams, you first need to be able to determine if a word is a subset of another word. Remember that duplicates count for anagrams, in that "aabc" is not a subset of "abcd." There are many, many ways of checking subsets. In my ruby code example, I just went for the most concise way. It actually performs really poorly.

Once you have a way to determine subsets, all you need to do is iterate over all the keys in your anagram dictionary to determine if they are subsets of your target word. You could also create a new dictionary that maps all words in your word list to their sub anagrams, which would make many future sub anagram lookups instant (it won't be instant for words you haven't seen before.)

Here's my ruby code:
AnagrammerBySort.rb - Part 2
view plaincopy to clipboardprint?
  1. # Whether word1 a subset of word2, duplicates are not ignored.  
  2. def isSubset( word1, word2 )  
  3.   word1.split("").uniq.each { |f|   
  4.     return false if(word1.count(f) > word2.count(f))   
  5.   }  
  6.   return true  
  7. end  
  8.   
  9. def subAnagrams word  
  10.   solution = Array.new  
  11.   NWORDS.keys.each {|f| solution.push(NWORDS[f]) if(isSubset(f,word)) }  
  12.   return solution.flatten!  
  13. end  
(Edit: I found this page which explains a much faster (although much more memory intensive) method for finding Sub Anagrams that uses a tree algorithm *somewhat* similar to a tree. If you want to get deeper into anagrams, you should definitely take a look at it as well as its follow up. The comments are really useful to read too.)

Multi Word Anagrams

Multi Word Anagrams are easy after knowing how to make single word anagrams and sub anagrams. This is how I did it:

1) Make a candidate list of all possible sub anagrams of your target word.
2) Iterate the candidate list. In each iteration, remove the first word on the candidate list and compare it to all other words on the candidate list.
    A) Add a combination of the words (Word A Word B) to the candidate list if they are a subset of the target word.
    B) Record all words that have the same key as the target word key.
3) All the words you've recorded is your solution.

This has to be done carefully or you'll quickly run out of memory. You should add logic to make sure a word is added to the list only if you want to evaluate it later.

Here's my ruby code:
AnagrammerBySort.rb - Part 3
view plaincopy to clipboardprint?
  1. def multiWordAnagrams word  
  2.   solution = Array.new  
  3.   candidates = subAnagrams(word)  
  4.   while candidates.size > 0      
  5.     f = candidates.delete(candidates[0])  
  6.     candidates.each {|g|      
  7.       if( getWordKey(word) == getWordKey(f+" "+g) )   
  8.         solution.push(f+" "+g)  
  9.       elsif( isSubset( getWordKey(f+" "+g), getWordKey(word) ) )  
  10.         candidates.push(f+" "+g)  
  11.       end  
  12.     }  
  13.   end  
  14.   return solution  
  15. end  
  16.   
  17. # Testing #  
  18. require 'pp';  
  19. print "Enter word: "; word = gets.strip  
  20. print "Single Anagrams: "; pp singleWordAnagram(word)  
  21. print "Sub Anagrams: "; pp subAnagrams(word)  
  22. print "Multi Word Anagrams: "; pp multiWordAnagrams(word)  
Alternative Dictionary

I think alphabetical keys work very well for full word anagrams, but not as well for sub anagrams. The solution I preferred involved using a different key for the anagram dictionary. First assign each letter of the alphabet a prime number greater than 1. 'a' can be 2, 'b' can be 3, and so on. All characters you don't care about (such as apostraphes, periods, and spaces) should be assigned 1. You can find a list of prime numbers here. Use the smallest numbers you can, otherwise you'll have bigger problems later. The key for the new dictionary will be the product of the letters in the word. Like before, the value will be a list of words sharing the key. Since you're multiplying prime numbers, you'll know that if Word A / Word B is 0, then the words are anagrams of each other. If Word A % Word B is 0, then the Word A is a sub anagram of Word B. To determine sub anagrams, traverse all the keys in your dictionary and find the anagram lists that divide into the target word key evenly. Finding Multi Word Anagrams will also be basically the same as before, but switching out the way you determined words are anagrams or sub anagrams.

One thing to watch out for with the prime number method is the size the of the key. In java, a 32 Bit Int won't even hold the word resume. I used a long, but even that has issues if I'm trying to find the anagrams for a sentence, much less a paragraph. You can use code to deal with really large numbers or you can just just report an error if the word can't be represented. How you deal with this problem is up to you.

I admit, the prime number algorithm doesn't actually go noticably faster, although there should be significantly less comparisons being made. Furthermore, it does have a limit in the words based on the maximum size of the key. I still like this algorithm better. Anyways, here's the code using the prime number methodology:
  1. #!/usr/bin/ruby  
  2.   
  3. LETTERS = { 'a'=>2,'b'=>3,'c'=>5,'d'=>7,'e'=>11,'f'=>13,'g'=>17,'h'=>19,  
  4. 'i'=>23,'j'=>29,'k'=>31,'l'=>37,'m'=>41,'n'=>43,'o'=>47,'p'=>53,  
  5. 'q'=>59,'r'=>61,'s'=>67,'t'=>71,'u'=>73,'v'=>79,'w'=>83,'x'=>89,  
  6. 'y'=>97,'z'=>101 }  
  7. LETTERS.default=1  
  8.   
  9. # Warning: Requiring 2 Character Minimum, includes apostrophes  
  10. def words text  
  11.   text.downcase.scan(/['\w]{1}['\w]+/)  
  12. end  
  13.   
  14. # Warning: Not checking for value overflows  
  15. def getWordKey word  
  16.   product = 1  
  17.   n = word.length  
  18.   (0..n-1).collect {|c| product *= LETTERS[word[c,1]] }  
  19.   return product  
  20. end  
  21.   
  22. def train features  
  23.   model = Hash.new{|hash,key| hash[key] = Array.new}  
  24.   features.each {|f| model[getWordKey(f)].push(f)}  
  25.   return model  
  26. end  
  27.   
  28. NWORDS = train(words(File.new("words.txt").read))  
  29.   
  30. def singleWordAnagram word  
  31.   return NWORDS[getWordKey(word)]  
  32. end  
  33.   
  34. def subAnagrams word  
  35.   solution = Array.new  
  36.   NWORDS.keys.each {|f| solution.push(NWORDS[f]) if(getWordKey(word)%f==0) }  
  37.   return solution.flatten!  
  38. end  
  39.   
  40. def multiWordAnagrams word  
  41.   solution = Array.new  
  42.   candidates = subAnagrams(word)  
  43.   while candidates.size > 0   
  44.     f = candidates.delete(candidates[0])  
  45.     candidates.each { |g|   
  46.       if ( getWordKey(word) == getWordKey(f+" "+g) )   
  47.         solution.push(f+" "+g)  
  48.       elsif( getWordKey(word) % getWordKey(f+" "+g) == 0 )  
  49.         candidates.push(f+" "+g)  
  50.       end  
  51.     }  
  52.   end  
  53.   return solution  
  54. end  
  55.   
  56. # Testing #  
  57. require 'pp';  
  58. print "Enter word: "; word = gets.strip  
  59. print "Single Anagrams: "; pp singleWordAnagram(word)  
  60. print "Sub Anagrams: "; pp subAnagrams(word)  
  61. print "Multi Word Anagrams: "; pp multiWordAnagrams(word)  
Those are the basic solutions to all the problems I played with. The above should be good inspiration to make your own anagrammer. There's still lots of fine tuning and optimizations you can add that I didn't get into. For example, you may want to ignore words with apostrophes or words less than two characters. You could work in a multi-threaded fashion as well. There are also lots of word list tweaks you can do. There's also a lot of features you can add; fun behavioral tweaks. For example, you might want to look for sentences from your multi word anagrams by throwing them through a grammar checker. There are lots of really fun anagrams out there and I'm sure you could write a program to find many more.