/*
  Copyright (c) 2008, Adobe Systems Incorporated
  All rights reserved.

  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions are
  met:

  * Redistributions of source code must retain the above copyright notice,
    this list of conditions and the following disclaimer.

  * Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions and the following disclaimer in the
    documentation and/or other materials provided with the distribution.

  * Neither the name of Adobe Systems Incorporated nor the names of its
    contributors may be used to endorse or promote products derived from
    this software without specific prior written permission.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package com.adobe.serialization.json {
  import ruby.internals.RubyCore;

  public class JSONTokenizer {

    /** The object that will get parsed from the JSON string */
    private var obj:Object;

    /** The JSON string to be parsed */
    private var jsonString:String;

    /** The current parsing location in the JSON string */
    private var loc:int;

    /** The current character in the JSON string during parsing */
    private var ch:String;

    private var rc:RubyCore;

    /**
     * Constructs a new JSONDecoder to parse a JSON string
     * into a native object.
     *
     * @param s The JSON string to be converted
     *		into a native object
     */
    public function JSONTokenizer( s:String, rc:RubyCore ) {
      jsonString = s;
      loc = 0;
      this.rc = rc;

      // prime the pump by getting the first character
      nextChar();
    }

    /**
     * Gets the next token in the input sting and advances
    * the character to the next character after the token
     */
    public function getNextToken():JSONToken {
      var token:JSONToken = new JSONToken();

      // skip any whitespace / comments since the last
      // token was read
      skipIgnored();

      // examine the new character and see what we have...
      switch ( ch ) {

        case '{':
          token.type = JSONTokenType.LEFT_BRACE;
          token.value = '{';
          nextChar();
          break

        case '}':
          token.type = JSONTokenType.RIGHT_BRACE;
          token.value = '}';
          nextChar();
          break

        case '[':
          token.type = JSONTokenType.LEFT_BRACKET;
          token.value = '[';
          nextChar();
          break

        case ']':
          token.type = JSONTokenType.RIGHT_BRACKET;
          token.value = ']';
          nextChar();
          break

        case ',':
          token.type = JSONTokenType.COMMA;
          token.value = ',';
          nextChar();
          break

        case ':':
          token.type = JSONTokenType.COLON;
          token.value = ':';
          nextChar();
          break;

        case 't': // attempt to read true
          var possibleTrue:String = "t" + nextChar() + nextChar() + nextChar();

          if ( possibleTrue == "true" ) {
            token.type = JSONTokenType.TRUE;
            token.value = true;
            nextChar();
          } else {
            parseError( "Expecting 'true' but found " + possibleTrue );
          }

          break;

        case 'f': // attempt to read false
          var possibleFalse:String = "f" + nextChar() + nextChar() + nextChar() + nextChar();

          if ( possibleFalse == "false" ) {
            token.type = JSONTokenType.FALSE;
            token.value = false;
            nextChar();
          } else {
            parseError( "Expecting 'false' but found " + possibleFalse );
          }

          break;

        case 'n': // attempt to read null

          var possibleNull:String = "n" + nextChar() + nextChar() + nextChar();

          if ( possibleNull == "null" ) {
            token.type = JSONTokenType.NULL;
            token.value = rc.Qnil;
            nextChar();
          } else {
            parseError( "Expecting 'null' but found " + possibleNull );
          }

          break;

        case '"': // the start of a string
          token = readString();
          break;

        default:
          // see if we can read a number
          if ( isDigit( ch ) || ch == '-' ) {
            token = readNumber();
          } else if ( ch == '' ) {
            // check for reading past the end of the string
            return null;
          } else {
            // not sure what was in the input string - it's not
            // anything we expected
            parseError( "Unexpected " + ch + " encountered" );
          }
      }

      return token;
    }

    /**
     * Attempts to read a string from the input string.  Places
     * the character location at the first character after the
     * string.  It is assumed that ch is " before this method is called.
     *
     * @return the JSONToken with the string value if a string could
     *		be read.  Throws an error otherwise.
     */
    private function readString():JSONToken {
      // the token for the string we'll try to read
      var token:JSONToken = new JSONToken();
      token.type = JSONTokenType.STRING;

      // the string to store the string we'll try to read
      var string:String = "";

      // advance past the first "
      nextChar();

      while ( ch != '"' && ch != '' ) {

        // unescape the escape sequences in the string
        if ( ch == '\\' ) {

          // get the next character so we know what
          // to unescape
          nextChar();

          switch ( ch ) {

            case '"': // quotation mark
              string += '"';
              break;

            case '/':	// solidus
              string += "/";
              break;

            case '\\':	// reverse solidus
              string += '\\';
              break;

            case 'b':	// bell
              string += '\b';
              break;

            case 'f':	// form feed
              string += '\f';
              break;

            case 'n':	// newline
              string += '\n';
              break;

            case 'r':	// carriage return
              string += '\r';
              break;

            case 't':	// horizontal tab
              string += '\t'
              break;

            case 'u':
              // convert a unicode escape sequence
              // to it's character value - expecting
              // 4 hex digits

              // save the characters as a string we'll convert to an int
              var hexValue:String = "";

              // try to find 4 hex characters
              for ( var i:int = 0; i < 4; i++ ) {
                // get the next character and determine
                // if it's a valid hex digit or not
                if ( !isHexDigit( nextChar() ) ) {
                  parseError( " Excepted a hex digit, but found: " + ch );
                }
                // valid, add it to the value
                hexValue += ch;
              }

              // convert hexValue to an integer, and use that
              // integrer value to create a character to add
              // to our string.
              string += String.fromCharCode( parseInt( hexValue, 16 ) );

              break;

            default:
              // couldn't unescape the sequence, so just
              // pass it through
              string += '\\' + ch;

          }

        } else {
          // didn't have to unescape, so add the character to the string
          string += ch;

        }

        // move to the next character
        nextChar();

      }

      // we read past the end of the string without closing it, which
      // is a parse error
      if ( ch == '' ) {
        parseError( "Unterminated string literal" );
      }

      // move past the closing " in the input string
      nextChar();

      // attach to the string to the token so we can return it
      token.value = string;

      return token;
    }

    /**
     * Attempts to read a number from the input string.  Places
     * the character location at the first character after the
     * number.
     *
     * @return The JSONToken with the number value if a number could
     * 		be read.  Throws an error otherwise.
     */
    private function readNumber():JSONToken {
      // the token for the number we'll try to read
      var token:JSONToken = new JSONToken();
      token.type = JSONTokenType.NUMBER;

      // the string to accumulate the number characters
      // into that we'll convert to a number at the end
      var input:String = "";

      // check for a negative number
      if ( ch == '-' ) {
        input += '-';
        nextChar();
      }

      // the number must start with a digit
      if ( !isDigit( ch ) )
      {
        parseError( "Expecting a digit" );
      }

      // 0 can only be the first digit if it
      // is followed by a decimal point
      if ( ch == '0' )
      {
        input += ch;
        nextChar();

        // make sure no other digits come after 0
        if ( isDigit( ch ) )
        {
          parseError( "A digit cannot immediately follow 0" );
        }
// Commented out - this should only be available when "strict" is false
//				// unless we have 0x which starts a hex number\
//				else if ( ch == 'x' )
//				{
//					// include the x in the input
//					input += ch;
//					nextChar();
//
//					// need at least one hex digit after 0x to
//					// be valid
//					if ( isHexDigit( ch ) )
//					{
//						input += ch;
//						nextChar();
//					}
//					else
//					{
//						parseError( "Number in hex format require at least one hex digit after \"0x\"" );
//					}
//
//					// consume all of the hex values
//					while ( isHexDigit( ch ) )
//					{
//						input += ch;
//						nextChar();
//					}
//				}
      }
      else
      {
        // read numbers while we can
        while ( isDigit( ch ) ) {
          input += ch;
          nextChar();
        }
      }

      // check for a decimal value
      if ( ch == '.' ) {
        input += '.';
        nextChar();

        // after the decimal there has to be a digit
        if ( !isDigit( ch ) )
        {
          parseError( "Expecting a digit" );
        }

        // read more numbers to get the decimal value
        while ( isDigit( ch ) ) {
          input += ch;
          nextChar();
        }
      }

      // check for scientific notation
      if ( ch == 'e' || ch == 'E' )
      {
        input += "e"
        nextChar();
        // check for sign
        if ( ch == '+' || ch == '-' )
        {
          input += ch;
          nextChar();
        }

        // require at least one number for the exponent
        // in this case
        if ( !isDigit( ch ) )
        {
          parseError( "Scientific notation number needs exponent value" );
        }

        // read in the exponent
        while ( isDigit( ch ) )
        {
          input += ch;
          nextChar();
        }
      }

      // convert the string to a number value
      var num:Number = Number( input );

      if ( isFinite( num ) && !isNaN( num ) ) {
        token.value = num;
        return token;
      } else {
        parseError( "Number " + num + " is not valid!" );
      }
            return null;
    }

    /**
     * Reads the next character in the input
     * string and advances the character location.
     *
     * @return The next character in the input string, or
     *		null if we've read past the end.
     */
    private function nextChar():String {
      return ch = jsonString.charAt( loc++ );
    }

    /**
     * Advances the character location past any
     * sort of white space and comments
     */
    private function skipIgnored():void
    {
      var originalLoc:int;

      // keep trying to skip whitespace and comments as long
      // as we keep advancing past the original location
      do
      {
        originalLoc = loc;
        skipWhite();
        skipComments();
      }
      while ( originalLoc != loc );
    }

    /**
     * Skips comments in the input string, either
     * single-line or multi-line.  Advances the character
     * to the first position after the end of the comment.
     */
    private function skipComments():void {
      if ( ch == '/' ) {
        // Advance past the first / to find out what type of comment
        nextChar();
        switch ( ch ) {
          case '/': // single-line comment, read through end of line

            // Loop over the characters until we find
            // a newline or until there's no more characters left
            do {
              nextChar();
            } while ( ch != '\n' && ch != '' )

            // move past the \n
            nextChar();

            break;

          case '*': // multi-line comment, read until closing */

            // move past the opening *
            nextChar();

            // try to find a trailing */
            while ( true ) {
              if ( ch == '*' ) {
                // check to see if we have a closing /
                nextChar();
                if ( ch == '/') {
                  // move past the end of the closing */
                  nextChar();
                  break;
                }
              } else {
                // move along, looking if the next character is a *
                nextChar();
              }

              // when we're here we've read past the end of
              // the string without finding a closing */, so error
              if ( ch == '' ) {
                parseError( "Multi-line comment not closed" );
              }
            }

            break;

          // Can't match a comment after a /, so it's a parsing error
          default:
            parseError( "Unexpected " + ch + " encountered (expecting '/' or '*' )" );
        }
      }

    }

    /**
     * Skip any whitespace in the input string and advances
     * the character to the first character after any possible
     * whitespace.
     */
    private function skipWhite():void {

      // As long as there are spaces in the input
      // stream, advance the current location pointer
      // past them
      while ( isWhiteSpace( ch ) ) {
        nextChar();
      }

    }

    /**
     * Determines if a character is whitespace or not.
     *
     * @return True if the character passed in is a whitespace
     *	character
     */
    private function isWhiteSpace( ch:String ):Boolean {
      return ( ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' );
    }

    /**
     * Determines if a character is a digit [0-9].
     *
     * @return True if the character passed in is a digit
     */
    private function isDigit( ch:String ):Boolean {
      return ( ch >= '0' && ch <= '9' );
    }

    /**
     * Determines if a character is a digit [0-9].
     *
     * @return True if the character passed in is a digit
     */
    private function isHexDigit( ch:String ):Boolean {
      // get the uppercase value of ch so we only have
      // to compare the value between 'A' and 'F'
      var uc:String = ch.toUpperCase();

      // a hex digit is a digit of A-F, inclusive ( using
      // our uppercase constraint )
      return ( isDigit( ch ) || ( uc >= 'A' && uc <= 'F' ) );
    }

    /**
     * Raises a parsing error with a specified message, tacking
     * on the error location and the original string.
     *
     * @param message The message indicating why the error occurred
     */
    public function parseError( message:String ):void {
      throw new JSONParseError( message, loc, jsonString );
    }
  }

}

