Gamer Footprint Update

4. March 2014 11:27 by Cameron in Gamer Footprint, Programming  //  Tags: , ,   //   Comments (0)

Some of you may be wondering what is the current status of Gamer Footprint? Development is live and well! In fact, there is a slightly functional proof of concept available to test at https://www.gamerfootprint.com. I have also bought the domain www.gamrfp.com but this domain doesn't have any SSL configured yet. I mainly bought it for a shorter domain.

Please do note that the website is rapidly changing with new features several times a week and I sometimes have to clear out the database when my domain model changes or I find bugs that cause duplicate data. Therefore, the site is not 100% stable yet. I'm working very hard on making the user experience enjoyable. Some features that have been implemented are:

  • User profiles
    • The profiles are very basic right now, but I plan to implement a full timeline-like profile that includes a gamer's events such as played games or achievements/trophies
    • Your avatar is currently pulled from Gravatar and if you don't have a Gravatar, you should get one! It's a very nice service to have the same avatar across multiple websites. If no Gravatar can be found for your account email, it will display a generic image in place of your avatar.
    • If you have entered a PlayStation Network and/or an Xbox LIVE account, your profile will show your current presence on PlayStation Network and Xbox LIVE
    • Your information is safe and secured and transmitted over SSL. You only have to login once for your PSN or Xbox LIVE accounts. We don't store any passwords for accounts on our servers. I'm working on providing a method for not requiring account credentials, but you won't be able to send messages. If messaging your Xbox LIVE or PSN friends from a PC is important, you'll need to enter your account credentials.
  • Xbox LIVE games and achievements (Xbox One games and challenges support to come soon!)
  • Data APIs that directly interface with Xbox LIVE, PlayStation Network, and Steam
    • Get Xbox and Xbox One games, achievements, challenges, friends, presence and profile information
    • Get PlayStation games, trophies, friends, presence information and profile information - supports PSVITA, PS3, and PS4
    • These APIs have not yet been made public, but they should be available very soon. I will post documentation on how to request an API key and API endpoints for PSN and Xbox LIVE. I will not provide a data API for Steam since Valve provides their own and I don't want to use up my daily requests to the API with a wrapper API. There might be a way to let developers aggregate everything from all supported game networks (including Steam), but it would involve providing individual Valve issued API keys and I don't want to do that as it might be against their terms of service.
Planned features:
  • PlayStation Network games and trophies
    • The core for interfacing with PSN has been finished, but I have yet to write the data access layer and data persistence layer for this part
  • Timeline system - user level and global level
  • Message friends on Xbox LIVE and PSN from the website
  • Invite people via Xbox LIVE or PSN message
  • and much more!
Here are some preview screenshots:
 

Windows Path Environment Variable Length

10. February 2014 13:14 by Cameron in Windows  //  Tags: , , , , , ,   //   Comments (0)

I recently started getting "Target Invocation" errors while trying to launch Visual Studio 2012 or Visual Studio 2013. This was a strange error message as not much else was given to diagnose the problem. After some extended research, I found that having an extra long PATH variable can cause Visual Studio to hang on startup. Windows limits this length to 2048 characters. Although you can still have a PATH variable longer than that, some programs like Visual Studio can't address a PATH environment variable larger than 2048 characters. A remedy to this problem is to split out your PATH variable into at least two variables. 

First, you need to open your PATH variable and copy its value into a safe spot in case it gets messed up. Then you can extract the last half of your path and create a new environment variable and call it PATH2. After your new environment variable is setup, you can reference it in your main PATH

C:\bin;C:\anotherfolder\bin;%PATH2%

Some may be asking, why would my PATH ever exceed 2048 characters? The answer is that if you're a developer and have lots of compilers, IDEs, and toolchains installed on your development machine such as Visual Studio, Net Beans, GCC, Qt, or devkitpro, your PATH can grow fairly quickly. 

If you ever exceed 2048 characters in PATH2, you can append another variable such as PATH3 or PATH4. I'm not certain if there is a real physical limit to user created environment variables, but if you experience problems, you can do as I mentioned. Note, I have a Windows 7 x64 development machine at work and I haven't seen this issue in Windows XP or Windows 8. I haven't done development on Windows XP in several years since it is now showing its age and Microsoft is discontinuing support in April 2014.

On-the-Fly Windows Impersonation with C#

6. February 2014 09:37 by Cameron in Programming  //  Tags:   //   Comments (0)

Occasionally I need to perform tasks under another user so I created a nice wrapper class that allows me to impersonate as another user on the fly:

using System;

using System.Runtime.InteropServices;

using System.Security.Permissions;

using System.Security.Principal;

using Microsoft.Win32.SafeHandles;

using System.Runtime.ConstrainedExecution;

using System.Security;

using System.Configuration;



namespace Tinksoft.Tools

{

    /// <summary>

    /// Facilitates impersonation of a Windows User.

    /// </summary>

    [PermissionSet(SecurityAction.Demand, Name = "FullTrust")]

