We just released a Feb. 5 '89 prototype of DuckTales for the NES!
If you'd like to support our preservation efforts (and this wasn't cheap), please consider donating or supporting us on Patreon. Thank you!

Fruit Ninja (iOS)

From The Cutting Room Floor
Jump to navigation Jump to search

Title Screen

Fruit Ninja

Developer: Halfbrick Studios
Publisher: Halfbrick Studios
Platforms: iOS, Android
Released internationally: April 21, 2010 (iOS), September 17, 2010 (Android)


SourceIcon.png This game has uncompiled source code.
DevMessageIcon.png This game has a hidden developer message.
DevTextIcon.png This game has hidden development-related text.


Fruit Ninja is everyone's favorite game about murdering fruit.

Developer Comments

Seems to have changed from _SCORE to _KILLED in 1.7... not sure exactly why since Steve 
isn't here, but only need one leaderboard for total sliced
These are the lite achievements. The same things are defined for SD and HD Lite versions, 
with provider ids below  mik - Game Centre automagically gives you weekly friends 
leaderboards so that's why they differ to OF  SD on normal OF doesn't have the zen and 
classic weekly scores, so we just don't specify them
These achievements are specific to a product or platform combination.

Several developer comments can be found in socialnetworks.xml

Debug Menu

Hmmm...
To do:
Figure out how to access the debug menu.
UNLOCK BLADES & BACKGROUNDS
ADD 10000 STARFRUIT
RELOCK BLADES & BACKGROUNDS
LANGUAGE SWITCH
iCloud Options
Achievement Helpers
WIPE ALL SAVE DATA
BNET SEND JUNK DATA
BNET PERFORM SYNC
FORCE ADS
RELOCK BEINTOO OFFER
BACK
BACK
NOTHING BUT PLUMS
spawn pomegranate
spawn starfruit
Spawn a Dragonfruit
NOTHING BUT STRAWBERRIES
NOTHING BUT MANGOES
MAKE SCORE 69
MAKE SCORE 99
NOTHING BUT BANANAS
NOTHING BUT PINEAPPLES
MAKE SCORE 208
NOTHING BUT WATERMELONS
NOTHING BUT pASSIONFRUIT
NOTHING BUT PEACHES
MANY POWER BANANAS
FORCE ICLOUD SYNC
SEND iCLOUD GARBAGE
WIPE ICLOUD
CURRENT LANGUAGE:
INSERT LANGUAGE HERE
EXAMPLE STRING:

Text for a debug menu exists in debugMenu.uiscreen. It is currently unknown how to enable it, but...