/*
  Copyright (c) 2008, Adobe Systems Incorporated
  All rights reserved.

  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions are
  met:

  * Redistributions of source code must retain the above copyright notice,
    this list of conditions and the following disclaimer.

  * Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions and the following disclaimer in the
    documentation and/or other materials provided with the distribution.

  * Neither the name of Adobe Systems Incorporated nor the names of its
    contributors may be used to endorse or promote products derived from
    this software without specific prior written permission.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package com.adobe.serialization.json {
  import ruby.internals.RubyCore;

  public class JSONTokenizer {

    /** The object that will get parsed from the JSON string */
    private var obj:Object;

    /** The JSON string to be parsed */
    private var jsonString:String;

    /** The current parsing location in the JSON string */
    private var loc:int;

    /** The current character in the JSON string during parsing */
    private var ch:String;

    private var rc:RubyCore;

    /**
     * Constructs a new JSONDecoder to parse a JSON string
     * into a native object.
     *
     * @param s The JSON string to be converted
     *		into a native object
     */
    public function JSONTokenizer( s:String, rc:RubyCore ) {
      jsonString = s;
      loc = 0;
      this.rc = rc;

      // prime the pump by getting the first character
      nextChar();
    }

    /**
     * Gets the next token in the input sting and advances
    * the character to the next character after the token
     */
    public function getNextToken():JSONToken {
      var token:JSONToken = new JSONToken();

      // skip any whitespace / comments since the last
      // token was read
      skipIgnored();

      // examine the new character and see what we have...
      switch ( ch ) {

        case '{':
          token.type = JSONTokenType.LEFT_BRACE;
          token.value = '{';
          nextChar();
          break

        case '}':
          token.type = JSONTokenType.RIGHT_BRACE;
          token.value = '}';
          nextChar();
          break

        case '[':
          token.type = JSONTokenType.LEFT_BRACKET;
          token.value = '[';
          nextChar();
          break

        case ']':
          token.type = JSONTokenType.RIGHT_BRACKET;
          token.value = ']';
          nextChar();
          break

        case ',':
          token.type = JSONTokenType.COMMA;
          token.value = ',';
          nextChar();
          break

        case ':':
          token.type = JSONTokenType.COLON;
          token.value = ':';
          nextChar();
          break;

        case 't': // attempt to read true
          var possibleTrue:String = "t" + nextChar() + nextChar() + nextChar();

          if ( possibleTrue == "true" ) {
            token.type = JSONTokenType.TRUE;
            token.value = rc.Qtrue;
            nextChar();
          } else {
            parseError( "Expecting 'true' but found " + possibleTrue );
          }

          break;

        case 'f': // attempt to read false
          var possibleFalse:String = "f" + nextChar() + nextChar() + nextChar() + nextChar();

          if ( possibleFalse == "false" ) {
            token.type = JSONTokenType.FALSE;
            token.value = rc.Qfalse;
            nextChar();
          } else {
            parseError( "Expecting 'false' but found " + possibleFalse );
          }

          break;

        case 'n': // attempt to read null

          var possibleNull:String = "n" + nextChar() + nextChar() + nextChar();

          if ( possibleNull == "null" ) {
            token.type = JSONTokenType.NULL;
            token.value = rc.Qnil;
            nextChar();
          } else {
            parseError( "Expecting 'null' but found " + possibleNull );
          }

          break;

        case '"': // the start of a string
          token = readString();
          break;

        default:
          // see if we can read a number
          if ( isDigit( ch ) || ch == '-' ) {
            token = readNumber();
          } else if ( ch == '' ) {
            // check for reading past the end of the string
            return null;
          } else {
            // not sure what was in the input string - it's not
            // anything we expected
            parseError( "Unexpected " + ch + " encountered" );
          }
      }

      return token;
    }

    /**
     * Attempts to read a string from the input string.  Places
     * the character location at the first character after the
     * string.  It is assumed that ch is " before this method is called.
     *
     * @return the JSONToken with the string value if a string could
     *		be read.  Throws an error otherwise.
     */
    private function readString():JSONToken {
      // the token for the string we'll try to read
      var token:JSONToken = new JSONToken();
      token.type = JSONTokenType.STRING;

      // the string to store the string we'll try to read
      var string:String = "";

      // advance past the first "
      nextChar();

      while ( ch != '"' && ch != '' ) {

        // unescape the escape sequences in the string
        if ( ch == '\\' ) {

          // get the next character so we know what
          // to unescape
          nextChar();

          switch ( ch ) {

            case '"': // quotation mark
              string += '"';
              break;

            case '/':	// solidus
              string += "/";
              break;

            case '\\':	// reverse solidus
              string += '\\';
              break;

            case 'b':	// bell
              string += '\b';
              break;

            case 'f':	// form feed
              string += '\f';
              break;

            case 'n':	// newline
              string += '\n';
              break;

            case 'r':	// carriage return
              string += '\r';
              break;

            case 't':	// horizontal tab
              string += '\t'
              break;

            case 'u':
              // convert a unicode escape sequence
              // to it's character value - expecting
              // 4 hex digits

              // save the characters as a string we'll convert to an int
              var hexValue:String = "";

              // try to find 4 hex characters
              for ( var i:int = 0; i < 4; i++ ) {
                // get the next character and determine
                // if it's a valid hex digit or not
                if ( !isHexDigit( nextChar() ) ) {
                  parseError( " Excepted a hex digit, but found: " + ch );
                }
                // valid, add it to the value
                hexValue += ch;
              }

              // convert hexValue to an integer, and use that
              // integrer value to create a character to add
              // to our string.
              string += String.fromCharCode( parseInt( hexValue, 16 ) );

              break;

            default:
              // couldn't unescape the sequence, so just
              // pass it through
              string += '\\' + ch;

          }

        } else {
          // didn't have to unescape, so add the character to the string
          string += ch;

        }

        // move to the next character
        nextChar();

      }

      // we read past the end of the string without closing it, which
      // is a parse error
      if ( ch == '' ) {
        parseError( "Unterminated string literal" );
      }

      // move past the closing " in the input string
      nextChar();

      // attach to the string to the token so we can return it
      token.value = string;

      return token;
    }

    /**
     * Attempts to read a number from the input string.  Places
     * the character location at the first character after the
     * number.
     *
     * @return The JSONToken with the number value if a number could
     * 		be read.  Throws an error otherwise.
     */
    private function readNumber():JSONToken {
      // the token for the number we'll try to read
      var token:JSONToken = new JSONToken();
      token.type = JSONTokenType.NUMBER;

      // the string to accumulate the number characters
      // into that we'll convert to a number at the end
      var input:String = "";

      // check for a negative number
      if ( ch == '-' ) {
        input += '-';
        nextChar();
      }

      // the number must start with a digit
      if ( !isDigit( ch ) )
      {
        parseError( "Expecting a digit" );
      }

      // 0 can only be the first digit if it
      // is followed by a decimal point
      if ( ch == '0' )
      {
        input += ch;
        nextChar();

        // make sure no other digits come after 0
        if ( isDigit( ch ) )
        {
          parseError( "A digit cannot immediately follow 0" );
        }
// Commented out - this should only be available when "strict" is false
//				// unless we have 0x which starts a hex number\
//				else if ( ch == 'x' )
//				{
//					// include the x in the input
//					input += ch;
//					nextChar();
//
//					// need at least one hex digit after 0x to
//					// be valid
//					if ( isHexDigit( ch ) )
//					{
//						input += ch;
//						nextChar();
//					}
//					else
//					{
//						parseError( "Number in hex format require at least one hex digit after \"0x\"" );
//					}
//
//					// consume all of the hex values
//					while ( isHexDigit( ch ) )
//					{
//						input += ch;
//						nextChar();
//					}
//				}
      }
      else
      {
        // read numbers while we can
        while ( isDigit( ch ) ) {
          input += ch;
          nextChar();
        }
      }

      // check for a decimal value
      if ( ch == '.' ) {
        input += '.';
        nextChar();

        // after the decimal there has to be a digit
        if ( !isDigit( ch ) )
        {
          parseError( "Expecting a digit" );
        }

        // read more numbers to get the decimal value
        while ( isDigit( ch ) ) {
          input += ch;
          nextChar();
        }
      }

      // check for scientific notation
      if ( ch == 'e' || ch == 'E' )
      {
        input += "e"
        nextChar();
        // check for sign
        if ( ch == '+' || ch == '-' )
        {
          input += ch;
          nextChar();
        }

        // require at least one number for the exponent
        // in this case
        if ( !isDigit( ch ) )
        {
          parseError( "Scientific notation number needs exponent value" );
        }

        // read in the exponent
        while ( isDigit( ch ) )
        {
          input += ch;
          nextChar();
        }
      }

      // convert the string to a number value
      var num:Number = Number( input );

      if ( isFinite( num ) && !isNaN( num ) ) {
        token.value = num;
        return token;
      } else {
        parseError( "Number " + num + " is not valid!" );
      }
            return null;
    }

    /**
     * Reads the next character in the input
     * string and advances the character location.
     *
     * @return The next character in the input string, or
     *		null if we've read past the end.
     */
    private function nextChar():String {
      return ch = jsonString.charAt( loc++ );
    }

    /**
     * Advances the character location past any
     * sort of white space and comments
     */
    private function skipIgnored():void
    {
      var originalLoc:int;

      // keep trying to skip whitespace and comments as long
      // as we keep advancing past the original location
      do
      {
        originalLoc = loc;
        skipWhite();
        skipComments();
      }
      while ( originalLoc != loc );
    }

    /**
     * Skips comments in the input string, either
     * single-line or multi-line.  Advances the character
     * to the first position after the end of the comment.
     */
    private function skipComments():void {
      if ( ch == '/' ) {
        // Advance past the first / to find out what type of comment
        nextChar();
        switch ( ch ) {
          case '/': // single-line comment, read through end of line

            // Loop over the characters until we find
            // a newline or until there's no more characters left
            do {
              nextChar();
            } while ( ch != '\n' && ch != '' )

            // move past the \n
            nextChar();

            break;

          case '*': // multi-line comment, read until closing */

            // move past the opening *
            nextChar();

            // try to find a trailing */
            while ( true ) {
              if ( ch == '*' ) {
                // check to see if we have a closing /
                nextChar();
                if ( ch == '/') {
                  // move past the end of the closing */
                  nextChar();
                  break;
                }
              } else {
                // move along, looking if the next character is a *
                nextChar();
              }

              // when we're here we've read past the end of
              // the string without finding a closing */, so error
              if ( ch == '' ) {
                parseError( "Multi-line comment not closed" );
              }
            }

            break;

          // Can't match a comment after a /, so it's a parsing error
          default:
            parseError( "Unexpected " + ch + " encountered (expecting '/' or '*' )" );
        }
      }

    }

    /**
     * Skip any whitespace in the input string and advances
     * the character to the first character after any possible
     * whitespace.
     */
    private function skipWhite():void {

      // As long as there are spaces in the input
      // stream, advance the current location pointer
      // past them
      while ( isWhiteSpace( ch ) ) {
        nextChar();
      }

    }

    /**
     * Determines if a character is whitespace or not.
     *
     * @return True if the character passed in is a whitespace
     *	character
     */
    private function isWhiteSpace( ch:String ):Boolean {
      return ( ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' );
    }

    /**
     * Determines if a character is a digit [0-9].
     *
     * @return True if the character passed in is a digit
     */
    private function isDigit( ch:String ):Boolean {
      return ( ch >= '0' && ch <= '9' );
    }

    /**
     * Determines if a character is a digit [0-9].
     *
     * @return True if the character passed in is a digit
     */
    private function isHexDigit( ch:String ):Boolean {
      // get the uppercase value of ch so we only have
      // to compare the value between 'A' and 'F'
      var uc:String = ch.toUpperCase();

      // a hex digit is a digit of A-F, inclusive ( using
      // our uppercase constraint )
      return ( isDigit( ch ) || ( uc >= 'A' && uc <= 'F' ) );
    }

    /**
     * Raises a parsing error with a specified message, tacking
     * on the error location and the original string.
     *
     * @param message The message indicating why the error occurred
     */
    public function parseError( message:String ):void {
      throw new JSONParseError( message, loc, jsonString );
    }
  }

}

