Categories Displayed in Flash

Archive for December, 2007

AS3: Array.filter R0xr!

Array in AS3 has some nifty features that make managing and manipulating active data much easier. Thanks to Brandon Hall's nooks and crannies presentation at LA Flash for getting me to look. Here's an example of using Array.filter

Here's the minimum filter that doesn't do anything. I default the last parameters as often filters are useful outside of iterating over arrays, but the filter method nicely tells the filter where it is via the 'index' and a reference back to the Array.

  1.  
  2.         public class Filter {
  3.                 public function passesFilter(item:*,  index:int= 0, array:Array = null):Boolean{
  4.                         var passes:Boolean = true;
  5.                         return passes;
  6.                 }
  7.         }

Inside com.troyworks.data.filters. I've created a family of filters, in particular RangeFilter that allows inclusive and exclusive of a given range. Here's what a 3-8 filter looks like:


3-8 filter.. 0123456789012345678
* inclusive ---[PASS]----------
noninclusive ---]PASS[----------

The real power of filters is they can be stacked. Here's an example of using a color filter, that looks for color values in the midgray band, but adds an additional filter so that values to close to gray are thrown out.

  1.  
  2. //find values from 0x555555 to 0xBBBBBB non-inclusive on both sides
  3.         var midsFilter:ColorStatisticFilter = new ColorStatisticFilter( ColorUtil.GRAY5, ColorUtil.GRAYB, false, false);
  4.         midsFilter.distanceFromShadeFilter = new NumberRangeBooleanFilter(36, 255);
  5.      // second param needs to be null as this filter is a function closure instead of an anonymous function.
  6.       var midColors:Array = indexedColors.filter(midsFilter.passesFilter,null);

AS3: Image Posterization + ColorUtils + Adaptively Colored UI’s

Ported this posterization algorithm to AS3 . It will be in the com.troyworks.ui.ColorUtil, when released.

Posterization is basically compressing the color range of a photo into something smaller. Anybody who has worked with converting to 'indexed color' in GIF or PNG knows what this means. Say you have a sun against a sky of blue.  Since there are only say 8 colors, there is no need to have room for 24bit color across the entire range, making it dramatically smaller.  The other use is for artistic purposes,

Porting one to actionscript has allowed me to create something nifty. One of the design challenges when working with dynamically loaded images is complimenting the colors in the loaded image in the surrounding UI elements., and from a useability perspective making sure that text and UI elements are sufficiently contrasting from whatever dominate color is chosen, else they dissapear...is that "cut or delete?"

So towards that end, I created this prototype, click on one of the indexed colors to change the ui, the text will choose from one of the other color bands. The title will pick either white or black to attempt whatever the best contrast is from the selected color.

Click on any of the colored bars to have the entire UI adjust..all colors originate from the thumbnail.

(Either JavaScript is not active or you are using an old version of Adobe Flash Player. Please install the newest Flash Player.)

This was accomplished by first posterizing the loaded image (the second image) and indexing the colors with a bandpass filter (filtering out anything too black or too white) via com.troyworks.ui.ColorUtil , sorting by how often the color occurs in the image to generate the histogram. Used com.troyworks.core.tweeny.Tny to do the color tweening. com.troyworks.data.ArrayX to get a random color from the bands.

From a design perspective, it's interesting how the low occurance spot colors when selected makes the image seem more 'playful' while the more common dominate ones 'serious'. I find myself wanting to put a better color distance in, to filter out things close to grays from the options.

There are also method to get shades and hues from a given color, but no examples yet.

All in all a fun way to spend a few hours this evening, while listening to Lily Allen.

Adobe Updates AIR, for Flash CS3, “The application requires a version of the Adobe Integrated Runtime which is no longer supported”

Tried publishing in the Flash IDE to AIR this morning and it output...blank space. Left me scratching me head for a bit, tried another air app, and got this.

The Application requires a verion of the Adobe Integrated Runtime (AIR) which is no longer supported. Please contact the application author for an updated version.

Turns out that AIR had been updated like yesterday. But this requires a few steps to fix Flash CS3's publish for AIR. Instructions are spread across here.

  • http://www.adobe.com/support/flash/downloads.html#flashCS3
  • http://labs.adobe.com/wiki/index.php/AIR:Flash_CS3_Professional_Update#Download_and_Install

Which was far more involved than I was expecting, you have to uninstalled some things manually, and then to execute a jsfl script to cleanup afterward. To compound things, the updates want Firefox to be closed down, which have the instructions on it.

After all that....my file still didn't publish as AIR. Weird as it is, renaming the file allowed it to publish again *scratches head*

Gripe.

I realize AIR is beta, and it offers some really amazingly cool features. But it bums me out a little that the few AIR apps I've got installed are now all broken, and it's unknown if they will be updated in a timely fashion, being mostly in the widget, experimental category. Uninstalling isn't hard but it is annoying.

I find it also a bad user experience, if I can't get to the help/about to of an oddball named AIR app, to remember where I downloaded the widget in the first place, due to the above dialog, which isn't particularly helpful either in the user resolving the situation (like where to download the latest version). It makes me less gung-ho about delivering AIR products, if whatever I release can break in the wild at any time at Adobe's discretion.

AS3: Bug with TextField.appendText with whitespace

In Flash 9.0 r28, 9.0 r48 when appendingText I get wonkiness.

  1. output_txt.appendText("A:\r");
  2. output_txt.appendText("B:");

Outputs

A:B:

Should Be

A:
B:

In another case, when using other tabs and newlines, I've also had it do something like this
Outputs

A
:B:

Weird!

The solution I've found is adding an extra space at the end (after the \r)

  1. output_txt.appendText("A:\r ");
  2. output_txt.appendText("B:");

Outputs

A:
B:

AS3: Parsing XML with Nested Namespaces, SWF RDF metadata

Trying to parse the swf header to get at the metadata, which requires getting through nested namespaces in the RDF

The Flash Metadata embedded in the swf headers looks like:

<rdf:rdf xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:description xmlns:dc="http://purl.org/dc/1.1/">
<dc:title>A MetaData Example</dc:title>
<dc:description>This file has metadata embedded in it.</dc:description>
</rdf:description>
</rdf:rdf>

Namespaces are liked locked boxes, until you pass the key (e.g. setting default xml namespace = ns; or xml.ns::nodeName they are locked from opening anything beneath them, though it may appear otherwise when looking in the debugger.

So getting namespaces are required to parse the title and description. It would be easy to cheat and just hardcode the namespace, however it's bad form to hardcode the namespaces, as they change over different versions of the swf file format.

In addition the meta.namespaceDelcarations appears only to apply to the node it's associated with, meaning

  1.  
  2.    for (var i:uint = 0; i < meta.namespaceDeclarations().length; i++) {
  3.         var ns:Namespace = meta.namespaceDeclarations()[i];
  4.         trace(i + " ns " + ns.toString());
  5.         var prefix:String = ns.prefix;
  6.         if (prefix == "") {
  7.                 prefix = "(default)";
  8.         }
  9.         trace(prefix + ":" , ns.uri);
  10.  }

on the top level only returns the first name sapce of "http://www.w3.org/1999/02/22-rdf-syntax-ns#" when really we are after the dc namespace. But we need the first lock in order to open up the second.

Another approach is just parsing the string looking for the namespace prior to XML.

var rdfN:String = findXMLNS(nsr, 'xmlns:rdf="');
var dcN:String = findXMLNS(nsr, 'xmlns:dc="');
var rd:Namespace = new Namespace(rdfN);

  1.  
  2.   function findXMLNS(xmlS:String, nameSpace:String):String {
  3.      var a:Number = xmlS.indexOf(nameSpace);
  4.      var a2:Number = a + nameSpace.length;
  5.      var b:Number = xmlS.indexOf("\"", a2);
  6.      var res:String = xmlS.substring(a2,b);
  7.      return res;
  8.   }

Another warning is that namespaces var should be declared outside of a function if your else you'll get an error message of
VerifyError: Error #1025: An invalid register 13 was accessed.

Presumeably because namespaces as used by XML need to be scoped as non-temp local function scoped variables. So

  1.  
  2.  var dc:Namespace;
  3.  
  4.  function parseXML(Desc:XMLList){
  5.     //BAD! var ns = Desc.namespaceDeclarations()[0];
  6.     dc = Desc.namespaceDeclarations()[0]; //GOOD
  7.     //BAD         default xml namespace =  ns;
  8.     default xml namespace =  dc; //GOOD
  9.     trace("title:" + meta..title);
  10.  }

WordPress + GoogleCode’s SVN = FlashTextEditor + FlashVars + PHPProxy

Been looking for a way to get the actionscript code in SVN, onto the blog, nicely formatted, colorized, with eventually smart help and highlighting. So the blog and upcoming wiki can 'decorate' it. Finally figured it out.

I use Google Code SVN as it's free, and solid. To get it work with Wordpress a with the plugins 1)pb-embedFlash and 2) FlashTextEditor. through PHP Proxy for Flash Cross-Domain Security problems

Strictly speaking, 1) isn't required but the syntax is cleaner than using 2) directly. A sample post in wordpress looks like

[flash http://troyworks.com/blog/wp-content/plugins/FlashTextFormatter/ftf.swf f={file= http://troyworks.googlecode.com/svn-history/r7/trunk/AS3/dev/src/com/troyworks/ui/LayoutUtil.as} ]

Where f={} is the passing of the flashvars with the proxy and actionscript file name. I had to make a patch to the pb-embedFlash.php to pass flashvars...though honestly I'd prefer to be using SWFObject instead. Here's a snippet of the patch :

  1.  
  2.  } else { // not a flv file - what may it be?
  3.  
  4.        $i = 0; global $pb_embedflash;  if (preg_match('%f={(.+?)}%',$match[2],$hit) &amp;&amp; $hit[1] != ' ') {
  5.  
  6.                $flashvars = '?'.$hit[1];
  7.  
  8.        }
  9.  
  10.  while (isset($pb_embedflash[$i][0])) // search for YouTube, Google Video, etc.
  11.  
  12.        {
  13.  
  14.                if (preg_match(pb_buildpattern($pb_embedflash[$i][0]),$match[1],$hit) &amp;&amp; (count($pb_embedflash[$i]) == 5))
  15.  
  16.                {
  17.  
  18.                        $output = str_replace('###URL###', str_replace('###ID###', $hit[1], $pb_embedflash[$i][1]), $output);
  19.  
  20.                        $output = str_replace('###WIDTH###', $pb_embedflash[$i][2], $output);
  21.  
  22.                        $output = str_replace('###HEIGHT###', $pb_embedflash[$i][3], $output);
  23.  
  24.                        $break = TRUE; break 1; // stop searching if we found sth.
  25.  
  26.                }
  27.  
  28.                $i++; // we don't want an infinite loop ;)
  29.  
  30.        }
  31.  
  32. if (!isset($break)) // seems to be a normal swf or an unknown video hoster
  33.  
  34.        {
  35.  
  36.                $output = str_replace('###URL###', $match[1].$flashvars, $output);
  37.  
  38.        }
  39.  
  40. }

and also had to add a whitespace trim() to the FlashTextEditor, as for whatever reason the flash vars are getting passed in with an extra space in the front (I don't know PHP so I'm probably doing something), which causes it to fail.

Since my framework will be up on google, and I check in via SVN it's a sound development practice to make sure the latest code that shows up on the blog is that from SVN, instead of being cut and pasted here or uploaded to the webserver. Unfortunately, Google doesn't have a cross domain file in place so loading the text isn't possible directly, thus the need for PHP Proxy.

Here's an example of getting LayoutUtil.as from Google Code.

(Either JavaScript is not active or you are using an old version of Adobe Flash Player. Please install the newest Flash Player.)

What I'd like to do in the future as examples start coming out is highlighting selected lines + folding, and automatic linking to the adobe docs, making it more of a wiki. Probably will be a rewrite of FlashTextEditor.

If your contributing to this blog use the following tips:

All these require editing on the 'code' tab (not 'visual' tab) when writing a post.  When embedding classes examples that are on google SVN use this

You can upload and then embed flash examples via:

(Either JavaScript is not active or you are using an old version of Adobe Flash Player. Please install the newest Flash Player.)

and use this flash based editor for pulling code off of google

(Either JavaScript is not active or you are using an old version of Adobe Flash Player. Please install the newest Flash Player.)

and pretty format it via:

<pre lang="actionscript">
YOUR CODE
</pre>

but you'll need an return before the first pre

2) You can make small blocks like