TouchMove_X0:	TouchAxisX1;		move
TouchMove_X1:	TouchAxisX2;		move
TouchMove_X2:	TouchAxisX3;		move
TouchMove_X3:	TouchAxisX4;		move
TouchMove_X4:	TouchAxisX5;		move
TouchMove_X5:	TouchAxisX6;		move
TouchMove_X6:	TouchAxisX7;		move
TouchMove_X7:	TouchAxisX8;		move
TouchMove_X8:	TouchAxisX9;		move
TouchMove_X9:	TouchAxisX10;		move
TouchMove_X10:	TouchAxisX11;		move
TouchMove_X11:	TouchAxisX12;		move
TouchMove_X12:	TouchAxisX13;		move
TouchMove_X13:	TouchAxisX14;		move
TouchMove_X14:	TouchAxisX15;		move
TouchMove_X15:	TouchAxisX16;		move
TouchMove_Y0:	TouchAxisY1;		move
TouchMove_Y1:	TouchAxisY2;		move
TouchMove_Y2:	TouchAxisY3;		move
TouchMove_Y3:	TouchAxisY4;		move
TouchMove_Y4:	TouchAxisY5;		move
TouchMove_Y5:	TouchAxisY6;		move
TouchMove_Y6:	TouchAxisY7;		move
TouchMove_Y7:	TouchAxisY8;		move
TouchMove_Y8:	TouchAxisY9;		move
TouchMove_Y9:	TouchAxisY10;		move
TouchMove_Y10:	TouchAxisY11;		move
TouchMove_Y11:	TouchAxisY12;		move
TouchMove_Y12:	TouchAxisY13;		move
TouchMove_Y13:	TouchAxisY14;		move
TouchMove_Y14:	TouchAxisY15;		move
TouchMove_Y15:	TouchAxisY16;		move
TouchDown_0:	Touch1;		down
TouchDown_1:	Touch2;		down
TouchDown_2:	Touch3;		down
TouchDown_3:	Touch4;		down
TouchDown_4:	Touch5;		down
TouchDown_5:	Touch6;		down
TouchDown_6:	Touch7;		down
TouchDown_7:	Touch8;		down
TouchDown_8:	Touch9;		down
TouchDown_9:	Touch10;	down
TouchDown_10:	Touch11;		down
TouchDown_11:	Touch12;		down
TouchDown_12:	Touch13;		down
TouchDown_13:	Touch14;		down
TouchDown_14:	Touch15;		down
TouchDown_15:	Touch16;		down
TouchReleased_0:	Touch1;		released
TouchReleased_1:	Touch2;		released
TouchReleased_2:	Touch3;		released
TouchReleased_3:	Touch4;		released
TouchReleased_4:	Touch5;		released
TouchReleased_5:	Touch6;		released
TouchReleased_6:	Touch7;		released
TouchReleased_7:	Touch8;		released
TouchReleased_8:	Touch9;		released
TouchReleased_9:	Touch10;	released
TouchReleased_10:	Touch11;		released
TouchReleased_11:	Touch12;		released
TouchReleased_12:	Touch13;		released
TouchReleased_13:	Touch14;		released
TouchReleased_14:	Touch15;		released
TouchReleased_15:	Touch16;		released
PointerMove:	MouseAxisX,MouseAxisY;		move
PointerPressed:		MouseButton1;		pressed
PointerReleased:	MouseButton1;		released
PointerMove:	X360_LStick_AxisY;		active
PointerMove:	X360_LStick_AxisX;		active
PointerPressedX:		X360_A;		down
ShowDebug:			D;    pressed
ShowCollision:		C;    pressed
Particles:			P;		pressed
Fruit:				F;    pressed
PageUpPressed:		PgUp;	pressed
PageDownPressed:	PgDn;	pressed
ParticlesUp:		Up;		pressed
ParticlesDown:		Down;		pressed
PauseGame:			Enter;		pressed
ShowPauseMenu:		AppMenu;	released
ShowPauseMenu:		escape;		released
UpPressed:			Up;		    pressed
DownPressed:		Down;		pressed
LeftPressed:		Left;		pressed
RightPressed:		Right;	pressed
SpacePressed:		Space;	pressed
PowerUpPressed:		M;	pressed
Speed:				S;	pressed
RegressMenu:		escape;		released
QuitPressed:		Q;	pressed
AddCreditPressed:	Y;	pressed
OperatorOptions:	O;	pressed
RemoveTime:			Z;	pressed
AddTime:			A;	pressed
AddStarfruit:		G;	pressed
RemoveStarfruit:	B;	pressed
Launch:	L;	pressed
ForceBanana: b; pressed

...Input.txt mentions that pressing D will show the debug menu, as well as mentioning several other keys that correspond to debugging functions!

Debug Settings

In addition to the debug menu, there is also a file named debugSettings.cfg in the Config folder.

// Debug Settings file
// Get settings like this:
//   game_work.debugConfig.GetValue("value name"). Returns a string, will be empty ("") if not found, never null. so
//   if (strcmp(debugConfig.GetValue("enable_god_mode"), "true") == 0)) is safe.
// This file supports C++ style comments. just like this one.


// Display
display.clearOnNewFrame = 0


// Entities, Fruit
entities.fruit.draw = 1
entities.fruit.update = 1
entities.fruit.drawshadows = 1


// Entities, Bomb
entities.bomb.draw = 1
entities.bomb.update = 1


// BrickUI
brickui.draw_layer_0 = 1
brickui.draw_layer_1 = 1
brickui.draw_layer_4 = 1
brickui.draw_layer_5 = 1
brickui.update = 1


// Backgrounds
background.draw = 1


// Particles
particles.draw = 1
particles.update = 1


// Sound
sound.update = 1


// Music
music.update = 1


// Wavemanager
wavemanager.update = 1



Source Code

Source code for Flurry Web Adapter exists in the game's executable.