Add Qfalse and Qtrue support to tokenizer.


package aerys.minko.render.material.phong
{
	public final class PhongProperties
	{
		public static const RECEPTION_MASK				: String = 'lightReceptionMask';

		public static const LIGHT_MAP					: String = 'lightMap';
		public static const SPECULAR_MAP				: String = 'specularMap';
		public static const HEIGHT_MAP					: String = 'heightMap';

		public static const LIGHTMAP_MULTIPLIER			: String = 'lightMapMultiplier';
		public static const AMBIENT_MULTIPLIER			: String = 'ambientMultiplier';
		public static const DIFFUSE_MULTIPLIER			: String = 'aiffuseMultiplier';
		public static const SPECULAR					: String = 'specular';
		public static const SHININESS					: String = 'shininess';

		public static const NORMAL_MAPPING_TYPE			: String = 'normalMappingType';
		public static const NORMAL_MAP					: String = 'normalMap';
		public static const NORMAL_MAP_FILTERING		: String = 'normalMapFiltering';
		public static const NORMAL_MAP_MIPMAPPING		: String = 'normalMapMipMapping';
        public static const NORMAL_MAP_FORMAT   		: String = 'normalMapFormat';

		public static const PARALLAX_MAPPING_NBSTEPS	: String = 'parallaxMappingNbSteps';
		public static const PARALLAX_MAPPING_BUMP_SCALE	: String = 'parallaxMappingBumpScale';

		public static const SHADOW_BIAS					: String = 'shadowBias';
		public static const CAST_SHADOWS				: String = 'castShadows';
		public static const RECEIVE_SHADOWS				: String = 'receiveShadows';
	}
}

package aerys.minko.render.material.phong
{
	public final class PhongProperties
	{
		public static const RECEPTION_MASK				: String = 'lightReceptionMask';

		public static const LIGHT_MAP					: String = 'lightMap';
		public static const SPECULAR_MAP				: String = 'specularMap';
		public static const HEIGHT_MAP					: String = 'heightMap';

		public static const LIGHTMAP_MULTIPLIER			: String = 'lightMapMultiplier';
		public static const AMBIENT_MULTIPLIER			: String = 'ambientMultiplier';
		public static const DIFFUSE_MULTIPLIER			: String = 'diffuseMultiplier';
		public static const SPECULAR					: String = 'specular';
		public static const SHININESS					: String = 'shininess';

		public static const NORMAL_MAPPING_TYPE			: String = 'normalMappingType';
		public static const NORMAL_MAP					: String = 'normalMap';
		public static const NORMAL_MAP_FILTERING		: String = 'normalMapFiltering';
		public static const NORMAL_MAP_MIPMAPPING		: String = 'normalMapMipMapping';
        public static const NORMAL_MAP_FORMAT   		: String = 'normalMapFormat';

		public static const PARALLAX_MAPPING_NBSTEPS	: String = 'parallaxMappingNbSteps';
		public static const PARALLAX_MAPPING_BUMP_SCALE	: String = 'parallaxMappingBumpScale';

		public static const SHADOW_BIAS					: String = 'shadowBias';
		public static const CAST_SHADOWS				: String = 'castShadows';
		public static const RECEIVE_SHADOWS				: String = 'receiveShadows';
	}
}

fix typo

fix typo


package dolly {
import dolly.core.dolly_internal;
import dolly.core.metadata.MetadataName;

import org.as3commons.reflect.Accessor;
import org.as3commons.reflect.Field;
import org.as3commons.reflect.IMetadataContainer;
import org.as3commons.reflect.Type;
import org.as3commons.reflect.Variable;

use namespace dolly_internal;

public class Copier {

	private static function isVariableCopyable(variable:Variable, skipMetadataChecking:Boolean = true):Boolean {
		return !variable.isStatic && (skipMetadataChecking || variable.hasMetadata(MetadataName.COPYABLE));
	}

	private static function isAccessorCopyable(accessor:Accessor, skipMetadataChecking:Boolean = true):Boolean {
		return !accessor.isStatic && accessor.isReadable() && accessor.isWriteable() &&
				(skipMetadataChecking || accessor.hasMetadata(MetadataName.COPYABLE));
	}

	dolly_internal static function findCopyableFieldsForType(type:Type):Vector.<Field> {
		const result:Vector.<Field> = new Vector.<Field>();

		var variable:Variable;
		var accessor:Accessor;

		const isTypeCloneable:Boolean = type.hasMetadata(MetadataName.COPYABLE);
		if (isTypeCloneable) {
			for each(variable in type.variables) {
				if (isVariableCopyable(variable)) {
					result.push(variable);
				}
			}
			for each(accessor in type.accessors) {
				if (isAccessorCopyable(accessor)) {
					result.push(accessor);
				}
			}
		} else {
			const metadataContainers:Array = type.getMetadataContainers(MetadataName.COPYABLE);
			for each(var metadataContainer:IMetadataContainer in metadataContainers) {
				if (metadataContainer is Variable) {
					variable = metadataContainer as Variable;
					if (isVariableCopyable(variable, false)) {
						result.push(variable);
					}
				} else if (metadataContainer is Accessor) {
					accessor = metadataContainer as Accessor;
					if (isAccessorCopyable(accessor, false)) {
						result.push(accessor);
					}
				}
			}
		}

		return result;
	}

	public static function copy(source:*):* {
		const type:Type = Type.forInstance(source);
		const copy:* = new (type.clazz)();

		const fieldsToCopy:Vector.<Field> = findCopyableFieldsForType(type);
		var name:String;
		for each(var field:Field in fieldsToCopy) {
			name = field.name;
			copy[name] = source[name];
		}

		return copy;
	}
}
}

