Happy New Year 2014!

6. January 2014 22:48 by Cameron in Programming  //  Tags:   //   Comments

I know I'm a few days late for posting on New Year's day, but I was away in a cabin in northern California with limited Internet. 2014 is a new year and I plan to write at least one blog post a month. Last year, I didn't write a post each month, but I don't want to become uninterested in blog writing and learning new technologies. The best action a developer can take for his/her career is learning new skills - constantly. The world of technology is forever changing and evolving and those who sit complacently will fall behind and lose their competitive edge. Each year, as new students graduate college, they will be sharper and brighter with the newest tech in the industry. Anyone who fails to embrace new technologies will not survive in the coming wave of millenials entering the workforce, eventually replacing the vast majority of the workforce. People who fail to think about the future will sadly not have a future in IT. If you're in your mid to late 30's and haven't picked up a new skill lately, it's time to do so. Time is of the essence and the future of IT lies in the hearts and minds of the millenials and their children.

HDMI Audio Kext for NVIDIA Graphics - Hackintosh

6. January 2014 22:40 by Cameron in   //  Tags: , , , , , ,   //   Comments

I've been searching for HDMI audio for quite some time for my desktop hackintosh and tonight I found just the right thing! Simply install the kext by running the install.sh script from the dmg image and voila! I have tested my NVIDIA GTX 660 on OS X Mavericks 10.9.1 and it works beautifully! I tried the DSDT editing but I don't think I got it quite right and it wasn't detecting my TV as an audio output device. After I installed the kext, all was good! Note that all volume control must be done through your TV or audio receiver. OS X doesn't support volume control on digital audio devices. Also, I'm not sure if you can use this kext in conjunction with AppleHDAEnabler, but I don't see why this would be a problem. TonyMacx86 should include this in Multibeast as it would make life much easier for those who don't want to mess with their DSDT.

NVAudio-1.0.dmg (27.02 kb)

Compile kernel for Allwinner A20 Android Jelly Bean 4.2.2 tablet

12. December 2013 10:33 by Cameron in Android  //  Tags: , , , , , , ,   //   Comments

I recently bought an iView 777TPCII 7" Allwinner A20 tablet running Android Jelly Bean 4.2.2 and it has USB OTG support, but sadly no native joystick support! So naturally, I thought, I need to compile the necessary kernel modules to enable joysticks/gamepads. I'm no expert on compiling kernels for Android, but this method seems to work. You need to have a Linux or cygwin environment to compile your kernel. I've used VirtualBox on Windows 7 and installed Ubuntu 13.10 32-bit to setup my Linux build environment. I'm assuming you can install Linux in a virtual machine. It's fairly straight forward. After you have installed Ubuntu, you need to install the toolchain for building the kernel:

sudo apt-get install gcc-arm-linux-gnueabihf build-essential git u-boot-tools libncurses5-dev

Then you need to clone the linux-sunxi repository so you can build it:

git clone -b sunxi-3.4 https://github.com/linux-sunxi/linux-sunxi.git

After you have cloned the repository, change to the linux-sunxi directoy:

cd linux-sunxi

Then you need to setup the configuration for the A20 using this command:

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- sun7i_defconfig

Now you can configure your kernel options by running:

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig

Proceed to building your kernel and modules

make -j4 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- uImage modules

The -j4 option runs 4 make instances at the same time. Adjust to your CPUs available.

Finally, you need to create a full module tree:

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- INSTALL_MOD_PATH=output modules_install

GBA Development with HAM 2.71 SDK for Windows

30. September 2013 13:17 by Cameron in GBA  //  Tags: , , , , , ,   //   Comments

