<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Krotscheck.net</title>
	<atom:link href="http://www.krotscheck.net/feed" rel="self" type="application/rss+xml" />
	<link>http://www.krotscheck.net</link>
	<description></description>
	<lastBuildDate>Tue, 04 Dec 2012 00:26:33 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=</generator>
		<item>
		<title>JS-Maven Roundup and Roadmap</title>
		<link>http://www.krotscheck.net/2012/04/04/js-maven-roundup-and-roadmap.html</link>
		<comments>http://www.krotscheck.net/2012/04/04/js-maven-roundup-and-roadmap.html#comments</comments>
		<pubDate>Wed, 04 Apr 2012 17:51:37 +0000</pubDate>
		<dc:creator>Michael Krotscheck</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[js-maven]]></category>
		<category><![CDATA[js-maven-plugin]]></category>
		<category><![CDATA[jsdoc]]></category>
		<category><![CDATA[maven]]></category>

		<guid isPermaLink="false">http://www.krotscheck.net/?p=2334</guid>
		<description><![CDATA[To those of you who&#8217;ve been paying attention to the original project on GitHub, you&#8217;ve probably noticed that there&#8217;ve been a lot of changes there recently without any subsequent updates here. I&#8217;d like to take a moment to summarize what<span class="ellipsis">&#8230;</span><div class="read-more"><a href="http://www.krotscheck.net/2012/04/04/js-maven-roundup-and-roadmap.html">Read more &#8250;</a></div><!-- end of .read-more -->]]></description>
				<content:encoded><![CDATA[<p>To those of you who&#8217;ve been paying attention to the original project on GitHub, you&#8217;ve probably noticed that there&#8217;ve been a lot of changes there recently without any subsequent updates here. I&#8217;d like to take a moment to summarize what we&#8217;ve been up to, and keep everyone in the loop on where we&#8217;re going.</p>
<p>Inevitably as you start into a project you realize the full scope of what you&#8217;re trying to do, and as you do the finish line moves farther and farther towards the horizon. Most of the changes made were in respect to that.</p>
<h3>js-maven-plugin is now js-maven</h3>
<p>I renamed and moved the project because it was rapidly growing beyond the scope of a single maven plugin to include core libraries, tooling, archetypes and reports. Rather than try to hammer all these into one single java project I felt that switching over to a multi-module layout would give me the room I needed to grow. So far this seems to have been a good decision, as I now have the sense that I can (mentally) stretch my arms a little.</p>
<h3>No more specific version commitments.</h3>
<p>I&#8217;m making a concession to my own prioritization style here, which is very much a &#8220;Hey, this sounds like an interesting problem to solve&#8221; method. Needless to say, this doesn&#8217;t really work well with preplanned version releases, as there are some projects that are more fun and some that are less fun, and it resulted in me skipping around a lot. Instead, until I&#8217;ve got a few more contributors on the project, I&#8217;m simply going to outline a feature set for the various point versions and go after features as they strike me.</p>
<p>I understand that for an enterprise this is not the most optimal approach, so I will make this suggestion: If a particular feature is business critical enough for you to write your own solution, why not contribute it while you&#8217;re at it?</p>
<h3>Documentation!</h3>
<p>I&#8217;ve finally gotten around to setting up all the maven:site documentation for the project, and it&#8217;s now hosted on github&#8217;s pages for the project <a href="http://krotscheck.github.com/js-maven/">http://krotscheck.github.com/js-maven/</a> . Similarly, the README.md on github has been reduced to a quick start (since we know we all prefer copy/paste), as I don&#8217;t feel that much more was necessary.</p>
<h3>Version Dependencies</h3>
<p>We now support Maven 3 and Java 1.7 only. Annoying for some of you, yes, however in keeping with my philosophy of using the latest-and-greatest whenever possible we&#8217;re just going to put a line in the sand. That&#8217;s not to say we won&#8217;t ever support other versions, however those ports will have to come from the community (such as it is).</p>
<h3>Licensing</h3>
<p>I&#8217;m still debating licenses. Right now the project is under the MIT license, though I might move it over to New BSD. This project will <b><i>never</i></b> be licensed under the GPL or any similar viral/copyleft license, as those tend to greatly inhibit adoption.</p>
<h3>Roadmap Commitments for v0.2.0</h3>
<p>If you&#8217;ll take a look at the <a href="http://krotscheck.github.com/js-maven/roadmap.html">roadmap</a>, you&#8217;ll see the list of features which I want to have ready for the next minor version release. Notable additions were the reporting plugins for JSLint and JSDoc, as it didn&#8217;t make much sense to me to include those without making them accessible either. Here&#8217;s a list of where we stand right now, with some details:</p>
<h4>Plugin Documentation [branch- <a href="https://github.com/krotscheck/js-maven/tree/jsdoc-improvements">jsdoc-improvments</a>]</h4>
<p>Now that I&#8217;ve got the maven site reports running, they decided to get all unruly and hurt my feelings by insulting my coding style. The inevitable cleanup phase is in progress, which also includes a bit of judicious refactoring as the actual usability of the plugin gets a little focus.</p>
<h4>Cleanup</h4>
<p>As this is my first large maven plugin project, I&#8217;m still learning my way around. Refactoring and cleanup is necessary &#8211; for example, sourceEncoding should be handled via the global parameter and not individually per Mojo.</p>
<h4>Maven Reports: JSLint and JSDoc</h4>
<p>These are two new features I realized would be necessary as I got the site up and running. I&#8217;m not at all familiar how plugins like this get wired into maven as a whole, so they might go fast or they might not.</p>
<h4>Common JS Libraries in a repository [branch- <a href="https://github.com/krotscheck/js-maven/tree/jslib-redeploy-plugin">jslib-redeploy-plugin</a>]</h4>
<p>Having a javascript maven framework isn&#8217;t much use if you don&#8217;t have any libraries that you can depend on, so I&#8217;m writing a plugin that&#8217;ll take a URI-styled token string and will redeploy any artifacts found into a maven repository. This is proving tricky as I cannot resolve their own version dependencies easily (jqueryUI -&gt; jquery for instance), however it&#8217;s coming along nicely. Once this is complete I&#8217;ll be able to provide a few more archetypes for other projects. jQuery, JavascriptMVC, you name it.</p>
<h4>Unit Testing</h4>
<p>I&#8217;m still evaluating the best javascript unit testing framework out there. There are many solutions for &#8220;How to test a javascript library in different javascript engines and/or browsers, but nobody seems to have figured out the holy grail yet. This feature might get punted into its own release, if it turns out that the scope is too big.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.krotscheck.net/2012/04/04/js-maven-roundup-and-roadmap.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Building a JSDoc Runner for Maven</title>
		<link>http://www.krotscheck.net/2012/02/03/building-a-jsdoc-runner-for-maven.html</link>
		<comments>http://www.krotscheck.net/2012/02/03/building-a-jsdoc-runner-for-maven.html#comments</comments>
		<pubDate>Fri, 03 Feb 2012 05:10:40 +0000</pubDate>
		<dc:creator>Michael Krotscheck</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[js-maven]]></category>
		<category><![CDATA[js-maven-plugin]]></category>
		<category><![CDATA[jsdoc]]></category>
		<category><![CDATA[maven]]></category>

		<guid isPermaLink="false">http://www.krotscheck.net/?p=2326</guid>
		<description><![CDATA[The next step in this plugin is to ensure that we can generate documentation. While it may seem like a stretch to do this so early in the process, it forces us to build a few other pieces that we&#8217;ll<span class="ellipsis">&#8230;</span><div class="read-more"><a href="http://www.krotscheck.net/2012/02/03/building-a-jsdoc-runner-for-maven.html">Read more &#8250;</a></div><!-- end of .read-more -->]]></description>
				<content:encoded><![CDATA[<p>The next step in this plugin is to ensure that we can generate documentation. While it may seem like a stretch to do this so early in the process, it forces us to build a few other pieces that we&#8217;ll need later.</p>
<p>Our documentation generator will be JSDoc, chosen because it&#8217;s fairly mature, has a strong following, and its markup is broadly supported across IDE&#8217;s. In fact JSDoc seems to be one of the few broadly adopted standards out there, though to speculate why is beyond the scope of this post. What matters is that it&#8217;s a documentation writer written in Javascript that is run via Mozilla&#8217;s Rhino runtime. To properly run it we&#8217;ll have to resolve the dependency, unpack it into a temporary directory, and then spin up Rhino to execute the code.</p>
<p>I encountered a problem in the way JSDoc 2.4.0 interacts with Rhino 1.7RC3, a bug introduced by two inline function declarations without semicolons in TokenParser.js. While on one side one might argue that this is a bug in Rhino, declaring functions inside of other functions is a big no-no in the javascript world. As a result I&#8217;ve had to generate and deploy my own patched version of JSDoc.</p>
<h3>Resolving JSDoc</h3>
<p>All of the plugin artifacts for a given mojo are easily available as a parameter, thus locating the proper version of JSDoc is fairly simple.</p>
<div class="code">
<p><a href="https://github.com/krotscheck/js-maven">Full source available on github</a></p>
<pre>
/**
 * @parameter default-value="${plugin.artifacts}"
 */
private List&lt;Artifact&gt; pluginArtifacts;

public Artifact locate(String groupId, String artifactId) {

	getLog().info("Resolving " + groupId + ":" + artifactId);

	for (Iterator&lt;Artifact&gt; iterator = pluginArtifacts.iterator(); iterator.hasNext();) {
		Artifact artifact = (Artifact) iterator.next();

		if (artifact.getGroupId().equals(groupId) &#038;&#038; artifact.getArtifactId().equals(artifactId)) {
			return artifact;
		}
	}

	getLog().error(String.format("Failed to locate %s:%s", groupId, artifactId));
	getLog().error("This probably means that you didn't specify it as a dependency in the pom.xml file");

	throw new RuntimeException(String.format("Failed to locate %s:%s", groupId, artifactId));
}
</pre>
</div>
<h3>Unpacking JSDoc</h3>
<p>As all jar files are zip files, we can simply write a zip extraction routine to unpack it.</p>
<div class="code">
<p><a href="https://github.com/krotscheck/js-maven">Full source available on github</a></p>
<pre>
ZipFile zipFile = new ZipFile(artifact.getFile(), ZipFile.OPEN_READ);
Enumeration zipFileEntries = zipFile.entries();

while (zipFileEntries.hasMoreElements()) {
	ZipEntry entry = (ZipEntry) zipFileEntries.nextElement();

	// Construct the new name
	String currentName = entry.getName();
	File destFile = new File(destinationDirectory, currentName);

	if (entry.isDirectory()) {
		// If we are a directory, create it.
		destFile.mkdirs();
	} else {
		// If we're a file, unzip it.
		BufferedInputStream is = new BufferedInputStream(zipFile.getInputStream(entry));
		int currentByte;

		// establish buffer for writing file
		byte data[] = new byte[BUFFER];

		// write the current file to disk
		FileOutputStream fos = new FileOutputStream(destFile);
		BufferedOutputStream dest = new BufferedOutputStream(fos, BUFFER);

		// read and write until last byte is encountered
		while ((currentByte = is.read(data, 0, BUFFER)) != -1) {
			dest.write(data, 0, currentByte);
		}
		dest.flush();
		dest.close();
		is.close();
	}
}
</pre>
</div>
<h3>Configure JSDoc</h3>
<p>At this point we&#8217;re back in the drudgery of maven configuration. Since we&#8217;d like to keep our configurations relatively separate (in a &lt;jsdoc&gt; sub tag in the mojo configuration), I&#8217;ve created a separate JSDocOptions class that can accept all of our options. I&#8217;m not going to bother copying it all here as there&#8217;s quite a bit of code, but you can see the <a href="https://github.com/krotscheck/js-maven" target="_blank">full source code</a> here.</p>
<h3>Running JSDoc via Rhino</h3>
<p>Lastly, we have to execute JSDoc, which is done via Rhino. This, again, is fairly straightforward.</p>
<div class="code">
<p><a href="https://github.com/krotscheck/js-maven">Full source available on github</a></p>
<pre>
public void run(File inputDirectory, File outputDirectory, JSDocOptions options)
	throws JSDocRunnerException
{
	// Build the string arguments.
	String[] args = options.buildArguments(jsDocRoot, inputDirectory, outputDirectory);

	// Run the javascript engine.
	getLog().info("Building JSDoc...");

	// Create our logging streams
	MojoLoggerOutputStream errorStream = new MojoLoggerOutputStream(LogLevel.ERR);
	Main.setErr(new PrintStream(errorStream));

	MojoLoggerOutputStream outputStream = new MojoLoggerOutputStream(LogLevel.WARN);
	Main.setOut(new PrintStream(outputStream));

	Main.main(args);
	getLog().info("Complete");

}
</pre>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.krotscheck.net/2012/02/03/building-a-jsdoc-runner-for-maven.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Building a Javascript Dependency Resolver in Maven</title>
		<link>http://www.krotscheck.net/2012/01/27/building-a-javascript-dependency-resolver-in-maven.html</link>
		<comments>http://www.krotscheck.net/2012/01/27/building-a-javascript-dependency-resolver-in-maven.html#comments</comments>
		<pubDate>Sat, 28 Jan 2012 04:00:25 +0000</pubDate>
		<dc:creator>Michael Krotscheck</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[aether]]></category>
		<category><![CDATA[dependency]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[js-maven]]></category>
		<category><![CDATA[js-maven-plugin]]></category>
		<category><![CDATA[maven]]></category>

		<guid isPermaLink="false">http://www.krotscheck.net/?p=2324</guid>
		<description><![CDATA[Dependency resolution, to most javascript developers, means adding another &#60;script&#62; include in the header of their html page, and in most cases this is fine. In fact in 95% of any javascript applications you don&#8217;t even have to host this<span class="ellipsis">&#8230;</span><div class="read-more"><a href="http://www.krotscheck.net/2012/01/27/building-a-javascript-dependency-resolver-in-maven.html">Read more &#8250;</a></div><!-- end of .read-more -->]]></description>
				<content:encoded><![CDATA[<p>Dependency resolution, to most javascript developers, means adding another &lt;script&gt; include in the header of their html page, and in most cases this is fine. In fact in 95% of any javascript applications you don&#8217;t even have to host this file- just include a link to <a href="http://jquery.com/" target="_blank">JQuery</a> on <a href="http://code.google.com/apis/libraries/" target="_blank">Google Libraries</a> and you won&#8217;t need to worry.</p>
<p>In the enterprise, however, different concerns start to take over. The project you&#8217;re working on might be dependent on an internal library built by another team, which is subsequently dependent on yet another library, and so on and so forth. As those libraries are incrementally updated, managing dependencies becomes a headache. Furthermore, the true power of javascript compilers like <a href="http://code.google.com/closure/" target="_blank">Google Closure</a> are realized when all of the code is available at compile time. In fact, both the Simple and Advanced optimization modes require it, as it teaches Closure which code isn&#8217;t used and may thus be discarded.</p>
<p>Maven already has a very mature <a href="http://www.sonatype.com/people/2010/08/introducing-aether/" target="_blank">dependency resolution mechanism</a> built into it, which is backed by a <a href="http://search.maven.org/" target="_blank">large public repository</a> of common libraries. Javascript is still underrepresented in this arena, true, yet hopefully this plugin will eventually remedy that situation.</p>
<h3>Choosing Scope</h3>
<p>The maven dependency system requires a scope for each individual dependency to determine when it is needed in the build cycle. This is quite handy- you don&#8217;t for instance, want to have all the JUnit libraries be part of your final project compile, but you do want them available during the testing phase.</p>
<p>Similarly, Google&#8217;s closure compiler can process an external file (dependency) in two ways: Directly, immediately compiled into the final delivery source, and externally, files which are assumed to be self-contained and included in the final product via a different script tag. These two types of dependencies map rather nicely to Maven&#8217;s &#8220;compile&#8221; and &#8220;runtime&#8221; scope, however compiling a javascript file into a library causes complexity: If two libraries have the same compiled-in dependency, with different versions, perhaps even with different optimization levels, I run the risk of version and feature conflicts.</p>
<p>As a result, all of our dependencies will be treated as externals.</p>
<h3>Resolving a dependency graph</h3>
<p>The first step to building dependency resolution into my plugin requires constructing the dependency graph. Maven makes this (relatively) easy.</p>
<div class="code">
<p>Full source available on github: <a href="https://github.com/krotscheck/js-maven">DependencyResolver.java</a></p>
<pre>
private DependencyNode getDependencyGraph(Artifact rootArtifact)
        throws DependencyResolverException {
        try {
                Dependency rootDependency = new Dependency(rootArtifact, "compile");
                CollectRequest collectRequest = new CollectRequest(rootDependency,projectRepos);

                // Collect all the nodes
                CollectResult collectResult = repoSystem.collectDependencies(repoSession, collectRequest);
                return collectResult.getRoot();
        } catch (DependencyCollectionException e) {
                throw new DependencyResolverException("Cannot build project dependency graph", e);
        }
}
</pre>
</div>
<h3>Filtering dependencies by scope and extension</h3>
<p>Now that I have a graph of dependency relationships, I should now visit each node and only collect those nodes that match our required scopes. Since I&#8217;ll also use this extension for resolving jsunit, envjs or others, it behooves me to abstract it.</p>
<div class="code">
<p>Full source available on github: <a href="https://github.com/krotscheck/js-maven">DependencyResolver.java</a></p>
<pre>
public List&lt;Artifact&gt; resolve(String scope, String extension)
                throws DependencyResolverException {

        getLog().debug("Resolving dependencies: [scope:" + scope + "] [extension:"  + extension + "]");
        // Construct the dependency tree of our project.
        Artifact rootArtifact = new DefaultArtifact(project.getGroupId(),
                project.getArtifactId(), project.getPackaging(),
                project.getVersion());
        DependencyNode rootNode = this.getDependencyGraph(rootArtifact);

        // Gather dependency nodes in post order
        PostorderNodeListGenerator postOrderVisitor = new PostorderNodeListGenerator();

        // Filter out the root node.
        DependencyVisitor visitor = new FilteringDependencyVisitor(
                postOrderVisitor, new PatternExclusionsDependencyFilter(
                        rootArtifact.toString()));

        // If a scope is configured, add a scope filter.
        if (null != scope) {
                visitor = new FilteringDependencyVisitor(visitor,
                                new ScopeDependencyFilter(scope));
        }

        // If a type is configured, add a pattern exclusion filter
        if (null != extension) {
                String patternFilter = "*:*:" + extension + ":*";
                visitor = new FilteringDependencyVisitor(visitor,
                                new PatternInclusionsDependencyFilter(patternFilter));
        }

        // Run the collection.
        rootNode.accept(visitor);
        return postOrderVisitor.getArtifacts(true);
}
</pre>
</div>
<h3>Resolving dependencies</h3>
<p>As it turns out, maven dependencies may, or may not, be resolved. In practice this means that the system won&#8217;t bother to download the file until it&#8217;s actually needed, so we have to do it manually. The new Aether Dependency API in Maven3 means that artifacts are immutable, so we have to make a copy of each.</p>
<div class="code">
<p>Full source available on github: <a href="https://github.com/krotscheck/js-maven">DependencyResolver.java</a></p>
<pre>
        List&lt;Artifact&gt; unresolvedArtifacts = postOrderVisitor.getArtifacts(true);
        List&lt;Artifact&gt; resolvedArtifacts = new ArrayList&lt;Artifact&gt;();

        for (Iterator&lt;Artifact&gt; iterator = unresolvedArtifacts.iterator(); iterator.hasNext();) {
                Artifact artifact = iterator.next();
                ArtifactRequest artifactRequest = new ArtifactRequest(artifact,projectRepos, null);
                ArtifactResult artifactResult = repoSystem.resolveArtifact(repoSession, artifactRequest);
                getLog().debug(" + " + artifactResult.getArtifact().toString());
                resolvedArtifacts.add(artifactResult.getArtifact());
        }
        return resolvedArtifacts;
</pre>
</div>
<h3>Including dependencies in our compiler</h3>
<p>With a list of resolved dependency artifacts in hand, I can now include them in the compile method from the last post.</p>
<div class="code">
<p>Full source available on github: <a href="https://github.com/krotscheck/js-maven">JSLibraryCompilerMojo.java</a></p>
<pre>
        // Generate any externals that we need.
        List&lt;JSSourceFile&gt; externs = new ArrayList&lt;JSSourceFile&gt;();
        getLog().info("Resolving External Includes...");
        externs.addAll(resolveDependencies("compile","js"));

        // Generate the list of source files to include.
        List&lt;JSSourceFile&gt; source = new ArrayList&lt;JSSourceFile&gt;();
        getLog().info("Resolving Compile Includes...");
        source.addAll(generateJavascriptSourceList());
</pre>
</div>
<p>And there we are! We are now resolving dependencies from other javascript libraries that live in your, or someone else&#8217;s, maven repository.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.krotscheck.net/2012/01/27/building-a-javascript-dependency-resolver-in-maven.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Building a Javascript Compiler for Maven</title>
		<link>http://www.krotscheck.net/2012/01/25/building-a-javascript-compiler-for-maven.html</link>
		<comments>http://www.krotscheck.net/2012/01/25/building-a-javascript-compiler-for-maven.html#comments</comments>
		<pubDate>Wed, 25 Jan 2012 15:25:22 +0000</pubDate>
		<dc:creator>Michael Krotscheck</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[closure]]></category>
		<category><![CDATA[compression]]></category>
		<category><![CDATA[google]]></category>
		<category><![CDATA[js-maven]]></category>
		<category><![CDATA[js-maven-plugin]]></category>
		<category><![CDATA[maven]]></category>
		<category><![CDATA[optimization]]></category>

		<guid isPermaLink="false">http://www.krotscheck.net/?p=2317</guid>
		<description><![CDATA[This post is one in a series where I slowly assemble a Maven workflow for large javascript projects. If you came here via google, I recommend starting at the beginning: Designing a Javascript Maven Plugin. Alternatively, you can just go<span class="ellipsis">&#8230;</span><div class="read-more"><a href="http://www.krotscheck.net/2012/01/25/building-a-javascript-compiler-for-maven.html">Read more &#8250;</a></div><!-- end of .read-more -->]]></description>
				<content:encoded><![CDATA[<div class="callout">
<p>This post is one in a series where I slowly assemble a Maven workflow for large javascript projects. If you came here via google, I recommend starting at the beginning: <a href="http://www.krotscheck.net/2012/01/22/designing-a-javascript-maven-plugin.html" title="Designing a Javascript Maven Plugin">Designing a Javascript Maven Plugin</a>. Alternatively, you can just go directly to the <a href="https://github.com/krotscheck/js-maven">js-maven</a> project on github.</p>
</div>
<p>Since there’s no sense in rebuilding something that already exists, I decided to start with <a href="http://code.google.com/closure/compiler/">google’s excellent closure compiler</a> as a baseline, and simply write a maven wrapper around it. There’s nothing inherently wrong with the <a href="http://developer.yahoo.com/yui/compressor/">YUI Compressor</a>; It’s quite a nice compressor. In the light of supporting more use cases, however, I feel that a compiler with more optimization options would be a better choice, especially since all of those options are individually configurable.</p>
<p>However before I wrote the plugin, there are a few things I had to take into consideration:</p>
<ol>
<li>Developers should be able to debug while developing. This means that the compiled code needs to be human readable.</li>
<li>Optimization may impact code function, so the compiled code should be optimized.</li>
<li>Once packaged, the code should be minified.</li>
</ol>
<p>In practice, this means two compiler passes over the source code. The first is to perform code optimizations, yet provide a human readable source file for debugging (in jetty, for instance). The second is to minify, but not optimize, shortly before the asset is packaged. This suggests the following steps for my Javascript Library lifecycle.</p>
<dl>
<dt><b>compile</b></dt>
<dd>net.krotscheck:js-maven-plugin:optimize-js-lib</dd>
<dt><b>prepare-package</b></dt>
<dd>net.krotscheck:js-maven-plugin:minify-js-lib</dd>
</dl>
<p>Given that with Google Closure two steps are practically identical, most of the functionality will be abstracted. This means I’ll effectively be running the compiler twice, not a problem unless a browser decides to throw errors on whitespace usage.</p>
<h3>The Compiler Plugin</h3>
<p>There are three steps to compiling using Closure. First we need to gather all of our source files, then we need to configure the compiler, and then we’ll run the compiler and output our source. There is a fourth step- gathering dependencies, which I’ll cover in a subsequent post. None of these steps are especially difficult. Here’s step one, finding all of our source code.</p>
<div class="code">
<p>Full source available on github: <a href="https://github.com/krotscheck/js-maven">JSLibraryCompilerMojo.java</a></p>
<pre>
/**
 * Location of the source directory.
 * 
 * @parameter expression="${project.build.sourceDirectory}"
 * @required
 */
protected File sourceDirectory;

/**
 * This method scans the configured source directory of the Mojo and returns all
 * javascript documents, filtering by extension.
 */
protected List&lt;JSSourceFile&gt; generateJavascriptSourceList() {
    ArrayList&lt;JSSourceFile&gt; sourceList = new ArrayList&lt;JSSourceFile&gt;();

    String[] extensions = { "js" };
    getLog().debug("Discovering Source Files");

    Collection&lt;File&gt; sourceFiles = FileUtils.listFiles(sourceDirectory, extensions, true);

    for (Iterator&lt;File&gt; iterator = sourceFiles.iterator(); iterator.hasNext();) {
         File file = (File) iterator.next();

        sourceList.add(JSSourceFile.fromFile(file));

        getLog().debug(" + " + file.getAbsolutePath());
    }

    return sourceList;
}
</pre>
</div>
<p>Here’s step two, writing our compiler configuration. Note that I consciously made the choice to reduce the complexity of what my users can alter for the sake of illustration; This is primarily done</p>
]]></content:encoded>
			<wfw:commentRss>http://www.krotscheck.net/2012/01/25/building-a-javascript-compiler-for-maven.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Designing a Javascript Maven Plugin</title>
		<link>http://www.krotscheck.net/2012/01/22/designing-a-javascript-maven-plugin.html</link>
		<comments>http://www.krotscheck.net/2012/01/22/designing-a-javascript-maven-plugin.html#comments</comments>
		<pubDate>Sun, 22 Jan 2012 23:11:33 +0000</pubDate>
		<dc:creator>Michael Krotscheck</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[js-maven-plugin]]></category>
		<category><![CDATA[maven]]></category>

		<guid isPermaLink="false">http://www.krotscheck.net/?p=2315</guid>
		<description><![CDATA[As mentioned in my previous post, I believe that the tooling for enterprise grade javascript applications is simply not there yet. What is needed is a set of tools, preferably open source, that are framework agnostic and that fit into<span class="ellipsis">&#8230;</span><div class="read-more"><a href="http://www.krotscheck.net/2012/01/22/designing-a-javascript-maven-plugin.html">Read more &#8250;</a></div><!-- end of .read-more -->]]></description>
				<content:encoded><![CDATA[<p>As mentioned in my previous post, I believe that the tooling for enterprise grade javascript applications is simply not there yet. What is needed is a set of tools, preferably open source, that are framework agnostic and that fit into established development practice. In this and the subsequent posts, I will walk you through the process of building just this toolset using the Maven as a framework to glue it all together.</p>
<h3>Overall Philosophy</h3>
<p>First and foremost, the toolset must be independent of the code that is written. We simply cannot have a compiler that will only work for JQuery, or a testing harness that will only work if the test artifacts are composited via Rake.</p>
<p>Furthermore, I would like to adhere to Java conventions as much as possible, by which I mean JSDoc, JUnit-style unit tests and so forth. Java is syntactically very close to Javascript and Java&#8217;s strong prevalence in the enterprise space will reduce engineer friction.</p>
<p>The project artifacts will be packaged in as close to a native file type as possible. This becomes tricky: For something like a Javascript Library, a simple minified .js file will do. For a full web application with images, media, html and more this will be trickier as the nature of the server will define one packaging type over another: Jetty/Tomcat will prefer a .jar file, Apache will serve up an uncompressed archive, and so forth.</p>
<p>When possible, we&#8217;re going to take advantage of the latest and greatest: CSS compilers, for instance.</p>
<h3>Why choose maven?</h3>
<p>Maven is an obvious choice for various reasons. Firstly, it enjoys broad IDE integration. Secondly, it has an extremely powerful plugin framework that allows a user to use entire groups of plugins or focus on only the ones they really need. Thirdly, its dependency resolution mechanism is very powerful and very portable, which makes your builds extremely easy to bring to other platforms. Fourthly, it is open source and well supported by the community. Lastly, it enjoys broad support among continuous integration frameworks. All of these together make it a no-brainer to use as the core engine for our javascript toolset.</p>
<h3>What workflow steps are needed?</h3>
<p>Since maven defines a specific artifact lifecycle, we should start there and decide what we need our plugin to do. After starting to write this for a little bit however I realized that trying to declare it all up front is a significant undertaking, and should be split up by broader concepts:</p>
<ol>
<li>Compilation</li>
<li>Optimization</li>
<li>Unit Testing</li>
<li>Functional Testing</li>
<li>Packaging and Publishing</li>
<li>Dependency Resolution</li>
<li>Debug Runtime</li>
<li>Headless Runtime</li>
<li>PMD/Linting</li>
<li>Documentation</li>
<li>Reporting</li>
</ol>
<h3>Should we create an Archetype?</h3>
<p>The short answer: Yes. The long answer: Archetypes are absolutely critical to drive adoption, examples and acceptance, and are a very useful speed-of-workflow tool. Given the many different potential framework projects out there however, we&#8217;re going to have to create many of these; One for JQuery, one for Mootools, one for Backbone… you get the idea. So how about we worry about that once we get more pieces of the compiler in place.</p>
<h3>Where will the source live?</h3>
<p>I&#8217;m glad you asked! I&#8217;ll be <a href="https://github.com/krotscheck/js-maven">hosting the project on GitHub</a>. Please feel free to contribute!</p>
<h3>Where will the maven repository be?</h3>
<p>This is as yet undecided. For now I recommend you clone the project and install it locally. Once there&#8217;s enough functionality on the project to warrant a full point release, we&#8217;ll revisit this.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.krotscheck.net/2012/01/22/designing-a-javascript-maven-plugin.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>So long Actionscript, so long PHP.</title>
		<link>http://www.krotscheck.net/2012/01/21/so-long-actionscript-so-long-php.html</link>
		<comments>http://www.krotscheck.net/2012/01/21/so-long-actionscript-so-long-php.html#comments</comments>
		<pubDate>Sat, 21 Jan 2012 23:38:56 +0000</pubDate>
		<dc:creator>Michael Krotscheck</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[actionscript]]></category>
		<category><![CDATA[architecture]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://www.krotscheck.net/?p=2312</guid>
		<description><![CDATA[To those of you not keeping up with my career as a technologist, I&#8217;ve long since abandoned my Actionscript roots (PHP is in serious decline) in favor of Javascript and Java. There are many reasons for this: Industry movement away<span class="ellipsis">&#8230;</span><div class="read-more"><a href="http://www.krotscheck.net/2012/01/21/so-long-actionscript-so-long-php.html">Read more &#8250;</a></div><!-- end of .read-more -->]]></description>
				<content:encoded><![CDATA[<p>To those of you not keeping up with my career as a technologist, I&#8217;ve long since abandoned my Actionscript roots (PHP is in serious decline) in favor of Javascript and Java. There are many reasons for this: Industry movement away from Flash, a shift in implementation practices, and a personal desire to keep my own skill set fresh and interesting. Wait a sec… Java? Fresh and interesting? What am I smoking, right? Well, read on:</p>
<h3>Speed and Scalability</h3>
<p>If you&#8217;re working on smaller projects with no notable load, &#8220;popular&#8221; languages such as Ruby, PHP and Python are great; After all, they are optimized for developer productivity rather than runtime performance, and in 99% of all cases this is fine. This is the main reason they&#8217;re so popular in the startup scene, as they enable extremely rapid feature development as a business evolves to find its place in the world.</p>
<p>At some point, however, a designed system must perform at scale, and as most detailed examinations such as <a href="http://blog.gmarceau.qc.ca/2009/05/speed-size-and-dependability-of.html">this one</a> show, not all languages are created equal. Delivering software at that level in a language that has a poor performance profile changes the discussion entirely: If your system chokes, you lose business transactions, customer confidence, and reporting data, all of which translates into money. In short, the argument stops being about the salary of one or two additional engineers, and more about the reliability and maintainability of your codebase.</p>
<p>Not only have years of optimization made it a very reliable and performant platform, the religious arguments about What Is The Best Tooling™ out there have been had and are mostly over, with configuration winning out over convention every time. The IDE&#8217;s support it, Continuous Integration Environments support it, Unit Testing frameworks exist and are very mature, and even though the code itself is extremely verbose, shitty Java will still run faster than shitty Ruby. Mind you, the study in the post linked above was done several years ago, and I&#8217;m quite certain that the various languages have improved since, however given the lack of community trumpeting about oh-look-we-finally-beat-Java, I&#8217;m going to take that post as mostly-still-accurate.</p>
<h3>B2C vs. B2B</h3>
<p>The second big shift that happens at scale is a shift from a consumer-based business to a service-based business. Don&#8217;t get me wrong: Consumers are important, however onboarding more consumers is a linear function, and usually not a very steep one. Onboarding businesses to your platform, however, is an entirely different beast, as each new partnership could bring orders of magnitude of extra load to your system. Is this a provisioning problem? Yes, yet with it come a whole new set of problems: Will you need to provide authentication integration with their corporate LDAP system? Will you have to Whitelabel your service? Will you need to provide API support? A dedicated and/or isolated data cluster?</p>
<p>To be fair, these are language-agnostic architectural problems, ones which encourage a clear separation of UI and API layer, forcing all business logic into the latter. Websites in this system are simply UI clients and serve no purpose other than making the API human-friendly (not to be discounted- UX is super important).</p>
<p>Now that the UI is simply a facade, does it really make sense to render it on a server before sending it back to a client? Let me illustrate with an example:</p>
<p>Consider a website written in PHP that consumes an API.</p>
<ol>
<li>I visit this website</li>
<li>The Application Server makes an API call</li>
<li>The API returns the data</li>
<li>Application Server Renders the data.</li>
<li>Browser renders the HTML</li>
<li>I get my html</li>
</ol>
<p>Now consider a website written mostly in Javascript that consumes an API:</p>
<ol>
<li>I visit this website</li>
<li>Browser calls the API</li>
<li>The API returns the data</li>
<li>Browser renders the HTML</li>
</ol>
<p>See the difference? In the former case, you&#8217;ve got two times as many network transactions (added points of failure), and the additional cost of maintaining an application server. In the latter case, you can host the files on a glorified hard drive (S3 for instance) and are talking to the API directly.</p>
<h3>But Javascript Sucks!</h3>
<p>It really doesn&#8217;t: Javascript is an amazing, powerful language that is hamstrung by browsers, an outdated standards body, and a lack of a unified toolset.</p>
<p>Thankfully, browsers are starting to come around (Chrome at the lead) and implementation difference are starting to be eroded. Most of the javascript libraries out there (such as JQuery) don&#8217;t seem to have caught up to this fact yet, and are still rooted in the philosophy that they can only work for what works everywhere &#8211; no worries, they&#8217;ll evolve soon enough if their communities will let them.</p>
<p>The current arguments between the WhatWG and the W3C are obvious to anyone in our industry, and different business philosophies between browser vendors make sites like caniuse.com an unfortunate necessity. Add to that the never-ending political maneuvering in the ECMAScript standardization process, and javascript will forever be a bastard child of 5 different parents each telling it to follow a different career. Having said that, Google has successfully used Chrome as a strategic tool that established a de-facto standard, forcing other vendors to catch up.</p>
<p>Javascript tooling is still in its infancy, and many tools out there have not yet grown beyond themselves. Take, for instance, a unit testing framework like QUnit that is sadly dependent on JQuery, or a functional testing framework like Lebowski which is inexorably tied to Ruby and Sproutcore. Furthermore, many frameworks are differentiated by philosophical differences (take QUnit vs Jasmine for instance) which muddies the water even more. Lastly, even with a plethora of tools, nobody has managed to wrap it all into one single, cohesive whole that combines Formatting, PMD/Linting, Unit Testing, Functional Testing, Documentation and Optimization.</p>
<p>However… the tools are (mostly) all there, individually. JSDoc has become a de-facto standard. Google&#8217;s Closure compiler is mostly platform agnostic, drawing most of its cues from JSDoc. Jasmine could be your one-size-fits-all Unit Testing framework (assuming you like behavioral testing), and JSTD is a powerful testing framework that can be used for either unit or functional testing (It&#8217;d be even more powerful if the various browser runtime engines could be run headlessly like Mozilla&#8217;s Rhino). All it takes is for some enterprising individual to put them all together.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.krotscheck.net/2012/01/21/so-long-actionscript-so-long-php.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Database Upgrades and Migrations with Adobe AIR</title>
		<link>http://www.krotscheck.net/2011/01/13/database-upgrades-and-migrations-with-adobe-air.html</link>
		<comments>http://www.krotscheck.net/2011/01/13/database-upgrades-and-migrations-with-adobe-air.html#comments</comments>
		<pubDate>Thu, 13 Jan 2011 15:16:15 +0000</pubDate>
		<dc:creator>Michael Krotscheck</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[actionscript]]></category>
		<category><![CDATA[database]]></category>
		<category><![CDATA[flex]]></category>
		<category><![CDATA[migration]]></category>
		<category><![CDATA[sqlite]]></category>

		<guid isPermaLink="false">http://www.krotscheck.net/2011/01/13/database-upgrades-and-migrations-with-adobe-air.html</guid>
		<description><![CDATA[This post will show you how to update your SQLite application when you release a new version of your AIR application (Android or otherwise). For those of you who are impatient, just copy the two classes provided and use them<span class="ellipsis">&#8230;</span><div class="read-more"><a href="http://www.krotscheck.net/2011/01/13/database-upgrades-and-migrations-with-adobe-air.html">Read more &#8250;</a></div><!-- end of .read-more -->]]></description>
				<content:encoded><![CDATA[<p>This post will show you how to update your SQLite application when you release a new version of your AIR application (Android or otherwise). For those of you who are impatient, just copy the two classes provided and use them as demonstrated at the end of the post (or roll your own, your choice).</p>
<p>When releasing a new version of an AIR application that makes use of SQLite, it&#8217;s often necessary to upgrade the schema for that database as well. While taking a Hail Mary approach to the problem and just deleting the old database may work for some, it&#8217;s not an elegant option and will ensure that you can never persist data between versions. Instead, creating a way for your application to gracefully migrate its own database to the most recent version will ensure that your local data is not compromised, providing a smooth and seamless experience for the end user.</p>
<h3>The Concept</h3>
<p>We know that a database is the accumulation of all the CREATE, UPDATE and DELETE statements that have come before it. This means it may be easily represented and reconstructed by an <strong><em>ordered</em></strong> sequence of SQL files. It then becomes our task to manage which SQL files have already been executed in a given application version, and to execute (in order) those files which have not.</p>
<p>To accomplish this, we do the following:</p>
<ol>
<li>We create a migration table within your database in which we store which scripts have been executed.</li>
<li>We check each script against this table before we run it.</li>
</ol>
<p>There are other optimizations we can perform, however for this case we&#8217;re going to keep the idea simple.</p>
<h3>Part 1: The Migration Class</h3>
<p>The Migration class is a simple value container that contains your SQL Script as well as a Unique ID. Both of these are derivatives, since we want to give options on how to include the SQL file, and we don&#8217;t want to make our users have to think too much about how to set up a migration.</p>
<div class="code">
<pre>
package com.fancybrandname.core.db
{
        import com.adobe.crypto.MD5;
        import com.fancybrandname.core.utils.LogUtil;

        import flash.data.SQLConnection;
        import flash.data.SQLStatement;
        import flash.errors.IllegalOperationError;

        import mx.logging.ILogger;

        /**
         * A specific database migration instance. It should contain both a version
         * and an embedded SQL source file that will be executed against the database.
         *
         * @author Michael Krotscheck
         */
        public class Migration
        {
                /**
                 * Logger
                 */
                private static const LOG : ILogger = LogUtil.getLogger( Migration );

                /**
                 * The SQL Source to use for this migration.
                 */
                private var _source : *;

                /**
                 * The SQL Statement extracted from the SQL Source object.
                 */
                private var _sqlStatement : String;

                /**
                 * This is the unique version key we use to identify this particular migration.
                 */
                private var _versionKey : String;

                /**
                 * The SQL Source to use for this migration.
                 */
                public function get source () : *
                {
                        return _source;
                }

                /**
                 * @private
                 */
                public function set source ( value : * ) : void
                {
                        _source = value;

                        // Here we attempt to extract the SQL statement from the passed object. If 
                        // the object is a Class (as with the @Embed directive), we instantiate and convert it.
                        // If it's anything else we try to invoke the toString method, and throw an error if we
                        // can't find it.
                        if ( _source is Class )
                        {
                                _sqlStatement = ( new _source() ).toString();
                        }
                        else
                        {
                                try
                                {
                                        _sqlStatement = _source.toString();
                                }
                                catch ( e : Error )
                                {
                                        throw new IllegalOperationError( 'Unrecognized type for SQL Migration. Please use Embeds or Strings' );
                                }
                        }

                        // Now we generate a unique ID from this string.
                        // You could request this key manually so that you don't have a dependency
                        // on the adobe crypto library, but I prefer doing it this way.
                        _versionKey = MD5.hash( sqlStatement );
                }

                /**
                 * This is the unique version key we use to identify this particular migration.
                 *
                 * @read-only
                 */
                public function get versionKey () : String
                {
                        return _versionKey;
                }

                /**
                 * This is the unique version key we use to identify this particular migration.
                 *
                 * @read-only
                 */
                public function get sqlStatement () : String
                {
                        return _sqlStatement;
                }

                /**
                 * Constructor.
                 */
                public function Migration ()
                {
                }
        }
}
</pre>
</div>
<h3>Step 2: The Migration Manager</h3>
<p>Our migration manager does the heavy lifting for this class, by checking the database for the last applied migration key and only applying those keys that come after it. It assumes several things. Firstly, that the migrations are in order of execution. Secondly, that the SqlConnection instance passed to it is a synchronous, not asynchronous connection. This method would definitely work for asynchronous connections, however you&#8217;d have to adjust the class to iterate using eventListeners. I leave this as an exercise to the reader.</p>
<div class="code">
<pre>package com.fancybrandname.core.db
{
	import flash.data.SQLConnection;
	import flash.data.SQLResult;
	import flash.data.SQLStatement;
	import flash.errors.IllegalOperationError;
	import flash.errors.SQLError;
	
	/**
	 * This metadata sets the default property for child nodes used in MXML. This
	 * makes MXML markup a lot easier to understand.
	 */
	[DefaultProperty( &quot;migrations&quot; )]
	/**
	 * A simple class that assists in managing multiple SQL files that may need
	 * to be run against a locally stored database. It makes the assumption
	 * that the migrations must be executed in the order in which they are provided,
	 * and that the database starts &quot;clean&quot; and untouched.
	 *
	 * @author Michael Krotscheck
	 */
	public class MigrationManager
	{
		
		/**
		 * The SQL Connection to use to connect to the database and check for migration.
		 */
		public var sqlConnection : SQLConnection;
		
		/**
		 * The migrations to run against the database. These must be in order of execution.
		 */
		public var migrations : Vector.&lt;Migration&gt; = new Vector.&lt;Migration&gt;();
		
		/**
		 * The name of the table within the database to store the migrations in.
		 */
		public var tableName : String = 'migration';
		
		/**
		 * Constructor
		 */
		public function MigrationManager ( sqlConnection : SQLConnection = null )
		{
			this.sqlConnection = sqlConnection;
		}
		
		/**
		 * This method runs the database migrations.
		 */
		public function migrate () : void
		{
			// Can we migrate?
			if ( !sqlConnection )
			{
				throw new IllegalOperationError( 'No SQLConnection provided' );
				return;
			}
			
			try
			{
				// Make sure the migration table exists.
				createMigrationTable();
				
				// Get the last version key applied to the database.
				var lastVersionKey : String = getLastVersionKey();
				
				// Iterate through our collection and execute every script AFTER the version key we found.
				var len : int = migrations.length;
				
				// Switch to let us know whether the last version key was found.
				// If the last version key is empty, apply all of them.
				var lastKeyFound : Boolean = lastVersionKey == '' ? true : false;
				
				for ( var i : int = 0; i &lt; len; i++ )
				{
					var currentMigration : Migration = migrations[ i ];
					
					if ( lastKeyFound )
					{
						apply( currentMigration );
					}
					else if ( currentMigration.versionKey == lastVersionKey )
					{
						lastKeyFound = true;
					}
				}
			}
			catch ( e : SQLError )
			{
				throw( e );
			}
		}
		
		/**
		 * This method creates the migration table if it doesn't exist yet.
		 */
		private function createMigrationTable () : void
		{
			var sql : String = 'CREATE TABLE IF NOT EXISTS ' + tableName + ' (version varchar(32) NOT NULL PRIMARY KEY, applied_on timestamp NOT NULL);';
			
			var statement : SQLStatement = new SQLStatement();
			statement.sqlConnection = sqlConnection;
			statement.text = sql;
			statement.execute();
		}
		
		/**
		 * This method gets the last version key recorded in the database.
		 */
		private function getLastVersionKey () : String
		{
			var statement : SQLStatement = new SQLStatement();
			statement.text = 'SELECT version FROM ' + tableName + ' ORDER BY applied_on DESC LIMIT 0,1';
			statement.sqlConnection = sqlConnection;
			statement.execute();
			
			var sqlResult : SQLResult = statement.getResult();
			
			if ( sqlResult == null || !sqlResult.data || sqlResult.data.length == 0 )
			{
				// No migrations found.
				return '';
			}
			else
			{
				// We found one, return it.
				return sqlResult.data[ 0 ].version;
			}
		}
		
		/**
		 * This method applies the database migration to the database passed to this function.
		 * Please note that this version of the class only works with Synchronous SQLConnections.
		 */
		private function apply ( migration : Migration ) : void
		{
			// Apply the migration
			var updateStatement : SQLStatement = new SQLStatement();
			updateStatement.text = migration.sqlStatement;
			updateStatement.sqlConnection = sqlConnection;
			updateStatement.execute();
			
			// Update the version key
			var versionStatement : SQLStatement = new SQLStatement();
			versionStatement.text = 'INSERT INTO ' + tableName + ' (version, applied_on) VALUES ( :version , :timestamp )';
			versionStatement.parameters[ ':version' ] = migration.versionKey;
			versionStatement.parameters[ ':timestamp' ] = ( new Date() ).getTime();
			versionStatement.sqlConnection = sqlConnection;
			versionStatement.execute();
		}
	}
}</pre>
</div>
<h3>Step 3: Usage</h3>
<p>Finally it&#8217;s time to use our class. As you can see the MXML markup is pretty straightforwar, and usage in ActionScript is similarly easy. Note that I&#8217;m using both @Embed directives and raw text, and pay particular attention to the embed mime-type. Without it, this doesn&#8217;t really work.</p>
<div class="code">
<pre>&lt;s:Application 
	xmlns:fx="http://ns.adobe.com/mxml/2009"
	xmlns:parsley="http://www.spicefactory.org/parsley"
	xmlns:s="library://ns.adobe.com/flex/spark"
	xmlns:db="com.fancybrandname.core.db.*"
	&gt;
	&lt;fx:Script&gt;
		&lt;![CDATA[
			override protected function initializationComplete():void
			{
				super.initializationComplete();
				
				var dbFile :File = File.applicationStorageDirectory.resolvePath('myDb.db');
				var connection :SQLConnection = new SQLConnection();
				connection.open( dbFile );
				
				migrationManager.sqlConnection = connection;
				migrationManager.migrate();
			}
		]]&gt;
	&lt;/fx:Script&gt;

	&lt;fx:Declarations&gt;
		&lt;db:MigrationManager id="migrationManager" tableName="migrations"&gt;
			&lt;db:Migration source="@Embed(source='/sql/CreateSomeTable.sql',mimeType='application/octet-stream')"/&gt;
			&lt;db:Migration source="DROP TABLE IF EXISTS someTable;"/&gt;
			&lt;db:Migration source="@Embed(source='/sql/CreateSomeOtherTable.sql',mimeType='application/octet-stream')"/&gt;
		&lt;/db:MigrationManager&gt;
	&lt;/fx:Declarations&gt;
&lt;/s:Application&gt;</pre>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.krotscheck.net/2011/01/13/database-upgrades-and-migrations-with-adobe-air.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Zend_Auth_Adapter_Facebook</title>
		<link>http://www.krotscheck.net/2010/08/21/zend_auth_adapter_facebook.html</link>
		<comments>http://www.krotscheck.net/2010/08/21/zend_auth_adapter_facebook.html#comments</comments>
		<pubDate>Sat, 21 Aug 2010 22:00:13 +0000</pubDate>
		<dc:creator>Michael Krotscheck</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Auth]]></category>
		<category><![CDATA[facebook]]></category>
		<category><![CDATA[zend]]></category>

		<guid isPermaLink="false">http://www.krotscheck.net/2010/08/21/zend_auth_adapter_facebook.html</guid>
		<description><![CDATA[This post is rather more nerdy than my other ones, and goes to describe how to create a Facebook authentication adapter for the Zend Framework, using the new Facebook Graph API. I do not intend to support this code explicitly,<span class="ellipsis">&#8230;</span><div class="read-more"><a href="http://www.krotscheck.net/2010/08/21/zend_auth_adapter_facebook.html">Read more &#8250;</a></div><!-- end of .read-more -->]]></description>
				<content:encoded><![CDATA[<p>This post is rather more nerdy than my other ones, and goes to describe how to create a Facebook authentication adapter for the Zend Framework, using the new Facebook Graph API. I do not intend to support this code explicitly, but I do work with it and will update it to suit my own needs. If you&#8217;re impatient, the full code for the adapter and a sample controller are the last two code samples at the bottom of this post.</p>
<h3>A discussion about OAuth and OpenID</h3>
<p>Strictly speaking, Facebook supports <a href="http://oauth.net/" target="_blank">OAuth</a>, not <a href="http://openid.net/foundation/" target="_blank" title="The OpenID Foundation">OpenID</a>. OAuth is a way for your application to act on behalf of someone else on another side, while OpenId exists solely for you to use the other website as an authorization authority. The difference is subtle, however telling that Facebook has explicitly stated that it does not want to be an authorization authority. In practice, however, the two standards are interchangeable, and OAuth works pretty well as a way to authenticate a user.</p>
<h3>How Facebook Auth Actually Works</h3>
<p>Here&#8217;s the flow in four easy steps:</p>
<ol>
<li>The user clicks on a &#8220;Login to Facebook&#8221; link on your server, which redirects them to another page on your server that handles the authentication.</li>
<li>Your Facebook Auth page puts all the parameters for your authentication, such as your app ID and scope, into a URL and sends the user to Facebook via that URL.</li>
<li>Once Facebook returns the user (presumably authenticated) to your server, you can use the parameters sent via the URL to request an authentication token from Facebook. This is done via curl or some other server-to-server communication by calling the graph API.</li>
<li>You use this authentication token to access the user&#8217;s information on Facebook.</li>
</ol>
<h4>Step 1: Get all the data you need</h4>
<p>To properly authenticate with Facebook, you need four pieces of data. The first two are your application id and your application secret, both of which are available on your developer application page.</p>
<div class="image">
  <img src="http://www.krotscheck.net/wp-content/uploads/2010/08/Screen-shot-2010-08-21-at-1.50.04-PM.png" width="479" height="480" alt="Screen shot 2010-08-21 at 1.50.04 PM.png" /></p>
<p>A sample Facebook application page</p>
</div>
<p>The second two pieces of data are specific to your implementation. These are the redirect URI, which is used to tell Facebook where to send the user once they are done authorizing your application, and the permission scope, which you use to tell Facebook what permissions you want to request from the user. This latter one actually warrants some more documentation, which Facebook has graciously provided <a href="http://developers.facebook.com/docs/authentication/permissions" target="_blank">here</a>. Be careful: Users can get really suspicious if you ask for too much data.</p>
<h4>Step 2: Redirect your user to Facebook.</h4>
<p>With this data, you can redirect your user to Facebook. Facebook will then work some magic and ask the user whether they want to grant your application access to their profile. Don&#8217;t forget to urlencode that Redirect URI.</p>
<div class="code">
<pre>
$loginUri = "https://graph.facebook.com/oauth/authorize?client_id={$appId}&amp;redirect_uri={$redirectUri}&amp;scope={$scope}";
header('Location: ' . $loginUri);
</pre>
</div>
<h4>Step 3: Request an Auth Token</h4>
<p>Assuming that the user authorizes your application, Facebook will return them to your redirect URI with the &#8220;code&#8221; parameter in the URL. You can use this parameter to request an authorization token from Facebook. In this case I&#8217;m using the Zend Request handler to simplify things a little.</p>
<div class="code">
<pre>
$client = new Zend_Http_Client( "https://graph.facebook.com/oauth/access_token" );
$client-&gt;setParameterGet('client_id', $appId);
$client-&gt;setParameterGet('client_secret', $secret);
$client-&gt;setParameterGet('code', $code);
$client-&gt;setParameterGet('redirect_uri', $redirectUri);

$result = $client-&gt;request('GET');
$params = array();
parse_str($result-&gt;getBody(), $params);
$token = $params['access_token'];</pre>
</div>
<h4>Step 4: Read the user&#8217;s profile</h4>
<p>At this point, you have an auth token that grants you access to read the user&#8217;s profile information in accordance to the permissions they have granted you. These permissions are completely blind- you don&#8217;t have to additionally specify what you want to access &#8211; the requests will simply return the information to which you have access.</p>
<div class="code">
<pre>
$client = new Zend_Http_Client( "https://graph.facebook.com/me" );
$client-&gt;setParameterGet('client_id', $appId);
$client-&gt;setParameterGet('access_token', $token);
$result = $client-&gt;request('GET');
$user = json_decode($result-&gt;getBody());</pre>
</div>
<h4>Zend_Auth_Adapter_Facebook</h4>
<p>For those of you who would rather not take the above code and wrap it into your own Auth Adapter, I&#8217;ve gone ahead and done all that work for you. Below you will find a sample Zend Controller, as well as a pre-baked Auth Adapter. If you come across any major security problems in it, I&#8217;d love to know, since I use this adapter myself <img src='http://www.krotscheck.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> .</p>
<div class="code">
<p>file: Zend/Auth/Adapter/Facebook.php</p>
<pre>
class Zend_Auth_Adapter_Facebook implements Zend_Auth_Adapter_Interface
{
    /**
     * The Authentication URI, used to bounce the user to the facebook redirect uri.
     * 
     * @var string
     */
    const AUTH_URI = 'https://graph.facebook.com/oauth/authorize?client_id=%s&amp;redirect_uri=%s';
    
    /**
     * The token URI, used to retrieve the OAuth Token.
     * 
     * @var string
     */
    const TOKEN_URI = 'https://graph.facebook.com/oauth/access_token';
    
    
    /**
     * The user URI, used to retrieve information about the user.
     * 
     * @var string
     */
    const USER_URI = 'https://graph.facebook.com/me';
    
    /**
     * The application ID
     *
     * @var string
     */
    private $_appId = null;

    /**
     * The application secret
     *
     * @var string
     */
    private $_secret = null;

    /**
     * The authentication scope (advanced options) requested
     *
     * @var string
     */
    private $_scope = null;

    /**
     * The redirect uri
     *
     * @var string
     */
    private $_redirectUri = null;

    /**
     * Constructor
     *
     * @param string $appId the application ID
     * @param string $secret the application secret
     * @param string $scope the application scope
     * @param string $redirectUri the URI to redirect the user to after successful authentication
     */
    public function __construct($appId, $secret, $redirectUri, $scope)
    {
        $this-&gt;_appId = $appId;
        $this-&gt;_secret = $secret;
        $this-&gt;_scope = $scope;
        $this-&gt;_redirectUri   = $redirectUri;
    }

    /**
     * Sets the value to be used as the application ID
     *
     * @param  string $appId The application ID
     * @return Zend_Auth_Adapter_Facebook Provides a fluent interface
     */
    public function setAppId($appId)
    {
        $this-&gt;_appId = $id;
        return $this;
    }

    /**
     * Sets the value to be used as the application secret
     *
     * @param  string $secret The application secret
     * @return Zend_Auth_Adapter_Facebook Provides a fluent interface
     */
    public function setSecret($secret)
    {
        $this-&gt;_secret = $secret;
        return $this;
    }

    /**
     * Sets the value to be used as the application scope (array())
     *
     * @param  string $scope The application scope
     * @return Zend_Auth_Adapter_Facebook Provides a fluent interface
     */
    public function setApplicationScope($scope)
    {
        $this-&gt;_scope = $scope;
        return $this;
    }

    /**
     * Sets the redirect uri after successful authentication
     *
     * @param  string $redirectUri The redirect URI
     * @return Zend_Auth_Adapter_Facebook Provides a fluent interface
     */
    public function setRedirectUri($redirectUri)
    {
        $this-&gt;_redirectUri = $redirectUri;
        return $this;
    }


    /**
     * Authenticates the user against facebook
     * Defined by Zend_Auth_Adapter_Interface.
     *
     * @throws Zend_Auth_Adapter_Exception If answering the authentication query is impossible
     * @return Zend_Auth_Result
     */
    public function authenticate()
    {
    	// Get the request object.
    	$frontController = Zend_Controller_Front::getInstance();
    	$request = $frontController-&gt;getRequest();
    	
    	// First check to see wether we're processing a redirect response.
    	$code = $request-&gt;getParam('code');
    	
    	if ( empty ($code ) )
    	{
	    	// Create the initial redirect
	    	$loginUri = sprintf(Zend_Auth_Adapter_Facebook::AUTH_URI , $this-&gt;_appId, $this-&gt;_redirectUri);
	 		
	    	if ( !empty($this-&gt;_scope) )
	    	{
	    		$loginUri .= "&amp;scope=" . $this-&gt;_scope;
	    	}
	    	
	    	header('Location: ' . $loginUri );
    	}
    	else
    	{
    		// Looks like we have a code. Let's get ourselves an access token
	    	$client = new Zend_Http_Client( Zend_Auth_Adapter_Facebook::TOKEN_URI );
	    	$client-&gt;setParameterGet('client_id', $this-&gt;_appId);
	    	$client-&gt;setParameterGet('client_secret', $this-&gt;_secret);
	    	$client-&gt;setParameterGet('code', $code);
	    	$client-&gt;setParameterGet('redirect_uri', $this-&gt;_redirectUri);
	    	
	    	$result = $client-&gt;request('GET');
	    	$params = array();
	    	parse_str($result-&gt;getBody(), $params);
	    	
	    	// REtrieve the user info
	    	$client = new Zend_Http_Client(Zend_Auth_Adapter_Facebook::USER_URI );
	    	$client-&gt;setParameterGet('client_id', $this-&gt;_appId);
	    	$client-&gt;setParameterGet('access_token', $params['access_token']);
	    	$result = $client-&gt;request('GET');
	    	$user = json_decode($result-&gt;getBody());
	    	
            return new Zend_Auth_Result( Zend_Auth_Result::SUCCESS, $user-&gt;id, array('user'=&gt;$user, 'token'=&gt;$params['access_token']) );
    	}
    	
        return new Zend_Auth_Result( Zend_Auth_Result::FAILURE, null, 'Error while attempting to redirect.' );
    }
}
</pre>
</div>
<div class="code">
<p>file: modules/default/controllers/FacebookauthController.php</p>
<pre>
/**
 * Sample Facebook Auth Controller.
 * 
 * @author Michael Krotscheck
 */
class FacebookauthController extends Zend_Controller_Action
{
	/**
	 * Application default action
	 */
	public function indexAction ()
	{
		$appId = 'YOUR_APP_ID';
		$secret = 'YOUR_APP_SECRET';
		$redirectUri = 'http://path-to-this-controller-and-action';
		$scope = 'YOUR_COMMA_SEPARATED_APPLICATION_SCOPE';
		
		// Create the authentication adapter.
		$adapter = new Zend_Auth_Adapter_Facebook( $appId, $secret, $redirectUri, $scope );
		
		// Get an authenticator instance
		$auth = Zend_Auth::getInstance();
		
		// This call will automatically redirect to facebook with the passed parameters.
		$result = $auth-&gt;authenticate($adapter);
		
		if ( $result-&gt;isValid() )
		{
			// Get the messages
			$messages = $result-&gt;getMessages();
			
			// Get the user object from the returned messages.
			$fbUser = $messages['user'];
			
			var_dump($fbUser);
		}
	}
}
</pre>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.krotscheck.net/2010/08/21/zend_auth_adapter_facebook.html/feed</wfw:commentRss>
		<slash:comments>15</slash:comments>
		</item>
		<item>
		<title>Breaking down a Client Application</title>
		<link>http://www.krotscheck.net/2010/08/02/breaking-down-a-client-application.html</link>
		<comments>http://www.krotscheck.net/2010/08/02/breaking-down-a-client-application.html#comments</comments>
		<pubDate>Tue, 03 Aug 2010 01:36:09 +0000</pubDate>
		<dc:creator>Michael Krotscheck</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[actionscript]]></category>
		<category><![CDATA[architecture]]></category>
		<category><![CDATA[flash]]></category>
		<category><![CDATA[flex]]></category>
		<category><![CDATA[software]]></category>

		<guid isPermaLink="false">http://www.krotscheck.net/2010/08/02/breaking-down-a-client-application.html</guid>
		<description><![CDATA[With so little time to blog over the past few months, I took a few moments to really think about why I&#8217;d fallen out of the habit. I believe (personally) that much of this is because my writing time now<span class="ellipsis">&#8230;</span><div class="read-more"><a href="http://www.krotscheck.net/2010/08/02/breaking-down-a-client-application.html">Read more &#8250;</a></div><!-- end of .read-more -->]]></description>
				<content:encoded><![CDATA[<p>With so little time to blog over the past few months, I took a few moments to really think about why I&#8217;d fallen out of the habit. I believe (personally) that much of this is because my writing time now goes into guiding and educating my own development team, and once I realized that I saw no reason to exclude all of you from any of these emails either. So yes, you should expect the content to start picking up again, but the topics will be focused around applied software development rather than the marketing and retail topics I spoke about while I was still at Resource.</p>
<p>This particular email was written to demystify the difference (as far as I&#8217;m concerned) of all the different parts of a client application. However rather than a heavy discussion on methods and algorithms, what I present here are actually the higher level concepts that govern the structure of an application. I tried to order them in a fairly logical fashion, starting at the &#8220;front&#8221; of the application (what you see) and moving towards the &#8220;back&#8221; (the bits that the user should never see).</p>
<p>But first, I feel it is important to understand the difference between business logic and view logic:</p>
<ul>
<li>Business logic manages data and enforces business rules. It cleans, saves, reads, compares, and makes sure that the data models are properly updated. It is also important to make the distinction between server-side business logic and client business logic. That which lives on the server is usually focused more on business rules, while that which lives in the client usually cares more about server interaction and data manipulation.</li>
<li>View logic manages how data is displayed. It manages state, formatters, strings and view indexes, and doesn&#8217;t really care about how that data got to where it is, it only cares about how it should be displayed <i>within this particular view</i>.</li>
</ul>
<p>Having said that, here are the major components of a client application. Caveat, this might not mean much to you Javascript guys.</p>
<p><b>Skin</b></p>
<p>A skin acts to describe the containers, colors and graphics that a control or view use. It can change its appearance based on a skin state (not to be confused with view state), and can refer to styles set by the component which it is skinning. It should not have any business or data logic whatsoever.</p>
<p><b>Control</b></p>
<p>A Control is the lowest level of functional components which comprise an application. These are our buttons, labels, data grids, view containers and so forth, and they are characterized by the fact that the data they display is not specialized, nor do they contain any real internal business logic at all. They know how to interact with a generic type and dispatch events when a particular action occurs.</p>
<p><b>View</b></p>
<p>A view is a collection of controls, containers, formatters, skins and subviews, all connected via a presentation model. It acts to collect and arrange elements rather than figuring out what each piece is supposed to do. As such, Views should contain little to no code at all, and should be managed by states and properties.</p>
<p><b>Item Renderer</b></p>
<p>An Item renderer is a very specialized kind of view, which deals with the display of a single piece of data in a collection. As a result, it is the only view which should be dependent on an external piece of data &#8211; one that is injected into a property of that ItemRenderer from a parent (the data property). Item renderers may contain Presentation MOdels to help them manage user gestures, but rarely make use of a data model as this is already provided.</p>
<p><b>Presentation Model</b></p>
<p>It is the job of the presentation model to act as a mediator between the view and the rest of the application. This does not mean that it should manage data, nor necessarily contain it. Instead, its job is to expose all the methods and data which are being used by the View, which includes models (bindable), states, actions which describe user methods and (in some cases) validators.</p>
<p><b>Data Model</b></p>
<p>The data model is a dumb data container. It should contain little-to-no logic on its own, and instead allow the tasks to clean, sort and manipulate anything that is assigned to the model. Thinking of it differently: The Data Model is the <i>authoritative source</i> of any data used in the application. All data starts here and ends here. Views get their data from the Data Model via binding. Tasks retrieve model instances. Presentation models make data available by exposing a public instance of a data model.</p>
<p><b>Task</b></p>
<p>Tasks are where our &#8220;business&#8221; logic resides, in the most generic and granular way possible. As an example, the act of loading a user might require reading the user object, retrieving their preferences, and initializing the application locale. Rather than try to handle this all in one task, it is better to use a SequenceTask or ParalellTask to collect the three different actions. Why? Because your preferences screen might need to reload user preferences after they&#8217;ve been saved, but you don&#8217;t want to refresh the entire user.</p>
<p>Tasks, much like presentation models, are able to collect any data and utilities they need to achieve what they need to achieve, however when they are done they need to let go of those items and dispose of themselves properly. The important thing to note here is that any business logic that can be put into the service layer <i>should</i> live in the service layer; We don&#8217;t want to expose the guts of our business rules to the world, and servers are much easier to protect from questionable data manipulation.</p>
<p><b>Delegate</b></p>
<p>A delegate is our service proxy, and acts as a channel back and forth from the database. It allows us access to the business logic that lives on the server in a reliable and consistent way. In most cases, each delegate method will have one task that wraps it and makes sure that the data is properly cleaned and presented.</p>
<p><b>Utility</b></p>
<p>Utilities are classes that provide common data manipulation routines that are global to all aspects of the application. A good utility, for instance, would be a method that handles date conversions from GMT to Local and back. A less desirable utility method would be one that formats a piece of data for a specific view, as this should be handled within the view itself.</p>
<p><b>Libraries</b></p>
<p>Libraries are the catchall for everything that was left out, and it includes pieces of highly specialized logic that don&#8217;t really fit neatly elsewhere. Good examples of this are video encoding libraries, classes that manage encryption, filesystem manipulation and other tasks like that.</p>
<p><b>VO</b></p>
<p>A VO, or Value Object (also known as DO/Data Object) is the raw data which we manipulate. It describes a particular Domain Object and acts as a package that we pass from method to model to view. They only contain data related to that same object, and should not contain any formatting logic and only limited validation logic (is-not-zero checks and so forth). Formatting should be handled by the view, validation should be handled by tasks or utilities.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.krotscheck.net/2010/08/02/breaking-down-a-client-application.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Hi, my name is Mike, and I&#8217;m a Flash Developer</title>
		<link>http://www.krotscheck.net/2010/05/03/hi-my-name-is-mike-and-im-a-flash-developer.html</link>
		<comments>http://www.krotscheck.net/2010/05/03/hi-my-name-is-mike-and-im-a-flash-developer.html#comments</comments>
		<pubDate>Tue, 04 May 2010 03:24:58 +0000</pubDate>
		<dc:creator>Michael Krotscheck</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[apple]]></category>
		<category><![CDATA[flamewar]]></category>
		<category><![CDATA[flash]]></category>
		<category><![CDATA[flex]]></category>

		<guid isPermaLink="false">http://www.krotscheck.net/2010/05/03/hi-my-name-is-mike-and-im-a-flash-developer.html</guid>
		<description><![CDATA[Let me ask you this: Am I less of a person because I write code for a living? How about this: Am I less of a person because I work in Flash? I haven&#8217;t really (well, sortof) weighted in on<span class="ellipsis">&#8230;</span><div class="read-more"><a href="http://www.krotscheck.net/2010/05/03/hi-my-name-is-mike-and-im-a-flash-developer.html">Read more &#8250;</a></div><!-- end of .read-more -->]]></description>
				<content:encoded><![CDATA[<p>Let me ask you this: Am I less of a person because I write code for a living?</p>
<p>How about this: Am I less of a person because I work in Flash?</p>
<p>I haven&#8217;t really (well, sortof) weighted in on the Flash vs. HTML5 debate yet, mostly because the main posters pro and con are both more technically qualified, have a stronger social following, and/or have more backing from marketers. It is the futility of the debate itself that interests me, both from a very personal perspective and from the perspective of an internet veteran.</p>
<p>The nature of the debate that I observe from the comfort of my Laptop is the following:</p>
<ul>
<li>Camp A: Here&#8217;s a bunch of reasons why Flash sucks!</li>
<li>Camp B: Nuh-uh! Here&#8217;s a list of reasons why that&#8217;s not the case!</li>
</ul>
<p>As you probably realize yourself, this argument structure is essentially religious, and can be replayed whenever two people have different opinions and are not willing to reconcile. It&#8217;s certainly not restricted to the technology space (Choice vs. Life anyone?), and the futility of entering into such an argument is well known to anyone who&#8217;s ever been involved in a flame war.</p>
<p>Now take this Adobe/Apple debate and pose it to our society (full of technology-advocates, evangelists and gurus), and you&#8217;ll soon come to realize that Adobe cannot win this argument, not given its current strategy. This is for two reasons:</p>
<ol>
<li>You cannot win a flamewar from a defensive position.</li>
<li>You cannot win a flamewar with reason.</li>
</ol>
<p>Adobe&#8217;s Flash Team are doing an admirable job at defending against everything that&#8217;s coming out of Apple, the Javascript community, and the standards purists. Unfortunately by the time they get to debunking these statements the damage has been done, and no matter how quickly they respond they will never get the same media penetration that Apple will. Why? Because people don&#8217;t like to be told they&#8217;re wrong, and anyone who listens to a flamewar long enough will start to tune out. Just ask Fox News- they make a living on this &#8211; and there&#8217;s no way you can reach an unreceptive audience no matter how good your arguments are.</p>
<p>Secondly, any aggressor can very easily cherry-pick its arguments to attack the defender on weak points, and thus invalidate their entire argument simply because one point wasn&#8217;t well researched. While the overall flash platform is a strong contender on the web, you&#8217;ll notice that the argument is focused on a few key shortcomings &#8211; performance, accessibility, &#8216;open-ness&#8217; and the like &#8211; in which HTML5 has strength. By defending specifically against these weak points, Adobe is then empowering critics to further choose sub-points where they have strength, and through this cycle the argument is diminished and diminished until at the end all we remember is that Adobe was trying to defend itself and their critics never ran out of anything to point to and say: &#8220;Hey you suck&#8221;.</p>
<p>Lastly, as I have seen in several cases, arguments have started go get personal, and as soon as you enter <i>that</i> arena you can invalidate someone&#8217;s argument simply by pointing out their own shortcomings. To use myself as an example, you can invalidate anything I have to say about Flash and HTML5 by pointing out that I&#8217;m not a real CS major, that I haven&#8217;t remained at a job for more than 4 years, or that I go so far as to claim that there are people more qualified to talk about this than I in the very first paragraph in this post. My experience and job title doesn&#8217;t matter &#8211; as soon as you say &#8220;Oh, you don&#8217;t know what you&#8217;re talking about, you&#8217;re not a CS Major&#8221; you&#8217;ve got me completely discredited.</p>
<p>But what bothers me the most is the first concession which the Adobe Community had to make, and that is that their pool of developers draws from the design community and are subsequently not the best. Now, every technology has a wide range of developer competence, yet with Flash it&#8217;s becoming a banner cry: &#8220;Flash Developers suck&#8221;. Your technology choice does not define how skilled you are, and yet it&#8217;s becoming pretty clear that those of us who choose Actionscript and Flash are seen as incompetent, less than human, and not worth listening to because we&#8217;re blind and ignorant fanboys who don&#8217;t understand what they&#8217;re missing with [Insert Language Here].</p>
<p>This last point is perhaps the most damaging, because it&#8217;s eroding Adobe&#8217;s hard-won community. Do you like feeling like a shitty developer? Do you want to be the pariah of the web? Do you like being told that you are the scum of the earth? No, and I don&#8217;t either, and if like myself you&#8217;re simply trying to make a living, chances are you&#8217;re seriously considering learning something else to make sure you remain employable.</p>
<p>So the real question is: Will rational minds prevail? I doubt it.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.krotscheck.net/2010/05/03/hi-my-name-is-mike-and-im-a-flash-developer.html/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>What makes a &#8216;Rockstar&#8217; Developer?</title>
		<link>http://www.krotscheck.net/2010/01/10/what-makes-a-rockstar-developer.html</link>
		<comments>http://www.krotscheck.net/2010/01/10/what-makes-a-rockstar-developer.html#comments</comments>
		<pubDate>Sun, 10 Jan 2010 15:11:30 +0000</pubDate>
		<dc:creator>Michael Krotscheck</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[developer]]></category>
		<category><![CDATA[entrepreneurship]]></category>
		<category><![CDATA[rockstar]]></category>
		<category><![CDATA[startup]]></category>

		<guid isPermaLink="false">http://www.krotscheck.net/2010/01/10/what-makes-a-rockstar-developer.html</guid>
		<description><![CDATA[I&#8217;ve recently been involved in a discussion about what makes a rockstar developer for a startup. This has always surprised me- the reality of the matter is that there are no rockstars, only people who think of themselves as rockstars,<span class="ellipsis">&#8230;</span><div class="read-more"><a href="http://www.krotscheck.net/2010/01/10/what-makes-a-rockstar-developer.html">Read more &#8250;</a></div><!-- end of .read-more -->]]></description>
				<content:encoded><![CDATA[<p>I&#8217;ve recently been involved in a discussion about what makes a rockstar developer for a startup. This has always surprised me- the reality of the matter is that there are no rockstars, only people who think of themselves as rockstars, and those are the last people you want in charge of your product. So I figure, as someone who&#8217;s been around the block a few times, it would be good to come up with a list of what actually makes for a &#8220;rockstar&#8221; developer. If I miss anything, feel free to contribute in the comments.</p>
<h4>1- They don&#8217;t think of themselves as rock stars.</h4>
<p>Arrogance is perhaps a key requirement in being an entrepreneur, but overconfidence will drain your cash pool faster than hookers and blow.</p>
<h4>2- They have a proven track record of multiple shipped products.</h4>
<p>You don&#8217;t want a hotshot kid out of school, you want a seasoned professional, preferably one who knows how to write applications for the industry you&#8217;re trying to reach.</p>
<h4>3- They care more about frameworks than plumbing.</h4>
<p>Unless you&#8217;re trying to design a complex new mathematical algorithm (in which case you should probably be partnering with a university research lab), you want someone who can grasp a system rather than a method. If this guy ends up in deep technical discussions about the optimal way of implementing a sort, you&#8217;ve got the wrong guy.</p>
<h4>4- They&#8217;re not willing to work for free</h4>
<p>Risk management and strategic thinking is key to long-term project viability. If you have someone willing to work for equity, they&#8217;re willing to take risks with your payment processing gateway just as easily as they&#8217;re taking a risk on you.</p>
<h4>5- They believe in development process and best practices to speed up their work.</h4>
<p>The last thing you want is someone who&#8217;s trying to reinvent the wheel. Mind you, this also likely means that the first two weeks or so of development you&#8217;ll see a lot of development support tools get set up and used before code actually starts, but that&#8217;ll give you time to get your documentation in order.</p>
<h4>6- They have a positive attitude.</h4>
<p>If someone bitches, they&#8217;re looking to blame themselves. Instead, you want them to identify their concern as a problem they can solve.</p>
<h4>7- They get uncomfortable when you ask about their social life.</h4>
<p>&#8217;cause, well, currently it&#8217;s still socially odd to prefer coding on a saturday night.</p>
<h4>8- You don&#8217;t want Alphabet/Acronym soup in their technical skills.</h4>
<p>Lots of languages means little depth in each, and depth = speed. Pick a serverside language (PHP, .Net, Ruby, etc), pick a database (MySQL, SQLServer, Postgres, etc), and pick a frontend (Flex, Mootools, JQuery, etc). Focus on that. If a dev has only a few languages this does not mean they&#8217;re stupid- it means they know how to focus.</p>
<h4>9- They&#8217;re involved in the community.</h4>
<p>Speaking, attending, whatever, you need to make sure their technical skills don&#8217;t stagnate, and that they&#8217;re willing to accept ideas from outside.</p>
<h4>10- You respect them</h4>
<p>Respect means you are willing to listen when they tell you you&#8217;re full of it, and that&#8217;s key in a partnership. You&#8217;re not looking for a monkey you can put in a corner who can bang out some code- you&#8217;re looking for a partner who&#8217;ll act as a technical sounding board.</p>
<div class="hr"></div>
<p>So now I have this question: What makes for a rockstar business partner?</p>
]]></content:encoded>
			<wfw:commentRss>http://www.krotscheck.net/2010/01/10/what-makes-a-rockstar-developer.html/feed</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>How to Publish a Flash Application to the Facebook Stream</title>
		<link>http://www.krotscheck.net/2009/12/21/how-to-publish-a-flash-application-to-the-facebook-stream.html</link>
		<comments>http://www.krotscheck.net/2009/12/21/how-to-publish-a-flash-application-to-the-facebook-stream.html#comments</comments>
		<pubDate>Mon, 21 Dec 2009 20:19:23 +0000</pubDate>
		<dc:creator>Michael Krotscheck</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[facebook]]></category>
		<category><![CDATA[flash]]></category>
		<category><![CDATA[share]]></category>
		<category><![CDATA[social]]></category>

		<guid isPermaLink="false">http://www.krotscheck.net/2009/12/21/how-to-publish-a-flash-application-to-the-facebook-stream.html</guid>
		<description><![CDATA[If you&#8217;re in an agency and/or have been paying attention to Business Week and the Wall Street Journal recently, you&#8217;ll know that my former employer Resource Interactive recently released a service offering called &#8220;Off The Wall&#8220;, which in short is<span class="ellipsis">&#8230;</span><div class="read-more"><a href="http://www.krotscheck.net/2009/12/21/how-to-publish-a-flash-application-to-the-facebook-stream.html">Read more &#8250;</a></div><!-- end of .read-more -->]]></description>
				<content:encoded><![CDATA[<p>If you&#8217;re in an agency and/or have been paying attention to <a href="http://investing.businessweek.com/research/markets/news/article.asp?docKey=600-200910301156BIZWIRE_USPR_____BW5656-2QHHJKCOH16I2N0SL20B0UG0AN&amp;params=timestamp||10/30/2009%2011:56%20AM%20ET||headline||Resource%20Interactive%20Unveils%20Facebook%20Ecommerce%20Experience||docSource||Business%20Wire||provider||ACQUIREMEDIA" target="_blank">Business Week</a> and the <a href="http://blogs.wsj.com/digits/2009/12/21/shopping-comes-to-your-facebook-stream/" target="_blank">Wall Street Journal</a> recently, you&#8217;ll know that my former employer <a href="http://www.resource.com" target="_blank">Resource Interactive</a> recently released a service offering called &#8220;<a href="http://offthewall.resource.com/" target="_blank">Off The Wall</a>&#8220;, which in short is a way to extend your e-commerce workflow into the Facebook stream. &#8220;Share on Facebook&#8221; can now push a product to a user&#8217;s news feed, and if someone wants more information they never actually have to leave the Facebook environment to perform a &#8220;me too&#8221; purchase.</p>
<p>Cool, huhn? Security concerns aside (Believe me, I am never giving <i>anything</i> on facebook my credit card information), this isn&#8217;t exactly new- pushing product information into the Facebook stream was what the original <a href="http://en.wikipedia.org/wiki/Facebook_Beacon">Facebook Beacon</a> was all about, and that was shut down via a class action lawsuit because it published user sales data without user approval. Additionally, pushing rich media applications into the Facebook stream is not new- anyone who&#8217;s viewed a youtube video in their Facebook stream knows how seamless that can be. What&#8217;s interesting though is that Resource has overcome the legal concerns with two changes: First, by giving users control of what to share when, and secondly by actually launching a full commerce application into something that people check every day.</p>
<p>If your initial reaction is disgust (&#8220;What? Another way for people to sell us their stuff? Blegh&#8221;) then you and I are pretty much on the same page, however don&#8217;t be blinded by other creative uses of this. For instance, if you want to buy someone a Christmas present, wouldn&#8217;t it be nice if you saw their wishlist items in the stream? What about gaming- if a friend of yours is playing some kind of a live flash mini game&#8230; wouldn&#8217;t you want to join them immediately? There are legitimate uses for this that don&#8217;t turn your stomach, so I figured I&#8217;d write a quick overview on how to put it together.</p>
<h2>So how did they do that?</h2>
<p>If you already have an application you want to run inside the Facebook news stream, then the process of getting it shareable is extremely simple, and is easily accessible to anyone who knows a little bit about flash, HTML metadata and the facebook platform. You have to perform the following tasks, most of which are trivial unless you are trying to do anything covered by a regulatory body (like accepting credit card information). For that you have to have a secure and federally accredited server, and that&#8217;s way outside of the scope of this article.</p>
<h3>Step 1: Add the &#8220;Share on Facebook&#8221; link on the page in question.</h3>
<p>The first thing you need to do is give your users the ability to actually share your page. This can be as easy as <a href="http://www.facebook.com/facebook-widgets/share.php" target="_blank">including a particularly formatted link</a> in your product page or as complicated as including <a href="http://wiki.developers.facebook.com/index.php/Fb:share-button" target="_blank">FBML</a> in your site&#8217;s header and namespace. Note that the share URL can include URL parameters that will customize the content of the page, and should be pointed at the hosted URL of your flash application- this is crucial for step 2.</p>
<div class="code">
<pre>
&lt;a name="fb_share" type="button_count" href="http://www.facebook.com/sharer.php?u=[url to share]&amp;t=[title of content]"&gt;Share&lt;/a&gt;&lt;script src="http://static.ak.fbcdn.net/connect.php/js/FB.Share" type="text/javascript"&gt;&lt;/script&gt;
</pre>
</div>
<h3>Step 2: Add the correct meta tags to the page you want to share.</h3>
<p>When a user clicks on the above link, it actually triggers the Facebook Sharer script to scrape the provided URL for metadata that tells it how to share this page. All of this data is contained in the metadata tags of a page, and you can read the extensive documentation <a href="http://wiki.developers.facebook.com/index.php/Facebook_Share/Specifying_Meta_Tags" target="_blank">here</a>, however the important piece you&#8217;re looking for is how to share multimedia content. If you&#8217;ll read the documentation carefully, you&#8217;ll notice that while all references talk about video, in reality this share functionality allows you to display <i>any</i> flash content in the Facebook stream simply by replacing video_url with the URL to your flash SWF. This is still restricted to user action of course- nobody will see a flash app launched immediately, they&#8217;ll still see the icon and title as with any Youtube Video, and the application won&#8217;t launch until the user actually clicks on the icon.</p>
<div class="code">
<pre>
&lt;meta name="title" content="video_title" /&gt;
&lt;meta name="description" content="video_description" /&gt;
&lt;link rel="image_src" href="video_screenshot_image_src url" /&gt;
&lt;link rel="video_src" href="video_src url"/&gt;
&lt;meta name="video_height" content="video_height" /&gt;
&lt;meta name="video_width" content="video_width" /&gt;
&lt;meta name="video_type" content="application/x-shockwave-flash" /&gt;
</pre>
</div>
<p class="small"><span style="color: #BBBBBB; font-size: .8em">EDITORIALIZING: What worries me on this is that Facebook&#8217;s documentation is very clearly targeted at video sharing, and that this may be a violation of their intent of the sharer script. In short, what Resource is publishing as an innovation to social commerce is little more than a hack bolted into a loophole. Even so, I don&#8217;t believe Facebook will try to blacklist retailer sites to put this genie back in its bottle, because it both encourages use of their platform while also opening the gates to more legitimate uses. The ability to see that someone is, say, playing a game right now and your ability to join them is only a single click away puts an entire new spin on live online gaming, especially with the recent release of Adobe Collaboration Services, but I digress&#8230;</span></p>
<h3>Step 3: Get your domain whitelisted by Facebook</h3>
<p>If you paid especially close attention to the documentation linked above, you&#8217;ll also note that multimedia sharing won&#8217;t work if your domain is not whitelisted by Facebook. This is to protect Facebook from people who might want to distribute illegal content that would get them in trouble (licensed movies for instance), but also gives Facebook ultimate white and blacklist control over any activity they don&#8217;t want subverting their functionality. The process is actually extremely simple: <a href="http://www.facebook.com/developers/developer_help.php" target="_blank">Click this link</a>, fill out the form, and wait for them to get back to you. Last time I did it it took less than 24 hours, but that was for a major retail site; your experience might vary.</p>
<p>That&#8217;s it. Enjoy!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.krotscheck.net/2009/12/21/how-to-publish-a-flash-application-to-the-facebook-stream.html/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Looking at Student Debt as an Opportunity</title>
		<link>http://www.krotscheck.net/2009/12/10/looking-at-student-debt-as-an-opportunity.html</link>
		<comments>http://www.krotscheck.net/2009/12/10/looking-at-student-debt-as-an-opportunity.html#comments</comments>
		<pubDate>Thu, 10 Dec 2009 16:02:19 +0000</pubDate>
		<dc:creator>Michael Krotscheck</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[business]]></category>
		<category><![CDATA[loans]]></category>
		<category><![CDATA[market analysis]]></category>
		<category><![CDATA[opportunity]]></category>
		<category><![CDATA[scholarship]]></category>
		<category><![CDATA[student debt]]></category>

		<guid isPermaLink="false">http://www.krotscheck.net/2009/12/10/looking-at-student-debt-as-an-opportunity.html</guid>
		<description><![CDATA[<p>There is a $128 billion dollar untapped demand for student debt assistance, if you can find a way to meet it. The conditions of the environment in which this demand exists may even contribute to an increase in the demand as you provide a debt-assistance service.<br /></p><div class="read-more"><a href="http://www.krotscheck.net/2009/12/10/looking-at-student-debt-as-an-opportunity.html">Read more &#8250;</a></div><!-- end of .read-more -->]]></description>
				<content:encoded><![CDATA[<p><b>Summary:</b> There is a $128 billion dollar untapped demand for student debt assistance, if you can find a way to meet it. The conditions of the environment in which this demand exists may even contribute to an increase in the demand as you provide a debt-assistance service.</p>
<div class="hr"></div>
<p>We all know that students have no money- many of us have been there and scraped by on ramen and coffee often for weeks on end, and now we are all, to a greater or lesser extent, burdened by the cost of our education as we have leveraged part of our future to gain the success we have now. It&#8217;s part of our environment. It&#8217;s who we are, it&#8217;s what we expect, it&#8217;s part of our lives, and it will be part of our childs&#8217; lives as they grow up. We don&#8217;t think much about it- it&#8217;s simply there.</p>
<p>If you&#8217;ve watched this video from TED on how <a target="_blank" href="http://www.ted.com/talks/ken_robinson_says_schools_kill_creativity.html">schools kill creativity</a>, you know that there are some salient points to be made about how our primary and secondary educational system encourages a certain type of talent &#8211; science and maths &#8211; while actively discouraging the humanities and arts. While I would love to see more study on the topic, I want to extrapolate on Sir Ken Robinson&#8217;s argument and apply it to the space of postsecondary education.</p>
<p>Consider: If you were a student entering college today, and you were told that you&#8217;re going to walk out with an average of $23,000 in debt ($33,000 for private schools, according to <a target="_blank" href="http://projectonstudentdebt.org/files/File/Debt_Facts_and_Sources.pdf">this study</a> [PDF] ), would you choose a career in engineering or in the fine arts? To <a target="_blank" href="http://www.democratandchronicle.com/article/20090329/NEWS01/903290339/Many-college-students-face-mountain-of-debt-once-they-graduate">quote one</a> student, borrowing so much only makes sense &#8220;as long as you&#8217;re going to the school for a career that will pay enough&#8221;, so it certainly seems like we are actively discouraging pursuit of &#8220;cultural&#8221; careers in the arts and humanities.</p>
<p>Is this a problem? Good question, but it certainly shapes our national identity. If we want to be known as a country of technical innovators, then this system is perfectly fine as it fills our homes with highly technical thinkers. If in contrast we want to be known as a cultural mecca, it&#8217;s the worst thing ever as we are actively discouraging our students from pursuing fields that contribute to that.</p>
<p>But that&#8217;s not the point I&#8217;m trying to make here, it is simply the path to how I got to this blog post. See, I see this as a problem, and problems need solutions, so I want to take a business-side approach to this issue and ponder on any market opportunities that might exist. After all, if federal programs are unable to meet this country&#8217;s educational needs, then private business will have to pick up the slack, and they&#8217;re only going to do it if there&#8217;s money to be made.</p>
<h3>Some Numbers</h3>
<p>To take some numbers from <a target="_blank" href="http://www.trends-collegeboard.com/student_aid/pdf/2009_Trends_Student_Aid.pdf">this study</a> [PDF], I&#8217;ve extracted the following table:</p>
<h5>Table 1: Total Student Aid and Nonfederal Loans Used to Finance Postsecondary Education Expenses in Constant (2008) Dollars (in Millions), 1998-99 to 2008-09</h5>
<table border="0" cellpadding="0" cellspacing="0" class="callout">
<tbody>
<tr>
<th>Year</th>
<th>2004</th>
<th>2005</th>
<th>2006</th>
<th>2007</th>
<th>2008</th>
</tr>
<tr>
<th>Federal Grants</th>
<td>$21,441</td>
<td>$20,503</td>
<td>$20,579</td>
<td>$22,328</td>
<td>$24,784</td>
</tr>
<tr>
<th>Federal Loans</th>
<td>$63,674</td>
<td>$65,272</td>
<td>$66,327</td>
<td>$72,938</td>
<td>$83,981</td>
</tr>
<tr>
<th>Work-Study</th>
<td>$1,257</td>
<td>$1,183</td>
<td>$1,127</td>
<td>$1,123</td>
<td>$1,171</td>
</tr>
<tr>
<th>Tax Credit</th>
<td>$7,030</td>
<td>$6,990</td>
<td>$7,000</td>
<td>$7,000</td>
<td>$6,830</td>
</tr>
<tr>
<th>State Grants</th>
<td>$7,681</td>
<td>$7,696</td>
<td>$8,195</td>
<td>$8,446</td>
<td>$8,492</td>
</tr>
<tr>
<th>Institutional Grants</th>
<td>$25,140</td>
<td>$26,840</td>
<td>$28,330</td>
<td>$29,960</td>
<td>$31,160</td>
</tr>
<tr>
<th>Private Grants</th>
<td>$9,890</td>
<td>$10,620</td>
<td>$11,280</td>
<td>$12,200</td>
<td>$11,960</td>
</tr>
<tr>
<th>Private Loans</th>
<td>$16,030</td>
<td>$19,250</td>
<td>$22,050</td>
<td>$23,760</td>
<td>$11,900</td>
</tr>
</tbody>
</table>
<p>What we can easily extract from this is the individual line items which add load to students. The loans are easy, and I am also including Work Study and Institutional Grants. The former, because it&#8217;s activity that actively detracts from a student&#8217;s attention to their studies (by having a job) and the latter for reasons I discuss below. Given that, I&#8217;ve generated the following table:</p>
<h5>Table 2: Total unmet need covered by students in Constant (2008) Dollars (in Millions), 1998-99 to 2008-09</h5>
<table border="0" cellpadding="0" cellspacing="0" class="callout">
<tbody>
<tr>
<th>Year</th>
<th>2004</th>
<th>2005</th>
<th>2006</th>
<th>2007</th>
<th>2008</th>
</tr>
<tr>
<th>Total Unmet Need Financed by Debt</th>
<td>$106,101</td>
<td>$112,545</td>
<td>$117,834</td>
<td>$127,781</td>
<td>$128,212</td>
</tr>
</tbody>
</table>
<p>Do you see what I see? I see a $128 billion dollar demand for a solution, but demand is only useful if a supply may be found that may be profitably offered to that market. Thankfully, the actual act of marketing any solution you can come up with is easy- between high school career counselors and college students&#8217; naturally viral nature you effectively have a captive audience, assuming your solution is a good one. But unless you&#8217;re the treasury or the federal bank you can&#8217;t exactly pull $128 billion dollars and slap it on the table, and even if you were I doubt the taxpayers would be willing to pay for that (though we do love our <a target="_blank" href="http://en.wikipedia.org/wiki/Military_budget_of_the_United_States">bombers</a>).</p>
<h3>Universities as Contributors to the Problem</h3>
<p>On of the real culprits in this whole situation is Universities themselves. College Tuition has been increasing at an average rate of <a target="_blank" href="http://www.finaid.org/savings/tuition-inflation.phtml">8% a year</a>, while the <a target="_blank" href="http://en.wikipedia.org/wiki/Median_household_income">median household income</a> is hardly keeping up, especially if you take inflation into account. My own Alma Mater for instance (Carnegie Mellon) posted an annual tuition rate of $40,000 dollars this year, which from what I can tell is the highest in the nation and a significant uptick from the $18,000 I was paying in 2000. So how exactly can universities justify this increase?</p>
<p>Fact is, those tuition numbers are simply not real, because universities are skimming the market. Simply put, all the financial data a student is asked to report when they apply for financial aid year after year is used to calculate exactly how much the student and their family can afford. Once they have this number, they will add as many student loans as the student is eligible for (maxxed out of course), and might even add some private loans to it as well. Once they have that number, they will add something called a &#8220;Need based grant&#8221;, &#8220;Merit based grant&#8221; or &#8220;institutional grant&#8221; (or something similar) as a line item to make up the difference because they can&#8217;t charge you any more.</p>
<p>This makes identifying a good solution to student debt a far more difficult problem, because as soon as you find a business solution to meet the above noted demand, universities can simply respond by adding another line item to their financial aid calculations and the problem is right back where it started.</p>
<h3>Or&#8230; is it?</h3>
<p>Here&#8217;s where things get a little devious, and I apologize for suspending my personal ethics to even suggest this. Consider: If you provide a method for students to raise money against their debt, and universities in response raise their tuition to capture that value so that the debt doesn&#8217;t actually go away&#8230; then they are <i>increasing the size of the market.</i> That&#8217;s right, simply by helping students find a way to meet their debt obligations, the behavior of the other actors in the market environment will ensure that your market size grows. And while this certainly doesn&#8217;t provide a real solution to the <i>actual</i> problem, it should have any finance guy&#8217;s salivary glands working in overtime.</p>
<p>If, of course, you can meet the demand. In a new and successful way.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.krotscheck.net/2009/12/10/looking-at-student-debt-as-an-opportunity.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Looking for a Partner</title>
		<link>http://www.krotscheck.net/2009/12/06/looking-for-a-partner.html</link>
		<comments>http://www.krotscheck.net/2009/12/06/looking-for-a-partner.html#comments</comments>
		<pubDate>Mon, 07 Dec 2009 00:00:31 +0000</pubDate>
		<dc:creator>Michael Krotscheck</dc:creator>
				<category><![CDATA[Blog]]></category>

		<guid isPermaLink="false">http://www.krotscheck.net/2009/12/06/looking-for-a-partner.html</guid>
		<description><![CDATA[I think it&#8217;s about high time that I find a partner. Let me explain: I have an Idea- and I think it&#8217;s a pretty big idea- but as I&#8217;ve moved forward with the tech implementation I&#8217;m starting to realize that<span class="ellipsis">&#8230;</span><div class="read-more"><a href="http://www.krotscheck.net/2009/12/06/looking-for-a-partner.html">Read more &#8250;</a></div><!-- end of .read-more -->]]></description>
				<content:encoded><![CDATA[<p>I think it&#8217;s about high time that I find a partner.</p>
<p>Let me explain: I have an Idea- and I think it&#8217;s a pretty big idea- but as I&#8217;ve moved forward with the tech implementation I&#8217;m starting to realize that my biggest hurdle is that I&#8217;m not a designer (no matter how much I might think I am). It&#8217;s not a question of skill- well, ok, in some cases it is &#8211; but more a question of speed: I can sling code with the best of them, but I can&#8217;t for the sake of me figure out how to make something easy use and/or pretty without beating my head against the wall for days on end. I don&#8217;t have the practice, skills or experience to do that quickly, so I end up finding more and more excuses to refine the technology than really focusing on what matters: the User experience.</p>
<p>As such, the skill set should complement my own- I can handle the implementation, you should be able to handle the look, feel, and experience. This goes beyond simple design, too- we&#8217;re going to have to collaborate on feature priorities, but as for the how to and now what that would be left largely in your hands. This means you&#8217;ll have to have a strong work ethic, and be willing and able to receive and reciprocate mutual encouragement- if one of us slips, we both fall, so in the truest sense of the word I&#8217;m looking for a Partner.</p>
<p>I don&#8217;t care about location- we can do meetings by Skype, phone or whatever as long as you are recommended and vetted by someone I know and trust. In fact, if you&#8217;re located in Pittsburgh that would be pretty awesome, as the startup community there with <a href="http://www.innovationworks.org/">InnovationWorks</a> and the <a href="http://alphalab.org/">Alpha Lab</a> are incredibly supportive of getting endeavors of the ground. That&#8217;s hardly a requirement though, so don&#8217;t let that turn you off.</p>
<p>There are two real requirements though: 1- You&#8217;re a seasoned professional (feel free to define that as you see fit), and 2- You have a highly developed sense of ethics. You&#8217;ll understand why that second one is important as soon as you get a whiff of the idea.</p>
<p>What do you get? Well, first of all you get to work with a seasoned code nerd who appreciates (as you saw above) good UI and UX, and really wants to make it part of the core of the team. I can&#8217;t exactly pay you- No startup at this stage of the game can, but you&#8217;ll be happy to know that I&#8217;m not getting paid either (In fact, I&#8217;m currently paying for the servers). As for equity- well, partner is partner, and I&#8217;m willing to go even-split, but that might include more people down the road as the business side of the idea starts to become more prominent.</p>
<p>So&#8230; uh&#8230; what&#8217;s the idea? There are a lot of people out there who know what it is already- I&#8217;m certainly not unwilling to share, but I&#8217;m not about to blog about it. I firmly believe that there&#8217;s no such thing as a new idea on the internet, and the only way you can differentiate yourself is to do it better. Having said that, a current google search doesn&#8217;t turn up with much, so I figure it&#8217;s worth a shot.</p>
<p>Interested? Know someone who might be interested? Well then drop me a line, send me some visual samples, get a mutual friend to introduce you and I&#8217;ll fill you in on the actual scope of the idea.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.krotscheck.net/2009/12/06/looking-for-a-partner.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Forging ahead at SxSW</title>
		<link>http://www.krotscheck.net/2009/12/01/forging-ahead-at-sxsw.html</link>
		<comments>http://www.krotscheck.net/2009/12/01/forging-ahead-at-sxsw.html#comments</comments>
		<pubDate>Tue, 01 Dec 2009 14:00:26 +0000</pubDate>
		<dc:creator>Michael Krotscheck</dc:creator>
				<category><![CDATA[Blog]]></category>

		<guid isPermaLink="false">http://www.krotscheck.net/?p=2263</guid>
		<description><![CDATA[First, the big news: <a href="http://www.afhill.com/blog">Andrea Hill</a> and I will be jointly leading one of the core conversations at <a href="http://sxsw.com/">South By Southwest</a>. Cool, huhn? Even better, our conversation will be focused on managing your career and figuring out how to pursue opportunities, somethign that's been at the forefront of both of our minds recently.<div class="read-more"><a href="http://www.krotscheck.net/2009/12/01/forging-ahead-at-sxsw.html">Read more &#8250;</a></div><!-- end of .read-more -->]]></description>
				<content:encoded><![CDATA[<p>First, the big news: <a href="http://www.afhill.com/blog">Andrea Hill</a> and I will be jointly leading one of the core conversations at <a href="http://sxsw.com/node/3854">South By Southwest</a>. Cool, huhn? Even better, our conversation will be focused on managing your career and figuring out how to pursue opportunities, something that&#8217;s been at the forefront of both of our minds recently. But before I extrapolate more on where we&#8217;re going with this, let me first show you what our session will be all about:</p>
<div class="callout">
<h4><a href="http://panelpicker.sxsw.com/ideas/view/4553">Forging Your Ideal Career</a></h4>
<p>You’ve proven you’re a great developer / designer. How do you rise above the production floor to share your ideas and insights, and drive the solution rather than simply implementing it? Presenters will share their strategies for cultivating your career and attaining personal satisfaction while still keeping a steady paycheck!</p>
<ul>
<li>What if you feel your company&#8217;s career path is not for you?</li>
<li>How do you position yourself as what you want to be doing, versus what you&#8217;re currently doing?</li>
<li>How can networking help?</li>
<li>What opportunities exist outside work?</li>
<li>Forget work-life balance: how do you maintain paid work-unpaid work balance?</li>
<li>How do you get support from your organization for your outside activities?</li>
<li>What ideas do you share with your employer, versus keeping them to yourself?</li>
<li>Wherein lies the problem: Your career, your job, or your company?</li>
<li>When is it time to leave?</li>
<li>How do you move on without burning bridges? </li>
</ul>
</div>
<p><span style="color: #BBBBBB; font-size: .8em">
<p class="small">Personally, I find this ironically appropriate because I recently left an employer whom I absolutely loved in favor of a new opportunity, but I digress&#8230;</p>
<p></span></p>
<p>Now that we&#8217;ve been chosen (muchas gracias), we&#8217;ve entered into a tacit agreement with the organizers that we will help them make this years&#8217; SxSW as awesome as humanly possible. No pressure, right? Well, they&#8217;ve also thrown us a bit of a curve ball in that we&#8217;ve been asked to lead a discussion (Known as a Core Conversation) rather than holding a joint presentation. This means no A/V equipment, and the content coming from the discourse rather than the presentation.</p>
<p>After thinking about it for a bit, I really feel this is a much better format for the topic. Consider: Careers are very personal things, and for either of us to claim that we have all the answers is just a mite bit arrogant. So rather than proclaim to be career management experts (which we&#8217;re not), we&#8217;re just two people with applicable history who are willing to seek out guidance from others with similar experiences.</p>
<p>Yet it&#8217;s also extremely important to frame what the topic is NOT. This is not a way for you to get out of a stifling company, nor a way for you to get your unappreciative boss fired. This is especially not a forum where you can bitch about lazy coworkers who are holding you back. This is a forum where we discuss how to frame your career goals, evaluate your current situation for opportunities, and move from there.</p>
<p>Which brings me to you, our readers, as we&#8217;re looking for feedback and information to help us lay the foundations. We&#8217;re looking for any kind of feedback- experiences, questions, data- everything from real experiences about why you made a career based move to silly topics about your lucky teddy bear. Spit it out, we&#8217;d love to know it. </p>
]]></content:encoded>
			<wfw:commentRss>http://www.krotscheck.net/2009/12/01/forging-ahead-at-sxsw.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MAX Report, Day 1</title>
		<link>http://www.krotscheck.net/2009/10/06/max-report-day-1.html</link>
		<comments>http://www.krotscheck.net/2009/10/06/max-report-day-1.html#comments</comments>
		<pubDate>Tue, 06 Oct 2009 13:35:33 +0000</pubDate>
		<dc:creator>Michael Krotscheck</dc:creator>
				<category><![CDATA[Blog]]></category>

		<guid isPermaLink="false">http://www.krotscheck.net/?p=2254</guid>
		<description><![CDATA[Miss me? Yes, I haven&#8217;t posted for&#8230; oh man, way too long, and I honestly don&#8217;t think my schedule&#8217;s going to change much at all, so I doubt I&#8217;m going to pick up the pace anytime soon. But having said<span class="ellipsis">&#8230;</span><div class="read-more"><a href="http://www.krotscheck.net/2009/10/06/max-report-day-1.html">Read more &#8250;</a></div><!-- end of .read-more -->]]></description>
				<content:encoded><![CDATA[<p>Miss me? Yes, I haven&#8217;t posted for&#8230; oh man, way too long, and I honestly don&#8217;t think my schedule&#8217;s going to change much at all, so I doubt I&#8217;m going to pick up the pace anytime soon. But having said that, I&#8217;m currently in L.A. for the Adobe MAX conference, and since one of the caveats of Resource sending me here was that I&#8217;d try to collate all the things I came across and bring them back to the company, I figure I might as well make a few blog posts about it. Also, since I know my general readership isn&#8217;t as nerdy as I, I&#8217;ll try to put things in non-technical terms. I&#8217;m not going to explicitly critique individual sessions here- that&#8217;s tedious and boring, and you can see them online anyway (The keynote, for instance, is <a href="http://max.adobe.com/online/?sdid=EXCFD">here</a>) &#8211; but I will talk about the new stuff that&#8217;s coming out and give you some minor editorializing on it.</p>
<h3>Flash to iPhone!</h3>
<p>Yes, you&#8217;ve probably heard it everywhere- the next version of Flash will be able to compile for the iPhone. Chances are you&#8217;ve already learned all the details, so here&#8217;s a recap:</p>
<ol>
<li>Flash will be able to compile natively to the iPhone. This is a bytecode compiler, not a version of the AIR runtime or anything like that (Well, it might be, but Adobe&#8217;s not telling us what&#8217;s up).</li>
<li><em>Right Now</em> the support for mobile features is limited. For instance you can write to the camera, but you can&#8217;t read from the camera. So AR isn&#8217;t an option&#8230; yet.</li>
<li>Since it&#8217;s pretty limited from a hardware standpoint, it will require mastery of a new application and component framework called &#8220;Slider&#8221; (Introduced today).</li>
<li>As Adobe works on a roughly 18 month release cycle, you can expect the new version of Flash CS5 to be out around April/May, with betas available in the next month or three (Though they might accelerate it to coincide with the Catalyst/Builder release slated for Q1).</li>
</ol>
<p><span style="color: #BBBBBB; font-size: .8em"></p>
<h4>Editorializing</h4>
<p>The interesting thing to note here isn&#8217;t that it&#8217;s &#8220;ooh ooh, iPhone&#8221;, but that it&#8217;s &#8220;ooh ooh, native bits!&#8221;. Adobe&#8217;s shown that Actionscript isn&#8217;t restricted to the flash player anymore, which could mean one of two things: 1- It&#8217;s Saberrattling directed at Microsoft and Sun to take their hands off the web space, else they&#8217;ll have competition in the Desktop space, 2- They&#8217;re trying to push AS as a legitimate development environment, or 3- Nothing, really, it&#8217;s just cool tech.</p>
<p></span></p>
<h3>Flash Player 10.1</h3>
<p>Secondly, Adobe announced a <a href="http://www.adobe.com/devnet/logged_in/jchurch_flashplayer10.1.html?devcon=f2">new point release of the Flash Player</a> this morning. There are lots of features, but perhaps the largest is that this player has been designed to work on 29 out of 30 mobile platforms (guess which one&#8217;s not in the list). Yes- that&#8217;s the full flash player available to smartphones. Additionally, here are some more takeaways:</p>
<h4>Resource Usage</h4>
<p>Mobile devices simply don&#8217;t have the computing power of desktop or laptop computers, so one of the major hurdles (and criticisms, if you listen to Apple and Google) is that the Flash Player puts a pretty significant strain on your system. While no amount of player improvement will save you from badly written software, it&#8217;s nice to see Adobe put some money into improving their own platform, and we&#8217;ll see exactly what the actual impact is.</p>
<h4>Multitouch Support</h4>
<p>Multitouch screens are everywhere now, mostly thanks to Apple, and for the Flash player to be competitive on a mobile platform it must accept input from a multitouch screen. This now opens the door to multitouch web experiences, which also makes Flash a competitive development platform for interactive walls and the such.</p>
<h4>Streaming Enhancements</h4>
<p>I doubt you&#8217;ll notice the actual impact of this, other than you won&#8217;t see as many interruptions while watching youtube&#8230; on your phone&#8230; while driving. No, really- the streaming enhancements are there to smooth out video playback in an environment where the video player is rapidly moving across different network access points (like cellular towers). You as a mobile user probably don&#8217;t realize how often your phone switches from one tower to the next because it&#8217;s handled so seamlessly, however it really did become obvious while watching video. If this enhancement really does what Adobe says it will, then live television on mobile devices will actually become technically feasible&#8230; while moving.</p>
<p><span style="color: #BBBBBB; font-size: .8em"></p>
<h4>Editorializing</h4>
<p>Personally I&#8217;m going to take all the marketing promises with a grain of salt, however whether or not these features perform is secondary to the nature of the features themeselves: This is probably the first time I&#8217;ve seen such an obvious example of how the desktop environment is no longer the feature driver, but is rather subject to how mobile devices are evolving. In order to bring Flash to the mobile platform, Adobe had to make some significant updates to the Flash Player, and desktop users stand to benefit greatly from them.</p>
<p></span></p>
<h3>Mosaic</h3>
<p>I highly suspect that this is the rebranding of the <a href="http://www.krotscheck.net/2008/10/04/adobe-genesis-make-your-own-mashup.html">Adobe Genesis</a> project which I blogged about some time ago. In short, it&#8217;s a way to create a series of interactive pods that can intercommunicate, but which in and of themselves have their own independent functionality. These pods can then be arranged on a page as you see fit (to, say, build out an HR application) and these pages can be managed (either at the page or pod level) by a workflow.</p>
<p>This is probably one of the strongest moves I&#8217;ve seen recently into the Enterprise software space (Well, other than the Oracle-Sun acquisition), and means that we might finally see a crack in the armor of monolithic ERP systems.</p>
<p><span style="color: #BBBBBB; font-size: .8em"></p>
<h4>Editorializing</h4>
<p>99.9% of you won&#8217;t care about this. To the remaining .1% who are operating with enterprise-scale budgets and are sick of hiring arrogant SAP consultants, this is a watershed product. Also, go follow <a href="http://twitter.com/dan_mcweeney">Dan McWeeney</a>- he&#8217;s one of the Devs on the project.</p>
<p></span></p>
<h3>AIR 2.0</h3>
<p>The announcement of AIR 2.0 addresses most of the major complaints people have had with the AIR platform. These are as follows:</p>
<ol>
<li><b>Native Installer support</b><br />
This sounds like you can create an installer which is not dependent on having the AIR runtime installed. There wasn&#8217;t too much detail on this, but I&#8217;m hopeful.</li>
<li><b>Memory Improvements</b><br />
Tweetdeck won&#8217;t kill your machine anymore (Well, it still will, but it&#8217;ll do less of that- expect a 50% improvement).</li>
<li><b>Launching Native Applications</b><br />
It will be possible to launch already installed applications from your AIR application, so if, for instance, you&#8217;re building some kind of a file browser, you can now open those files in the application they were meant to be opened in.</li>
<li><b>USB Recognition</b><br />
We saw a demo of reading files from a USB drive. While this may mean that only device recognition is possible (hey, there&#8217;s some kind of new USB device, but I don&#8217;t know what it does), if this is fully built out we can see hardware device UI&#8217;s managed completely via the flash platform.</li>
</ol>
<p><span style="color: #BBBBBB; font-size: .8em"></p>
<h4>Editorializing</h4>
<p>Honestly, this (plus the snippets pane in Flash which I don&#8217;t cover here) pretty much spell the end of Director. Good riddance.</p>
<p></span></p>
<h3>Flash CS5</h3>
<p>There are a ton of new features available in the upcoming Flash CS5, and as I&#8217;ve talked about the iPhone above, I&#8217;ll highlight the other ones here.</p>
<ul>
<li><b>Real Text Support</b><br />
This version of &#8220;Real Text Support&#8221; (Wasn&#8217;t there a buzzword like this a few years back?) means left to right, ligatures, underline, strikethrough, paragraph flow and the consolidation of all text embedding.</li>
<li><b>XFL as the base file format</b><br />
The base file format of a Flash file is moving to XML, so anyone can create/author flash files, and we won&#8217;t step on each other&#8217;s toes when they&#8217;re committed to a versioning system. Personally, I wonder how long it&#8217;s going to take Microsoft to write a XAML conversion script.</li>
</ul>
<p><span style="color: #BBBBBB; font-size: .8em"></p>
<h4>Editorializing</h4>
<p>About bloody time. Also, I should note that we just upgraded to CS4 two weeks ago, so I don&#8217;t expect to have official corporate blessing to use any of this stuff for another two years.</p>
<p></span></p>
<h3>LiveCycle Collaboration Services</h3>
<p>This is what I spent most of my day on yesterday, and will be spending most of my day on on Wednesday as well. In short, it is a way to create live multiuser experiences easily on the flash platform. If that doesn&#8217;t make sense to you, think of your favorite webconferencing solution (WebEx, Acrobat Connect, etc) and realize that now you can put this into your branded flash application. Oh yeah, and that works on mobile, too.</p>
<p>To be honest, this is really hard to describe unless you have a working sample, but imagine for a moment that you&#8217;re on the ESPN site doing your draft picks for fantasy football. Normally, you&#8217;d have to take turns, and it would take forever for emails to work their way around and so fort. Well, if this site was LCCS enabled you would see all the other players in your league interacting real time (no really, you&#8217;ll see their mice moving around), and could hand the baton around as to who gets to pick next.</p>
<p>Now, this has been around for a while known first as Cocomo and AFCS- but the big change now is that they&#8217;ve announced pricing. The best place to look is <a href="http://forums.adobe.com/message/2292267#2292267">here</a>, though I expect it&#8217;ll be officially posted somewhere else as well. Something to note- their blog doesn&#8217;t appear to be linked from the labs site, so here&#8217;s the link to the <a href="http://blogs.adobe.com/collabmethods/">LCCS Blog</a>.</p>
<p><span style="color: #BBBBBB; font-size: .8em"></p>
<h4>Editorializing</h4>
<p>It&#8217;s going to take a while to figure out what neat things people will do with this. I already have a few ideas, but I&#8217;m hardly the only mensa-grade genius thinking of these things, so we&#8217;re bound to see some really cool stuff.</p>
<p></span></p>
<hr />
<p>That&#8217;s about it for now. Today is going to be a really long day, so I doubt I&#8217;ll be able to post again, but you&#8217;ll definitely get an update from me on Wednesday-ish. If I missed anything, don&#8217;t hesitate to comment.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.krotscheck.net/2009/10/06/max-report-day-1.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Video on the Web: An Overview for Non-Geeks</title>
		<link>http://www.krotscheck.net/2009/07/01/video-on-the-web-an-overview-for-non-geeks.html</link>
		<comments>http://www.krotscheck.net/2009/07/01/video-on-the-web-an-overview-for-non-geeks.html#comments</comments>
		<pubDate>Wed, 01 Jul 2009 15:54:55 +0000</pubDate>
		<dc:creator>Michael Krotscheck</dc:creator>
				<category><![CDATA[Blog]]></category>

		<guid isPermaLink="false">http://www.krotscheck.net/?p=2216</guid>
		<description><![CDATA[<p>In combination with my presentation on Streaming Media on the Web given to <a href="http://www.columbusdigital.org">Columbus Digital</a> last night, I figured I'd provide a high-level overview of how streaming media works on the web. I'm very intentionally trying to write this for a non-technical audience, so please provide feedback if I get a little too dense.</p>
<p>There are, in essence, three different ways to consume media on the internet. This is regardless of what kind it is- a solution that would work for sound will also work for video and vice-versa. While technical implementation may limit the formats you can broadcast, those choices are usually made well after the project requirements have been set.</p><div class="read-more"><a href="http://www.krotscheck.net/2009/07/01/video-on-the-web-an-overview-for-non-geeks.html">Read more &#8250;</a></div><!-- end of .read-more -->]]></description>
				<content:encoded><![CDATA[<p>In combination with my presentation on Streaming Media on the Web given to <a href="http://www.columbusdigital.org">Columbus Digital</a> last night, I figured I&#8217;d provide a high-level overview of how streaming media works on the web. I&#8217;m very intentionally trying to write this for a non-technical audience, so please provide feedback if I get a little too dense.</p>
<p>There are, in essence, three different ways to consume media on the internet. This is regardless of what kind it is- a solution that would work for sound will also work for video and vice-versa. While technical implementation may limit the formats you can broadcast, those choices are usually made well after the project requirements have been set.</p>
<h3>Progressive Download</h3>
<p>The first is Progressive Download. This is the easiest and the one you&#8217;re most likely to encounter in your day to day life, and will also be the cheapest for you to implement. In essence, you copy a video file and a player out onto a normal web server, and when a user loads the page with the player, that player will start to download the video and begin playing it as soon as it has enough to ensure a continuous stream.</p>
<p>The advantages are many. First, it&#8217;s easy to do- dozens of prepackaged players exist, and encoders are pretty easy to find as well. In some cases, you don&#8217;t even need a player- quicktime will play directly in your browser as long as you have the plugin. The downside is that your video is available for anyone and everyone to download and, presumably, rebroadcast on their own servers. </p>
<p>If you&#8217;re working on a viral campaign this is actually an advantage, but in most cases it&#8217;s probably not- who knows how some enterprising individual will mashup your video, right?</p>
<h3>Server Based Streaming</h3>
<p>The second method is server-based streaming. Rather than using a single web server, you&#8217;re now using two: A web server for your player, and a streaming server for your media. The user experience is practically identical- all changes happen under the hood as the user is only receiving the part of the media they&#8217;re currently watching. Once a particular second has been consumed, it&#8217;s discarded.</p>
<p>The advantages of this method are several: First, it&#8217;s a lot easier to detect how fast your client&#8217;s connection is, so you can provide them a smaller file that will still give them a good user experience. Secondly it is more secure- your user can&#8217;t really save the media without a third-party program, and those fail if you encrypt your stream. Thirdly, you can publish live media streams with this method- concerts, conventions, presentations and the like are now all accessible in real time.</p>
<p>Unfortunately this method isn&#8217;t exactly cheap&#8230; if done in house. It usually means a new server, server software that will cost thousands, and a developer who knows how to set up and maintain your server. To keep costs low you can contract with a media hosting company that already has the hardware and software set up. The free ones include Vimeo and Youtube, though they limit you to certain players and encryption is usually not available.</p>
<h3>Peer to Peer Streaming</h3>
<p>This method is (surprise surprise) very popular in the adult industry, but is also used for more common applications like Skype. The role of the server is cut out almost completely in this, as we instead broadcast media directly from one user to another.</p>
<p>The nice thing about this is that you can have a high-quality person-to-person interaction without paying an arm and a leg for bandwidth.</p>
<p>The disadvantages are largely experience related, since one of your users must act as the media publisher via a camera, microphone, or pre-downloaded file. That user will then be limited to how many people they can broadcast to simultaneously by how fast their internet connection is. 
</p>
<h3>Strategies for Selection</h3>
<p>Given the above, choosing a media streaming approach is relatively easy. The default is progressive download- if you don&#8217;t have a lot of media and don&#8217;t need anything encrypted or fancy, just go with that. If that&#8217;s not enough for you, decide whether you need a live feed: If not, use a streaming server.</p>
<p>After this things get a little trickier, because live media may be broadcast in many forms. The rule of thumb I use is as follows: If the number of consumers of a single media stream exceed the number of streams that can be provided at the highest bitrate given the internet connection, use a streaming server.</p>
<p>Some examples:</p>
<ul>
<li><strong>The Democratic National Convention</strong><br />
		Single source of video, many users: Server Based Streaming</li>
<li><strong>YouTube</strong><br />
		Many sources of video, many users: Progressive download or Server Based Streaming (I recommend the latter based on scale).</li>
<li><strong>Pandora</strong><br />
		Many individual audio files, must be secured from copying: Streaming server</li>
<li><strong>Amazon.com Album Previews</strong><br />
		Many individual audio clips: Progressive download</li>
<li><strong>Customer service training video (internal)</strong><br />
		Lives on internal network, not live, single video: Progressive download.</li>
<li><strong>Internet Phone</strong><br />
		Thousands of sources, thousands of consumers: Peer to Peer.</li>
</ul>
<p>I hope this guide was helpful. If you have any additional questions, don&#8217;t hesitate to put them in the comments.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.krotscheck.net/2009/07/01/video-on-the-web-an-overview-for-non-geeks.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Bootstrapping a Startup: Zend and WordPress Auth Integration</title>
		<link>http://www.krotscheck.net/2009/05/16/bootstrapping-a-startup-zend-and-wordpress-auth-integration.html</link>
		<comments>http://www.krotscheck.net/2009/05/16/bootstrapping-a-startup-zend-and-wordpress-auth-integration.html#comments</comments>
		<pubDate>Sat, 16 May 2009 11:00:47 +0000</pubDate>
		<dc:creator>Michael Krotscheck</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[bootstrap]]></category>
		<category><![CDATA[startup]]></category>
		<category><![CDATA[wordpress]]></category>
		<category><![CDATA[zend]]></category>

		<guid isPermaLink="false">http://www.krotscheck.net/2009/04/22/bootstrapping-a-startup-zend-and-wordpress-auth-integration.html</guid>
		<description><![CDATA[Three weeks ago, Columbus hosted Startup Weekend, and one of the presenters (blah name here) effectively stated that the first step of a startup should be to get something out there to gauge interest. This is fair- fact is there’s<span class="ellipsis">&#8230;</span><div class="read-more"><a href="http://www.krotscheck.net/2009/05/16/bootstrapping-a-startup-zend-and-wordpress-auth-integration.html">Read more &#8250;</a></div><!-- end of .read-more -->]]></description>
				<content:encoded><![CDATA[<p>Three weeks ago, Columbus hosted Startup Weekend, and one of the presenters (blah name here) effectively stated that the first step of a startup should be to get something out there to gauge interest. This is fair- fact is there’s no point in throwing development hours at a project if you don’t know whether it’ll gain traction. This also gives you an opportunity to gather metrics and information that you can take to potential investors.</p>
<p>The real challenge, however, is “Getting Something Out There” that you can build on. I don’t mean setting up a blog or a couple of static pages, I mean putting in place a scaffolding that you don’t have to replace in its entirety as your business concept matures. The optimal solution then seems to be to use an established software package that can be extended to suit your needs.</p>
<p>Easier said than done. Every CMS out there claims to be extendable, yet not all are created equal. Furthermore extensibility usually requires that you build within their own framework, which then locks you into a third party whom you don’t have control over.</p>
<p>This can be overcome by developing your business services independently, and create a loose integration between your application and your CMS. By doing this you’re suddenly free to proceed with your own plans without the added worry of being locked into a platform.</p>
<p>So why did I choose WordPress and Zend? Well, WordPress has an easily understood plugin structure as well as an active developer community, plus its plugins allow you to do pretty much anything your heart desires. Zend was chosen because it’s a professionally supported application framework with quite a few corporate backers, and it’s written in the same language as WordPress- PHP (Plus, it’s what I know- Added Bonus).</p>
<p>The rest of this post is going to get technical, so I hope those of you who aren’t as geeky as I don’t mind. In essence I describe how to accomplish a loose WordPress-to-Zend integration with all the benefits I described above.</p>
<h3>Step 0: Assumptions</h3>
<p>Before I begin, there are some assumptions I’m going to make.</p>
<ol>
<li>You know how a Zend MVC application is structured.</li>
<li>Your Zend code base will be hosted on the same server as your WordPress install.</li>
<li>You are running application stacks on the same primary domain. (blog.fancybrandname.com and www.fancybrandname.com works)</li>
<li>Your Zend application will handle user authentication records. This is because you don’t necessarily want to be restricted to WordPress’ table structure.</li>
<li>Your application uses the MVC Templating System that comes with Zend.</li>
<li>The WordPress integration code will live in the plugins directory on the WordPress side and (with one notable exception) in the ~library/ directory on the Zend side.</li>
</ol>
<p>Most importantly, please understand that this implementation is NOT for the faint of heart, and requires additional code on your part. I cannot easily make any assumptions about how user authentication is handled within your Zend application, nor what models or methods you have built to simplify object retrieval.</p>
<h3>Step 1, Database: Create a linking table</h3>
<p>The first fundamental requirement is that we need some way of linking the WordPress user table (usually named wp_users) to the user table in the zend application. Usually this is done via a linking table, that might look something like this:</p>
<div class="code">
<pre>
CREATE TABLE `user_id_link_table` (
  `id_zend` bigint(20) unsigned NOT NULL,
  `id_wordpress` bigint(20) unsigned NOT NULL,
  KEY `id_zend ` (`id_zend `),
  KEY `id_wordpress ` (`id_wordpress `)
);
</pre>
</div>
<h3>Step 2, Zend and WordPress: Configure the Cookie Domain</h3>
<p>To make sure your authentication cookies are available across your two domains, you’ll need to make sure both WordPress and Zend are looking for the same cookie. The way to do this is to set a wildcard Cookie domain so it transfers from one domain to another. If you look through the various configuration files and session initialization methods, you might see entries like “www.yourdomain.com” or “blog.yourdomain.com” near a reference to a cookie domain. To make sure they transfer, replace all instances with “.yourdomain.com” (the period at the beginning is important). That should ensure that your cookies are portable.</p>
<h3>Step 3, Zend: Setting up an integration controller</h3>
<p>The first thing we need to do is make sure that your Zend Application is fully loaded. Since you might want to use view helpers in your page templates, this means that we actually have to set up a ‘dummy’ controller that is used for integration purposes only, but which doesn’t try to output anything. This is easily done:</p>
<div class="code">
<p>File: ~controllers/IntegrationController.php</p>
<pre>
&lt;?php
/**
 * The Integration Controller.
 */
class IntegrationController extends Zend_Controller_Action
{
    /**
     * Index action. Sets up the entire framework but disables output.
     */
    public function indexAction()
    {
        $this-&gt;_helper-&gt;viewRenderer-&gt;setNoRender();
    }
}
</pre>
</div>
<h3>Step 4, Zend: Extending the AutoLoader</h3>
<p>The fourth step is that we need to extend the Zend AutoLoader, because otherwise it will get confused when WordPress tries to load its plugins. Since we don’t really know which plugins will be loaded ( and thus we can’t explicitly include them in our $PATH ), we’re simply going to restrict the Zend Autoloader to restrict its activities to certain namespaces.</p>
<p>This file is called ~library/Wordpress/Loader.php</p>
<div class="code">
<p>File: ~library/Wordpress/Loader.php</p>
<pre>
&lt;?php
require_once('Zend/Loader.php');

/**
 * The WordPress loader class is a quick filter that ensures only specific application
 * libraries are passed through to load handling.
 */
class WordPress_Loader extends Zend_Loader
{
    /**
     * Override of the loadClass method.
     *
     * @param string $class
     * @param string|array $dirs
     */
    public static function loadClass($class, $dirs = null)
    {
        $parts = split("_", $class );

        switch ( $parts[0] )
        {
            case 'Zend':
            case 'Wordpress':
            case 'YourNamespace':
                parent::loadClass($class, $dirs);
        }
    }

    /**
     * This handler has to be here for Zend_Loader invocation purposes
     *
     * @param class $class
     * @return string|boolean
     */
    public static function autoload($class)
    {
        try {
            self::loadClass($class);
            return $class;
        } catch (Exception $e) {
            return false;
        }
    }
}
?&gt;
</pre>
</div>
<p>Once we’ve extended our AutoLoader, we now have to properly invoke it in our Zend Bootstrapper.</p>
<p class="note">NOTE: You may have to adjust the following code somewhat so it fits in with your application. My own application has a Bootstrap Class within which this is a private method.</p>
<div class="code">
<p>File: ~bootstrap.php</p>
<pre>
/**
 * Application Bootstrapper.
 */
class Bootstrap
{
    private function setAutoLoad()
    {
        require_once ( 'Zend/Loader.php' );
        // Notice that I'm still calling Zend_Loader, but I'm passing the new Classname.
        Zend_Loader::registerAutoload('Wordpress_Loader');
    }
} 
</pre>
</div>
<h3>Step 5, Zend: Creating a Session Model</h3>
<p>This fifth step is necessary if you’re going to delegate all authentication tasks to the Zend application rather than to WordPress itself. By treating our user sessions like a CRUD-based application, we can abstract it entirely into a Model rather than keeping the code within a Controller. By doing this we can invoke the method from anywhere, including a WordPress plugin.</p>
<p class="note">NOTE: I’m putting this session class into the WordPress namespace, while it really should go into a namespace appropriate to your application.</p>
<div class="code">
<p>File: ~library/Wordpress/Model/Session.php</p>
<pre>
&lt;?php
/**
 * The session model wraps basic session creation and destruction methods
 * into one single interface. 
 */
class WordPress_Model_Session extends WordPress_Model_Abstract
{
    /**
     * Creates a new session (aka logs in a user)
     *
     * @param string $user
     * @param string $password
     * @return 
     */
    public function create ( $user, $password )
    {   
        // Get our authentication adapter and check credentials
        $adapter    =   $this-&gt;_getAuthAdapter( $user, $password );
        $auth       =   Zend_Auth::getInstance();
        $result     =   $auth-&gt;authenticate($adapter);

        if ( !$result-&gt;isValid() )
        {
            return false;
        }
        else
        {
            // We're authenticated! Add your own logic here.


            return true;
        }
    }

    /**
     * Destroys a session (aka logs out a user)
     */
    public function destroy ( )
    {
        Zend_Session::forgetMe();
        Zend_Auth::getInstance()-&gt;clearIdentity();
    }

    /**
     * Constructs an instance of the auth adapter for this model.
     *
     * @return Zend_Auth_Adapter_DbTable
     */
    protected function _getAuthAdapter( $login, $password )
    {
        // Put your authentication plugin loader code here.

        return $adapter;
    }
}

</pre>
</div>
<h3>Step 4, Zend: Add an integration method to your Zend Bootstrapper</h3>
<p>The last thing we need to do is create a method in our bootstrapper that lets us load the entire application without Zend trying to parse the URL into which it was loaded. To do this, we create our own HTTP Request instance with a URL that invokes the Controller and Action we created in step 3, thus effectively ‘fooling’ the FrontController into thinking it was invoked from somewhere else.</p>
<div class="code">
<p>File: ~/bootstrap.php</p>
<pre>
/**
 * Application Bootstrapper.
 */
class Bootstrap
{
    /**
     * Executes the application in a bootstrapped integration state.
     */
    public function integrate()
    {
        // Construct a 'Dummy' Url to use for our Request.
        $uri = sprintf ( 'http://%s/integration/index',$_SERVER['HTTP_HOST'] );
        // Create a new request object
        $request = new Zend_Controller_Request_Http( $uri );
        // Dispatch our FrontController
        $this-&gt;_frontController-&gt;dispatch( $request );
    }
}
</pre>
</div>
<p>At this point, we’re done with all the work we need to do on the Zend side of things. On to the WordPress Plugin!</p>
<h3>Step 6, WordPress: Create a plugin</h3>
<p>The sixth step is to make sure that your entire Zend Application is available to WordPress. This is a security risk- the instant someone discovers a vulnerability in WordPress they’ve got access to everything, so make sure you have a competent PHP developer who knows how to secure an application.</p>
<div class="code">
<p>File: ~/wp-content/plugins/zend/zend.php</p>
<pre>
&lt;?php
/*
Plugin Name: Zend Integration Plugin
Version: 1.0.0
Description: Allows WordPress to authenticate users against the a Zend Session Model
Author: Michael Krotscheck
Author URI: http://www.krotscheck.net/
*/

class ZendIntegrationPlugin
{
    /**
     * Constructor. Initializes this class.
     */
    function __construct()
    {

    }
}

// Load the plugin hooks, etc.
$zend_integration_plugin = new ZendIntegrationPlugin();

</pre>
</div>
<h3>Step 7, WordPress: Load the Zend Framework</h3>
<p>The next step is to load your Zend application. By creating a method that explicitly loads our Bootstrapper and then invoking the integration method we created in Step 3 above, we load all necessary classes and dependencies without them interfering with WordPress.</p>
<div class="code">
<p>File: ~/wp-content/plugins/zend/zend.php</p>
<pre>
class ZendIntegrationPlugin
{
    function __construct()
    {
        // .... previous code ....
        $this-&gt;Wordpress_framework_init();
    }

    /**
     * Initialize the Zend framework for inclusion.
     */
    public function WordPress_framework_init()
    {
        // Import the Zend Bootstrapper. This path needs to be absolute.
        require_once ( '@APPLICATIONROOT@/bootstrap.php' );

        // Create a new Bootstrapper instance and invoke the integration method.
        $bootstrap = new Bootstrap ( );
        $bootstrap-&gt;integrate();
    }
}
</pre>
</div>
<h3>Step 8, WordPress: Disable Unnecessary Functions</h3>
<p>Since we’re delegating all session authentication tasks to your Zend application, we need to explicitly disable many of WordPress’ default functionality related to password and account management. We do this by using the application hooks created explicitly for that purpose.</p>
<div class="code">
<p>File: ~/wp-content/plugins/zend/zend.php</p>
<pre>
&lt;?php

class ZendIntegrationPlugin
{
    function __construct()
    {
        // ... previous code ...

        // Disable Lost Password, Retrieve Password, and Password Reset
        add_action('lost_password', array(&amp;$this, 'disable_function'));
        add_action('retrieve_password', array(&amp;$this, 'disable_function'));
        add_action('password_reset', array(&amp;$this, 'disable_function'));

        // Remove Password Fields from the wordpress user profile.
        add_filter('show_password_fields', array(&amp;$this, 'disable_password_fields'));
    }

    /**
     * Used to disable certain display elements, e.g. password
     * fields on profile screen.
     */ 
    function disable_password_fields($show_password_fields)
    {
        return false;
    }

    /*
     * Used to disable certain login functions, e.g. retrieving a
     * user's password.
     */
    function disable_function()
    {
        die('Disabled');
    }
}
</pre>
</div>
<h3>Step 9, WordPress: Autoload the session</h3>
<p>This is perhaps the most complex piece of the plugin, because we have to do three things: First, we have to detect whether the authentication states between your Zend application and WordPress match. If they don’t, we have to either create a wordpress session or destroy it. The tricky bit here is that WordPress requires use of its own user database, so we have to retrieve basic information from the Zend User tables and construct a WordPress user should it not already exit.</p>
<p>Unfortunately, I cannot say how your Zend application is built nor what models exist that would allow you to retrieve a user record. As such I’ve inserted pseudocode in the method below that describes what needs to happen rather than make guesses about your implementation.</p>
<div class="code">
<p>File: ~/wp-content/plugins/zend/zend.php</p>
<pre>
&lt;?php

class WordPressAuthenticationPlugin
{
    function __construct()
    {
        // ... previous code ...

        add_filter('plugins_loaded', array(&amp;$this, 'auto_login'));
    }

    /**
     * This method runs after the plugins is loaded, and attempts to detect
     * an out-of-sync session.
     */
    public function auto_login()
    {
        $isZendAuthenticated = Zend_Auth::getInstance()-&gt;hasIdentity();
        $isWordpressAuthenticated = is_user_logged_in();

        // Check to see if we're logged out of Zend but still logged in to WordPress
        if ( !$isZendAuthenticated &amp;&amp; $isWordpressAuthenticated )
        {
            // Log out of WordPress.
            wp_logout();
            wp_clearcookie();
            set_current_user(null);
        }

        // Check to see if we're logged in to Zend but not WordPress
        if ( $isZendAuthenticated &amp;&amp; !$isWordpressAuthenticated )
        {
            // Retrieve the user record from Zend
            $yourUserObject = yourUserRetrievalMethod();
            $wordpress_user_id = yourWordpressIdRetrievalMethod($user);

            // Check for the wordpress user ID, create a new user if necessary.
            if ( $wordpress_user_id == NULL )
            {
                // Retrieve the user creation scripts.
                require_once(ABSPATH . WPINC . DIRECTORY_SEPARATOR . 'registration.php');

                // Create a user object, using the hashed password value (It matter doesn't what you use as long as it's unique)
                wp_create_user($yourUserObject-&gt;login, $yourUserObject-&gt;password, $yourUserObject-&gt;email);

                // Check for a successful insert
                $wordpress_user_id = username_exists($login);
                if ( !$user_id )
                {
                    die("Error creating user!");
                }
                else
                {
                    yourWordpressIdUpdateMethod($user, $user_id);
                }
            }

            // Now that we know we have an existing wordpress user record that matches our Zend Table,
            // try to create a wordpress session
            $wpUser = new WP_User($wordpress_user_id, $yourUserObject-&gt;login);
            $wpPassword = md5($yourUserObject-&gt;password);
            wp_login($yourUserObject-&gt;login, $wpPassword, true);
            wp_setcookie($yourUserObject-&gt;login, $wpPassword, true);
            wp_set_current_user($wpUser-&gt;ID, $yourUserObject-&gt;login);
            return;
        }
    }
}
</pre>
</div>
<h3>Step 10, WordPress: Enable Login via WordPress</h3>
<p>At this point we are maintaining the authenticated session across our applications, but we don’t yet have WordPress authenticating users against our Zend user table. As above, I can’t make assumptions about how your authentication is set up, but I can show you which application hooks to set up, leaving the rest of the logic for you to fill in.</p>
<div class="code">
<p>File: ~/wp-content/plugins/zend/zend.php</p>
<pre>
&lt;?php

class WordPressAuthenticationPlugin
{
    function __construct()
    {
        // ... previous code ...

        add_filter('check_password', array(&amp;$this, 'check_password'), 10, 4);
    }

    /**
     * Override Check Password
     */
    public function check_password($check, $password, $hash, $user_id)
    {
        // Retrieve a user by the WordPress User ID. You can use any class in your Zend application.
        $user = findZendUserByWordpressId ( $user_id );

        // Check for a valid return data.
        if ( $user )
        {
            // Try to log in.
            $sessionModel = new WordPress_Model_Session();
            return $sessionModel-&gt;create( $user-&gt;login, $password );
        }

        return false;
    }
}
</pre>
</div>
<h3>Step 11, WordPress: Enable Logout via WordPress</h3>
<p>The very last vanity task to perform is to enable logging out via the WordPress buttons. Again we use an action handler, and in this case we explicitly call the Session destroy method we created in Step 5.</p>
<div class="code">
<p>File: ~/wp-content/plugins/zend/zend.php</p>
<pre>
&lt;?php

class WordPressAuthenticationPlugin
{
    function __construct()
    {
        // ... previous code ...

        add_action('wp_logout', array(&amp;$this, 'logout'));
    }

    /**
     * Runs Logout routines against the Zend controller.
     */
    public function logout ()
    {
        $sessionModel = new WordPress_Model_Session();
        $sessionModel-&gt;destroy();
    }
}
</pre>
</div>
<div class="hr">&nbsp;</div>
<p>And that&#8217;s it. With all these pieces in place your Zend application should now be integrated with your WordPress intall. Congratulations! Now your startup has a fully functional, plugin ready CMS without being tied to a commercial solution for the long term.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.krotscheck.net/2009/05/16/bootstrapping-a-startup-zend-and-wordpress-auth-integration.html/feed</wfw:commentRss>
		<slash:comments>17</slash:comments>
		</item>
		<item>
		<title>Advanced WordPress Installs</title>
		<link>http://www.krotscheck.net/2009/05/11/advanced-wordpress-install.html</link>
		<comments>http://www.krotscheck.net/2009/05/11/advanced-wordpress-install.html#comments</comments>
		<pubDate>Mon, 11 May 2009 21:30:23 +0000</pubDate>
		<dc:creator>Michael Krotscheck</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[columbus]]></category>
		<category><![CDATA[install]]></category>
		<category><![CDATA[wordcamp]]></category>
		<category><![CDATA[wordpress]]></category>
		<category><![CDATA[wordpress mu]]></category>

		<guid isPermaLink="false">http://www.krotscheck.net/?p=2200</guid>
		<description><![CDATA[<p>As some of you might know, I'll be speaking at <a href="http://www.wordcampcolumbus.com/" target="_blank">WordCamp Columbus</a> this Saturday. The title of the presentation is &#34;Advanced WordPress Installs&#34;, but I figured I'd put out a slightly more detailed overview of what I'll be speaking about.</p><div class="read-more"><a href="http://www.krotscheck.net/2009/05/11/advanced-wordpress-install.html">Read more &#8250;</a></div><!-- end of .read-more -->]]></description>
				<content:encoded><![CDATA[<p>As some of you might know, I&#8217;ll be speaking at <a href="http://www.wordcampcolumbus.com/" target="_blank">WordCamp Columbus</a> this Saturday. The title of the presentation is &quot;Advanced WordPress Installs&quot;, but I figured I&#8217;d put out a slightly more detailed overview of what I&#8217;ll be speaking about.</p>
<p>To begin with, this session starts where the <a href="http://codex.wordpress.org/Installing_WordPress#Famous_5-Minute_Install" target="_blank">5 minute install</a> stops. There are plenty of tutorials out there that will help you set up your own WordPress blog, so I&#8217;m not going to bother repeating them. Instead I&#8217;m going to start covering topics that you&#8217;ll run into when you want to have your WordPress install do more than what it was originally designed to do.</p>
<p>Since the topics covered are very technical in nature, I will also take the time to demystify some of them. In other words, if you&#8217;re already a developer in your own right you might not get much out of this presentation, as I will be covering some basic PHP syntax, server redirects as well as an overview of modifying DNS records.</p>
<p>On the other hand, if you are a blogger who&#8217;d like to have a good introduction, or are curious about how WordPress might fit into your corporate environment, this will be an excellent overview.</p>
<h3>Section 1: One Install, Many Blogs</h3>
<p>11:00AM-11:20AM</p>
<p>If you&#8217;re an avid blogger and/or maintain more than one WordPress blog, consolidating all of your blogs onto one single WordPress install can help with everything from plugin management to upgrades. Most plugins, however, naturally assume that they exist on a solitary install, so if you want to use something like <a href="http://wordpress.org/extend/plugins/google-sitemap-generator/" target="_blank">Google XML Sitemaps</a> there are some additional steps you need to take. As such, this first part will cover the following topics:</p>
<ol>
<li>Writing a Dynamic Configuration File (PHP)</li>
<li>Request Redirects with mod_rewrite</li>
<li>Configuring plugins for multi-site use</li>
</ol>
<h3>Section 2: WordPress<sup>&mu;</sup></h3>
<p>	11:20AM-11:40AM</p>
<p>In many corporate environments it&#8217;s often optimal to manage multiple blogs through one single administrative interface, which is where <a href="http://mu.wordpress.org/">WordPress<sup>&mu;</sup></a> (Multi-User) comes into play. Installs such as these are often tricky, because they require a bit more technical expertise to get them set up properly. As such, I will be covering the following:</p>
<ol>
<li>A brief feature overview of WordPress<sup>&mu;</sup></li>
<li>Installing WordPress<sup>&mu;</sup>.</li>
<li>Redirecting for subfolders (http://www.yourdomain.com/<strong>blogname</strong>).</li>
<li>Redirecting for subdomains (http://<strong>blogname</strong>.yourdomain.com/ ).</li>
<li>Updating CNAME DNS records for subdomains.</li>
</ol>
<p>If we have time at the end of the session I will open the floor for any additional questions you might have about installation challenges you might have faced. I can&#8217;t promise a comprehensive answer to all of them, but between myself and the rest of the room we should be able to get you pointed in the right direction.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.krotscheck.net/2009/05/11/advanced-wordpress-install.html/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Do You Follow Me On Twitter?</title>
		<link>http://www.krotscheck.net/2009/04/22/do-you-follow-me-on-twitter.html</link>
		<comments>http://www.krotscheck.net/2009/04/22/do-you-follow-me-on-twitter.html#comments</comments>
		<pubDate>Wed, 22 Apr 2009 12:49:23 +0000</pubDate>
		<dc:creator>Michael Krotscheck</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[conversation]]></category>
		<category><![CDATA[twitter]]></category>

		<guid isPermaLink="false">http://www.krotscheck.net/2009/05/12/do-you-follow-me-on-twitter.html</guid>
		<description><![CDATA[<p>One thing that has really started to bother me since the advent of Tweetdeck is the fact that I can't tell who's interested in actually having a conversation, and who's stuffed me into a filter and only follows me out of some... misplaced belief that a mutual follow will ensure that I provide them with my undying adulation. Thus I pose to you a social experiment: If you actually clicked on the twitter link to this post, and are reading this paragraph, either send me a private line, @ me or comment on this post, and I'll put you on the list of "people who are actually interested in having a conversation".</p>
<p>Everyone on that list gets followed. Everyone else gets dropped.</p>
<div class="read-more"><a href="http://www.krotscheck.net/2009/04/22/do-you-follow-me-on-twitter.html">Read more &#8250;</a></div><!-- end of .read-more -->]]></description>
				<content:encoded><![CDATA[<p>One thing that has really started to bother me since the advent of Tweetdeck is the fact that I can&#8217;t tell who&#8217;s interested in actually having a conversation, and who&#8217;s stuffed me into a filter and only follows me out of some&#8230; misplaced belief that a mutual follow will ensure that I provide them with my undying adulation. Thus I pose to you a social experiment: If you actually clicked on the twitter link to this post, and are reading this paragraph, either send me a private line, @ me or comment on this post, and I&#8217;ll put you on the list of &#8220;people who are actually interested in having a conversation&#8221;.</p>
<p>Everyone on that list gets followed. Everyone else gets dropped.</p>
<p>Yes, there are caveats. If I&#8217;ve never met you before in my life there&#8217;s a good chance I&#8217;m not going to follow you anyway, for reasons you&#8217;ll see below. Also if we&#8217;ve had more than a cursory set of @changes, have emailed each other regularly or (even better) have hung out in person you&#8217;re automatically on the list.</p>
<p>The true power of human communication is interaction, discussion and argument. It is not doe eyed consumption of what the latest celebrity has said, nor is it short-burst updates in the hope of being profound. It&#8217;s not link propagation, marketing, spin, advertising, or a long list of messages that boil down to &#8220;OMG I&#8217;m # away from ### Followers, Pay Attention to MEE!&#8221;. Human communication and true discussion requires time, effort, and thought, and cannot be acquired via txt messages or 140 character snippets. Think paragraphs. Think books. Think libraries.</p>
<p>Yes, it requires effort. It requires we meet, or have an email exchange, or talk on the phone, or have some kind of meaningful exchange other than &#8220;@krotscheck omg that picture is so cute&#8221;. Once that social vibe and comfort is established then yes, casual methods of communication (like twitter) are great ways to maintain it over distance, but you can&#8217;t do that just because you listened to their presentation at some conference.</p>
<p>If you want me to follow you, you have to convince me to care, and no small &#8220;follow&#8221; button or automated bot is going to do that. If you want me to treat you like a human being, to <em>really</em> listen to what you have to say, then you really should reciprocate.</p>
<p>Hypocrite? Not really. Listen, I give people day-to-day updates because I assume that they&#8217;re interested in what&#8217;s going on in my life. I use twitter for banter, not for a meaningful conversation or professional exchanges. Banter, by its very nature, assumes a level of familiarity you can&#8217;t just get from a website, and if I don&#8217;t feel comfortable bantering with you then yes, you&#8217;re not going to get followed.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.krotscheck.net/2009/04/22/do-you-follow-me-on-twitter.html/feed</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
	</channel>
</rss>