"In order to print, You will need to listen for <code> addListener</code>"

AS3: How low can you go? Tny, a 1.9KB Tweening engine for Banner Ads

Challenged by a Banner ad size limit, I was curious how small I could create a tweening engine with basic color and sound support. Got it down to 1919 bytes, it can get down to ~1500 bytes if you don't need sound or color. Leaving room for more assets (damn Myriad Pro is a hog!)

Of course it's not just for banner ads, it basically wraps a given DisplayObject (including TextFields), and behaves just like setting properties of a clip directly (x, y, xscale), except that it eases to get there. Setting the duration acts as the play().

This makes it pretty easy to prototype with, so much so I'm contemplating using it as the proxy for whever I normally position things, to force me to think about motion earlier, just set duration = 0, and it will jump to the end.  It shares the same basic API as Tweeny, so progressive enhancement (if you need the playhead API) is easy to do.
It' s not the fastest engine purely on code, but with rendering overhead, it's among the best available in GreenSock's great little starfield tweening benchmark util

(Either JavaScript is not active or you are using an old version of Adobe Flash Player. Please install the newest Flash Player.)

Here's an example of tweening the color and position of textfields, note that the engine is 1.9K, this banner is 10K due to fonts:

(Either JavaScript is not active or you are using an old version of Adobe Flash Player. Please install the newest Flash Player.)