I'm starting development for the GBA with Jonathan S. Harbour's book and the HAM SDK. Jonathan's website links to the HAM 2.80 SDK, but I have read many reports that this version of the SDK does not compile C++ code properly and that one should use the HAM 2.71 SDK for Windows. It was quite difficult to find the HAM 2.71 SDK for Windows because nobody seemed to have it and the original website, www.ngine.de, has been down for quite some time. This is not surprising as the peek of GBA development was over 10 years ago. However, some of us are nostalgic for the old GBA especially if we can manage to get ahold of a flash cart like the discontinued EZ-Flash IV (Best GBA flashcart in existence and super rare) or the SuperCard MinSD (not so great for commercial roms but acceptable for development). Provided below is a link to the Windows version of the HAM 2.71 SDK:

HAM 2.7 SDK

HAM 2.71 Update

Dropbox Mirror HAM 2.7

Dropbox Mirror HAM 2.71

QUnit, JSCoverage and Jenkins

24. September 2013 10:09 by Cameron in Continuous Integration, Jenkins, PhantomJS  //  Tags: , , , , , , ,   //   Comments

A few years back I worked with a colleague of mine on getting JSCoverage integrated with QUnit to generate code coverage reports for QUnit. The process was fairly simple. We learned a ton about how to setup JSCoverage from this blog: http://www.eviltester.com/index.php/2008/06/08/test-driven-javascript-code-coverage-using-jscoverage/ You can either build the sources from JSCoverage's Subversion repository or if you are running Ubuntu, you can use the apt package manager to install JSCoverage. After obtaining JSCoverage, we were able to generate html coverage reports from JSCoverage for our unit tests that we wrote using QUnit, a unit testing framework for jQuery.

To generate coverage with JSCoverage, we used the command:

jscoverage [source_dir] [destination_dir]

Understand that the all files in the source directory will be copied to the destination directory and will be instrumented. We had to be careful not to instrument jQuery or QUnit so we put our tests in a separate folder. 

After that command has been run, one can browse to jscoverage.html and run the tests through the browser. JSCoverage also has a nice API that can accept querystrings to open test pages that will intrument the javascript. JSCoverage provides a summary for all instrumented files in the Summary tab and with each file in the summary, one can view a detailed breakdown of the coverage. 

As far as integrating this into Jenkins, there are a number of possible options, but it is not critical since JSCoverage provides its own reporting. Integration with Jenkins might be possible in the future however.

When you are working with JavaScript it's great to do unit testing, but integrating these tests into an automated system can be tricky.  Your code is made to be run in a browser, not on the command prompt.  Furthermore, you are probably manipulating the DOM and are dependant on HTML pages, so how could you automate something like this without opening up a browser? 

Enter PhantomJS and QUnit. 

PhantomJS is a headless browser with JavaScript API that will print any console.log() call to the command line. 

QUnit is a unit testing framework from the guys at JQuery.  It is made to display the results of your tests in a browser window.  Fortunately, QUnit provides callbacks that allow us to hook into the tests and provide proper output to PhantomJS.  In our case, this format is JUnit XML format. 

I followed someone who was doing something similar, but unfortunately his code was incomplete and also weird/broken.  Niltz's blog is: http://www.niltzdesigns.com Unfortunately Niltz's website is no longer online.

He did provide a nice .js file that hooked into QUnit's callbacks and stored the tests in a nice JS object.  From there, I edited his QUnit result printer to be able to output the correct XML.  These files were working great and they did their work without changing the way that our QUnit tests displayed when we viewed the tests manually in a browser.

The real trouble was the driver js file.  This Niltz guy had a driver, but it didn't properly use PhantomJS' interface and broke on execution.  I was able to use some of his code as a guide, but I was forced to almost completely re-write my own driver file. 

var page = require('webpage');

