<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" xml:lang="en-US" xml:base="http://jrfom.com/wp-atom.php">
	<title type="text">Room Full of Mirrors</title>
	<subtitle type="text">... and all I could see was me</subtitle>

	<updated>2013-03-22T00:12:28Z</updated>

	<link rel="alternate" type="text/html" href="http://jrfom.com" />
	<id>http://jrfom.com/feed/</id>
	

	<generator uri="http://wordpress.org/" version="3.5.1">WordPress</generator>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/jrfom/cCSs" /><feedburner:info uri="jrfom/ccss" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry>
		<author>
			<name>James Sumners</name>
					</author>
		<title type="html"><![CDATA[A Note On Java Culture And A RESTlet Tutorial]]></title>
		<link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/jrfom/cCSs/~3/ZEDZ7xm5czE/" />
		<id>http://jrfom.com/?p=399</id>
		<updated>2013-03-22T00:12:28Z</updated>
		<published>2013-03-22T00:12:28Z</published>
		<category scheme="http://jrfom.com" term="Code" /><category scheme="http://jrfom.com" term="Java" /><category scheme="http://jrfom.com" term="Technology" />		<summary type="html"><![CDATA[My first real experience with web development was based on PHP. I opted to learn it over Perl because it was more popular at the time and its syntax is very similar to C. One of the things I liked most about PHP was the excellent manual on the official website. The tutorial at the [...]]]></summary>
		<content type="html" xml:base="http://jrfom.com/2013/03/21/a-note-on-java-culture-and-a-restlet-tutorial/">&lt;p&gt;My first real experience with web development was based on &lt;a href="http://php.net/"&gt;PHP&lt;/a&gt;. I opted to learn it over &lt;a href="http://perl.org/"&gt;Per&lt;/a&gt;l because it was more popular at the time and its syntax is very similar to &lt;a href="https://en.wikipedia.org/wiki/C_(programming_language)"&gt;C&lt;/a&gt;. One of the things I liked most about PHP was the excellent manual on the official website. The tutorial at the start of the manual was all I needed to get started, and the rest was a great reference. It did, however, take a long time to learn what constituted bad practice with the language. But, I digress.&lt;/p&gt;