package dolly {

import dolly.core.dolly_internal;
import dolly.core.metadata.MetadataName;

import org.as3commons.reflect.Accessor;
import org.as3commons.reflect.Field;
import org.as3commons.reflect.IMetadataContainer;
import org.as3commons.reflect.Type;
import org.as3commons.reflect.Variable;

use namespace dolly_internal;

public class Copier {

	private static function isAccessorCopyable(accessor:Accessor, skipMetadataChecking:Boolean = true):Boolean {
		return !accessor.isStatic && accessor.isReadable() && accessor.isWriteable() &&
				(skipMetadataChecking || accessor.hasMetadata(MetadataName.COPYABLE));
	}

	dolly_internal static function findCopyableFieldsForType(type:Type):Vector.<Field> {
		const result:Vector.<Field> = new Vector.<Field>();

		var variable:Variable;
		var accessor:Accessor;

		const isTypeCloneable:Boolean = type.hasMetadata(MetadataName.COPYABLE);
		if (isTypeCloneable) {
			for each(variable in type.variables) {
				if (!variable.isStatic) {
					result.push(variable);
				}
			}
			for each(accessor in type.accessors) {
				if (isAccessorCopyable(accessor)) {
					result.push(accessor);
				}
			}
		} else {
			const metadataContainers:Array = type.getMetadataContainers(MetadataName.COPYABLE);
			for each(var metadataContainer:IMetadataContainer in metadataContainers) {
				if (metadataContainer is Variable) {
					variable = metadataContainer as Variable;
					if (!variable.isStatic && variable.hasMetadata(MetadataName.COPYABLE)) {
						result.push(variable);
					}
				} else if (metadataContainer is Accessor) {
					accessor = metadataContainer as Accessor;
					if (isAccessorCopyable(accessor, false)) {
						result.push(accessor);
					}
				}
			}
		}

		return result;
	}

	public static function copy(source:*):* {
		const type:Type = Type.forInstance(source);
		const copy:* = new (type.clazz)();

		const fieldsToCopy:Vector.<Field> = findCopyableFieldsForType(type);
		var name:String;
		for each(var field:Field in fieldsToCopy) {
			name = field.name;
			copy[name] = source[name];
		}

		return copy;
	}
}
}

Remove private static method Copier.isVariableCopyable().


/*
 * Copyright (c) 2012 the original author or authors
 *
 * Permission is hereby granted to use, modify, and distribute this file
 * in accordance with the terms of the license agreement accompanying it.
 */

package org.swiftsuspenders.typedescriptions
{
	import avmplus.getQualifiedClassName;

	import flash.utils.Dictionary;

	import org.swiftsuspenders.Injector;
	import org.swiftsuspenders.errors.InjectorMissingMappingError;
	import org.swiftsuspenders.dependencyproviders.DependencyProvider;
	import org.swiftsuspenders.utils.SsInternal;

	public class MethodInjectionPoint extends InjectionPoint
	{
		//----------------------       Private / Protected Properties       ----------------------//
		private static const _parameterValues : Array = [];

		protected var _parameterMappingIDs : Array;
		protected var _requiredParameters : int;

		private var _isOptional : Boolean;
		private var _methodName : String;

		//----------------------               Public Methods               ----------------------//
		public function MethodInjectionPoint(methodName : String, parameters : Array,
			requiredParameters : uint, isOptional : Boolean, injectParameters : Dictionary)
		{
			_methodName = methodName;
			_parameterMappingIDs = parameters;
			_requiredParameters = requiredParameters;
			_isOptional = isOptional;
			this.injectParameters = injectParameters;
		}

		override public function applyInjection(
				target : Object, targetType : Class, injector : Injector) : void
		{
			var p : Array = gatherParameterValues(target, targetType, injector);
			if (p.length >= _requiredParameters)
			{
				(target[_methodName] as Function).apply(target, p);
			}

			p.length = 0;
		}

		//----------------------         Private / Protected Methods        ----------------------//
		protected function gatherParameterValues(
				target : Object, targetType : Class, injector : Injector) : Array
		{
			var length : int = _parameterMappingIDs.length;
			var parameters : Array = _parameterValues;
			parameters.length = length;
			for (var i : int = 0; i < length; i++)
			{
				var parameterMappingId : String = _parameterMappingIDs[i];
				var provider : DependencyProvider =
					injector.SsInternal::getProvider(parameterMappingId);
				if (!provider)
				{
					if (i >= _requiredParameters || _isOptional)
					{
						break;
					}
					throw(new InjectorMissingMappingError(
						'Injector is missing a mapping to handle injection into target "' +
						target + '" of type "' + getQualifiedClassName(targetType) + '". \
						Target dependency: ' + parameterMappingId +
						', method: ' + _methodName + ', parameter: ' + (i + 1)
					));
				}

				parameters[i] = provider.apply(targetType, injector, injectParameters);
			}
			return parameters;
		}
	}
}

/*
 * Copyright (c) 2012 the original author or authors
 *
 * Permission is hereby granted to use, modify, and distribute this file
 * in accordance with the terms of the license agreement accompanying it.
 */

package org.swiftsuspenders.typedescriptions
{
	import avmplus.getQualifiedClassName;

	import flash.utils.Dictionary;

	import org.swiftsuspenders.Injector;
	import org.swiftsuspenders.errors.InjectorMissingMappingError;
	import org.swiftsuspenders.dependencyproviders.DependencyProvider;
	import org.swiftsuspenders.utils.SsInternal;

	public class MethodInjectionPoint extends InjectionPoint
	{
		//----------------------       Private / Protected Properties       ----------------------//
		protected var _parameterMappingIDs : Array;
		protected var _requiredParameters : int;

		private var _isOptional : Boolean;
		private var _methodName : String;

		//----------------------               Public Methods               ----------------------//
		public function MethodInjectionPoint(methodName : String, parameters : Array,
			requiredParameters : uint, isOptional : Boolean, injectParameters : Dictionary)
		{
			_methodName = methodName;
			_parameterMappingIDs = parameters;
			_requiredParameters = requiredParameters;
			_isOptional = isOptional;
			this.injectParameters = injectParameters;
		}

		override public function applyInjection(
				target : Object, targetType : Class, injector : Injector) : void
		{
			var p : Array = gatherParameterValues(target, targetType, injector);
			if (p.length >= _requiredParameters)
			{
				(target[_methodName] as Function).apply(target, p);
			}

			p.length = 0;
		}

		//----------------------         Private / Protected Methods        ----------------------//
		protected function gatherParameterValues(
				target : Object, targetType : Class, injector : Injector) : Array
		{
			var length : int = _parameterMappingIDs.length;
			var parameters : Array = [];
			parameters.length = length;
			for (var i : int = 0; i < length; i++)
			{
				var parameterMappingId : String = _parameterMappingIDs[i];
				var provider : DependencyProvider =
					injector.SsInternal::getProvider(parameterMappingId);
				if (!provider)
				{
					if (i >= _requiredParameters || _isOptional)
					{
						break;
					}
					throw(new InjectorMissingMappingError(
						'Injector is missing a mapping to handle injection into target "' +
						target + '" of type "' + getQualifiedClassName(targetType) + '". \
						Target dependency: ' + parameterMappingId +
						', method: ' + _methodName + ', parameter: ' + (i + 1)
					));
				}

				parameters[i] = provider.apply(targetType, injector, injectParameters);
			}
			return parameters;
		}
	}
}

Fix for a bug in MethodInjectionPoint

Fix for a bug in MethodInjectionPoint

The global Array _parameterValues was incorrectly shared between
reentrant calls to MethodInjectionPoint.applyInjection, thus losing
some dependencies for injection.


/**
 * Copyright (c) 2010 Digital Primates
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 *
 * @author     Michael Labriola
 * @version
 **/
