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());
}
}
}
}