/**
* @preserve Copyright 2012 Twitter, Inc.
* @license http://www.apache.org/licenses/LICENSE-2.0.txt
*/
var Hogan={};(function(a){function h(a){return a=String(a===null||a===undefined?"":a),g.test(a)?a.replace(b,"&").replace(c,"<").replace(d,">").replace(e,"'").replace(f,"""):a}a.Template=function j(a,b,c){a&&(this.r=a),this.c=c,this.text=b||""},a.Template.prototype={r:function(a,b,c){return""},v:h,render:function(b,c,d){return this.ri([b],c||{},d)},ri:function(a,b,c){return this.r(a,b,c)},rp:function(a,b,c,d){var e=c[a];return e?(this.c&&typeof e=="string"&&(e=this.c.compile(e)),e.ri(b,c,d)):""},rs:function(a,b,c){var d="",e=a[a.length-1];if(!i(e))return d=c(a,b);for(var f=0;f<e.length;f++)a.push(e[f]),d+=c(a,b),a.pop();return d},s:function(a,b,c,d,e,f,g){var h;return i(a)&&a.length===0?!1:(typeof a=="function"&&(a=this.ls(a,b,c,d,e,f,g)),h=a===""||!!a,!d&&h&&b&&b.push(typeof a=="object"?a:b[b.length-1]),h)},d:function(a,b,c,d){var e=a.split("."),f=this.f(e[0],b,c,d),g=null;if(a==="."&&i(b[b.length-2]))return b[b.length-1];for(var h=1;h<e.length;h++)f&&typeof f=="object"&&e[h]in f?(g=f,f=f[e[h]]):f="";return d&&!f?!1:(!d&&typeof f=="function"&&(b.push(g),f=this.lv(f,b,c),b.pop()),f)},f:function(a,b,c,d){var e=!1,f=null,g=!1;for(var h=b.length-1;h>=0;h--){f=b[h];if(f&&typeof f=="object"&&a in f){e=f[a],g=!0;break}}return g?(!d&&typeof e=="function"&&(e=this.lv(e,b,c)),e):d?!1:""},ho:function(a,b,c,d,e){var f=this.c,g=a.call(b,d,function(a){return f.compile(a,{delimiters:e}).render(b,c)}),h=f.compile(g.toString(),{delimiters:e}).render(b,c);return this.b=h,!1},b:"",ls:function(a,b,c,d,e,f,g){var h=b[b.length-1],i=null;if(!d&&this.c&&a.length>0)return this.ho(a,h,c,this.text.substring(e,f),g);i=a.call(h);if(typeof i=="function"){if(d)return!0;if(this.c)return this.ho(i,h,c,this.text.substring(e,f),g)}return i},lv:function(a,b,c){var d=b[b.length-1],e=a.call(d);return typeof e=="function"&&(e=e.call(d)),e=e.toString(),this.c&&~e.indexOf("{{")?this.c.compile(e).render(d,c):e}};var b=/&/g,c=/</g,d=/>/g,e=/\'/g,f=/\"/g,g=/[&<>\"\']/,i=Array.isArray||function(a){return Object.prototype.toString.call(a)==="[object Array]"}})(typeof exports!="undefined"?exports:Hogan),function(a){function h(a){a.n.substr(a.n.length-1)==="}"&&(a.n=a.n.substring(0,a.n.length-1))}function i(a){return a.trim?a.trim():a.replace(/^\s*|\s*$/g,"")}function j(a,b,c){if(b.charAt(c)!=a.charAt(0))return!1;for(var d=1,e=a.length;d<e;d++)if(b.charAt(c+d)!=a.charAt(d))return!1;return!0}function k(a,b,c,d){var e=[],f=null,g=null;while(a.length>0){g=a.shift();if(g.tag=="#"||g.tag=="^"||l(g,d))c.push(g),g.nodes=k(a,g.tag,c,d),e.push(g);else{if(g.tag=="/"){if(c.length===0)throw new Error("Closing tag without opener: /"+g.n);f=c.pop();if(g.n!=f.n&&!m(g.n,f.n,d))throw new Error("Nesting error: "+f.n+" vs. "+g.n);return f.end=g.i,e}e.push(g)}}if(c.length>0)throw new Error("missing closing tag: "+c.pop().n);return e}function l(a,b){for(var c=0,d=b.length;c<d;c++)if(b[c].o==a.n)return a.tag="#",!0}function m(a,b,c){for(var d=0,e=c.length;d<e;d++)if(c[d].c==a&&c[d].o==b)return!0}function n(a){return'i = i || "";var b = i + "";var _ = this;'+q(a)+"return b;"}function o(a){return a.replace(f,"\\\\").replace(c,'\\"').replace(d,"\\n").replace(e,"\\r")}function p(a){return~a.indexOf(".")?"d":"f"}function q(a){var b="";for(var c=0,d=a.length;c<d;c++){var e=a[c].tag;e=="#"?b+=r(a[c].nodes,a[c].n,p(a[c].n),a[c].i,a[c].end,a[c].otag+" "+a[c].ctag):e=="^"?b+=s(a[c].nodes,a[c].n,p(a[c].n)):e=="<"||e==">"?b+=t(a[c]):e=="{"||e=="&"?b+=u(a[c].n,p(a[c].n)):e=="\n"?b+=w('"\\n"'+(a.length-1==c?"":" + i")):e=="_v"?b+=v(a[c].n,p(a[c].n)):e===undefined&&(b+=w('"'+o(a[c])+'"'))}return b}function r(a,b,c,d,e,f){return"if(_.s(_."+c+'("'+o(b)+'",c,p,1),'+"c,p,0,"+d+","+e+', "'+f+'")){'+"b += _.rs(c,p,"+'function(c,p){ var b = "";'+q(a)+"return b;});c.pop();}"+'else{b += _.b; _.b = ""};'}function s(a,b,c){return"if (!_.s(_."+c+'("'+o(b)+'",c,p,1),c,p,1,0,0,"")){'+q(a)+"};"}function t(a){return'b += _.rp("'+o(a.n)+'",c,p,"'+(a.indent||"")+'");'}function u(a,b){return"b += (_."+b+'("'+o(a)+'",c,p,0));'}function v(a,b){return"b += (_.v(_."+b+'("'+o(a)+'",c,p,0)));'}function w(a){return"b += "+a+";"}var b=/\S/,c=/\"/g,d=/\n/g,e=/\r/g,f=/\\/g,g={"#":1,"^":2,"/":3,"!":4,">":5,"<":6,"=":7,_v:8,"{":9,"&":10};a.scan=function(c,d){function w(){p.length>0&&(q.push(new String(p)),p="")}function x(){var a=!0;for(var c=t;c<q.length;c++){a=q[c].tag&&g[q[c].tag]<g._v||!q[c].tag&&q[c].match(b)===null;if(!a)return!1}return a}function y(a,b){w();if(a&&x())for(var c=t,d;c<q.length;c++)q[c].tag||((d=q[c+1])&&d.tag==">"&&(d.indent=q[c].toString()),q.splice(c,1));else b||q.push({tag:"\n"});r=!1,t=q.length}function z(a,b){var c="="+v,d=a.indexOf(c,b),e=i(a.substring(a.indexOf("=",b)+1,d)).split(" ");return u=e[0],v=e[1],d+c.length-1}var e=c.length,f=0,k=1,l=2,m=f,n=null,o=null,p="",q=[],r=!1,s=0,t=0,u="{{",v="}}";d&&(d=d.split(" "),u=d[0],v=d[1]);for(s=0;s<e;s++)m==f?j(u,c,s)?(--s,w(),m=k):c.charAt(s)=="\n"?y(r):p+=c.charAt(s):m==k?(s+=u.length-1,o=g[c.charAt(s+1)],n=o?c.charAt(s+1):"_v",n=="="?(s=z(c,s),m=f):(o&&s++,m=l),r=s):j(v,c,s)?(q.push({tag:n,n:i(p),otag:u,ctag:v,i:n=="/"?r-v.length:s+u.length}),p="",s+=v.length-1,m=f,n=="{"&&(v=="}}"?s++:h(q[q.length-1]))):p+=c.charAt(s);return y(r,!0),q},a.generate=function(b,c,d){return d.asString?"function(c,p,i){"+b+";}":new a.Template(new Function("c","p","i",b),c,a)},a.parse=function(a,b){return b=b||{},k(a,"",[],b.sectionTags||[])},a.cache={},a.compile=function(a,b){b=b||{};var c=a+"||"+!!b.asString,d=this.cache[c];return d?d:(d=this.generate(n(this.parse(this.scan(a,b.delimiters),b)),a,b),this.cache[c]=d)}}(typeof exports!="undefined"?exports:Hogan)


//
//  flurry_bridge.js
//  Flurry Web Adapter
//
//  Copyright 2012 Flurry, Inc. All rights reserved.
//	
//	Methods in this header file are for use with Flurry Ads WebView

// constructor, taking the global window object
var flurryBridgeCtor = function(w) {
    var flurryadapter = {};
    // could be private?
    flurryadapter.flurryCallQueue = [ ];
    
    flurryadapter.callComplete = function( cmd ) {
        if ( this.flurryCallQueue.length == 0 ) {
            return;
        }
        var adapterCall = this.flurryCallQueue.splice(0,1)[0];
        this.executeNativeCall(adapterCall);
        return "OK";
    };
    flurryadapter.executeCall = function( command ) {
        var adapterCall = "flurry://flurrycall?event=" + command;
        var value;
        for ( var i = 1; i < arguments.length; i += 2 ) {
            value = arguments[i + 1];
            if ( value == null ) {
                continue;
            }
            adapterCall += "&" + arguments[i] + "=" + escape( value );
        }
        if ( this.flurryCallQueue.length > 0 ) {
            this.flurryCallQueue.push( adapterCall );
        }
        else {
            this.executeNativeCall(adapterCall);
        }
    };
    // also could be private?
    flurryadapter.executeNativeCall = function( adapterCall ) {
        if ( adapterCall.length == 0 ) {
            return;
        }

        var iframe = document.createElement("IFRAME");
        iframe.setAttribute("src", adapterCall);
        document.documentElement.appendChild(iframe);
        iframe.parentNode.removeChild(iframe);
        iframe = null;
    };
    return flurryadapter;
};h�//document.write("<script src=\"mraid.js\"></script>");

var mraidCtor = function(flurryBridge, initState) {
    
	// to be returned
	var mraid = {};
    
	var STATES = mraid.STATES  = {
        LOADING           : 'loading',
        UNKNOWN           : 'unknown', // not in MRAID 1.0 spec?
        DEFAULT           : 'default',
        EXPANDED          : 'expanded',
        HIDDEN            : 'hidden'
	};
    
	var EVENTS = mraid.EVENTS = {
        // where did these other states come from?
        ASSETREADY        : 'assetReady',
        ASSETREMOVED      : 'assetRemoved',
        ASSETRETIRED      : 'assetRetired',
        INFO              : 'info',
        // only the states below are defined in MRAID 1.0 spec
        ERROR             : 'error',
        ORIENTATIONCHANGE : 'orientationChange',
        READY             : 'ready',
        STATECHANGE       : 'stateChange',
        VIEWABLECHANGE    : 'viewableChange'
	};
    
	// private vars
	var listeners = {}; // this is an associative array mapping strings (event names) to lists of either functions or strings
    // {'eventA':[function(e){...}, 'listenerFoo', ...], eventB: ...}
	var currentState = STATES.LOADING; // start out in LOADING state, SDK puts MRAID into DEFAULT state
	var expandProperties = {
    width:initState.width,
    height:initState.height,
    isModal:initState.isModal,
    useCustomClose:false
	};
	var collapseProperties = {};
	var placementType = initState.placementType;
    var disable = false;
    
	// default close button
	var closeId = 'flurry-mraid-default-close';
	var imgUrl = 'http://flurry.cachefly.net/adSpaceStyles/images/bttn-close-bw.png';
    
	var safeClose = function() {
	    try {
	        if(window.mraid) {
	            window.mraid.close();
	        } else if(window.flurryadapter) {
	            flurryadapter.executeCall('adWillClose');
	        } else {
	            console.log('unable to close');
	        }
	    } catch (error) {
	        console.log('unable to close: ' + error);
	    }
	};
    
	var makeDefaultClose = function() {
	    var img = document.createElement('img');
	    img.src = imgUrl;
	    img.id = closeId;
        // we can't use img.onclick or img.addEventListener for 'click' because phluant sdk ruthlessly
        // cleans any event listeners by recreating body content using code like this: a.innerHTML += "".
        // As workaround, we use document.body.addEventListener for 'click' in setupDefaultCloseHandler
        //        img.onclick = safeClose;
	    img.style.position = 'absolute';
	    img.style.top = '10px';
	    img.style.right = '10px';
	    img.style.width = '50px';
	    img.style.height = '50px';
        img.style.zIndex = 10000;
	    return img;
	}
    
     var setupDefaultCloseHandler = function() {
        document.body.addEventListener('click', function(e) {
        e = e || window.event;
        var target = e.target || e.srcElement;
        if (target.id === closeId) {
          safeClose();
        }
       });
  }
    
	var updateDefaultClose = function() {
	    // show default close button only for interstitial or expanded ad with expandProperties.useCustomClose === false
	    if (!expandProperties.useCustomClose && (placementType === 'interstitial' || currentState === STATES.EXPANDED)) {
            addDefaultClose();
        } else {
            removeDefaultClose();
        }
	}
    
	var addDefaultClose = function() {
	    var closeButton = document.getElementById(closeId);
	    if(!closeButton) {
	        closeButton = makeDefaultClose();
	        document.body.appendChild(closeButton);
	    }
	}
    
	var removeDefaultClose = function() {
	    var closeButton = document.getElementById(closeId);
	    if(closeButton) {
            document.body.removeChild(closeButton);
	    }
	}
    
	/*
	 * Checking for the state of the mraid client library and subscribing to the ready event if necessary
	 * When the client library is ready call the showAd method to render the ad
	 */
    
	/* js helper functions */
    
    var contains = function(value, obj) {
        for (var i in obj) {
            if (obj[i] === value) {
                return true;
            }
        }
        return false;
    };
    
    
	var stringify = function(obj) {
        if (typeof obj == 'object') {
            if (obj.push) {
                var out = [];
                for (var p in obj) {
                    if(obj.hasOwnProperty(p)) {
                        out.push(obj[p]);
                    }
                }
                return '[' + out.join(',') + ']';
            } else {
                var out = [];
                for (var p in obj) {
                    if(obj.hasOwnProperty(p)) {
                        out.push('\''+p+'\':'+obj[p]);
                    }
                }
                return '{' + out.join(',') + '}';
            }
        } else {
            return new String(obj);
        }
    };
    
	var broadcastEvent = function() {
		var args = new Array(arguments.length);
		for (var i = 0; i < arguments.length; i++) {
		    args[i] = arguments[i];
		}
		var event = args.shift();
        
		try {
		    if (listeners[event]) {
		        for(var j = 0; j < listeners[event].length; j++) {
		            if(typeof listeners[event][j] === 'function') {
		                listeners[event][j].apply(undefined, args);
		            } else if(typeof listeners[event][j] === 'string' && typeof window[listeners[event][j]] === 'function') {
		                window[listeners[event][j]].apply(undefined, args);
		            }
		        }
			}
		} catch(e) {
		    console.log(e);
		}
	}
    
    mraid.disable = function() {
        removeDefaultClose();
        disable = true;
    }
    
	// Takes an event name (string) and either a function or a string, Registers a listener for this event.
	// String listener is taken to be the name of a global var -- ie a property of window
	mraid.addEventListener = function(event, listener) {
        if (disable) {
            return;
        }
        
	    if (!event || !listener) {
	        broadcastEvent(EVENTS.ERROR, 'Both event and listener are required.', 'addEventListener');
	    } else if (!contains(event, EVENTS)) {
	        broadcastEvent(EVENTS.ERROR, 'Unknown event: ' + event, 'addEventListener');
	    } else {
	        if (!listeners[event]) {
	            listeners[event] = [listener];
	        } else {
	            listeners[event].push(listener);
	        }
	    }
        flurryBridge.executeCall("eventListenerAdded");
	}
    
	mraid.stateChange = function(newState) {
        if (disable) {
            return;
        }
        
	    if(currentState === newState) {
	        return;
	    }
        
	    broadcastEvent(EVENTS.INFO, 'setting state to ' + stringify(newState));
	    var oldState = currentState;
	    currentState = newState;
	    if(oldState === STATES.LOADING && newState === STATES.DEFAULT) {
            setupDefaultCloseHandler();
            updateDefaultClose();
            broadcastEvent(EVENTS.READY);
        } else if(oldState === STATES.HIDDEN || newState === STATES.HIDDEN) {
            broadcastEvent(EVENTS.VIEWABLECHANGE);
        } else if(oldState === STATES.DEFAULT && newState === STATES.EXPANDED) {
            updateDefaultClose();
        } else if(newState === STATES.DEFAULT && oldState === STATES.EXPANDED) {
            updateDefaultClose();
        }
        broadcastEvent(EVENTS.STATECHANGE, currentState);
	}
    
	mraid.close = function () {
        if (disable) {
            return;
        }
        
		// webview should downgrade its state, should also fire the
		// stateChange event.
		// ads in expanded state -> close() -> default
		// ads in default state-> close() -> hidden
	    var state = mraid.getState();
	    if(state === STATES.DEFAULT) {
	        mraid.stateChange(STATES.HIDDEN);
	        flurryBridge.executeCall("adWillClose");
	    } else if(state === STATES.EXPANDED) {
	        mraid.stateChange(STATES.DEFAULT);
	        flurryBridge.executeCall("collapse");
	    } else {
            console.log("close() called in state " + state);
	        // TODO
	    }
	};
    
	mraid.expand = function(url) {
        if (disable) {
            return;
        }
        
        var state = mraid.getState();
	    if(state !== STATES.DEFAULT) {
            console.log("expand() called in state " + state);
	        return;
	    }
	    if(url) {
            flurryBridge.executeCall('expand', 'width', expandProperties.width, 'height', expandProperties.height, 'url', url);
	    } else {
            flurryBridge.executeCall('expand', 'width', expandProperties.width, 'height', expandProperties.height);
	    }
	    mraid.stateChange(STATES.EXPANDED);
	};
    
	mraid.setExpandProperties = function(properties) {
        if (disable) {
            return;
        }
        
	    if(typeof properties.width === 'number' && !isNaN(properties.width)) {
	        expandProperties.width = properties.width;
	    }
	    if(typeof properties.height === 'number' && !isNaN(properties.height)) {
	        expandProperties.height = properties.height
	    }
	    if(typeof properties.useCustomClose === 'boolean') {
	        expandProperties.useCustomClose = properties.useCustomClose;
	        updateDefaultClose();
	    }
	};
    
	mraid.getExpandProperties = function(properties) {
        if (disable) {
            return;
        }
        
	    var ret = {};
	    ret.width = expandProperties.width;
	    ret.height = expandProperties.height;
	    ret.isModal = expandProperties.isModal;
	    ret.useCustomClose = expandProperties.useCustomClose;
	    return ret;
	};
    
	mraid.getPlacementType = function() {
	    return placementType;
	};
    
	/*
	 * The getversion method should return the version of mraid. Since we are 1.0 compliant, should
	 * return 1.0.
	 */
	mraid.getVersion = function () {
        if (disable) {
            return "";
        }
        
		return "1.0";
	};
    
	mraid.getState = function() {
        if (disable) {
            return "";
        }
        
		// the default states are loading, default, expanded, hidden
		// loading: the sdk is not yet ready for interactions with the Controller
		// default: initial position and size of the ad container as placed by app and sdk
		// expanded: the ad container has expanded to cover the app. content at top of view hierarchy
		// hidden: the ad container no longer displays the ad
	    return currentState;
	};
    
	mraid.isViewable = function() {
        if (disable) {
            return false;
        }
        
	    if(mraid.getState() === 'hidden') {
	        return false;
	    } else {
	        return true;
	    }
	};
    
	mraid.open = function(url) {
        if (disable) {
            return;
        }
        
	    try{
	        flurryBridge.executeCall("open", "url", url);
	    } catch (e) {
	        console.log(e);
	    }
	};
    
	// Deregisters the listener for this event
	mraid.removeEventListener = function(event, listener) {
        if (disable) {
            return;
        }
        
	    if (!event) {
	        broadcastEvent('error', 'Must specify an event.', 'removeEventListener');
	    } else {
	        if(listener && (listeners[event])) {
	            for(var i = 0; i < listeners[event].length; i++) {
	                if(listeners[event][i] === listener) {
	                    listeners[event].splice(i,1); // remove listener from array
	                }
	            }
	        }
	        else if (listeners[event]) {
	        	listeners[event] = [];
	        }
	    }
	};
    
	mraid.useCustomClose = function(use) {
        if (disable) {
            return;
        }
        
		// true - ad creative supplies its own designed for the close area
		// false - SDK defualt image should be displayed for the close area
	    if(typeof use === 'boolean') {
	        expandProperties.useCustomClose = use;
	        updateDefaultClose();
	    }
	};
    
	return mraid;
};