(function() {
    page.onConsoleMessage = function (msg) { 
        if(msg === 'phantomexit')
            phantom.exit(0);
        console.log(msg);
    };

    page.onLoadFinished = function(status){
        var PAGE_FAILED = 1;
        var TEST_FAILED = 2;
        var EXCEPTION = 3;

        if (status === 'success') {
            page.evaluate(function() {
                var testDone = function() {
                    var r = QUnitLogger.results;
                    var msg = qunitResultPrinter.print();
                    console.log(msg);
                    console.log('phantomexit');
                };

                if (QUnitLogger.done) {
                    return testDone();

                } else {
                    QUnitLogger.addEventListener('done', testDone);
                }
            });
        } else {
            console.log('Page failed to load: ' + phantom.args[0]);
            phantom.exit(PAGE_FAILED);
        }
    };

    try {
        if (1 !== phantom.args.length) {
            console.log('Usage: phantomjs-driver.js URL');
            phantom.exit();
        } else {
            phantom.state = 'phantomjs-driver-running';
            page.open(phantom.args[0]);
        }
    } catch(e) {
        console.log('Unhandled exception: ' + e);
        phantom.exit(EXCEPTION);
    }
})();

The tricky part here is the page.evaluate() function.  This allows me to execute code within the context of the loaded page, but the problem here is that it is run in a completely different scope, unaware of the variable 'status' for example.  The only way I can communicate with the code inside this function is either by a return or a console.log().  PhantomJS provides a nice callback for any console.log() inside of this phantom.evaluate() function called page.onConsoleMessage().

Using this we were able to fully integrate with QUnit and output the results of my tests in an XML format using the command:

./phantomjs phantomjs-qunit-driver.js ../test/index.html

An example of output is:

<testsuites><testsuite name="utilities" assertions="32" failures="0" time="38"><testcase name="setupValItems and cleanupValItems" assertions="5" time="20">....

From there, integration into Jenkins is fairly trivial.

Attached is the modified QUnit PhantomJS driver. I have left the tests out since your unit tests will be different.

qunit.zip (3.37 mb)

Super 8 by Innovation - Review

7. April 2013 18:34 by Cameron in   //  Tags: , , , , , , , , , , ,   //   Comments

I recently purchased a rare accessory for my SNES that allows me to play NES and Famicom games on my SNES called the Super 8, designed by Innovation in 1993.  One can also play SNES and Super Famicom games using the pass-through slot. The system uses a NOAC for playing NES and Famicom games in a similar fashion to how the Super Gameboy used Gameboy hardware for playing Gameboy games on the SNES. Since I have an NES, it's more of a novelty item for being able to use only one console to play each set of NES and SNES games. It's compatible with most NES and Famicom games out of the box including Castlevania III with the MMC5 mapper and Akumajou Densetsu, the Japanese version of Castlevania III, with the VRC6 mapper and enhanced audio. Some games do not work due to the system being a NOAC and not original NES hardware. The NES PowerPak by RetroZone does not work on the Super 8 for some reason, but perhaps this will be fixed in a later firmware update for the PowerPak.

Once my unit arrives, I will begin compiling a list of compatible games and how it compares to the NES.

Known issues with fixes:

  • The Super 8 does not include native support for SNES games that use co-processors, but this can be fixed by adding a few solder points on the mainboard - I will update this later with the exact guide on how to fix
  • The Super 8 suffers from the same jailbars issue that the top loading NES and some Famiclones experience - this can be fixed by soldering a 470micro farad cpacitor - I will update this post with where to solder later

My NES and SNES game collection

7. April 2013 18:01 by Cameron in   //  Tags: , , , , , , , , , , ,   //   Comments

It's been a while since I've posted a new blog post. I've been fairly busy with life and work lately. Over the past couple of weeks, I've been expanding my NES and SNES game library. I plan to collect several original titles that I enjoyed playing as a kid. Some of the games that I recently acquired for the NES are:

  • Donkey Kong Classics
  • Tengen's Pacman
  • Tetris
  • Othello
  • Mario Bros. Arcade Classics
  • Castlevania I
  • Castlevania II
  • Castlevania III
  • Duck Tales
  • Dr. Mario
  • Caesar's Palace
  • The Bugs Bunny Birthday Blowout
  • Tengen's Road Runner
  • The Bugs Bunny Crazy Castle