&lt;p&gt;Nowadays I find that I have to work with &lt;a href="https://en.wikipedia.org/wiki/Java_(software_platform)"&gt;Java&lt;/a&gt; as a web development platform. The major third-party platforms we use at work are almost always written in Java, or at least against the &lt;a href="https://en.wikipedia.org/wiki/Java_Virtual_Machine"&gt;JVM&lt;/a&gt;, so it&amp;#8217;s basically what I am forced to deal with. Before being forced to deal with the Java platform in this manner, I didn&amp;#8217;t think much of it at all. In fact, I would usually deride it. There are some tools written in Java that I liked, and used, but overall I just wished it would go away. But that attitude has been changing.&lt;/p&gt;
&lt;p&gt;Let me backtrack a little. I mentioned that most of our third party software is developed in Java. Well, most of our in-house software is not. No, most of our in-house software is developed in &lt;a href="https://en.wikipedia.org/wiki/.NET_Framework"&gt;.Net&lt;/a&gt;. I thought I wouldn&amp;#8217;t mind working with .Net, at first. &lt;a href="https://en.wikipedia.org/wiki/C_Sharp_(programming_language)"&gt;C#&lt;/a&gt; is actually a rather nice language, and the .Net framework has a lot of useful libraries. But then I tried to do web development in .Net. I have never seen a bigger mismatch of technologies than .Net and the web. The .Net name is a total misnomer. It was clearly designed for traditional application development with web development tacked on after-the-fact.&lt;/p&gt;
&lt;p&gt;So, I was primarily a PHP web developer in a .Net house that has to manage some Java web applications. Clearly, something had to give. Well, as I spent more time with the Java applications, and learned how they are developed, I started to like the platform a little more. It became clear to me that the Java platform is &lt;em&gt;much&lt;/em&gt; better suited to web development than the .Net platform. Thus, I have been trying to learn how to properly do web development with the Java platform.&lt;/p&gt;
&lt;p&gt;Notice that I said &amp;#8220;trying&amp;#8221; &amp;#8212; it hasn&amp;#8217;t been easy. The Java platform comes from a &lt;a href="https://en.wikipedia.org/wiki/Java_(software_platform)#Java_meets_the_Internet"&gt;corporate environment&lt;/a&gt;. As such, the knowledgable developers of, and community around, the platform are steeped corporate ways and thinking. This means it is very difficult to find good, free, information on the web, but very easy to find a million overpriced books. Not only that, but all of the innovation has happened in the free spaces like PHP, &lt;a href="https://en.wikipedia.org/wiki/Python_(programming_language)"&gt;Python&lt;/a&gt;, and &lt;a href="https://en.wikipedia.org/wiki/Ruby_(programming_language)"&gt;Ruby&lt;/a&gt; (gee, I wonder why?). So you&amp;#8217;ll find a lot of stuff implemented in Java, because the folks working with Java would like to play with the new toys, but no documentation for the Java implementations. This means there are hundreds of ways to get started in Java web development but no clear path.&lt;/p&gt;
&lt;p&gt;Anyway, as I mentioned a &lt;a title="JavaScript Via Java On The Back Of A Rhino" href="http://jrfom.com/2013/01/23/javascript-via-java-on-the-back-of-a-rhino/"&gt;few posts ago&lt;/a&gt;, I had a new idea in mind for a project at work and came to the conclusion that it would be best done in Java. Mostly because I can&amp;#8217;t stand .Net more than Java, and because I need to learn how to properly develop web applications in Java for some third party stuff we&amp;#8217;ll be dealing with at work soon(ish). This project was to be a web API, and I wanted it to be a &amp;#8220;&lt;a href="https://en.wikipedia.org/wiki/Representational_state_transfer#RESTful_web_services"&gt;RESTful API&lt;/a&gt;&amp;#8220;. So I started researching Java APIs.&lt;/p&gt;
&lt;p&gt;I started out trying to use the &lt;a href="http://www.springsource.org"&gt;Spring&lt;/a&gt; framework because it is the basis for pretty much every major web application developed in Java nowadays (including the third party stuff I&amp;#8217;ll have to deal with soon). But that is an &lt;a href="https://twitter.com/jsumners79/status/304069747455164416"&gt;exercise&lt;/a&gt; in &lt;a href="https://twitter.com/jsumners79/status/304322246837678080"&gt;frustration&lt;/a&gt;. So I decided to try something else just so that I could actually accomplish something. Thus, I came across the &lt;a href="http://restlet.org/"&gt;RESTlet API&lt;/a&gt;. Again, the API is very poorly documented, but it looked rather clean. So I read &lt;a href="http://www.manning.com/louvel/"&gt;the book&lt;/a&gt; and found myself really liking the API.&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s worth noting that the RESTlet site, at the time of this writing, has been updated with a much better tutorial than when I started learning the API a month ago. Evidently the site was, and still is, really, undergoing some major updating. So it is possible to get started with the API without using the book, now.&lt;/p&gt;
&lt;p&gt;However, I still think the tutorial is lacking. It doesn&amp;#8217;t really show &lt;em&gt;how&lt;/em&gt; to use the API. It imparts some information that you really should know, but it doesn&amp;#8217;t help the person that just wants to &amp;#8220;write a damn application.&amp;#8221; So after getting basics of the API figured out myself, I decided I would write a tutorial.&lt;/p&gt;
&lt;p&gt;Before I link you to my tutorial I should briefly discuss the format of it. I &lt;strong&gt;hate&lt;/strong&gt; it when a tutorial is basically just a link to some source code. But there really isn&amp;#8217;t a better way of introducing this topic (unless you want to write a book). So my tutorial is mostly source code, but I did it a little differently. The tutorial itself is in the comments of the source code, with an overview of the technology, and how things are put together, in the text only part. Additionally, the source code isn&amp;#8217;t tucked away in some damn zip file you have to download or just in a web browsable directory. I put it in a &lt;a href="http://mercurial.selenic.com"&gt;Mercurial&lt;/a&gt; repository and hosted it on &lt;a href="http://bitbucket.org/"&gt;BitBucket&lt;/a&gt;. So it is browsable, easily updatable, and you can see the history of the tutorial.&lt;/p&gt;
&lt;p&gt;Without further ado the tutorial &amp;#8212; &lt;a href="https://bitbucket.org/jsumners/restlet-2.1-demo"&gt;https://bitbucket.org/jsumners/restlet-2.1-demo&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I hope you find it helpful. And if you can think of any way to improve it, feel free to send me your suggestions via a &lt;a href="https://confluence.atlassian.com/display/BITBUCKET/Fork+a+Repo%2C+Compare+Code%2C+and+Create+a+Pull+Request"&gt;pull request&lt;/a&gt;.&lt;/p&gt;
&lt;div name="googleone_share_1" style="position:relative;z-index:5;float: right; margin-left: 10px;"&gt;&lt;g:plusone size="small" count="1" href="http://jrfom.com/2013/03/21/a-note-on-java-culture-and-a-restlet-tutorial/"&gt;&lt;/g:plusone&gt;&lt;/div&gt;&lt;a href='http://twitter.com/share?url=http%3A%2F%2Fwp.me%2FpQ9on-6r&amp;count=horizontal&amp;related=&amp;text=A%20Note%20On%20Java%20Culture%20And%20A%20RESTlet%20Tutorial' class='twitter-share-button' data-text='A Note On Java Culture And A RESTlet Tutorial' data-url='http://wp.me/pQ9on-6r' data-counturl='http://jrfom.com/2013/03/21/a-note-on-java-culture-and-a-restlet-tutorial/' data-count='horizontal' data-via='jsumners79'&gt;&lt;/a&gt;&lt;img src="http://feeds.feedburner.com/~r/jrfom/cCSs/~4/ZEDZ7xm5czE" height="1" width="1"/&gt;</content>
		<link rel="replies" type="text/html" href="http://jrfom.com/2013/03/21/a-note-on-java-culture-and-a-restlet-tutorial/#comments" thr:count="2" />
		<link rel="replies" type="application/atom+xml" href="http://jrfom.com/2013/03/21/a-note-on-java-culture-and-a-restlet-tutorial/feed/" thr:count="2" />
		<thr:total>2</thr:total>
	<feedburner:origLink>http://jrfom.com/2013/03/21/a-note-on-java-culture-and-a-restlet-tutorial/</feedburner:origLink></entry>
		<entry>
		<author>
			<name>James Sumners</name>
					</author>
		<title type="html"><![CDATA[CacheViewer Continued, A History And Status Update]]></title>
		<link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/jrfom/cCSs/~3/4Og7bll5N3E/" />
		<id>http://jrfom.com/?p=384</id>
		<updated>2013-02-07T21:22:36Z</updated>
		<published>2013-02-06T01:26:06Z</published>
		<category scheme="http://jrfom.com" term="CacheViewer Continued" /><category scheme="http://jrfom.com" term="Software" /><category scheme="http://jrfom.com" term="Technology" />		<summary type="html"><![CDATA[A word of warning: this situation has me very upset. There will be strong language in this post. As you may, or may not, know, I maintain a Firefox add-on named CacheViewer Continued. I did not originally author this add-on; it was originally developed by someone named &#8220;benki&#8221; as &#8220;CacheViewer.&#8221; This add-on was extremely helpful [...]]]></summary>
		<content type="html" xml:base="http://jrfom.com/2013/02/05/cacheviewer-continued-a-history-and-status-update/">&lt;p&gt;&lt;em&gt;A word of warning: this situation has me very upset. There will be strong language in this post.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;As you may, or may not, know, I maintain a &lt;a href="https://mozilla.org/firefox"&gt;Firefox&lt;/a&gt; add-on named &lt;a href="https://addons.mozilla.org/en-US/firefox/addon/cacheviewer-continued/"&gt;CacheViewer Continued&lt;/a&gt;. I did not originally author this add-on; it was originally developed by someone named &amp;#8220;&lt;a href="http://park2.wakwak.com/~benki/"&gt;benki&lt;/a&gt;&amp;#8221; as &amp;#8220;CacheViewer.&amp;#8221; This add-on was &lt;em&gt;extremely&lt;/em&gt; helpful when doing web development with Firefox. CacheViewer made it very easy to find all of the cached items for a given domain or of a given name. Not only that, but you could preview those items directly from the cache, delete them, or even save them elsewhere. So, CacheViewer was one of the add-ons I always installed in Firefox. Then came Firefox 4.0.&lt;/p&gt;
&lt;p&gt;Firefox 4.0 broke CacheViewer in such a fashion that it wouldn&amp;#8217;t even load. I waited several weeks for an update, but benki seemed to have dropped off the planet. Making matters worse, there were no alternatives to CacheViewer (and there still aren&amp;#8217;t to my knowledge). So, I decided to look into the problem and see if I could correct it myself. It was a &lt;a href="https://bitbucket.org/jsumners/cacheviewer-continued/commits/0a4766e3eaba7d59eb1ec7f50080fd98f3cc95be"&gt;simple fix&lt;/a&gt;. Thus was CacheViewer Continued born and since May of 2011 I have been maintaining it as I am able (and is required).&lt;/p&gt;
&lt;p&gt;Everything was working out well. I was releasing CacheViewer Continued into the &amp;#8220;not fully tested&amp;#8221; add-on repository, and people were happy. Then Mozilla noticed that people &lt;em&gt;really&lt;/em&gt; liked CacheViewer and it was missing from the &amp;#8220;fully reviewed&amp;#8221; repository. As a result, Mozilla contacted me to see if I would be willing to submit CacheViewer Continued for full review so that people could install it directly from the browser add-ons tool. I said sure, even though I had planned to clean up the code before doing that. After a while, Mozilla started automatically bumping the supported version number in add-ons after an automated scan confirmed no problems with the next Firefox release. So it was really easy to &amp;#8220;maintain&amp;#8221; CacheViewer Continued &amp;#8212; I didn&amp;#8217;t have to do anything! Then they released Firefox 18.&lt;/p&gt;
&lt;p&gt;With Firefox 18 they &lt;strong&gt;completely fucked&lt;/strong&gt; CacheViewer Continued. First, I got the usual email after the automated add-on compatibility review. Whereas they normally consisted of &amp;#8220;everything&amp;#8217;s cool, we&amp;#8217;ve bumped the version compatibility number for you,&amp;#8221; this one resulted in a whole bunch of &lt;a href="https://bitbucket.org/jsumners/cacheviewer-continued/issue/23/not-compatible-with-firefox-18"&gt;red text&lt;/a&gt;. Evidently, the guy that maintains the cache API upon which CacheViewer, and subsequently CacheViewer Continued, relied decided it would be cool to &lt;a href="https://bugzilla.mozilla.org/show_bug.cgi?id=695399"&gt;up and delete the god damn API&lt;/a&gt;. No warning whatsoever was sent to add-on developers; and there sure as hell wasn&amp;#8217;t a deprecation notice for at least one release of Firefox. Nope. It&amp;#8217;s just fucking gone!&lt;/p&gt;
&lt;p&gt;Oh, and you remember that automated email I got about the problem? Yeah, they went ahead and automatically marked CacheViewer Contiued as compatible with Firefox 18 anyway. So that means everyone who uses CacheViewer Continued, almost 52,000 people, see no reason to hold off upgrading their browser. Let me summarize:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Lot&amp;#8217;s of people love having CacheViewer Continued&lt;/li&gt;
&lt;li&gt;Mozilla breaks the API on which CacheViewer Continued relies without warning&lt;/li&gt;
&lt;li&gt;Mozilla tells people CacheViewer Continued will work anyway&lt;/li&gt;
&lt;li&gt;I&amp;#8217;m fucked&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Why am I fucked? The original CacheViewer was written under the assumption that the removed API will always exist. It relied on cache entries being able to be read in real-time. Thus, the code was not structured in such a way that it would be easy, or maybe even possible, to restructure into an asychronous model. Therefore, CacheViewer Continued requires a complete rewrite to solve the problem of the missing synchronous API. At the same time, I&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Haven&amp;#8217;t used Firefox full-time in at least a year, so the add-on has not been a priority for me&lt;/li&gt;
&lt;li&gt;Have been swamped at work so I can&amp;#8217;t devote any time to CacheViewer Continued there (where it does benefit me)&lt;/li&gt;
&lt;li&gt;Was in the middle of shopping for, and buying, a house&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Yes, that&amp;#8217;s right, I don&amp;#8217;t use Firefox any longer. So why do I maintain an add-on for it? Because I know how useful CacheViewer Continued is to the people who do use Firefox (and know they need the add-on). As long as I am able, I cannot in good conscience leave these people hanging like benki did. But it is really fucking hard to so when when Mozilla does all they can to make it not worth my time. Keeping up with the god damn &lt;strong&gt;insane&lt;/strong&gt; release schedule of Firefox was enough to drive me mad before they started automatically bumping the compatibility number. But now they&amp;#8217;re telling users the add-on will work after they tell me it won&amp;#8217;t? What the fuck? Even so, I have been working on the rewrite for a month.&lt;/p&gt;
&lt;p&gt;The rewrite has not been easy. Like I said, I have a lot going on. But when I do get time to work on it, it&amp;#8217;s a slow process. The documentation for Mozilla&amp;#8217;s APIs is abysmal which results in a lot of digging just to figure out what I need, much less how to use it. The only saving grace is their new API specifically for add-on development. It is decently documented and has made it relatively easy to get up to the point where I am now &amp;#8212; something that lists cache entries, shows entry details, and loads cached images for preview from the original URL. But all of the advanced features, namely deleting and saving of entries and loading entries directly from the cache, requires digging through the poorly documented API and figuring out how to use it from within the new API.&lt;/p&gt;
&lt;p&gt;I really wish I could provide you with a release date for something at least more usable than the &amp;#8220;about:cache&amp;#8221; page built into the browser, but I can&amp;#8217;t. I don&amp;#8217;t want to release something that is going to upset you, the user, even more than you already are. Please understand that I will make it available as soon as I can.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update 07 February 2013:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I have submitted a very basic version (0.9.1) for review. Hopefully it will be available directly through the browser add-on manager within a day or so. In the meantime, you can download &lt;a href="https://bitbucket.org/jsumners/cacheviewer-continued/downloads"&gt;cacheviewer-continued-3e47cf8e944e.xpi&lt;/a&gt; from the &lt;a href="https://bitbucket.org/jsumners/cacheviewer-continued/"&gt;BitBucket page&lt;/a&gt;.&lt;/p&gt;
&lt;div name="googleone_share_1" style="position:relative;z-index:5;float: right; margin-left: 10px;"&gt;&lt;g:plusone size="small" count="1" href="http://jrfom.com/2013/02/05/cacheviewer-continued-a-history-and-status-update/"&gt;&lt;/g:plusone&gt;&lt;/div&gt;&lt;a href='http://twitter.com/share?url=http%3A%2F%2Fwp.me%2FpQ9on-6c&amp;count=horizontal&amp;related=&amp;text=CacheViewer%20Continued%2C%20A%20History%20And%20Status%20Update' class='twitter-share-button' data-text='CacheViewer Continued, A History And Status Update' data-url='http://wp.me/pQ9on-6c' data-counturl='http://jrfom.com/2013/02/05/cacheviewer-continued-a-history-and-status-update/' data-count='horizontal' data-via='jsumners79'&gt;&lt;/a&gt;&lt;img src="http://feeds.feedburner.com/~r/jrfom/cCSs/~4/4Og7bll5N3E" height="1" width="1"/&gt;</content>
		<link rel="replies" type="text/html" href="http://jrfom.com/2013/02/05/cacheviewer-continued-a-history-and-status-update/#comments" thr:count="18" />
		<link rel="replies" type="application/atom+xml" href="http://jrfom.com/2013/02/05/cacheviewer-continued-a-history-and-status-update/feed/" thr:count="18" />
		<thr:total>18</thr:total>
	<feedburner:origLink>http://jrfom.com/2013/02/05/cacheviewer-continued-a-history-and-status-update/</feedburner:origLink></entry>
		<entry>
		<author>
			<name>James Sumners</name>
					</author>
		<title type="html"><![CDATA[JavaScript Via Java On The Back Of A Rhino]]></title>
		<link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/jrfom/cCSs/~3/0XielkVDYIY/" />
		<id>http://jrfom.com/?p=374</id>
		<updated>2013-02-16T02:53:57Z</updated>
		<published>2013-01-23T18:24:03Z</published>
		<category scheme="http://jrfom.com" term="Code" /><category scheme="http://jrfom.com" term="Java" /><category scheme="http://jrfom.com" term="JavaScript" /><category scheme="http://jrfom.com" term="Oracle" /><category scheme="http://jrfom.com" term="Technology" />		<summary type="html"><![CDATA[I have been formulating a project with a couple of at odds requirements: It must interface with an Oracle database It should be easily extensible via a language others wouldn&#8217;t mind Requirement #2 leads me to JavaScript, it being the most common programming language available. So, I could do this project as a Node.js based [...]]]></summary>
		<content type="html" xml:base="http://jrfom.com/2013/01/23/javascript-via-java-on-the-back-of-a-rhino/">&lt;p&gt;I have been formulating a project with a couple of at odds requirements:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;It must interface with an Oracle database&lt;/li&gt;
&lt;li&gt;It should be easily extensible via a language others wouldn&amp;#8217;t mind&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Requirement #2 leads me to JavaScript, it being the most common programming language available. So, I &lt;em&gt;could&lt;/em&gt; do this project as a &lt;a href="http://nodejs.org/"&gt;Node.js&lt;/a&gt; based project, but the &lt;a href="https://github.com/mariano/node-db-oracle"&gt;Oracle driver&lt;/a&gt; is a pain to setup since it depends on the &amp;#8220;instant client&amp;#8221; binaries and SDK (particularly on OS 10.7 or later; unless you like running Node.js in 32-bit mode). There is also a &lt;a href="https://github.com/pekim/node-jdbc"&gt;JDBC driver&lt;/a&gt; for Node.js, but it&amp;#8217;s incomplete, hasn&amp;#8217;t been worked on it two years, and would add Java as a dependency. Thus, why not skip straight to Java? Oh, but there&amp;#8217;s that pesky problem of wanting to use JavaScript for extensibility.&lt;/p&gt;
&lt;p&gt;Enter &lt;a href="https://en.wikipedia.org/wiki/Rhino_(JavaScript_engine)"&gt;Rhino&lt;/a&gt;. Rhino is a JavaScript library for Java that provides a JavaScript interpreter. As a side note, it sounds like Rhino may be superceeded by a new library, &lt;a href="https://en.wikipedia.org/wiki/Nashorn_(JavaScript_engine)"&gt;Nashorn&lt;/a&gt;, in late 2013. In any event, I want to share what I have learned. The &lt;a href="https://developer.mozilla.org/en-US/docs/Rhino_documentation"&gt;documentation&lt;/a&gt; for Rhino is a bit difficult to follow, so a simple introduction is warranted.&lt;/p&gt;
&lt;p&gt;This brief introduction will:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Read an external JavaScript file&lt;/li&gt;
&lt;li&gt;Create an instance of the Rhino interpreter&lt;/li&gt;
&lt;li&gt;Use the Rhino interpreter to provide a new host object to the JavaScript script&lt;/li&gt;
&lt;li&gt;Execute the JavaScript script
&lt;p&gt;The source code in this article is &lt;a href="http://dl.dropbox.com/u/1038672/jrfom/misc/JavaScriptRunner.zip"&gt;available for download&lt;/a&gt;. The zip contains all of the code in this article, the Rhino library, and a Bash script to build and test the code.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Let&amp;#8217;s first look at meat of the program:&lt;/p&gt;
&lt;pre class="brush:java"&gt;
package com.jrfom;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.File;

import org.mozilla.javascript.Context;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableObject;

public class JavaScriptRunner {
    public static void main(String[] args)
        throws java.lang.Exception,
        java.io.IOException,
        java.io.FileNotFoundException
    {
        if (args.length &lt; 1) {
            System.err.println("Must pass in a JavaScript file to run.");
            System.exit(1);
        }

        File scriptFile = new File(args[0]);
        if (!scriptFile.exists()) {
            System.err.println("Script file '%s' does not exist.".format(args[1]));
            System.exit(1);
        }

        // Read in the JavaScript file.
        byte[] buffer = new byte[512];
        StringBuilder sb = new StringBuilder();
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(scriptFile), 512);
        int bytesRead = bis.read(buffer);
        while (bytesRead != -1) {
            sb.append(new String(buffer));
            bytesRead = bis.read(buffer);
        }
        String script = sb.toString();

        // Initialize the interpreter.
        Context context = Context.enter();
        context.setLanguageVersion(Context.VERSION_1_8);
        Scriptable scope = context.initStandardObjects();
        ScriptableObject.defineClass(scope, Foo.class);

        if (!context.stringIsCompilableUnit(script)) {
            Context.exit();
            System.err.println("Script is not compilable!");
            System.exit(1);
        }

        // Try to run the JavaScript through the interpreter.
        try {
            context.evaluateString(scope, script.trim(), null, 1, null);
        } finally {
            Context.exit();
        }
    }
}
&lt;/pre&gt;
&lt;p&gt;Lines 40 through 56 are where Rhino is loaded, the new host object defined (line 43), and the script executed (line 53). The rest of the code is merely checking for error conditions and reading in the JavaScript file.&lt;/p&gt;
&lt;p&gt;So, what is this new host object, &lt;code&gt;Foo&lt;/code&gt;? It is a plain Java object that extends an object provided by the Rhino library:&lt;/p&gt;
&lt;pre class="brush:java"&gt;
package com.jrfom;

import org.mozilla.javascript.ScriptableObject;

public class Foo extends ScriptableObject {
    private String bar;
    
    public Foo() {}

    @Override
    public String getClassName() {
        return "Foo";
    }
    
    public void jsConstructor() {
        this.bar = "";
    };
    
    public void jsSet_bar(String value) {
        this.bar = value;
    }
    
    public String jsGet_bar() {
        return this.bar;
    }
}
&lt;/pre&gt;
&lt;p&gt;Our &lt;code&gt;Foo&lt;/code&gt; class follows some Rhino specific requirements in order to expose our Java methods to the JavaScript being interpreted. First, we define the JavaScript class name by the &lt;code&gt;getClassName&lt;/code&gt; method. Next, we define the constructor that will be called when we do &lt;code&gt;new Foo()&lt;/code&gt; in our JavaScript; if the Java class doesn't have a &lt;code&gt;jsConstructor&lt;/code&gt; method then one will be derived. From &lt;a href="http://www.jarvana.com/jarvana/view/org/mozilla/rhino/1.7R3/rhino-1.7R3-javadoc.jar!/org/mozilla/javascript/ScriptableObject.html"&gt;defineClass&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;If no method is found that can serve as constructor, a Java constructor will be selected to serve as the JavaScript constructor in the following manner. If the class has only one Java constructor, that constructor is used to define the JavaScript constructor. If the the class has two constructors, one must be the zero-argument constructor (otherwise an EvaluatorException would have already been thrown when the prototype was to be created). In this case the Java constructor with one or more parameters will be used to define the JavaScript constructor. If the class has three or more constructors, an EvaluatorException will be thrown.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Finally, we define getters and setters for our one property by prepending &lt;code&gt;jsGet_&lt;/code&gt; or &lt;code&gt;jsSet_&lt;/code&gt;, respectively, to method names. We could also define static methods on our &lt;code&gt;Foo&lt;/code&gt; object by prepending &lt;code&gt;jsStaticFunction_&lt;/code&gt; to method names. Additionally, we can create global JavaScript functions via our Java class by prepending &lt;code&gt;jsFunction_&lt;/code&gt; to method names (but I'd shy away from this one to prevent polluting the global space).&lt;/p&gt;
&lt;p&gt;So, now that we have the Java written, what about the JavaScript? Here's a simple "hello world" type example:&lt;/p&gt;
&lt;pre class="brush:js"&gt;
"use strict;"

var foo = new Foo();

foo.bar = "This is a string";

java.lang.System.out.println(foo.bar + " from JavaScript!");
&lt;/pre&gt;
&lt;p&gt;Running this script through our Java program will result in "This is a string from JavaScript!" being printed to stdout via the Java &lt;code&gt;System&lt;/code&gt; object. Notice that we don't have to reference our &lt;code&gt;Foo&lt;/code&gt; object in any special way, other than instantiating an instance of it. This works just like the standard &lt;code&gt;Array&lt;/code&gt; object, except it doesn't have a literal syntax.&lt;/p&gt;
&lt;p&gt;Notice, also, how we have used a standard Java library in our JavaScript. Rhino provides a new host object named &lt;code&gt;Packages&lt;/code&gt;. The properties of this &lt;code&gt;Packages&lt;/code&gt; object are all of the Java libraries available to the JVM under which the program is running. In our script, we use an alias, &lt;code&gt;java&lt;/code&gt;, defined by Rhino to access the &lt;code&gt;Packages.java&lt;/code&gt; objects. Further information about this, and other scripting additions, can be read in the &lt;a href="https://developer.mozilla.org/en-US/docs/Scripting_Java"&gt;Scripting Java&lt;/a&gt; article.&lt;/p&gt;
&lt;p&gt;This isn't as sexy as Node.js. But it does provide a convenient way to include JavaScript into a Java based application that is more flexible than the &lt;a href="http://docs.oracle.com/javase/6/docs/technotes/guides/scripting/programmer_guide/"&gt;javax.script&lt;/a&gt; interface.&lt;/p&gt;
&lt;div name="googleone_share_1" style="position:relative;z-index:5;float: right; margin-left: 10px;"&gt;&lt;g:plusone size="small" count="1" href="http://jrfom.com/2013/01/23/javascript-via-java-on-the-back-of-a-rhino/"&gt;&lt;/g:plusone&gt;&lt;/div&gt;&lt;a href='http://twitter.com/share?url=http%3A%2F%2Fwp.me%2FpQ9on-62&amp;count=horizontal&amp;related=&amp;text=JavaScript%20Via%20Java%20On%20The%20Back%20Of%20A%20Rhino' class='twitter-share-button' data-text='JavaScript Via Java On The Back Of A Rhino' data-url='http://wp.me/pQ9on-62' data-counturl='http://jrfom.com/2013/01/23/javascript-via-java-on-the-back-of-a-rhino/' data-count='horizontal' data-via='jsumners79'&gt;&lt;/a&gt;&lt;img src="http://feeds.feedburner.com/~r/jrfom/cCSs/~4/0XielkVDYIY" height="1" width="1"/&gt;</content>
		<link rel="replies" type="text/html" href="http://jrfom.com/2013/01/23/javascript-via-java-on-the-back-of-a-rhino/#comments" thr:count="0" />
		<link rel="replies" type="application/atom+xml" href="http://jrfom.com/2013/01/23/javascript-via-java-on-the-back-of-a-rhino/feed/" thr:count="0" />
		<thr:total>0</thr:total>
	<feedburner:origLink>http://jrfom.com/2013/01/23/javascript-via-java-on-the-back-of-a-rhino/</feedburner:origLink></entry>
		<entry>
		<author>
			<name>James Sumners</name>
					</author>
		<title type="html"><![CDATA[RE: The Pew Pew Manifesto]]></title>
		<link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/jrfom/cCSs/~3/nNrHdCPhW1U/" />
		<id>http://jrfom.com/?p=346</id>
		<updated>2012-06-18T22:50:21Z</updated>
		<published>2012-06-18T17:44:14Z</published>
		<category scheme="http://jrfom.com" term="Code" /><category scheme="http://jrfom.com" term="JavaScript" /><category scheme="http://jrfom.com" term="Opinion" /><category scheme="http://jrfom.com" term="Personal" /><category scheme="http://jrfom.com" term="Technology" />		<summary type="html"><![CDATA[Ben Simpson made a post to Twitter a few days ago about an article that advocates avoiding writing applications directly in JavaScript. I reponded that the article is worthless, and Mr. Simpson wanted to know which points, specificially, I think are &#8220;hogwash.&#8221; There a few reponses in the article&#8217;s comments section that highlight my simple [...]]]></summary>
		<content type="html" xml:base="http://jrfom.com/2012/06/18/346/">&lt;p&gt;&lt;a href="http://mrfrosti.com/"&gt;Ben Simpson&lt;/a&gt; made a &lt;a href="https://twitter.com/mrfrosti/status/213464123533565952"&gt;post to Twitter&lt;/a&gt; a few days ago about &lt;a href="http://blogs.adobe.com/bparadie/2012/05/07/the-pew-pew-manifesto/"&gt;an article&lt;/a&gt; that advocates avoiding writing applications directly in JavaScript. I reponded that the article is worthless, and Mr. Simpson wanted to know which points, specificially, I think are &amp;#8220;hogwash.&amp;#8221; There a few reponses in the article&amp;#8217;s comments section that highlight my simple summary, but I&amp;#8217;m going to attempt to go into a bit more detail here.&lt;/p&gt;
&lt;p&gt;I have a hard time believing that the author of the article really thinks his arguments are accurate. His suggestion is to use Adobe&amp;#8217;s &lt;a href="https://en.wikipedia.org/wiki/ActionScript"&gt;ActionScript&lt;/a&gt; language instead of JavaScript. This makes sense because he is an Adobe employee. But he did write the article, or at least attached his name to it, so let&amp;#8217;s dig into this load of bunk.&lt;/p&gt;
&lt;h2&gt;&amp;#8220;JavaScript is not suitable for large web apps&amp;#8221;&lt;/h2&gt;
&lt;p&gt;This is the &amp;#8220;point&amp;#8221; that Mr. Simpson found most interesting and the one that I think is the biggest fallacy. I would like to include a small quote from this section, but it&amp;#8217;s all so ludicrous I can&amp;#8217;t pick a single representative part to quote. The author&amp;#8217;s argument breaks down to the following points:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;He was asked to help work on a large internal JavaScript based project&lt;/li&gt;
&lt;li&gt;The project&amp;#8217;s source code was organized in a horrible fashion&lt;/li&gt;
&lt;li&gt;The project&amp;#8217;s code was written by people who didn&amp;#8217;t understand the language&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The author then blames all three of these points on JavaScript itself. First, the project evidently contained large chunks of JavaScript in &amp;#8220;few files.&amp;#8221; In this regard, he says that ActionScript, the language, leads the coder to using multiple files for various classes and such. You can do the same exact thing with JavaScript. Case and point: &lt;a href="https://github.com/jquery/jquery/tree/master/src"&gt;jQuery&lt;/a&gt;. jQuery is a large, very popular, JavaScript project. Its source code is broken down into different components with each component being defined in its own source file. These files are then &amp;#8220;compiled&amp;#8221; into a single JavaScript file that is &amp;#8220;jQuery.&amp;#8221;&lt;/p&gt;
&lt;p&gt;The primary, somewhat, valid complaint in this section is about JavaScript functions returning inconsistent data types. His example code consists of the following two functions:&lt;/p&gt;
&lt;pre class="brush:javascript"&gt;
  // (bad) JavaScript
  function createBunnyOrToaster(createBunny)
  {
    if( createBunny )
      return new Bunny();
    return new Toaster();
  }

  // (bad) JavaScript
  function feedBunnyOrToaster(bunnyOrToaster)
  {
    if( bunnyOrToaster instanceof Toaster )
      bunnyOrToaster.insert(new Toast());
    else
      bunnyOrToaster.feed(new Carrot());
  }
&lt;/pre&gt;
&lt;p&gt;How are these functions the fault of the language? They&amp;#8217;re not. They&amp;#8217;re the fault of a programmer being stupid. What would &amp;#8220;proper&amp;#8221; JavaScript of this example look like? First, understand that the example assumes the coder is being lazy about creating &lt;a href="http://www.crockford.com/javascript/inheritance.html"&gt;&amp;#8220;class&amp;#8221; based objects&lt;/a&gt;. Second, recognize that&lt;br /&gt;
&lt;samp&gt;createBunnyOrToaster()&lt;/samp&gt;
&lt;p&gt; is the constructor for two class based objects. Thus, we would write something akin to:&lt;/p&gt;
&lt;pre class="brush:javascript"&gt;
  var Bunny = function(bunnyName) {
    if ( !(this instanceof Bunny) ) {
      return new Bunny();
    }

    this.name = bunnyName;
  };

  var Toaster = function(toasterModel) {
    if ( !(this instanceof Toaster) ) {
      return new Toaster();
    }

    this.model = toasterModel;
  };
&lt;/pre&gt;
&lt;p&gt;With this code, the programmer can still be lazy (e.g.&lt;br /&gt;
&lt;samp&gt;var myBunny = Bunny(&amp;#8220;FooFoo&amp;#8221;);&lt;/samp&gt;
&lt;p&gt;), but the JavaScript isn&amp;#8217;t total garbage. John Resig has written an &lt;a href="http://ejohn.org/blog/simple-class-instantiation/"&gt;excellent article&lt;/a&gt; on this pattern.&lt;/p&gt;
&lt;p&gt;His second example,&lt;br /&gt;
&lt;samp&gt;feedBunnyOrToaster()&lt;/samp&gt;
&lt;p&gt;, assumes the usage of the constructor that we just showed is ridiculous. Therefore, I will not waste any further time on it. Suffice it to say, if the code is written in a sane manner, then the constructor will always return the correct type. Thus, functions that require type inference are pointless.&lt;/p&gt;
&lt;h2&gt;&amp;#8220;JavaScript is the browser&amp;#8217;s assembly language&amp;#8221;&lt;/h2&gt;
&lt;p&gt;This point(?) doesn&amp;#8217;t even really deserve acknowledgement if it weren&amp;#8217;t referenced in the next couple sections. This one just dumbfounds me. I&amp;#8217;m going to let a couple &amp;#8220;Hello World&amp;#8221; examples deal with this one for me. First up, vanilla &lt;a href="http://en.literateprograms.org/index.php?title=Special:DownloadCode/Hello_World_(Assembly_Intel_x86_Linux)&amp;amp;oldid=15308"&gt;x86 assembly&lt;/a&gt;:&lt;/p&gt;
&lt;pre class="brush:plain"&gt;
  section .data
    msg db "Hello World!", 0x0a

    len equ $-msg

  section .text
    global _start

  _start:
    mov ebx, 0x01
    mov ecx, msg
    mov edx, len
    mov eax, 0x04
    int 0x80

    mov ebx, 0x00
    mov eax, 0x01
    int 0x80
&lt;/pre&gt;
&lt;p&gt;JavaScript (as run in a browser):&lt;/p&gt;
&lt;pre class="brush:javascript"&gt;
  (function() {
    var msg = "Hello World!";
    alert(msg);
  }());
&lt;/pre&gt;
&lt;h2&gt;Some garbage about high level languages&lt;/h2&gt;
&lt;p&gt;I&amp;#8217;m going to address the &amp;#8220;Choose a high-level language for developing web apps&amp;#8221; and &amp;#8220;Cross-compile from a high-level language to JavaScript&amp;#8221; points at the same time. Put simply, as I illustrated in the previous section, JavaScript is a high-level language. There is absolutey &lt;em&gt;no reason&lt;/em&gt; to use another high-level language to write JavaScript.&lt;/p&gt;
&lt;p&gt;Here&amp;#8217;s the thing. If you choose something like &lt;a href="http://coffeescript.org/"&gt;CoffeeScript&lt;/a&gt;, one of the more popular options that the author recommends, then your code is going to be &amp;#8220;compiled&amp;#8221; at least twice: first by the &amp;#8220;high-level&amp;#8221; language&amp;#8217;s compiler and second by the runtime&amp;#8217;s (e.g. browser&amp;#8217;s) JavaScript interpreter. When you go the route that the author suggests, then the compiler for your chosen high-level language is merely translating the code you wrote into JavaScript. As has been shown in the original article, and this article, that code may not be appropriate. Yet, that is the code that will be run by the JavaScript interpreter.&lt;/p&gt;
&lt;h2&gt;&amp;#8220;It&amp;#8217;s optimized so it&amp;#8217;s better!&amp;#8221;&lt;/h2&gt;
&lt;p&gt;That&amp;#8217;s the title I&amp;#8217;m giving to the &amp;#8220;Use Google&amp;#8217;s Closure Compiler for optimizing JavaScript&amp;#8221; and &amp;#8220;Optimized JavaScript is obfuscated and protects your intellectual property&amp;#8221; points. Unless you use Closure&amp;#8217;s &amp;#8220;advanced&amp;#8221; option, the code returned from Closure is &lt;em&gt;the exact same code&lt;/em&gt; as the code you wrote. The only difference is reduced white space and variable name length. The only benefit here is a smaller file size to be sent to the client. The advanced option &lt;em&gt;will&lt;/em&gt; try to alter your code to be more efficient, but that can have serious side effects. Don&amp;#8217;t trust it implicitly as the author seems to suggest.&lt;/p&gt;
&lt;p&gt;Along the same lines, the author equates &amp;#8220;optimized&amp;#8221; JavaScript with hard to read assembly or deliberately confusing code. This is utter nonsense. As I have already stated, this optimized code is nothing more than compressed code. Run the compressed code through something like &lt;a href="https://github.com/jdc0589/JsFormat"&gt;JsFormat&lt;/a&gt; (a &lt;a href="http://www.sublimetext.com/2"&gt;SublimeText 2&lt;/a&gt; plugin) and you&amp;#8217;ll get code that is quite legible. Sure, the variable names won&amp;#8217;t be pretty, but the logic is still there.&lt;/p&gt;
&lt;h2&gt;&amp;#8220;Use best practices&amp;#8221;&lt;/h2&gt;
&lt;p&gt;The last two points, &amp;#8220;Let your app degrade gracefully when OS features are missing&amp;#8221; and &amp;#8220;Invade every Web Platform!&amp;#8221;, are nothing more than the statement &amp;#8220;use best practices&amp;#8221; written in many more words. If the JavaScript you are writing has a chance of being run in more than one environment (Internet Explorer, Firefox, &lt;a href="http://nodejs.org/"&gt;Node.js&lt;/a&gt;, etc.), then you should be checking to make sure the features you need are present. It&amp;#8217;s a very old concept to people writing JavaScript for the web. There&amp;#8217;s nothing special or new about these two points.&lt;/p&gt;
&lt;h2&gt;My summary&lt;/h2&gt;
&lt;p&gt;Back when JavaScript was first introduced, and people used it for really annoying garbage like &lt;a href="http://javascript.about.com/library/blsnow2.htm"&gt;snow flakes&lt;/a&gt;, I was one of the people who hated the language. What I was too young, or uneducated, to realize is that I hated how the language was being used (and implemented). Nowadays, it&amp;#8217;s one of the most impressive languages available. The runtimes/interpreters are phenominal, and the subtleties of the language have been exposed. So when I read &lt;a href="https://en.wikipedia.org/wiki/Fear,_uncertainty_and_doubt"&gt;FUD&lt;/a&gt; like the referenced article, it grates me the wrong way.&lt;/p&gt;
&lt;p&gt;If you find yourself looking for ways to write JavaScript without writing JavaScript (see the above mentioned CoffeeScript), then you need to stop and re-think what you are doing. Take a little time to learn the language. You don&amp;#8217;t have to read &lt;a href="http://shop.oreilly.com/product/9780596805531.do"&gt;JavaScript: The Definitive Guide&lt;/a&gt; to get a handle on the language. Familiarize yourself with &lt;a href="https://developer.mozilla.org/en/JavaScript/Guide"&gt;the basics&lt;/a&gt; and then read &lt;a href="http://shop.oreilly.com/product/9780596517748.do"&gt;JavaScript: The Good Parts&lt;/a&gt; and &lt;a href="http://shop.oreilly.com/product/9780596806767.do"&gt;JavaScript Patterns&lt;/a&gt;. Both are short books, but they will teach you (almost) everything you need to know to write some damn fine JavaScript.&lt;/p&gt;
&lt;div name="googleone_share_1" style="position:relative;z-index:5;float: right; margin-left: 10px;"&gt;&lt;g:plusone size="small" count="1" href="http://jrfom.com/2012/06/18/346/"&gt;&lt;/g:plusone&gt;&lt;/div&gt;&lt;a href='http://twitter.com/share?url=http%3A%2F%2Fwp.me%2FsQ9on-346&amp;count=horizontal&amp;related=&amp;text=RE%3A%20The%20Pew%20Pew%20Manifesto' class='twitter-share-button' data-text='RE: The Pew Pew Manifesto' data-url='http://wp.me/sQ9on-346' data-counturl='http://jrfom.com/2012/06/18/346/' data-count='horizontal' data-via='jsumners79'&gt;&lt;/a&gt;&lt;img src="http://feeds.feedburner.com/~r/jrfom/cCSs/~4/nNrHdCPhW1U" height="1" width="1"/&gt;</content>
		<link rel="replies" type="text/html" href="http://jrfom.com/2012/06/18/346/#comments" thr:count="2" />
		<link rel="replies" type="application/atom+xml" href="http://jrfom.com/2012/06/18/346/feed/" thr:count="2" />
		<thr:total>2</thr:total>
	<feedburner:origLink>http://jrfom.com/2012/06/18/346/</feedburner:origLink></entry>
		<entry>
		<author>
			<name>James Sumners</name>
					</author>
		<title type="html"><![CDATA[WinLN &#8211; A Windows Symbolic Link Manager]]></title>
		<link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/jrfom/cCSs/~3/U-Sf8PUsF_w/" />
		<id>http://jrfom.com/?p=340</id>
		<updated>2012-05-23T18:07:42Z</updated>
		<published>2012-05-23T18:07:42Z</published>
		<category scheme="http://jrfom.com" term="C#" /><category scheme="http://jrfom.com" term="Code" /><category scheme="http://jrfom.com" term="Software" /><category scheme="http://jrfom.com" term="Technology" /><category scheme="http://jrfom.com" term="Windows" />		<summary type="html"><![CDATA[Prices on SSDs have been dropping fast lately. I&#8217;ve been wanting one for my gaming computer for some time, and one of the recent deals was very acceptible to me. Which is to say, I just added a new 250GB SSD to my gaming computer. Since I could fill up 250GB with all of my [...]]]></summary>
		<content type="html" xml:base="http://jrfom.com/2012/05/23/winln-a-windows-symbolic-link-manager/">&lt;p&gt;Prices on &lt;a href="https://en.wikipedia.org/wiki/Solid-state_drive"&gt;SSDs&lt;/a&gt; have been dropping fast lately. I&amp;#8217;ve been wanting one for my gaming computer for some time, and one of the recent deals was very acceptible to me. Which is to say, I just added a new 250GB SSD to my gaming computer. Since I could fill up 250GB with all of my games in a hurry, I decided to manage it a little bit differently. I am using &lt;a href="https://en.wikipedia.org/wiki/Symlink"&gt;symlinks&lt;/a&gt; from my existing installation locations to the new locations on my SSD for the games that I copy over.&lt;/p&gt;
&lt;p&gt;This works great. It doesn&amp;#8217;t matter how the games were installed. The game could have been installed via a traditional installer or via &lt;a href="http://steampowered.com/"&gt;Steam&lt;/a&gt;, they still work. I simply move the game from its installed location to my SSD, and then create a symlink from the SSD to the &amp;#8220;old&amp;#8221; install location, using the original directory name for the link name.&lt;/p&gt;
&lt;p&gt;There&amp;#8217;s a caveat to this, however. When I say &amp;#8220;gaming computer,&amp;#8221; what I really mean is &amp;#8220;Windows computer.&amp;#8221; Since Windows Vista, Windows has supported symlinks (took them long enough), but the &lt;a href="https://en.wikipedia.org/wiki/Command-line_interface"&gt;CLI&lt;/a&gt; for Windows is the worst ever invented. So I needed a way to manage these links easily. There are few GUI tools out there, but they all fall short in at least one of two ways:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;All of the ones I found that were open source were just frontends to the &lt;code&gt;mklink&lt;/code&gt; utility.&lt;/li&gt;
&lt;li&gt;None of them kept a history of the links they created.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Thus, I decided that I would have to write my own tool. That tool is &lt;a href="https://bitbucket.org/jsumners/winln/"&gt;WinLN&lt;/a&gt;. It&amp;#8217;s written against the &lt;a href="https://en.wikipedia.org/wiki/.NET_Framework"&gt;.NET Framework&lt;/a&gt; because writing a GUI for Windows any other way is worse than using a plastic spoon to dig out your own beating heart. It isn&amp;#8217;t much better with the .NET Framework, either. But it&amp;#8217;s done, and I think it works quite well. Enjoy.&lt;/p&gt;
&lt;div name="googleone_share_1" style="position:relative;z-index:5;float: right; margin-left: 10px;"&gt;&lt;g:plusone size="small" count="1" href="http://jrfom.com/2012/05/23/winln-a-windows-symbolic-link-manager/"&gt;&lt;/g:plusone&gt;&lt;/div&gt;&lt;a href='http://twitter.com/share?url=http%3A%2F%2Fwp.me%2FpQ9on-5u&amp;count=horizontal&amp;related=&amp;text=WinLN%20-%20A%20Windows%20Symbolic%20Link%20Manager' class='twitter-share-button' data-text='WinLN - A Windows Symbolic Link Manager' data-url='http://wp.me/pQ9on-5u' data-counturl='http://jrfom.com/2012/05/23/winln-a-windows-symbolic-link-manager/' data-count='horizontal' data-via='jsumners79'&gt;&lt;/a&gt;&lt;img src="http://feeds.feedburner.com/~r/jrfom/cCSs/~4/U-Sf8PUsF_w" height="1" width="1"/&gt;</content>
		<link rel="replies" type="text/html" href="http://jrfom.com/2012/05/23/winln-a-windows-symbolic-link-manager/#comments" thr:count="0" />
		<link rel="replies" type="application/atom+xml" href="http://jrfom.com/2012/05/23/winln-a-windows-symbolic-link-manager/feed/" thr:count="0" />
		<thr:total>0</thr:total>
	<feedburner:origLink>http://jrfom.com/2012/05/23/winln-a-windows-symbolic-link-manager/</feedburner:origLink></entry>
	</feed>
