package { /* This class has functions similar to the Utils.as in the /flash/Dialogs folder. However, some of * those functions are different here than in /flash/Dialogs/Utils.as for... reasons? flash folder reasons! */ import flash.utils.*; import flash.net.*; import flash.display.*; import flash.text.TextField; import flash.text.TextFormat; import flash.text.TextFieldType; import flash.text.TextFieldAutoSize; import flash.text.TextFormatAlign; import flash.geom.Point; import flash.geom.Matrix; import flash.geom.Rectangle; import flash.geom.ColorTransform; import fl.motion.Color; import fl.transitions.Tween; import fl.transitions.easing.*; import fl.transitions.TweenEvent; import flash.net.navigateToURL; import flash.external.ExternalInterface; import flash.system.Capabilities; import flash.filters.*; import flash.filters.ColorMatrixFilter; import com.adobe.images.JPGEncoder; import flash.globalization.DateTimeFormatter; import djarts.utils.Base64; import djarts.utils.PNGEnc; import User.UserOptions; public class Utils { //["K","M","B","T","q", "Q", "s", "S","O","N","d","U","D","!","@","#","$","%","^","&","*"] static var symbols = ["K","M","B","t","q", "Q", "s", "S","o","n","d","U","D","T","Qt","Qd","Sd","St","O","N","v","c"]; static var divisors = []; public static function FormatBigNumber(number:*, round:Boolean=false):String { if (number < 0) return '-' + FormatBigNumber(Math.abs(number), round); var isWholeNumber = (Math.floor(number) == number); round = round || isWholeNumber; if (number < 1000) { if (round) { return Math.round(number).toString(); } else { var decimalPlaces = (number >= 100) ? 1 : 2; // Below 100, show two decimal places. Above, only one. var roundMult = Math.pow(10, decimalPlaces); var rounded = Math.round(number); var bigRounded = Math.round(number * roundMult); var roundedDifferenceProportion = Math.abs(bigRounded / roundMult - rounded) / rounded; if (roundedDifferenceProportion < 0.001) { // Not a whole number, but the decimal places aren't worth showing // Below also handles this, but is slower return rounded.toString(); } else { var str:String = bigRounded.toString(); str = str.substr(0, str.length - decimalPlaces) + "." + str.substr(str.length - decimalPlaces); while (str.charAt(str.length - 1) == "0") str = str.substr(0, str.length - 1); //should only ever happen once if (str.charAt(str.length - 1) == ".") str = str.substr(0, str.length - 1); //probably won't happen at all return str; } } } // Determine which symbol to use var power = Math.floor(Math.log(number) / Math.log(1000)); var index = Math.min(power-1, symbols.length-1); var amount = number / Math.pow(1000, index+1); var symbol = (index >= 0 && index < symbols.length) ? symbols[index] : ""; // If it's too big for a symbol (or if we just WANT to) if (amount >= 1000 || UserOptions.ForceScientific) { // scientific notation var power = Math.floor(Math.log(number) / Math.log(10)); var num = number / Math.pow(10, power); if (num == 10) { num = 1; power += 1; } var numString = "" + num; numString = numString.substr(0, Math.min(4, numString.length)); return numString + "e" + power; } else { // Format with the symbol // determine number of whole digits (will dictate how many decimals we show) var whole = Math.floor(amount); var amount_str:String = String(whole); var decimalDivider = 100/Math.pow(10,amount_str.length-1); //round to nearest decimal place amount = int(amount*decimalDivider)/decimalDivider; var amountString:String = amount.toString(); var noDecimal:String = amountString.replace(".",""); if (noDecimal.length == 2) { if (amountString.indexOf(".") != -1) amountString += "0"; else amountString += ".0"; } else if (noDecimal.length == 1) amountString += ".00"; return amountString+symbol; // concat symbol } } private static var BigNumberRegex = new RegExp(/(\d*),?(\d*)(.*)/); // Note-DG: This is mostly just used for definitions in the database, that don't require precision. // This way we can define values in the database as 100B instead of 100000000000. public static function ParseBigNumberString(number:String):Number { var regexArray:Array = BigNumberRegex.exec(number); var magnitude = symbols.indexOf(regexArray[3]); var thousands:Number; if (regexArray[1]) { thousands = regexArray[1]; if (regexArray[2]) { // if numbers are split by comma, multiply by 1000 thousands *= 1000; } } else { thousands = 0; } var hundreds:Number = regexArray[2] ? regexArray[2] : 0; return (thousands + hundreds) * Math.pow(1000, magnitude + 1); } public static function ParseNumberRange(range:String):Array { var split:Array = range.split(','); return [Number(split[0]), Number(split[1])]; } public static function DesaturateFilter() { var desatMatrix:Array = []; var cmFilter; desatMatrix = desatMatrix.concat([0.309, 0.609, 0.082, 0, 0]); // red desatMatrix = desatMatrix.concat([0.309, 0.609, 0.082, 0, 0]); // green desatMatrix = desatMatrix.concat([0.309, 0.609, 0.082, 0, 0]); // blue desatMatrix = desatMatrix.concat([0, 0, 0, 1, 0]); // alpha cmFilter = new ColorMatrixFilter(desatMatrix); return cmFilter; } public static function GetUserAgent():String { try { var userAgent = ExternalInterface.call("window.navigator.userAgent.toString"); var browser:String = "[Unknown Browser]"; if (userAgent.indexOf("Safari") != -1) { browser = "Safari"; } if (userAgent.indexOf("Firefox") != -1) { browser = "Firefox"; } if (userAgent.indexOf("Chrome") != -1) { browser = "Chrome"; } if (userAgent.indexOf("MSIE") != -1) { browser = "Internet Explorer"; } if (userAgent.indexOf("Opera") != -1) { browser = "Opera"; } } catch (e:Error) { //could not access ExternalInterface in containing page return "[No ExternalInterface]"; } return browser; } public static function GetScreenshot(stage:Stage):String { var scale:Number = 0.25; var result:String = null; var blurFilter:BlurFilter = new BlurFilter(3, 3, BitmapFilterQuality.HIGH); var bData:BitmapData = new BitmapData(stage.stageWidth * scale, stage.stageHeight * scale, false, 0x348400); var matrix:Matrix = new Matrix(); matrix.scale(scale, scale); bData.draw(stage, matrix); bData.applyFilter(bData, bData.rect, new Point(0, 0), blurFilter); var imgBytes:ByteArray = new JPGEncoder(80).encode(bData); //var imgBytes:ByteArray = PNGEnc.encode(bData); if (imgBytes) { var screenshotBase64:String = Base64.encode(imgBytes); if (screenshotBase64) { result = screenshotBase64; } } return result; } public static function RecursivelyStop(clip, frame = null) { if (clip is MovieClip) { if (frame == null) { clip.stop(); } else { clip.gotoAndStop(frame); } } if (clip is DisplayObjectContainer) { for (var i = 0; i < clip.numChildren; i++) { RecursivelyStop(clip.getChildAt(i)); } } } public static function PlayerVersion() { // Get the player's version by using the getVersion() global function. var versionNumber:String = Capabilities.version; // The version number is a list of items divided by "," var versionArray:Array = versionNumber.split(","); var length:Number = versionArray.length; //for(var i:Number = 0; i < length; i++) _strace("versionArray["+i+"]: "+versionArray[i]); // The main version contains the OS type too so we split it in two // and we'll have the OS type and the major version number separately. var platformAndVersion:Array = versionArray[0].split(" "); //for(var j:Number = 0; j < 2; j++) _strace("platformAndVersion["+j+"]: "+platformAndVersion[j]); //_strace("-----"); var majorVersion:Number = parseInt(platformAndVersion[1]); var minorVersion:Number = parseInt(versionArray[1]); var buildNumber:Number = parseInt(versionArray[2]); return Number(majorVersion+"."+minorVersion); } public static function OpenLocalURLTop(url) { navigateToURL(new URLRequest(GameSettings.Approot+url), "_top" ); } public static function OpenLocalURL(url) { navigateToURL(new URLRequest(GameSettings.Approot+url), "_blank" ); } public static function OpenURL(url, window = "_blank") { navigateToURL(new URLRequest(url), window); } public static var ExitFullScreenCallback; public static function WallPublish(title:String, desc1:String, desc2:String, image:String, url = null, action = null) { if (Utils.ExitFullScreenCallback) Utils.ExitFullScreenCallback(); //_strace(title + "\n" + desc1 + "\n" + desc2 + "\n" + image + "\n"); ExternalInterface.call("askToPublish", title, url, desc1, desc2, image, action); //if (Settings.Platform == Settings.HI5) { //DialogManager.Instance().ShowMessageBox("The message was posted to your wall!", "", "OK", null); //} } public static function SendToRecipients(recipients:Array, description, data) { if (!GameSettings.IsFacebook) return; if (Utils.ExitFullScreenCallback) Utils.ExitFullScreenCallback(); try { ExternalInterface.call("sendToRecipients", recipients, description ,data); } catch (e) { _strace(e.message); } } public static function GetFriendData() { try { return ExternalInterface.call("pollInviteData"); } catch (e) { _strace(e.message); } } public static function singleBounceEase(t:Number, b:Number, c:Number, d:Number):Number { t = t / d; if (t < 0.7) { t *= 1.0 / 0.65; return c * (t * t) + b; } return c * (t * t) + b; } public static function Finish(e:TweenEvent) { //_strace("done " + e.currentTarget.obj.x + " " + e.currentTarget.obj.y + " " + e.currentTarget.obj.scaleX + " " + e.currentTarget.obj.scaleY); e.currentTarget.removeEventListener(TweenEvent.MOTION_FINISH, Finish); } public static function Popup(mc, startScale = 0.8, finishCallback = null) { var rect:Rectangle = mc.getRect(mc); var targetX = mc.x; var targetY = mc.y; var centerX = mc.x + rect.left + mc.width / 2.0; var centerY = mc.y + rect.top + mc.height / 2.0; var startX = centerX - (rect.left + mc.width / 2.0) * startScale; var startY = centerY - (rect.top + mc.height / 2.0) * startScale; var tweenSX = new Tween(mc, "scaleX", singleBounceEase, startScale, 1.0, 4, false); if (finishCallback) tweenSX.addEventListener(TweenEvent.MOTION_FINISH, finishCallback); var tweenSY = new Tween(mc, "scaleY", singleBounceEase, startScale, 1.0, 4, false); if (finishCallback) tweenSY.addEventListener(TweenEvent.MOTION_FINISH, finishCallback); var tweenX = new Tween(mc, "x", singleBounceEase, startX, targetX, 4, false); if (finishCallback) tweenX.addEventListener(TweenEvent.MOTION_FINISH, finishCallback); var tweenY = new Tween(mc, "y", singleBounceEase, startY, targetY, 4, false); if (finishCallback) tweenY.addEventListener(TweenEvent.MOTION_FINISH, finishCallback); return [tweenSX, tweenSY, tweenX, tweenY]; } public static function StringSplit(s:String, delim:String, max:int = -1):Array { var ret:Array = s.split(delim); if (max != -1) { var more:String = ret.slice(max - 1).join(delim); ret.splice(max - 1); ret[max - 1] = more; } return ret; } public static function StringStartsWith(str:String, substr:String):Boolean { if (substr.length > str.length) return false; return (str.substr(0, substr.length) == substr); } public static function StringEndsWith(str:String, substr:String):Boolean { if (substr.length > str.length) return false; return (str.substr(str.length - substr.length, substr.length) == substr); } public static function StringContains(str:String, substr:String):Boolean { return (str.indexOf(substr) !== -1); } private static var vowelsAndH = { "a":true, "A":true, "e":true, "E":true, "i":true, "I":true, "o":true, "O":true, "u":true, "U":true, "h":true, "H":true } public static function StringStartsWithVowelOrH(s:String):Boolean { if (vowelsAndH[s.charAt(0)]) return true; return false; } public static function CopyObject(obj, except = null) { var i; if (except == null) except = []; if (obj is Array) { var obj2 = []; for (i = 0; i < obj.length; i++) { obj2.push(Utils.CopyObject(obj[i])); } return obj2; } var ret:Object = {}; for (i in obj) { if (except.indexOf(i) == -1) { ret[i] = obj[i]; } } return ret; } public static function CopyToObject(objFrom, objTo, except = null) { if (except == null) except = []; for (var i in objFrom) { if (except.indexOf(i) == -1) { objTo[i] = objFrom[i]; } } } public static function CopyToObjectOnly(objFrom, objTo, only) { if (only == null) return; for (var i in only) { if (objFrom.hasOwnProperty(only[i])) { objTo[only[i]] = objFrom[only[i]]; } } } public static function ColorizeRGB(clip:MovieClip, r:int,g:int,b:int) { var cTransform = clip.transform.colorTransform; cTransform.redOffset = r; cTransform.greenOffset = g; cTransform.blueOffset = b; clip.transform.colorTransform = cTransform; } public static function hex2rgb (hex):Object { var red = hex>>16; var greenBlue = hex-(red<<16) var green = greenBlue>>8; var blue = greenBlue - (green << 8); return({r:red, g:green, b:blue}); } public static function RGBtoHEX(r, g, b) { return r << 16 | g << 8 | b; } /** * NOTE: An alpha of 1 will make the object a solid color (good for silhouettes) */ public static function TintDisplayObject(obj:DisplayObject, color:uint = 0xffffff, alpha:Number = 1.0) { var cTint:Color = new Color(); cTint.setTint(color, alpha); obj.transform.colorTransform = cTint; } // given an origin (ox, oy) and a look at point (tx, ty), // and a clip with the given number of rotation states, which // rotation should we pick? public static function Rotation(ox, oy, tx, ty, rotations) { var delta:Point = new Point(tx - ox, ty - oy); if (Point.distance(delta, new Point(0.0, 0.0)) < 0.00001) { delta.y = -1.0; } var d = ( (-Math.floor( /* calculate the rotation and scale it */ Math.atan2(delta.y, delta.x) / (Math.PI * 2.0) * rotations + 0.5 // add 0.5 and take the floor (round to closest int) ) + rotations) // atan2 returns in the range -pi to pi, measured ccw from +x, // we negate it and add rotations again to get it in the range // [0, rotations] % rotations) + 1; // add 1 to reference frames return d; } /* performs multiple operations asynchronously, but wait for them all to finish: * instead of calling a bunch of functions and passing callbacks, pass those callbacks to WaitForFunctions * and use ret.callbacks[0], ret.callbacks[1], etc... as the callbacks * this will wait until every command is complete and call all the callbacks at once. * * For instance, to load multiple graphics packs asynchronously and wait for them all to finish, * call var ret = WaitForFunctions([DoneLoading, null, null, null]); to generate * ret.callbacks[0]..ret.callbacks[3], and pass these to 4 calls to LoadExternalGraphics. * When these 4 calls complete, the provided 4 functions will be called with the arguments returned * from the callbacks (in this case, only DoneLoading will be called since the * other callbacks are null). */ public static function WaitForFunctions(...funcs):Object { var ret:Object = {}; // has a callback been hit? ret.hit = new Array(funcs.length); // what were the original arguments the callback was called with ret.args = new Array(funcs.length); // a list of the artifical callbacks we are providing ret.callbacks = new Array(funcs.length); // the real callbacks ret.funcs = funcs; ret.done = false; ret.immediate = []; for (var i = 0; i < funcs.length; i++) { // we have to setup this temp callback in another function, because the anon function's // activation object will contain the current scope, meaning that the variable // i will be updated in each function; if we do it in a seperate function each // activation object will reference a different i ret.callbacks[i] = Utils.SetupFunction(ret, i); } return ret; } /** * Returns the standard money format for an integer amount */ public static function FormatCurrency(amount:int, symbol:String = "$"):String { var afterDecimal:String = (amount % 100).toString(); while (afterDecimal.length < 2) afterDecimal = "0" + afterDecimal; //mmmm string concatenation var beforeDecimal:String; if (amount > 100) { beforeDecimal = Math.floor(amount/100).toString(); } else { beforeDecimal = "0"; } return symbol + beforeDecimal + "." + afterDecimal; } public static function FormatNumber(amount){ var whole = Math.floor(amount); // convert the number to a string var amount_str:String = String(whole); var total_str:String = String(amount); var number_array:Array = []; var start:Number; var end:Number = amount_str.length; while (end > 0) { start = Math.max(end - 3, 0); number_array.unshift(amount_str.slice(start, end)); end = start; } var point = total_str.indexOf("."); var ret = number_array.join(","); if (point != -1 && point < total_str.length) { ret += total_str.substr(point); } return ret; } protected static function SetupFunction(ret, i):Function { var a:Function = function(...rest) { if (ret.immediate[i]) ret.immediate[i].apply(null, rest); ret.hit[i] = true; ret.args[i] = rest; var ok:Boolean = true; var j; for (j = 0; j < ret.hit.length; j++) { if (!ret.hit[j]) { ok = false; break; } } if (ok && !ret.done) { ret.done = true; for (j = 0; j < ret.funcs.length; j++) { if (ret.funcs[j] != null) ret.funcs[j].apply(null, ret.args[j]); } } }; return a; } // useful for the paned dialogs to show a certain pane/button public static function OnlyVisible(obj, set:Array, index:int) { for (var i in set) { if (i != index) { obj[set[i]].visible = false; } else { obj[set[i]].visible = true; } } } public static function AllVisible(obj, set:Array) { for (var i in set) { obj[set[i]].visible = true; } } // set one of a list of tabs to be enabled public static function OnlyToggled(obj, set:Array, index:int) { for (var i in set) { if (i != index) { obj[set[i]].SetToggled(false); } else { obj[set[i]].SetToggled(true); } } } // get the frame number of a label in the timeline public static function GetLabelFrame(mc, name:String):int { for (var l in mc.currentLabels) { if (mc.currentLabels[l].name == name) return mc.currentLabels[l].frame; } return 1; } // generate a quick text field of a certain color/style public static function BasicTextField(color:uint, size:int, font:String, text:String, additional:Object = null, align = "left"):TextField { var t:TextField = new TextField(); var f:TextFormat = new TextFormat(); f.align = align; if (additional != null) for (var a in additional) f[a] = additional[a]; f.font = font; f.color = color; f.size = size; t.type = TextFieldType.DYNAMIC; t.defaultTextFormat = f; t.text = text; t.selectable = false; t.autoSize = TextFieldAutoSize.LEFT; return t; } public static function var_dump(_obj, name = "Dump") { _strace(name + " " + (_obj) + " {"); flash.utils.describeType(_obj); var varList:XMLList = flash.utils.describeType(_obj)..variable; for(var i:int; i < varList.length(); i++) { //Show the name and the value _strace(" " + varList[i].@name+' = '+ _obj[varList[i].@name]); } _strace("}"); } public static function SetChildFrames(parentClip, frame, exclude = null) { if (parentClip is MovieClip && parentClip.name != exclude) { parentClip.gotoAndStop(frame); for (var i = 0; i < parentClip.numChildren; i++) { Utils.SetChildFrames(parentClip.getChildAt(i), frame, exclude); } } } public static function SetChildFramesNoParent(parentClip, frame, exclude = null) { if (parentClip is MovieClip && parentClip.name != exclude) { for (var i = 0; i < parentClip.numChildren; i++) { Utils.SetChildFrames(parentClip.getChildAt(i), frame, exclude); } } } //modifies the array passed as parameter, following the MO of the built in Array.sort() public static function insertionSort(array:Array, compareFunction:Function):void { for(var i:int=1; i < array.length; i++) { var value:Object = array[i]; var k:int=i-1; while( k >= 0 && compareFunction(array[k], value) == -1) { array[k+1]=array[k]; k--; } array[k+1]=value; } } public static function Screenshot(sourceClip, receiverURL, filename) { var jpgSource:BitmapData; if (sourceClip is Stage) { jpgSource = new BitmapData (sourceClip.stageWidth, sourceClip.stageHeight); } else { jpgSource = new BitmapData (sourceClip.width, sourceClip.height); } jpgSource.draw(sourceClip); var jpgEncoder:JPGEncoder = new JPGEncoder(85); var jpgStream:ByteArray = jpgEncoder.encode(jpgSource); var header:URLRequestHeader = new URLRequestHeader("Content-type", "application/octet-stream"); var jpgURLRequest:URLRequest = new URLRequest(receiverURL+"?name="+filename); jpgURLRequest.requestHeaders.push(header); jpgURLRequest.method = URLRequestMethod.POST; jpgURLRequest.data = jpgStream; navigateToURL(jpgURLRequest, "_blank"); } public static function SetColors(clip, color) { var colorTransform:ColorTransform; if (clip == null || color == null) return; if (clip.hasOwnProperty("outline") && clip.outline != null) { colorTransform = clip.outline.transform.colorTransform; colorTransform.color = color.Outline; clip.outline.transform.colorTransform = colorTransform; } if (clip.hasOwnProperty("secondaryOutline") && clip.secondaryOutline != null) { colorTransform = clip.secondaryOutline.transform.colorTransform; colorTransform.color = color.LightOutline; clip.secondaryOutline.transform.colorTransform = colorTransform; } if (clip.hasOwnProperty("color") && clip.color != null) { colorTransform = clip.color.transform.colorTransform; colorTransform.color = color.Primary; clip.color.transform.colorTransform = colorTransform; } if (clip.hasOwnProperty("secondaryColor") && clip.secondaryColor != null) { colorTransform = clip.secondaryColor.transform.colorTransform; colorTransform.color = color.Secondary; clip.secondaryColor.transform.colorTransform = colorTransform; } if (clip.hasOwnProperty("shadow") && clip.shadow != null) { colorTransform = clip.shadow.transform.colorTransform; colorTransform.color = color.Shadow; clip.shadow.transform.colorTransform = colorTransform; } if (clip.hasOwnProperty("secondaryShadow") && clip.secondaryShadow != null) { colorTransform = clip.secondaryShadow.transform.colorTransform; colorTransform.color = color.SecondaryShadow; clip.secondaryShadow.transform.colorTransform = colorTransform; } } /* returns a rect with the x, and y pos to center and the scaleX and scaleY as width and height */ public static function GetUniformScaleRect(clip:MovieClip, maxWidth, maxHeight) { var rect:Rectangle = new Rectangle(0,0,0,0); var widthScale = Math.min(maxWidth / clip.width, 999); var heightScale = Math.min(maxHeight / clip.height, 999); var scale = 1; if (widthScale > heightScale) { scale = heightScale; } else { scale = widthScale; } rect.width = clip.width * scale; rect.height = clip.height * scale; var pb = clip.getBounds(clip); var xadjust = -pb.left * scale; var yadjust = -pb.top * scale; rect.x = xadjust + (maxWidth - rect.width) / 2; rect.y = yadjust + (maxHeight - rect.height) / 2; rect.width = scale; rect.height = scale; return rect; } public static function Dec2Hex(d) { var chars:String = "0123456789ABCDEF"; var str:String = ""; while (d > 0 || str.length < 2) { var digit = d % 16; d = (d - digit) / 16; str = chars.charAt(digit) + str; } return str; } public static function Hex2Dec(h:String) { var chars:String = "0123456789ABCDEF"; var val = 1; var res = 0; for (var i = h.length - 1; i >= 0; i--) { res += chars.indexOf(h.substr(i, 1)) * val; val *= 16; } return res; } public static function ShallowCopyArray(array:Array) { if (!array) return null; var newArray:Array = []; for (var i:int = 0; i < array.length; i++) { newArray.push(array[i]); } return newArray; } /* Note: Will fail if any items in either array have reference type semantics (unless they point to the same object) * (as opposed to value type semantics) */ public static function areEqual(a:Array,b:Array):Boolean { if(a.length != b.length) { return false; } var len:int = a.length; for(var i:int = 0; i < len; i++) { if(a[i] !== b[i]) { return false; } } return true; } /* Note: Will fail if any items in either array have reference type semantics * (as opposed to value type semantics) */ public static function objectsAreEqual(a:Object,b:Object):Boolean { for (var i in a) { if (!b.hasOwnProperty(i) || a[i] != b[i]) return false; } return true; } public static function DeepCopyClone (source : Object) : * { var array : ByteArray = new ByteArray (); array.writeObject (source); array.position = 0; return array.readObject (); } // {a:1, b:2} => [1,2] public static function ObjectValues (obj:Object):Array { var array = []; for (var key in obj) array.push(obj[key]); return array; } // {a:1, b:2} => ["a","b"] public static function ObjectKeys (obj:Object):Array { var array = []; for (var key in obj) array.push(key); return array; } // normal random variate generator; mean m, standard deviation s public static function BoxMullerRandomNormal(m:Number, s:Number) : Number { var x1, x2, w, y1:Number; var y2:Number; var use_last:Boolean = false; if (use_last == true) /* use value from previous call */ { y1 = y2; use_last = false; } else { do { x1 = 2.0 * Math.random() - 1.0; x2 = 2.0 * Math.random() - 1.0; w = x1 * x1 + x2 * x2; } while ( w >= 1.0 ); w = Math.sqrt( (-2.0 * Math.log( w ) ) / w ); y1 = x1 * w; y2 = x2 * w; use_last = true; } return( m + y1 * s ); } public static function SanitizeNumber(n) { if (n is Number) { if (n == Number.NEGATIVE_INFINITY || n == Number.POSITIVE_INFINITY || n == Number.NaN) return 0; } return n; } public static function IsNumberInvalid(n) { if (n is Number) { if (n == Number.NEGATIVE_INFINITY || n == Number.POSITIVE_INFINITY || n == Number.NaN) return true; } return false; } public static function LimitNumberToMax(n) { if (n == Number.POSITIVE_INFINITY) return Number.MAX_VALUE; return n; } /* value= Math.round(20/7); value= int((20/7)*10)/10; value= int((20/7)*100)/100; value= int((20/7)*1000)/1000; value= int((20/7)*10000)/10000; */ public static function RoundToDecimalPlaces(number:Number, places:int) { return Math.round((number)*Math.pow(10,places))/Math.pow(10,places); } public static function GetShuffledArray(a:Array) : Array { var r:Array = a.concat(); r.sort(randomSort); return r; } ///Convenience function since I keep forgetting the name of randomSort (hint: it's randomSort) public static function ShuffleArray(a:Array) { a.sort(randomSort); } public static function PickRandom(a:Array) { return a[Math.floor(Math.random() * a.length)]; } /** * Returns n elements of array a, up to a maximum of a's length. * If forceCopy is set, the returned array will always be a new instance. */ public static function PickRandomSet(a:Array, n:int, forceCopy:Boolean=false):Array { if (a.length <= n || a.length == 0) { if (forceCopy) return a.concat(); else return a; } if (n == 1) return [PickRandom(a)]; var shuffled:Array = GetShuffledArray(a); return shuffled.slice(0, n); } /** * Does not randomly sort an array! To do that, Use the default array.sort with this as its argument. * If you want a new, shuffled array, use GetShuffledArray */ public static function randomSort(a:*, b:*) : Number { if (Math.random() < 0.5) return -1; else return 1; } /** * Returns the union of arr1 and arr2. If the elements are not primitive types, you'll need to provide a sorting function. * If inPlace, a1 and a2 will be sorted. * If they already contain duplicates, then all bets are off. */ public static function MergeArrays(arr1:Array, arr2:Array, sortFunc:Function = null, inPlace:Boolean = false) : Array { var ret:Array = []; var a1:Array = (inPlace) ? arr1 : arr1.slice(); var a2:Array = (inPlace) ? arr2 : arr2.slice(); var len1:uint = a1.length; var len2:uint = a2.length; var i1:uint = 0; var i2:uint = 0; //Boring cases if (len1 == 0 && len2 == 0) return ret; if (len1 == 0) return (inPlace) ? a2.slice() : a2; if (len2 == 0) return (inPlace) ? a1.slice() : a1; if (sortFunc) { a1.sort(sortFunc); a2.sort(sortFunc); } else { a1.sort(); a2.sort(); } while (i1 < len1) { //add all from a2 up to a1[i1] while (i2 < len2 && a2[i2] <= a1[i1]) { ret.push(a2[i2]); i2 += 1; } if (ret.length == 0 || a1[i1] != ret[ret.length-1]) ret.push(a1[i1]); i1 += 1; } while (i2 < len2) ret.push(a2[i2]); return ret; } public static function ConvertToHHMMSS(seconds:Number):String { var s:Number = seconds % 60; var m:Number = Math.floor((seconds % 3600 ) / 60); var h:Number = Math.floor(seconds / (60 * 60)); var hourStr:String = (h == 0) ? "" : DoubleDigitFormat(h) + ":"; var minuteStr:String = DoubleDigitFormat(m) + ":"; var secondsStr:String = DoubleDigitFormat(s); return hourStr + minuteStr + secondsStr; } public static function DoubleDigitFormat(num:uint):String { if (num < 10) { return ("0" + num); } return String(num); } public static function CapitolizeString(str:String) : String { var firstChar:String = str.substr(0, 1); var restOfString:String = str.substr(1, str.length); return firstChar.toUpperCase()+restOfString.toLowerCase(); } // ^ Nice spelling, goof! public static function CapitalizeString(str:String) : String { return CapitolizeString(str); } public static function GetListString(listStrings:Array) : String { var andString:String = "&"; var count:int = 0; var listString:String = ""; for (var i = 0; i < listStrings.length; i++) { if (count > 0 && listStrings.length == 2) listString += " "+andString+" "; // For just 2 items else if (count == listStrings.length-1 && listStrings.length > 2) { // For adding "and" at the end of 3+ items. It is: ", and $(item)" var endingString:String = ""; endingString = endingString.replace("$(item)", listStrings[i]); listString += endingString; count++; continue; } else if (count > 0) listString += ", "; // Comma separated list listString += listStrings[i]; count++; } return listString; } /* * Flash doesn't like the way MySQL prints dates (2016-06-02 13:00:00) * "The year month and day terms can be separated by a forward slash (/) or by spaces, but never by a dash (-)." */ public static function ParseDate (dateString:String) : Date { var pattern:RegExp = /-/g; var date = new Date(); dateString = dateString.replace(pattern, "/"); date.setTime(Date.parse(dateString)); return date; } /* * For display only, not intended to be read by ParseDate * Tuesday, June 7th, 2016 at 10:32 AM */ public static function FormatDate (date:Date) : String { var f:DateTimeFormatter = new DateTimeFormatter("en-US"); var dateStr:String; var lastChar:String; //Flash can't do "1st", "2nd", etc f.setDateTimePattern("d"); dateStr = f.format(date); lastChar = dateStr.charAt(dateStr.length - 1); if (lastChar == "1" && dateStr != "11") dateStr += "st"; else if (lastChar == "2" && dateStr != "12") dateStr += "nd"; else if (lastChar == "3" && dateStr != "13") dateStr += "rd"; else dateStr += "th"; f.setDateTimePattern("EEEE, MMMM '" + dateStr + "', yyyy 'at' h:mm a"); return f.format(date); } /* Simply counts the number of properties on the object */ public static function CountObjectParameters(obj:Object):int { var cnt:int=0; for (var s:String in obj) cnt++; return cnt; } /** * For when shit gets real */ public static function PrintStackTrace() { try { throw new Error('StackTrace'); } catch (e:Error) { _strace(e.getStackTrace()); } } } }