My NES collection is rapidly growing as I previously only had these games in my library:
  • Super Mario Bros. / Duck Hunt
  • Super Mario Bros. 2
  • Super Mario Bros. 3
  • Home Alone
  • The Legend of Zelda
I plan to add the Teenage Mutant Ninja Turtles trilogy, Megaman 1-6, Metroid, and several other great games to my collection. Megaman collections can easily go for $150 or more on eBay while a single copy of Megaman can be easily $30. I'm hoping to find a collection with all six games when I'm ready to add them to my collection. I love super Metroid on the SNES so I'm sure that the original Metroid will be an excellent addition. Metroid has held its value fairly well over the years. Copies of Metroid typically sell for $30 or more. I will also be adding a RetroZone NES PowerPak to my library so I can play translated Famicom games and homebrew. I would like to try my hand at NES development with 6502 assembly too.
 
For my SNES, I recently added these games:
  • Sim City
  • Donkey Kong Country 3
  • Buster Busts Loose
  • Kirby's Avalanche
  • Super Mario World 2: Yoshi's Island
I've got quite a large collection of SNES cartridges that I've been building on over the past few years:
  • Super Mario Kart
  • Super Mario All Stars + World
  • Super Off Road the Baja
  • Jurassic Park
  • Donkey Kong Country
  • Donkey Kong Country 2
  • Final Fantasy Mystic Quest
  • The Legend of Zelda: A Link to the Past
  • Chrono Trigger
  • Starfox
  • Mario Paint
  • Final Fantasy II
  • Final Fantasy III
  • Super Battletank: War in the Gulf
  • Super Caesar's Palace
  • Super Mario RPG
  • SNES PowerPak
  • Super Gameboy
  • Super Metroid
Since I have a SNES PowerPak, I can play most all translated Super Famicom games, homebrew, and almost all of the SNES games available. I've used my SNES PowerPak for development of my own and playing various hacks or ROM translations. Even though I can play nearly every game available for the SNES using the SNES PowerPak, I still enjoy collecting the original carts. 
 
One may say that it's cheaper to just use a NES/SNES to USB adapter and play games on an emulator, but it's just not the same as playing on the original hardware. I grew up in the 1990's and the NES/SNES were a big part of my childhood. Arguably, I'd have to say the SNES is my favorite console as it's one that I played the most. I didn't have an NES at home as a kid, but I used to play at friend's houses. I have all the emulators and ROMS, but nothing compares to the feeling of playing a game they way it was meant to be played, on the glorious consoles themselves.

SNES SDK

12. January 2013 20:21 by Cameron in   //  Tags: , , , ,   //   Comments

Over the past few days, I have been playing around with the SNES SDK that compiles C code to SNES ROMs for running in emulators or on real hardware. The SDK supports floating point emulation, 16-bit integers, controller input, and a basic graphics system. There is no sound support in the SDK for the SPC of the SNES (yet). Libraries can be added to the SDK pretty easily by writing C code and compiling to assembly to be linked with other programs.

In playing with the SNES SDK, I noticed that in math.h, a lot of the ANSI C math functions were left out due to hardware limitations of the SNES. However, without much effort, I was able to create working functions for the six basic trig functions and a square root function.

In mathematics, sine and cosine can be approximated by Taylor polynomial expansions. This makes it easy to implement functions in C to compute the sine and cosine of a value to a certain degree of precision. The following is the Taylor expansion functions for sine and cosine:

// taylor series expansion of the sin function
float sin(float x)
{
  return x - (mult(x,  3) / fact(3)) + (mult(x, 5) / fact(5)) - (mult(x, 7) / fact(7))+ (mult(x, 9) / fact(9)) - (mult(x, 11) / fact(11)) + (mult(x, 13) / fact(13));
}

// taylor series expansion of the cos function
float cos(float x)
{
  return 1 - (mult(x,  2) / fact(2)) + (mult(x, 4) / fact(4)) - (mult(x, 6) / fact(6)) + (mult(x, 8) / fact(8)) - (mult(x, 10) / fact(10)) + (mult(x, 12) / fact(12));
}