package flex.lang.reflect.builders {
	import flash.utils.Dictionary;

	import flex.lang.reflect.Method;
	import flex.lang.reflect.cache.ClassDataCache;
	import flex.lang.reflect.utils.MetadataTools;

	/**
	 * Object responsible for building method objects
	 *
	 * @author mlabriola
	 *
	 */
	public class MethodBuilder {
		/**
		 * @private
		 */
		private var classXML:XML;
		/**
		 * @private
		 */
		private var inheritance:Array;
		/**
		 * @private
		 */
		private var methodMap:Object;

		/**
		 * @private
		 */
		private function buildMethod( methodData:XML, isStatic:Boolean ):Method {
			return new Method( methodData, isStatic );
		}

		/**
		 * @private
		 */
		private function buildMethods( parentBlock:XML, isStatic:Boolean = false ):Array {
			var methods:Array = new Array();
			var methodList:XMLList = new XMLList();

			if ( parentBlock ) {
				methodList = MetadataTools.getMethodsList( parentBlock );
			}

			for ( var i:int=0; i<methodList.length(); i++ ) {
				methods.push( buildMethod( methodList[ i ], isStatic ) );
			}

			return methods;
		}

		/**
		 * @private
		 */
		private function addMetaDataToMethod( subClassMethod:Method, superClassMethod:Method ):void {
			var subMetaDataArray:Array = subClassMethod.metadata;
			var superMetaDataArray:Array = superClassMethod.metadata;

			for ( var i:int=0; i<superMetaDataArray.length; i++ ) {
				subMetaDataArray.push( superMetaDataArray[ i ] );
			}
		}

		/**
		 * @private
		 */
		private function addMetaDataPerSuperClass( methodMap:Object, superXML:XML ):void {
			var methods:Array;
			var superMethod:Method;
			var instanceMethod:Method;

			if ( superXML.factory ) {
				methods = buildMethods( superXML.factory[ 0 ], false );

				for ( var i:int=0; i<methods.length; i++ ) {
					superMethod = methods[ i ] as Method;
					instanceMethod = methodMap[ superMethod.name ];

					if ( instanceMethod ) {
						//This one exists in the subclass, meaning it was overriden
						//Time to apply any metadata to the subclass method
						addMetaDataToMethod( instanceMethod, superMethod );
					}
				}
			}
		}

		/**
		 * Builds all Methods in this class, considering methods defined or overriden in this class and through inheritance
		 * @return An array of Method instances
		 *
		 */
		public function buildAllMethods():Array {
			var methods:Array = new Array();
			var method:Method;

			if ( classXML.factory ) {
				methods = methods.concat( buildMethods( classXML.factory[ 0 ], false ) );
			}

			methods = methods.concat( buildMethods( classXML, true ) );

			//If this object inherits from a class other than just Object
			if ( inheritance && ( inheritance.length > 1 ) ) {

				//Record all of these methods in an object so that we can check the inheritance hierarchy
				for ( var i:int=0; i<methods.length; i++ ) {
					method = methods[ i ] as Method;
					methodMap[ method.name ] = method;
				}

				for ( var j:int=0; j<inheritance.length; j++ ) {
					addMetaDataPerSuperClass( methodMap, ClassDataCache.describeType( inheritance[ j ] ) );
				}
			}

			return methods;
		}

		/**
		 * Resposible for building method instances from XML descriptions
		 * @param classXML
		 * @param inheritance
		 *
		 */
		public function MethodBuilder( classXML:XML, inheritance:Array ) {
			this.classXML = classXML;
			this.inheritance = inheritance;

			methodMap = new Object();
		}
	}
}

/**
 * Copyright (c) 2010 Digital Primates
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 *
 * @author     Michael Labriola
 * @version
 **/
package flex.lang.reflect.builders {
	import flash.utils.Dictionary;

	import flex.lang.reflect.Method;
	import flex.lang.reflect.cache.ClassDataCache;
	import flex.lang.reflect.utils.MetadataTools;

	/**
	 * Object responsible for building method objects
	 *
	 * @author mlabriola
	 *
	 */
	public class MethodBuilder {
		/**
		 * @private
		 */
		private var classXML:XML;
		/**
		 * @private
		 */
		private var inheritance:Array;
		/**
		 * @private
		 */
		private var methodMap:Object;

		/**
		 * @private
		 */
		private function buildMethod( methodData:XML, isStatic:Boolean ):Method {
			return new Method( methodData, isStatic );
		}

		/**
		 * @private
		 */
		private function buildMethods( parentBlock:XML, isStatic:Boolean = false ):Array {
			var methods:Array = new Array();
			var methodList:XMLList = new XMLList();

			if ( parentBlock ) {
				methodList = MetadataTools.getMethodsList( parentBlock );
			}

			for ( var i:int=0; i<methodList.length(); i++ ) {
				methods.push( buildMethod( methodList[ i ], isStatic ) );
			}

			return methods;
		}

		/**
		 * @private
		 */
		private function addMetaDataToMethod( subClassMethod:Method, superClassMethod:Method ):void {
			var subMetaDataArray:Array = subClassMethod.metadata;
			var superMetaDataArray:Array = superClassMethod.metadata;

			for ( var i:int=0; i<superMetaDataArray.length; i++ ) {
				subMetaDataArray.push( superMetaDataArray[ i ] );
			}
		}

		/**
		 * @private
		 */
		private function addMetaDataPerSuperClass( methodMap:Object, superXML:XML ):void {
			var methods:Array;
			var superMethod:Method;
			var instanceMethod:Method;

			if ( superXML.factory ) {
				methods = buildMethods( superXML.factory[ 0 ], false );

				for ( var i:int=0; i<methods.length; i++ ) {
					superMethod = methods[ i ] as Method;
					instanceMethod = methodMap[ superMethod.name ];

					if ( instanceMethod ) {
						//This one exists in the subclass, meaning it was overriden
						//Time to apply any metadata to the subclass method
						addMetaDataToMethod( instanceMethod, superMethod );
					}
				}
			}
		}

		/**
		 * Builds all Methods in this class, considering methods defined or overriden in this class and through inheritance
		 * @return An array of Method instances
		 *
		 */
		public function buildAllMethods():Array {
			var methods:Array = new Array();
			var method:Method;

			if ( classXML.factory ) {
				methods = methods.concat( buildMethods( classXML.factory[ 0 ], false ) );
			}

			methods = methods.concat( buildMethods( classXML, true ) );

			//If this object inherits from a class other than just Object
			if ( inheritance && ( inheritance.length > 1 ) ) {

				//Record all of these methods in an object so that we can check the inheritance hierarchy
				for ( var i:int=0; i<methods.length; i++ ) {
					method = methods[ i ] as Method;
					methodMap[ method.name ] = method;
				}

				for ( var j:int=0; j<inheritance.length; j++ ) {
					if ( inheritance[ j ] != Object ) {
						addMetaDataPerSuperClass( methodMap, ClassDataCache.describeType( inheritance[ j ] ) );
					}
				}
			}

			return methods;
		}

		/**
		 * Resposible for building method instances from XML descriptions
		 * @param classXML
		 * @param inheritance
		 *
		 */
		public function MethodBuilder( classXML:XML, inheritance:Array ) {
			this.classXML = classXML;
			this.inheritance = inheritance;

			methodMap = new Object();
		}
	}
}

Fix for release mode swfs

Fix for release mode swfs


function car(a = 1, b = 2) {
  return a + b;
}

trace(car(1));

function foo(a = 1, b = 2, c = 3) {
  return a + b + c;
}

trace(foo(1));

function bar(a = 1, b = 2, c = 3, d = 4) {
  return a + b + c + d;
}

trace(bar(1));

Update test case.

Update test case.


//
// $Id$
//
// Vilya library - tools for developing networked games
// Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/vilya/
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

package com.threerings.parlor.game.client {

import mx.core.Container;
import mx.core.UIComponent;

import mx.containers.Grid;
import mx.containers.GridItem;
import mx.containers.GridRow;
import mx.containers.HBox;

import com.threerings.parlor.game.data.GameConfig;
import com.threerings.parlor.util.ParlorContext;

/**
 * Provides the base from which interfaces can be built to configure games prior to starting them.
 * Derived classes would extend the base configurator adding interface elements and wiring them up
 * properly to allow the user to configure an instance of their game.
 *
 * <p> Clients that use the game configurator will want to instantiate one based on the class
 * returned from the {@link GameConfig} and then initialize it with a call to {@link #init}.
 */
public /*abstract*/ class FlexGameConfigurator extends GameConfigurator
{
    /**
     * Configures the number of columns to use when laying out our controls. This must be called
     * before any calls to {@link #addControl}.
     */
    public function setColumns (columns :int) :void
    {
        _columns = columns;
    }

    /**
     * Get the Container that contains the UI elements for this configurator.
     */
    public function getContainer () :Container
    {
        return _grid;
    }

    /**
     * Add a control to the interface. This should be the standard way that configurator controls
     * are added, but note also that external entities may add their own controls that are related
     * to the game, but do not directly alter the game config, so that all the controls are added
     * in a uniform manner and are well aligned.
     */
    public function addControl (label :UIComponent, control :UIComponent) :void
    {
        if (_gridRow == null) {
            _gridRow = new GridRow();
            _grid.addChild(_gridRow);
        }
        _gridRow.addChild(wrapItem(label));
        _gridRow.addChild(wrapItem(control));
        if (_gridRow.numChildren == _columns * 2) {
            _gridRow = null;
        }
    }

    protected function wrapItem (component :UIComponent) :GridItem
    {
        var item :GridItem = new GridItem();
        item.addChild(component);
        return item;
    }

    /** The grid on which the config options are placed. */
    protected var _grid :Grid = new Grid();

    /** The current row to which we're adding controls. */
    protected var _gridRow :GridRow;

    /** The number of columns in which to lay out our configuration. */
    protected var _columns :int = 2;
}
}

//
// $Id$
//
// Vilya library - tools for developing networked games
// Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/vilya/
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