Using this code.

  1.  
  2. import com.troyworks.core.tweeny.*;
  3.  
  4. //similar to t1.target = txt1;
  5. var t1:Tny = new Tny(txt1);
  6. var t2:Tny = new Tny(txt2);
  7. var t3:Tny = new Tny(txt3);
  8. var t4:Tny = new Tny(txt4);
  9.  
  10. //Setup colors to cycle through
  11. var c:Array =[0xFFFFFF, 0xCCCCCC, 0x333333, 0x000000];
  12.  
  13. //Set Bounds //
  14. var ow = stage.width - txt.width - 100;
  15. var oh = stage.height - 80;
  16.  
  17. function jump(t:Tny):void {
  18.         t.x =  txt.width + (ow * Math.random());
  19.         t.y = (oh* Math.random());
  20.         t.scaleY = t.scaleX  = Math.random()*3;
  21.         t.ease = Elastic.easeInOut;
  22.         /////// Re-Cycle Colors ////////////
  23.         var cc = c.shift();
  24.         t.color = cc;
  25.         t.colorP =10; //10% tint
  26.         c.push(cc);
  27.  
  28.         t.delay = Math.random() * 1;
  29.         t.duration = Math.random() * 4  + .5;
  30.         ///// on complete callback self ////
  31.         t.onComplete = jump;
  32.         t.onCompleteParams =[t];
  33. }
  34.  
  35. jump(t1);
  36. jump(t2);
  37. jump(t3);
  38. jump(t4);