I had to create helper functions for x^n and x! (x factorial) since those aren't built into the compiler. The function, mult(x, n), raises x to the power n. The function, fact(x), computes the factorial of x. There is a pow(x, n) function implemented in the SDK, but it doesn't produce as accurate of results as my mult(x, n) function. The result can be seen when running pow(2, 12) versus mult(2, 12). The pow function returns 4095 while mult returns 4096 (the correct result).

The other trig functions were built on the sin and cos functions. There is a Taylor expansion for tan(x), but I decided to go with sin(x)/cos(x) since I couldn't properly expand tan(x) for enough accuracy. Below is the rest of the trig functions:

float tan(float x)
{
  return sin(x) / cos(x);
}

float sec(float x)
{
  return 1 / cos(x);
}

float csc(float x)
{
  return 1 / sin(x);
}

float cot(float x)
{
  return 1 / tan(x);
}

I understand the practicality of computing trig values on the SNES might not be huge for everyday use. However, this was more of a "Can I do this?" type of exercise. Games like Starfox for the SNES may have used trig calculations on the Super FX co-processor, but I doubt many games needed cosine or sine functions calculated on the main CPU. Perhaps game demos with oscillating text used sine or cosine as a function of time. 

The square root function is based on Newton's method. I found the code for this method here: http://www.codeproject.com/Articles/69941/Best-Square-Root-Method-Algorithm-Function-Precisi

// babylonian method for square roots
float sqrt(int n)
{
  // double a = (eventually the main method will plug values into a)
  float a = (float) n;
  float x = 1;
  int i;
 
  // For loop to get the square root value of the entered number.
  for( i = 0; i < n; i++)
  {
    x = 0.5 * ( x+a / x );
  }
 
  return x;
}

double newton_sqrt(double n)
{
  double x = 0.0;
  double xn = 0.0;
  int iters = 0;
  int i;
  for (i = 0; i <= (int)n; ++i)
  {
    double val = i*i-n;
    if (val == 0.0)
      return i;
    if (val > 0.0)
    {
      xn = (i+(i-1))/2.0;
      break;
    }
  }
  while (!(iters++ >= 100 || x == xn))
  {
    x = xn;
    xn = x - (x * x - n) / (2 * x);
  }

  return xn;
}

There are tons of different ways to compute an approximation to the square root, but I was more concerned with precision vs. speed.

Here's the code I used including the SNES SDK:

snessdk.zip (1.27 mb)

 

Here is where I found the SNES SDK Win32 binary:

http://forums.nesdev.com/viewtopic.php?f=12&t=6253

You will need Windows XP or higher for the SDK. The source for the SDK may be found here: http://code.google.com/p/snes-sdk/source/checkout

Here's a screenshot of my test program running in ZSNESW:

Beginning with Neo4j and Neo4jClient

4. January 2013 18:07 by Cameron in   //  Tags: , , , , , , , , ,   //   Comments

I will try my best to include everything necessary to get started with Neo4j. This is not meant to be a guide on how to program with C#, Visual Basic, Java, Cypher, or Gremlin. You will need to either have prior experience with those languages or read other resources to learn about them. If you don’t understand some of the computer science jargon, please let me know and I will try and make the wording more clear.

I'm not going to go into too much graph theory in this tutorial. You should have a basic understanding of what a directed graph is and how to create a data model since you seem to be interested in graph databases. All that you really need to know about graph theory is that a graph is a set of related nodes representing entities with relationships connecting the nodes.

Graph databases are an excellent way to model social data compared traditional relational databases. Social networking websites such as Twitter and Facebook use graph dbs for quickly querying through millions of users and their relationships to other objects or users. It would be much slower to use an RDBMS for a website like Facebook because of the need to select from tables with millions of records and perform joins on those tables. Joins are expensive operations in SQL databases and graph databases don't require explicit joins due to the nature of a graph's structure.