package com.threerings.parlor.game.client {

import mx.core.Container;
import mx.core.UIComponent;

import mx.containers.Grid;
import mx.containers.GridRow;
import mx.containers.HBox;

import com.threerings.flex.GridUtil;

import com.threerings.parlor.game.data.GameConfig;
import com.threerings.parlor.util.ParlorContext;

/**
 * Provides the base from which interfaces can be built to configure games prior to starting them.
 * Derived classes would extend the base configurator adding interface elements and wiring them up
 * properly to allow the user to configure an instance of their game.
 *
 * <p> Clients that use the game configurator will want to instantiate one based on the class
 * returned from the {@link GameConfig} and then initialize it with a call to {@link #init}.
 */
public /*abstract*/ class FlexGameConfigurator extends GameConfigurator
{
    /**
     * Configures the number of columns to use when laying out our controls. This must be called
     * before any calls to {@link #addControl}.
     */
    public function setColumns (columns :int) :void
    {
        _columns = columns;
    }

    /**
     * Get the Container that contains the UI elements for this configurator.
     */
    public function getContainer () :Container
    {
        return _grid;
    }

    /**
     * Add a control to the interface. This should be the standard way that configurator controls
     * are added, but note also that external entities may add their own controls that are related
     * to the game, but do not directly alter the game config, so that all the controls are added
     * in a uniform manner and are well aligned.
     */
    public function addControl (label :UIComponent, control :UIComponent) :void
    {
        if (_gridRow == null) {
            _gridRow = new GridRow();
            _grid.addChild(_gridRow);
        }
        GridUtil.addToRow(_gridRow, label);
        GridUtil.addToRow(_gridRow, control);
        if (_gridRow.numChildren == _columns * 2) {
            _gridRow = null;
        }
    }

    /** The grid on which the config options are placed. */
    protected var _grid :Grid = new Grid();

    /** The current row to which we're adding controls. */
    protected var _gridRow :GridRow;

    /** The number of columns in which to lay out our configuration. */
    protected var _columns :int = 2;
}
}

Use GridUtil.

Use GridUtil.

git-svn-id: a3e1eb16dde062992de22c830ed8045c8013209a@496 c613c5cb-e716-0410-b11b-feb51c14d237


////////////////////////////////////////////////////////////////////////////////
//
//  Licensed to the Apache Software Foundation (ASF) under one or more
//  contributor license agreements.  See the NOTICE file distributed with
//  this work for additional information regarding copyright ownership.
//  The ASF licenses this file to You under the Apache License, Version 2.0
//  (the "License"); you may not use this file except in compliance with
//  the License.  You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////
package org.apache.flex.binding
{
	import org.apache.flex.core.IBead;
	import org.apache.flex.core.IStrand;
	import org.apache.flex.core.IDocument;

    /**
     *  The ConstantBinding class is lightweight data-binding class that
     *  is optimized for simple assignments of one object's constant to
     *  another object's property.
     *
     *  @langversion 3.0
     *  @playerversion Flash 10.2
     *  @playerversion AIR 2.6
     *  @productversion FlexJS 0.0
     */
	public class ConstantBinding implements IBead, IDocument
	{
        /**
         *  Constructor.
         *
         *  @langversion 3.0
         *  @playerversion Flash 10.2
         *  @playerversion AIR 2.6
         *  @productversion FlexJS 0.0
         */
		public function ConstantBinding()
		{
		}

        /**
         *  The source object who's property has the value we want.
         *
         *  @langversion 3.0
         *  @playerversion Flash 10.2
         *  @playerversion AIR 2.6
         *  @productversion FlexJS 0.0
         */
		protected var source:Object;

        /**
         *  The host mxml document for the source and
         *  destination objects.  The source object
         *  is either this document for simple bindings
         *  like {foo} where foo is a property on
         *  the mxml documnet, or found as document[sourceID]
         *  for simple bindings like {someid.someproperty}
         *
         *  @langversion 3.0
         *  @playerversion Flash 10.2
         *  @playerversion AIR 2.6
         *  @productversion FlexJS 0.0
         */
		protected var document:Object;

        /**
         *  The destination object.  It is always the same
         *  as the strand.  ConstantBindings are attached to
         *  the strand of the destination object.
         *
         *  @langversion 3.0
         *  @playerversion Flash 10.2
         *  @playerversion AIR 2.6
         *  @productversion FlexJS 0.0
         */
        public var destination:Object;

        /**
         *  If not null, the id of the mxml tag who's property
         *  is being watched for changes.
         *
         *  @langversion 3.0
         *  @playerversion Flash 10.2
         *  @playerversion AIR 2.6
         *  @productversion FlexJS 0.0
         */
        public var sourceID:String;

        /**
         *  If not null, the name of a property on the
         *  mxml document that is being watched for changes.
         *
         *  @langversion 3.0
         *  @playerversion Flash 10.2
         *  @playerversion AIR 2.6
         *  @productversion FlexJS 0.0
         */
        public var sourcePropertyName:String;

        /**
         *  The name of the property on the strand that
         *  is set when the source property changes.
         *
         *  @langversion 3.0
         *  @playerversion Flash 10.2
         *  @playerversion AIR 2.6
         *  @productversion FlexJS 0.0
         */
        public var destinationPropertyName:String;

        /**
         *  @copy org.apache.flex.core.IBead#strand
         *
         *  @langversion 3.0
         *  @playerversion Flash 10.2
         *  @playerversion AIR 2.6
         *  @productversion FlexJS 0.0
         */
		public function set strand(value:IStrand):void
		{
            if (destination == null)
                destination = value;

            if (sourceID != null)
    			source = document[sourceID];
            else
                source = document;
            var val:*;
            try
            {
                val = source[sourcePropertyName];
                destination[destinationPropertyName] = val;
            }
            catch (e:Error)
            {
                try {
                    val = source.constructor[sourcePropertyName];
                    destination[destinationPropertyName] = val;
                }
                catch (e2:Error)
                {
                }
            }
		}

        /**
         *  @copy org.apache.flex.core.IDocument#setDocument()
         *
         *  @langversion 3.0
         *  @playerversion Flash 10.2
         *  @playerversion AIR 2.6
         *  @productversion FlexJS 0.0
         */
		public function setDocument(document:Object, id:String = null):void
		{
			this.document = document;
		}

	}
}

////////////////////////////////////////////////////////////////////////////////
//
//  Licensed to the Apache Software Foundation (ASF) under one or more
//  contributor license agreements.  See the NOTICE file distributed with
//  this work for additional information regarding copyright ownership.
//  The ASF licenses this file to You under the Apache License, Version 2.0
//  (the "License"); you may not use this file except in compliance with
//  the License.  You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////
package org.apache.flex.binding
{
	import org.apache.flex.core.IBead;
	import org.apache.flex.core.IStrand;
	import org.apache.flex.core.IDocument;

    /**
     *  The ConstantBinding class is lightweight data-binding class that
     *  is optimized for simple assignments of one object's constant to
     *  another object's property.
     *
     *  @langversion 3.0
     *  @playerversion Flash 10.2
     *  @playerversion AIR 2.6
     *  @productversion FlexJS 0.0
     */
	public class ConstantBinding implements IBead, IDocument
	{
        /**
         *  Constructor.
         *
         *  @langversion 3.0
         *  @playerversion Flash 10.2
         *  @playerversion AIR 2.6
         *  @productversion FlexJS 0.0
         */
		public function ConstantBinding()
		{
		}

        /**
         *  The source object who's property has the value we want.
         *
         *  @langversion 3.0
         *  @playerversion Flash 10.2
         *  @playerversion AIR 2.6
         *  @productversion FlexJS 0.0
         */
		protected var source:Object;

        /**
         *  The host mxml document for the source and
         *  destination objects.  The source object
         *  is either this document for simple bindings
         *  like {foo} where foo is a property on
         *  the mxml documnet, or found as document[sourceID]
         *  for simple bindings like {someid.someproperty}
         *
         *  @langversion 3.0
         *  @playerversion Flash 10.2
         *  @playerversion AIR 2.6
         *  @productversion FlexJS 0.0
         */
		protected var document:Object;

        /**
         *  The destination object.  It is always the same
         *  as the strand.  ConstantBindings are attached to
         *  the strand of the destination object.
         *
         *  @langversion 3.0
         *  @playerversion Flash 10.2
         *  @playerversion AIR 2.6
         *  @productversion FlexJS 0.0
         */
        public var destination:Object;

        /**
         *  If not null, the id of the mxml tag who's property
         *  is being watched for changes.
         *
         *  @langversion 3.0
         *  @playerversion Flash 10.2
         *  @playerversion AIR 2.6
         *  @productversion FlexJS 0.0
         */
        public var sourceID:String;

        /**
         *  If not null, the name of a property on the
         *  mxml document that is being watched for changes.
         *
         *  @langversion 3.0
         *  @playerversion Flash 10.2
         *  @playerversion AIR 2.6
         *  @productversion FlexJS 0.0
         */
        public var sourcePropertyName:String;

        /**
         *  The name of the property on the strand that
         *  is set when the source property changes.
         *
         *  @langversion 3.0
         *  @playerversion Flash 10.2
         *  @playerversion AIR 2.6
         *  @productversion FlexJS 0.0
         */
        public var destinationPropertyName:String;

        /**
         *  @copy org.apache.flex.core.IBead#strand
         *
         *  @langversion 3.0
         *  @playerversion Flash 10.2
         *  @playerversion AIR 2.6
         *  @productversion FlexJS 0.0
         */
		public function set strand(value:IStrand):void
		{
            if (destination == null)
                destination = value;

            if (sourceID != null)
    			source = document[sourceID];
            else
                source = document;
            var val:*;
            if (sourcePropertyName in source)
            {
                try {
                    val = source[sourcePropertyName];
                    destination[destinationPropertyName] = val;
                }
                catch (e:Error)
                {
                }
            }
            else if (sourcePropertyName in source.constructor)
            {
                try {
                    val = source.constructor[sourcePropertyName];
                    destination[destinationPropertyName] = val;
                }
                catch (e2:Error)
                {
                }
            }
		}

        /**
         *  @copy org.apache.flex.core.IDocument#setDocument()
         *
         *  @langversion 3.0
         *  @playerversion Flash 10.2
         *  @playerversion AIR 2.6
         *  @productversion FlexJS 0.0
         */
		public function setDocument(document:Object, id:String = null):void
		{
			this.document = document;
		}

	}
}