It's open source, it will be up after the first of the year, still trying to figure out how to get google code's SVN to show up on the blog, and there may be a bug or two lurking I haven't found yet.

As an aside, as this post hopefully shows, the blog is improving technically in periodic jumps, with some exciting upgrades planned in 2008. While a webdev pro, It's my first time professionally blogging and first time using Wordpress. Over the weekend upgraded to the latest, moved it to the correct domain, added several plugins for flash, code snippets sand spam filtering so comments and registration have been reenabled should work correctly. Permalink structures have changed so hopefully google will start indexing correctly by post instead of category.

In theory you should be able to subscribe to changes on pages you're interested in.

AS3: Prelude to Tweeny, a fast and flexible Tweening engine

So I've been working over the weekend on the Tweening engine based on Cogs affectionately called Tweeny. I find it highly amusing as I've been working in Flash since Flash 4, I have built so many presentation engines it borders on comical when every new client inevitably asks for a powerpoint lite clone, and consider myself relatively advanced,..yet how much of a loop this one threw me for.

WhileI had an AS2.0 class already working, it's taken me 3 days to get the basics working in AS3.0. This is because yesterday I totally got schooled on Matrixes with Senocular's most excellent tutorial, (my brain still hurts) and then excited by Penner's lurking MatrixTransform and ended up scrapping several paragraphs that comprise most the standard tween engines. I find myself building this next presentation engine in a way that bears no resemblence to most engines I've used or seen, partly due on the architecture difference between AS3.0 and prior, and partly expanding the role of Tweening beyond the simple display classes. Every time I added a new feature or solved a bug, I found a way to make things simpler.
Matrixes are cool, as you can get away with just easing the Begin and End matrixes rather than doing every calculation, plus you get the ability to offset the registration point and skew, features both very useful for the Authoring type interfaces and kids content I'm creating. More power and more speed to boot! In running performance tests, it's about 2x faster than setting DisplayObject.rotate, DisplayObject.width, scale etc as most tween engines do. Not that running those scripts are typically the limiting factor relative to the overhead in rendering, but still it's nice to know that the underlying code isn't a bottle neck.
Like most Tween engines, Tweeny supports a pluggable easing that affects multiple properties (x, y, width etc) with individual ranges (x[-5, 100], pan[-1,1]). But something my math-whiz girlfriend help me realize was that since duration is fixed, the easing equasion (often filled with expensive Math operations) can be calculated once as the 'normal' and then scaled to the others ranges, cheaply with simple * + . This should significantly reduce tweening calculation overhead,...and dammit I like smart particles flying at 60fps!