About Tools

Java is a programming language that runs in a virtual environment allowing it to run on thousands of different devices that have a Java virtual machine. Neo4j is an enterprise level graph database written in Java. Neo4jClient is a .NET client for interfacing with Neo4j’s REST API.

About Neo4jClient

Neo4jClient serializes  and deserializes objects to and from JSON to interact with the server which makes it very easy to store and retrieve objects.

Installation

Java

I’m assuming you already have Java installed, but if you don’t, you will need the JRE for Windows installed in order to run Neo4j. You can download the JRE from Oracle. When downloading the JRE, you can choose either the standalone JRE or the JDK, which includes the JRE. The JDK is mainly for Java developers and is not required if you don’t do Java development. Also, about whether to choose x86 or x64, I’d recommend that you choose x86 for simplicity. Most likely, you won’t need 64-bit addressing with your Java installation. This would only be if you have another project that requires the x64 release. The easiest download is any of the .exe installers as it will guide you through the installation process. Installation should take about 5 minutes and then you’ll be ready to move to setting up Neo4j.

Neo4j

Next, you should download Neo4j from neo4j.org. Unless you want to be bleeding edge, it’s recommended to download the Major Stable Community Version. At the time of writing, this is version 1.8.1. Make sure to get the Windows specific download. Follow the directions on the download page and open up a command prompt with administrator privileges to start your newly installed Neo4j server. Once you have started the server, you can browse to your web admin interface at http://localhost:7474. From there, you can use the Data browser page to create nodes and relationships. In the console tab, you can query your database using Cypher or traverse the graph using Gremlin. You can even send HTTP requests to the REST API if you want to learn about how to talk to Neo4j from other tools. In the Indexes tab, you can create indexes for fast retrieval of nodes or relationships. I will talk more about indexes later. You are now ready to setup Neo4jClient.

Visual Studio and Neo4jClient

You need to have Visual Studio 2010 Professional or higher or Visual C# 2012 Express Edition (free) installed to be able to install Neo4jClient using the Nuget package manager.  Unfortunately, Nuget does not work with Visual C# 2010 Express Edition. 

Create a new Visual C# or Visual Basic project and then proceed to installing Neo4jClient. You can install Neo4jClient by managing Nuget packages on your project or by running the following command in the Package Manager Console:

Install-Package Neo4jClient

Brief Overview of Neo4j and Neo4jClient

Indexes

Indexes are created for fast retrieval of information at a later point. This is extremely useful when querying a graph database on the order of millions of nodes. Manual traversal is slower and less efficient. One of the advantages of graph databases is speed and it is important to utilize indexes to increase speed.

Full text vs. Exact

A full text index is for searching on a node’s properties text, allowing partial or complete text to be searched. For example, if you have a set of nodes representing the Star Wars movies, if you search for nodes in the Movie index with a name like “Star Wars” with a full text index, you will get all nodes containing the text “Star Wars” in the name property.

However, an exact index requires that you search on a node’s properties text with exact text. For example, if you have a set of nodes representing the Star Wars movies, if you search for just the text “Star Wars” in an exact index, it will not return anything because there are no nodes with just the text “Star Wars”

Relationship Properties

In addition to adding properties to nodes, relationships can also have properties. This can be helpful if you are trying to better describe a relationship. If you want a more complex data model, you can add a payload class to your relationship class to store properties on your relationship. This is often referred to as attributes of a relationship in graph theory.

For example, you could add a property called “comment” to the Directed relationship to add extra information about the direction of a movie from a director. This would improve the data model to provide more information about movies as a whole.

Sample Database Setup

Once Neo4jClient is installed, you can setup a sample database by using the following code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Neo4jClient;
using Neo4jClient_Tutorial.Models;
using Neo4jClient_Tutorial.Models.Relationships;