use 'in' since a missing property won't always throw


/*
#
# Copyright (c) 2009 rPath, Inc.
#
# This program is distributed under the terms of the MIT License as found
# in a file called LICENSE. If it is not present, the license
# is always available at http://www.opensource.org/licenses/mit-license.php.
#
# This program is distributed in the hope that it will be useful, but
# without any warranty; without even the implied warranty of merchantability
# or fitness for a particular purpose. See the MIT License for full details.
*/

package com.rpath.raf.views
{
    import mx.core.UIComponent;
    import mx.events.ValidationResultEvent;

    import spark.components.Group;

    public class CompoundInputItem extends Group
    {
        public function CompoundInputItem()
        {
            super();

            // force height computation
            minHeight = 0;
        }

        [Bindable]
        public var inputFields:Array;

        public override function validationResultHandler(event:ValidationResultEvent):void
        {
            // let our specific input controls mark themselves appropriately
            for each (var elem:UIComponent in inputFields)
            {
                elem.validationResultHandler(event);
            }

            // propagate events beyond ourselves
            super.validationResultHandler(event);
        }

    }
}

/*
#
# Copyright (c) 2009 rPath, Inc.
#
# This program is distributed under the terms of the MIT License as found
# in a file called LICENSE. If it is not present, the license
# is always available at http://www.opensource.org/licenses/mit-license.php.
#
# This program is distributed in the hope that it will be useful, but
# without any warranty; without even the implied warranty of merchantability
# or fitness for a particular purpose. See the MIT License for full details.
*/

package com.rpath.raf.views
{
    import mx.core.UIComponent;
    import mx.events.ValidationResultEvent;

    import spark.components.Group;

    public class CompoundInputItem extends Group
    {
        public function CompoundInputItem()
        {
            super();

            // force height computation
            minHeight = 0;
        }

        [Bindable]
        public var inputFields:Array;

        public override function validationResultHandler(event:ValidationResultEvent):void
        {
            // let our specific input controls mark themselves appropriately
            for each (var elem:UIComponent in inputFields)
            {
                if (elem)
                    elem.validationResultHandler(event);
            }

            // propagate events beyond ourselves
            super.validationResultHandler(event);
        }

    }
}

Handle null in validation elem iteration


////////////////////////////////////////////////////////////////////////////////
//
//  Licensed to the Apache Software Foundation (ASF) under one or more
//  contributor license agreements.  See the NOTICE file distributed with
//  this work for additional information regarding copyright ownership.
//  The ASF licenses this file to You under the Apache License, Version 2.0
//  (the "License"); you may not use this file except in compliance with
//  the License.  You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////

package components
{
	import flash.events.Event;
	import mx.core.IUIComponent;
	import mx.core.IVisualElement;
	import mx.events.FlexEvent;
	import mx.states.State;
	import spark.components.supportClasses.SkinnableComponent;

	[SkinState("rotatingState")]
	[SkinState("notRotatingState")]

	public class MobileBusyIndicator extends SkinnableComponent
	{
		private var effectiveVisibility:Boolean = false;
		private var effectiveVisibilityChanged:Boolean = true;

		public function BusyIndicator()
		{
			super();
			// Listen to added to stage and removed from stage.
			// Start rotating when we are on the stage and stop
			// when we are removed from the stage.
			addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
			addEventListener(Event.REMOVED_FROM_STAGE, removedFromStageHandler);
			states = 	[
							new State({name:"notRotatingState"}),
							new State({name:"rotatingState"})
						];
		}

		override protected function getCurrentSkinState():String
		{
			return currentState;
		}

		private function addedToStageHandler(event:Event):void
		{
			// Check our visibility here since we haven't added
			// visibility listeners yet.
			computeEffectiveVisibility();

			if (canRotate())
				currentState = "rotatingState";

			addVisibilityListeners();
			invalidateSkinState();
		}

		private function removedFromStageHandler(event:Event):void
		{
			currentState = "notRotatingState";

			removeVisibilityListeners();
			invalidateSkinState();
		}

		private function computeEffectiveVisibility():void
		{

			// Check our design layer first.
			if (designLayer && !designLayer.effectiveVisibility)
			{
				effectiveVisibility = false;
				return;
			}

			// Start out with true visibility and enablement
			// then loop up parent-chain to see if any of them are false.
			effectiveVisibility = true;
			var current:IVisualElement = this;

			while (current)
			{
				if (!current.visible)
				{
					if (!(current is IUIComponent) || !IUIComponent(current).isPopUp)
					{
						// Treat all pop ups as if they were visible. This is to
						// fix a bug where the BusyIndicator does not spin when it
						// is inside modal popup. The problem is in we do not get
						// an event when the modal window is made visible in
						// PopUpManagerImpl.fadeInEffectEndHandler(). When the modal
						// window is made visible, setVisible() is passed "true" so
						// as to not send an event. When do get events when the
						// non-modal windows are popped up. Only modal windows are
						// a problem.
						// The downside of this fix is BusyIndicator components that are
						// inside of hidden, non-modal, popup windows will paint themselves
						// on a timer.
						effectiveVisibility = false;
						break;
					}
				}

				current = current.parent as IVisualElement;
			}
		}

		/**
		 *  The BusyIndicator can be rotated if it is both on the display list and
		 *  visible.
		 *
		 *  @returns true if the BusyIndicator can be rotated, false otherwise.
		 */
		private function canRotate():Boolean
		{
			if (effectiveVisibility && stage != null)
				return true;

			return false;
		}

		/**
		 *  @private
		 *  Add event listeners for SHOW and HIDE on all the ancestors up the parent chain.
		 *  Adding weak event listeners just to be safe.
		 */
		private function addVisibilityListeners():void
		{
			var current:IVisualElement = this.parent as IVisualElement;
			while (current)
			{
				// add visibility listeners to the parent
				current.addEventListener(FlexEvent.HIDE, visibilityChangedHandler, false, 0, true);
				current.addEventListener(FlexEvent.SHOW, visibilityChangedHandler, false, 0, true);

				current = current.parent as IVisualElement;
			}
		}

		/**
		 *  @private
		 *  Remove event listeners for SHOW and HIDE on all the ancestors up the parent chain.
		 */
		private function removeVisibilityListeners():void
		{
			var current:IVisualElement = this;
			while (current)
			{
				current.removeEventListener(FlexEvent.HIDE, visibilityChangedHandler, false);
				current.removeEventListener(FlexEvent.SHOW, visibilityChangedHandler, false);

				current = current.parent as IVisualElement;
			}
		}

		/**
		 *  @private
		 *  Event call back whenever the visibility of us or one of our ancestors
		 *  changes
		 */
		private function visibilityChangedHandler(event:FlexEvent):void
		{
			effectiveVisibilityChanged = true;
			invalidateProperties();
		}

	}
}

////////////////////////////////////////////////////////////////////////////////
//
//  Licensed to the Apache Software Foundation (ASF) under one or more
//  contributor license agreements.  See the NOTICE file distributed with
//  this work for additional information regarding copyright ownership.
//  The ASF licenses this file to You under the Apache License, Version 2.0
//  (the "License"); you may not use this file except in compliance with
//  the License.  You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////

package spark.components
{
	import flash.events.Event;
	import mx.core.IUIComponent;
	import mx.core.IVisualElement;
	import mx.events.FlexEvent;
	import mx.states.State;
	import spark.components.supportClasses.SkinnableComponent;

	[SkinState("rotatingState")]
	[SkinState("notRotatingState")]

	public class MobileBusyIndicator extends SkinnableComponent
	{
		private var effectiveVisibility:Boolean = false;
		private var effectiveVisibilityChanged:Boolean = true;

		public function MobileBusyIndicator()
		{
			super();
			// Listen to added to stage and removed from stage.
			// Start rotating when we are on the stage and stop
			// when we are removed from the stage.
			addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
			addEventListener(Event.REMOVED_FROM_STAGE, removedFromStageHandler);
			states = 	[
							new State({name:"notRotatingState"}),
							new State({name:"rotatingState"})
						];
		}

		override protected function getCurrentSkinState():String
		{
			return currentState;
		}

		private function addedToStageHandler(event:Event):void
		{
			// Check our visibility here since we haven't added
			// visibility listeners yet.
			computeEffectiveVisibility();

			if (canRotate())
				currentState = "rotatingState";

			addVisibilityListeners();
			invalidateSkinState();
		}

		private function removedFromStageHandler(event:Event):void
		{
			currentState = "notRotatingState";

			removeVisibilityListeners();
			invalidateSkinState();
		}

		private function computeEffectiveVisibility():void
		{

			// Check our design layer first.
			if (designLayer && !designLayer.effectiveVisibility)
			{
				effectiveVisibility = false;
				return;
			}

			// Start out with true visibility and enablement
			// then loop up parent-chain to see if any of them are false.
			effectiveVisibility = true;
			var current:IVisualElement = this;

			while (current)
			{
				if (!current.visible)
				{
					if (!(current is IUIComponent) || !IUIComponent(current).isPopUp)
					{
						// Treat all pop ups as if they were visible. This is to
						// fix a bug where the BusyIndicator does not spin when it
						// is inside modal popup. The problem is in we do not get
						// an event when the modal window is made visible in
						// PopUpManagerImpl.fadeInEffectEndHandler(). When the modal
						// window is made visible, setVisible() is passed "true" so
						// as to not send an event. When do get events when the
						// non-modal windows are popped up. Only modal windows are
						// a problem.
						// The downside of this fix is BusyIndicator components that are
						// inside of hidden, non-modal, popup windows will paint themselves
						// on a timer.
						effectiveVisibility = false;
						break;
					}
				}

				current = current.parent as IVisualElement;
			}
		}

		/**
		 *  The BusyIndicator can be rotated if it is both on the display list and
		 *  visible.
		 *
		 *  @returns true if the BusyIndicator can be rotated, false otherwise.
		 */
		private function canRotate():Boolean
		{
			if (effectiveVisibility && stage != null)
				return true;

			return false;
		}

		/**
		 *  @private
		 *  Add event listeners for SHOW and HIDE on all the ancestors up the parent chain.
		 *  Adding weak event listeners just to be safe.
		 */
		private function addVisibilityListeners():void
		{
			var current:IVisualElement = this.parent as IVisualElement;
			while (current)
			{
				// add visibility listeners to the parent
				current.addEventListener(FlexEvent.HIDE, visibilityChangedHandler, false, 0, true);
				current.addEventListener(FlexEvent.SHOW, visibilityChangedHandler, false, 0, true);

				current = current.parent as IVisualElement;
			}
		}

		/**
		 *  @private
		 *  Remove event listeners for SHOW and HIDE on all the ancestors up the parent chain.
		 */
		private function removeVisibilityListeners():void
		{
			var current:IVisualElement = this;
			while (current)
			{
				current.removeEventListener(FlexEvent.HIDE, visibilityChangedHandler, false);
				current.removeEventListener(FlexEvent.SHOW, visibilityChangedHandler, false);

				current = current.parent as IVisualElement;
			}
		}

		/**
		 *  @private
		 *  Event call back whenever the visibility of us or one of our ancestors
		 *  changes
		 */
		private function visibilityChangedHandler(event:FlexEvent):void
		{
			effectiveVisibilityChanged = true;
			invalidateProperties();
		}

	}
}