    public class Impersonation : IDisposable

    {

        public string Environment { get; set; }



        public string UserName { get; set; }



        public string Password { get; set; }



        public string DomainName { get; set; }



        public enum LogonType

        {

            Interactive = 2,

            Network = 3,

            Batch = 4,

            Service = 5,

            Unlock = 7,

            NetworkClearText = 8,

            NewCredentials = 9

        }



        public enum LogonProvider

        {

            Default = 0,

            WinNT35 = 1,

            WinNT40 = 2,

            WinNT50 = 3

        }



        /// <summary>

        /// Windows Token.

        /// </summary>

        private readonly SafeTokenHandle _handle;



        /// <summary>

        /// The impersonated User.

        /// </summary>

        private WindowsImpersonationContext impersonatedUser;



        public Impersonation()

        {

        }



        /// <summary>

        /// Initializes a new instance of the Impersonation class. Provides domain, user name, and password for impersonation.

        /// </summary>

        /// <param name="domainName">Domain name of the impersonated user.</param>

        /// <param name="userName">Name of the impersonated user.</param>

        /// <param name="password">Password of the impersonated user.</param>

        /// <remarks>

        /// Uses the unmanaged LogonUser function to get the user token for

        /// the specified user, domain, and password.

        /// </remarks>

        public Impersonation(AccountCredentials credentials)

        {            

            string[] splitName = WindowsIdentity.GetCurrent().Name.Split('\\');

            string name = (splitName.Length > 0) ? splitName[0] : null;



            LogonType logonType = LogonType.Interactive;

            LogonProvider logonProvider = LogonProvider.Default;



            if (name != credentials.Domain)

            {

                logonType = LogonType.NewCredentials;

                logonProvider = LogonProvider.WinNT50;

            }



            // Call LogonUser to obtain a handle to an access token.

            bool returnValue = LogonUser(

                                credentials.UserName,

                                credentials.Domain,

                                credentials.Password,

                                (int)logonType,

                                (int)logonProvider,

                                out this._handle);



            if (false == returnValue)

            {

                // Something went wrong.

                int ret = Marshal.GetLastWin32Error();

                throw new System.ComponentModel.Win32Exception(ret);

            }



            this.impersonatedUser = WindowsIdentity.Impersonate(this._handle.DangerousGetHandle());    

        }



        /// <summary>

        /// Initializes a new instance of the Impersonation class. Provide domain, user name, and password for impersonation.

        /// </summary>

        /// <param name="domainName">Domain name of the impersonated user.</param>

        /// <param name="userName">Name of the impersonated user.</param>

        /// <param name="password">Password of the impersonated user.</param>

        /// <remarks>

        /// Uses the unmanaged LogonUser function to get the user token for

        /// the specified user, domain, and password.

        /// </remarks>

        public Impersonation(string domainName, string userName, string password)

        {

            string[] splitName = WindowsIdentity.GetCurrent().Name.Split('\\');

            string name = (splitName.Length > 0) ? splitName[0] : null;



            LogonType logonType = LogonType.Interactive;

            LogonProvider logonProvider = LogonProvider.Default;



            if (name != domainName)

            {

                logonType = LogonType.NewCredentials;

                logonProvider = LogonProvider.WinNT50;

            }



            // Call LogonUser to obtain a handle to an access token.

            bool returnValue = LogonUser(

                                userName,

                                domainName,

                                password,

                                (int)logonType,

                                (int)logonProvider,

                                out this._handle);



            if (false == returnValue)

            {

                // Something went wrong.

                int ret = Marshal.GetLastWin32Error();

                throw new System.ComponentModel.Win32Exception(ret);

            }



            this.impersonatedUser = WindowsIdentity.Impersonate(this._handle.DangerousGetHandle());

        }



        [DllImport("advapi32.dll", SetLastError = true)]

        private static extern bool LogonUser(

                string lpszUsername,

                string lpszDomain,

                string lpszPassword,

                int dwLogonType,

                int dwLogonProvider,

                out SafeTokenHandle phToken);



        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]

        private static extern bool CloseHandle(IntPtr handle);



        public void Dispose()

        {

            this.impersonatedUser.Dispose();

            this._handle.Dispose();

        }



        private static string[] GetAccountInfo(string accountInfo)

        {

            return accountInfo.Split(' ');

        }

    }



    public sealed class SafeTokenHandle : SafeHandleZeroOrMinusOneIsInvalid

    {

        private SafeTokenHandle()

            : base(true) { }



        [DllImport("kernel32.dll")]

        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]

        [SuppressUnmanagedCodeSecurity]

        [return: MarshalAs(UnmanagedType.Bool)]

        private static extern bool CloseHandle(IntPtr handle);



        protected override bool ReleaseHandle()

        {

            return CloseHandle(handle);

        }

    }

}
 

Happy New Year 2014!

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

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 (0)

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 (0)

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 (0)

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

QUnit, JSCoverage and Jenkins

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 (0)

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 (0)

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.

Month List

Tag cloud