namespace Neo4jClient_Tutorial.DAL
{
    /// <summary>
    /// Class to provide sample data for the graph
    /// </summary>
    public class Scaffolding
    {
        GraphClient client;

        public Scaffolding()
        {
            client = new GraphClient(new Uri("http://localhost:7474/db/data"));

            client.Connect();

            CreateNodesRelationshipsIndexes();  
        }

        private void CreateNodesRelationshipsIndexes()
        {
            // Create Indexes
            client.CreateIndex("Movie", new IndexConfiguration() { Provider = IndexProvider.lucene, Type = IndexType.fulltext }, IndexFor.Node); // full text node index
            client.CreateIndex("Director", new IndexConfiguration() { Provider = IndexProvider.lucene, Type = IndexType.exact }, IndexFor.Node); // exact node index
            client.CreateIndex("Genre", new IndexConfiguration() { Provider = IndexProvider.lucene, Type = IndexType.fulltext }, IndexFor.Node); // full text node index

            // Create Entities
            // Movies
            Movie swI = new Movie() { Name = "Star Wars: Episode I - The Phantom Menace", Description = "Begins the story of Anakin Skywalker" };

            var starWarsEpisodeI = client.Create(swI,
                new IRelationshipAllowingParticipantNode<Movie>[0],
                new []
                {
                    new IndexEntry("Movie")
                    {
                        { "Name", swI.Name },
                        { "Description", swI.Description },
                        { "Id", swI.Id.ToString() }
                    }
                });

            Movie swIV = new Movie() { Name = "Star Wars: Episode IV - A New Hope", Description = "First Starwars movie to debut on the big screen" };

            var starWarsEpisodeIV = client.Create(swIV,
                new IRelationshipAllowingParticipantNode<Movie>[0],
                new []
                {
                    new IndexEntry("Movie")
                    {
                        { "Name", swIV.Name },
                        { "Description", swIV.Description },
                        { "Id", swIV.Id.ToString() }
                    }
                });

            Movie indy = new Movie() { Name = "Indiana Jones and the Temple of Doom", Description = "Second movie in the original Indiana Jones trilogy" };

            var indianaJonesTempleOfDoom = client.Create(indy,
                new IRelationshipAllowingParticipantNode<Movie>[0],
                new[]
                {
                    new IndexEntry("Movie")
                    {
                        { "Name", indy.Name },
                        { "Description", indy.Description },
                        { "Id", indy.Id.ToString() }
                    }
                });

            Movie jp = new Movie() { Name = "Jurassic Park", Description = "First Jurassic park movie" };

            var jurassicPark = client.Create(jp,
                new IRelationshipAllowingParticipantNode<Movie>[0],
                new[]
                {
                    new IndexEntry("Movie")
                    {
                        { "Name", jp.Name },
                        { "Description", jp.Description },
                        { "Id", jp.Id.ToString() }
                    }
                });

            Movie et = new Movie() { Name = "ET", Description = "ET phone home" };

            var ET = client.Create(et,
                new IRelationshipAllowingParticipantNode<Movie>[0],
                new[]
                {
                    new IndexEntry("Movie")
                    {
                        { "Name", et.Name },
                        { "Description", et.Description },
                        { "Id", et.Id.ToString() }
                    }
                });

            // Directors

            Director lucas = new Director() { Name = "George Lucas" };

            var georgeLucas = client.Create(lucas,
                new IRelationshipAllowingParticipantNode<Director>[0],
                new[]
                {
                    new IndexEntry("Director")
                    {
                        { "Name", lucas.Name },
                        { "Id", lucas.Id.ToString() }
                    }
                });

            Director spielberg = new Director() { Name = "Steven Spielberg" };

            var stevenSpielberg = client.Create(spielberg,
                new IRelationshipAllowingParticipantNode<Director>[0],
                new[]
                {
                    new IndexEntry("Director")
                    {
                        { "Name", spielberg.Name },
                        { "Id", spielberg.Id.ToString() }
                    }
                });

            // Genres
            Genre sf = new Genre() { Name = "Science Fiction" };

            var sciFi = client.Create(sf,
                new IRelationshipAllowingParticipantNode<Genre>[0],
                new[]
                {
                    new IndexEntry("Genre")
                    {
                        { "Name", sf.Name },
                        { "Id", sf.Id.ToString() }
                    }
                });

            Genre adv = new Genre() { Name = "Adventure" };

            var adventure = client.Create(adv,
                new IRelationshipAllowingParticipantNode<Genre>[0],
                new[]
                {
                    new IndexEntry("Genre")
                    {
                        { "Name", adv.Name },
                        { "Id", adv.Id.ToString() }
                    }
                });

            // Create Relationships
            client.CreateRelationship(starWarsEpisodeI, new PartOf(sciFi));
            client.CreateRelationship(starWarsEpisodeIV, new PartOf(sciFi));

            client.CreateRelationship(indianaJonesTempleOfDoom, new PartOf(adventure));
            
            client.CreateRelationship(jurassicPark, new PartOf(sciFi));
            client.CreateRelationship(jurassicPark, new PartOf(adventure));

            client.CreateRelationship(ET, new PartOf(sciFi));

            client.CreateRelationship(georgeLucas, new Directed(starWarsEpisodeI, new Models.Payloads.Payload() { Comment = "George Lucas' second Star Wars trilogy" }));
            client.CreateRelationship(georgeLucas, new Directed(starWarsEpisodeIV, new Models.Payloads.Payload() { Comment = "First Starwars movie that George Lucas directed" }));                             client.CreateRelationship(stevenSpielberg, new Directed(indianaJonesTempleOfDoom, new Models.Payloads.Payload() { Comment = "Lucas wrote the story while Spielberg directed" }));
            client.CreateRelationship(stevenSpielberg, new Directed(jurassicPark, new Models.Payloads.Payload() { Comment = "Huge box office success" }));
            client.CreateRelationship(stevenSpielberg, new Directed(ET, new Models.Payloads.Payload() { Comment = "One of Spielberg's most successful movies" }));
        }
    }
}