To further that I realized that the normalized calculation, is easy to broadcast, so that other listeners keep in synch, and can conceivably modularize or patchwork tweens. One of the things that I've wanted to try for awhlie was a way to balance out top-down easing approaches with bottom up physics routine. This usually involves Euler or Verlet accumulation and integration of forces, but most tweening engines are rather possessive when it comes to updating display objects...only one at a time else they start overwriting, where's the fun in that?
Some other features I like, Sound or SoundChannel volume and pan, colorTransform tweening (which I use a lot for configuration dynamically styled UI's) easier constructors for Bounce and Elastic's extra params which I use with kids games.

One thing that I'm not currently planning on supporting soon is a JSON or XML based interface. I find it poor programming practice to do

TweenEngine.create(target, duration, {x:1,y:2, ....})

in AS3.0 when you can do:

var t:Tweeny = new Tweeny();
t.initFrom(target,duration);
t.x = 1;
t.y = 2;

t.addEventListener(...)

t.startFromBeginning();

Because using fully typed classes allow for autocomplete to help fill out the values, offer stricter type checking and setting of defaults. When they are on a line by line they are easy to comment out to turn on and off. There isn't any overhead to parse XML or JSON into useable values. Since it's part of the Class definition it should also be significantly faster than dynamically allocated Object properties on the prototype.
Keeping a tween around, keeps memory and garbage collection from churning, especially for most applications where the tween is reused over and over again to put thing back and forth. I realize why many tween engines opt not to go this route as managing transitions on top of other transitions can get tricky. But know that I know about these issues I'm glad I spent the extra time. Since Tweeny uses the Playhead API, it supports stop, rewind, play, playbackward etc, it's not really different than keeping an mp3 or swf around.
So far it's about 10K, so 3x larger than say Tweenlite, but much of that is the inclusion of the framework/Cogs is useful for many other things, websites and games especially, and I'm still working on it.
The morning had an epiphany and I was able to tie together many of the related ideas into a cohesive model, so I have a roadmap for the next few months, and even a relatively simple Authoring UI for all the features exposed. Looking at the one pager of noteobook, probably 7 boxes, and only a few UI elements, in that largely what I'm working on is creating much of the same metaphors (e.g. timeline) of Flash inside of Flash...just like Web 2.0 is largely recreating the OS inside of the WebBrowser. And Virtualization is recreating the connectivity of electronics. One that note, if your looking for good book on self-referentiality check out Gödel, Escher, Bach .

AS3: Tips for Floating Point Hell

Here's some tips for working with floating point round off errors in applications.

  1. use Math.round, or roundToPrecision late as possible, and only when you have to.
  2. when doing number comparisons, use the following notClose or fuzzyEquals instead of '=='
  3. truly think about the degree of precision you need and be consistent.

1) Keep things in MVC format, meaning changes percolate down as they are, and views get notified and can reformat on the way up as they need to for themselves without touching the actual model. This is important as floating point math is largely a blackbox like your x-girlfriend. Well behaved at times, and then damn quirky in the next second on something seeming innocuous, making it impossible to predict (and unit test)
Imagine that we are driving a car along the windy highway, and staying in the lanes is the goal to save us from the cliffs of insanity off to either side. Problem is our steering wheel only goes 100% left or 100% right., so for some particular curves it works well, others...lots of thrashing back and forth to stay on the road, in this case the thrashing is the computer trying to fit oddball things like 1/3 into a number system that really only has left or right angle turns. The first tendency is to try and wrangle say 4.0000001 into 4...as they are close right!? well what happens is by puttting on the brakes (e..g rounding) you introduce another set of steering wheels on the car, hoping that it will cancel it out, when in reality you've double the things that can go wrong.