Fix package name of spark/components/MobileBusyIndicator.as Fix constructor name


package io.github.jwhile.impetus
{
    import flash.media.Sound;
    import flash.media.SoundChannel;

    public class ImpetusSound
    {
        private var url:String;
        private var sound:Sound;

        private var channels:Vector.<SoundChannel>;

        public function ImpetusSound(url:String):void
        {
            this.url = url;
            this.sound = new Sound();

            this.channels = new Vector.<SoundChannel>;
        }
    }
}

package io.github.jwhile.impetus
{
    import flash.media.Sound;
    import flash.media.SoundChannel;
    import flash.net.URLRequest;

    public class ImpetusSound
    {
        private var sound:Sound;

        private var channels:Vector.<SoundChannel>;

        public function ImpetusSound(url:String):void
        {
            this.sound = new Sound();

            this.channels = new Vector.<SoundChannel>;

            this.sound.load(new URLRequest(url));
        }
    }
}

Load sound directly on constructor

Load sound directly on constructor


package aerys.minko.render.shader.compiler.graph.nodes.leaf
{
	import aerys.minko.render.shader.compiler.CRC32;
	import aerys.minko.render.shader.compiler.Serializer;
	import aerys.minko.render.shader.compiler.graph.nodes.AbstractNode;

	/**
	 * @private
	 * @author Romain Gilliotte
	 *
	 */
	public class Constant extends AbstractNode
	{
		private var _value : Vector.<Number>

		public function get value() : Vector.<Number>
		{
			return _value;
		}

		public function set value(v : Vector.<Number>) : void
		{
			_value = v;
		}

		public function Constant(value : Vector.<Number>)
		{
			super(new <AbstractNode>[], new <uint>[]);

			_value = value;
		}

		override protected function computeSize() : uint
		{
			return _value.length;
		}

		override protected function computeHash() : uint
		{
			return CRC32.computeForNumberVector(_value);
		}

		override public function toString() : String
		{
			return 'Constant';
		}

		override public function clone() : AbstractNode
		{
			return new Constant(_value.slice());
		}

	}
}

package aerys.minko.render.shader.compiler.graph.nodes.leaf
{
	import aerys.minko.render.shader.compiler.CRC32;
	import aerys.minko.render.shader.compiler.Serializer;
	import aerys.minko.render.shader.compiler.graph.nodes.AbstractNode;

	/**
	 * @private
	 * @author Romain Gilliotte
	 *
	 */
	public class Constant extends AbstractNode
	{
		private var _value : Vector.<Number>;

		public function get value() : Vector.<Number>
		{
			return _value;
		}

		public function set value(v : Vector.<Number>) : void
		{
			_value = v;
		}

		public function Constant(value : Vector.<Number>)
		{
			super(new <AbstractNode>[], new <uint>[]);

			_value = value;
		}

		override protected function computeSize() : uint
		{
			return _value.length;
		}

		override protected function computeHash() : uint
		{
			return CRC32.computeForNumberVector(_value);
		}

		override public function toString() : String
		{
			return 'Constant';
		}

		override public function clone() : AbstractNode
		{
			return new Constant(_value.slice());
		}

	}
}

fix missing ;

fix missing ;


package flash.utils
{
	import flash.events.*;

	[Event(name = "timerComplete", type = "flash.events.TimerEvent")]
	[Event(name = "timer", type = "flash.events.TimerEvent")]
	public class Timer extends EventDispatcher
	{

		private var m_delay:Number;

		private var m_repeatCount:int;

		private var m_iteration:int;
		private var intervalID:int;
		public function Timer(delay:Number, repeatCount:int = 0)
		{
			super();
			if (delay < 0 || !isFinite(delay))
			{
				Error.throwError(RangeError, 2066);
			}
			this.m_delay = delay;
			this.m_repeatCount = repeatCount;
		}

		public function get delay():Number
		{
			return this.m_delay;
		}

		public function get repeatCount():int
		{
			return this.m_repeatCount;
		}

		public function set repeatCount(value:int):void
		{
			this.m_repeatCount = value;
			if (this.running && this.m_repeatCount != 0 && this.m_iteration >= this.m_repeatCount)
			{
				this.stop();
			}
		}

		public function get currentCount():int
		{
			return this.m_iteration;
		}

		public function get running():Boolean
		{
			return false;
		}

		public function set delay(value:Number):void
		{
			if (value < 0 || !isFinite(value))
			{
				Error.throwError(RangeError, 2066);
			}
			this.m_delay = value;
			if (this.running)
			{
				this.stop();
				this.start();
			}
		}

		private function tick():void
		{
			this.m_iteration++;
			this._timerDispatch();
			if (this.m_repeatCount != 0 && this.m_iteration >= this.m_repeatCount)
			{
				this.stop();
				dispatchEvent(new TimerEvent(TimerEvent.TIMER_COMPLETE, false, false));
			}
		}

		public function start():void
		{
			if (!this.running)
			{
				this._start(this.m_delay, this.tick);
			}
		}

		public function reset():void
		{
			if (this.running)
			{
				this.stop();
			}
			this.m_iteration = 0;
		}

		private function _start(m_delay:Number, m_tick:Function):void
		{
			intervalID=setInterval(m_tick, m_delay);
		}

		private function _timerDispatch():void
		{
			dispatchEvent(new TimerEvent(TimerEvent.TIMER));
		}

		public function stop():void
		{
			clearInterval(intervalID);
		}
	}
}

package flash.utils
{
	import flash.events.*;

	[Event(name = "timerComplete", type = "flash.events.TimerEvent")]
	[Event(name = "timer", type = "flash.events.TimerEvent")]
	public class Timer extends EventDispatcher
	{

		private var m_delay:Number;

		private var m_repeatCount:int;

		private var m_iteration:int;
		private var intervalID:int;
		public function Timer(delay:Number, repeatCount:int = 0)
		{
			super();
			if (delay < 0 || !isFinite(delay))
			{
				Error.throwError(RangeError, 2066);
			}
			this.m_delay = delay;
			this.m_repeatCount = repeatCount;
			this.m_iteration = 0;
		}

		public function get delay():Number
		{
			return this.m_delay;
		}

		public function get repeatCount():int
		{
			return this.m_repeatCount;
		}

		public function set repeatCount(value:int):void
		{
			this.m_repeatCount = value;
			if (this.running && this.m_repeatCount != 0 && this.m_iteration >= this.m_repeatCount)
			{
				this.stop();
			}
		}

		public function get currentCount():int
		{
			return this.m_iteration;
		}

		public function get running():Boolean
		{
			return false;
		}

		public function set delay(value:Number):void
		{
			if (value < 0 || !isFinite(value))
			{
				Error.throwError(RangeError, 2066);
			}
			this.m_delay = value;
			if (this.running)
			{
				this.stop();
				this.start();
			}
		}

		private function tick():void
		{
			this.m_iteration++;
			this._timerDispatch();
			if (this.m_repeatCount != 0 && this.m_iteration >= this.m_repeatCount)
			{
				this.stop();
				dispatchEvent(new TimerEvent(TimerEvent.TIMER_COMPLETE, false, false));
			}
		}

		public function start():void
		{
			if (!this.running)
			{
				this._start(this.m_delay, this.tick);
			}
		}

		public function reset():void
		{
			if (this.running)
			{
				this.stop();
			}
			this.m_iteration = 0;
		}

		private function _start(m_delay:Number, m_tick:Function):void
		{
			intervalID=setInterval(m_tick, m_delay);
		}

		private function _timerDispatch():void
		{
			dispatchEvent(new TimerEvent(TimerEvent.TIMER));
		}

		public function stop():void
		{
			clearInterval(intervalID);
		}
	}
}

Fix small bug when setInterval never stops.