I've attached a sample ASP.NET MVC 4 project for Visual Studio 2012, but you should be able to get it working in Visual Studio 2010 by importing the code without any issues. It includes all entity, relationship, and payload models. I added a few basic views for visualizing the data. Feel free to fill out the method stubs to create views to view the rest of the entities. I will look at creating another tutorial building on this project for adding/deleting/updating items from the database. I've also attached an image of the final graph. It should be easy to determine which nodes are what type of entity based on the relationship definitions. Please let me know if you have questions in the comments below.

Neo4jClient Tutorial.zip (12.48 mb)

Planned features for the Gamer Footprint desktop client

6. December 2012 11:42 by Cameron in   //  Tags:   //   Comments

With the IGA's name change in the spring, I will also be launching the first version of the Gamer Footprint desktop client. The new Gamer Footprint desktop client will feature a complete code rebase meaning that it will be built from the ground up. There were a lot of things that needed improving in the IGA desktop client that will be addressed in the Gamer Footprint desktop client.

Some features:

  • Website integration - view full profile, achievements/trophies, upload videos/pictures/music/etc
  • Friends List - Xbox Live, PSN, Steam, Gamer Footprint
  • Achievement/Trophy tracking on Xbox Live, PSN, Steam - possibly later Ubisoft's Uplay, Starcraft II achievements
  • If Nintendo creates a web interface for the Nintendo Network, it is possible that there will be Nintendo Network integration in the desktop client
  • Video capturing (provided I can figure out how to do cross platform video capturing using FFMPEG) - this will allow you to capture game play of your PC, Mac, Linux, and console games (capture card required for consoles)
Those are just a few features that I plan to implement eventually. They may not all make it into the first release of the Gamer Footprint client, but they are definitely on the road map for some point in the future.

Month List

Tag cloud