The computer's number system is in binary sacrifices precision for speed, it represents numbers (variable and the results of calculationgs) with 16, 32...and 64 bit precision, which is often good enough for most things. What happens in many calculations is that while a particular number say 1/3 may not display perfectly on screen, that 1/3 * 3 gets us back to a whole number which the computer can represent. So by rounding early, you disrupt this balance, and the computer can never recover the perfect 10 again.

//BAD

model.num1 = round(someCal(var1, var2));

if(model.num1 == 0)...do something

//Better

model.num1 = someCal(var1, var2);

if(Math.round(model.num1) == 0)...do something


2) When working with a series of these black boxes chained together ( this includes assigning and retrieving from  displayObject.x, y), it's like playing the telephone game, where with each person playing, the number of people in the chain passing messages, the more problems that can happen grow. Using the car metaphor say we have 2 steering wheels for the front Left wheel and one for the front Right wheel. Both can go either all the way left or all the way right. We have 4 possibilities, 3 outcomes:

  • L+L=> Left turn
  • R+R =>Â Right turn
  • L+R or R+L => Straight ahead, but hella wobbly.

Something similar happens at the end of your calculations. You might get left (1) or right (0) or somewhere in the center (0.0001) . The problem with rounding here is that since the output is wobbly it might be 0.0001 or 0.056, or -0.0005 making it impossible to roundToPrecision well. Thus when operating on the output of a calculation, you have to compare against a range of precision, like center is somewhere between both wheels steering L and steering Right. You can think of this also as a Number holding an umbrella, and we are curious if it's under the umbrella or outside of it.
Here is a variant for outside.

  1.  
  2. public function notClose(number1:Number, number2:Number, precision:int = 0):Boolean
  3. {
  4.  
  5. var difference:Number = number1 - number2;
  6. var range:Number = Math.pow(10, -precision);
  7. trace(-range + " " + difference + " " + range);
  8. var res:Boolean = ( difference < -range ) || (range < difference) ;
  9. trace("notClose" + res);
  10. return res;
  11.  
  12. }
  13.  

This has two patterns I like. While var res:Object isn't strictly necessary, it's possible to return the calc directly, putting it in this pattern makes it easy to trace ..even if the code is working perfectly fine, when you might be combing through a bunch of calculations looking for how big of an umbrella to make. The second is
aligning the '<' in the left being lower and right being greater, as they it becomes easier to visualize spatially (for me), like it's on a number axis.
3) For some things like working with displayObjects, in the end it has to be rendered to a fixed number of pixels, and especially with text it's clearer when lines don't lie on half pixels, creating fuzziness. Â Â So while you can calculate in your function down to 0.00000000 etc. in the end it can only be displayed as 0.0, and similarly when expecting 0.0000000 out of your displayObject.x, width etc. you'll find that it's far more limited (lookup twips if your interested)

AS3: Understanding uint, int, Number

Curious if uint and int when typed were actually just Number, ran the following test. All int, uint, Number are typeof "number" and 'is Number' will return true, except when containing a decimal.

This isn't quite what I'd expect, I wouldn't expect a variable declared as Number to type as a int or uint or vice versa. So flash is doing some juggling under the Number covers...

  1.  
  2. var a:int = 1;
  3. var b:uint = 2;
  4. var c:Number = 3;
  5. var d:Number = 4.5;
  6. var args:Array = [ a, b, c, d];
  7.  
  8. function testNumber(a:Object):void{
  9. trace(a + " ------");
  10. trace(" isNumber?" + (a is Number));
  11. trace(" isInt?" + (a is int));
  12. trace(" isUint?" + (a is uint));
  13. trace(" typeof number? " + (typeof(a) == "number"));
  14. }
  15.  
  16. for(var i in args){
  17. testNumber(args[i]);
  18. }
  19.  

OUTPUTS:
1 ------
isNumber?true
isInt?true
isUint?true
typeof number? true
2 ------
isNumber?true
isInt?true
isUint?true
typeof number? true
3 ------
isNumber?true
isInt?true
isUint?true
typeof number? true
4.5 ------
isNumber?true
isInt?false
isUint?false
typeof number? true