SmartFoxServer 2X Tutorial: How To Create A Custom MySQL Login Extension

Comments 59 Standard

As usual the documentation for SFS is really lacking in this area (or scattered across several pages and consequently vague– not sure why they do that). Here is my attempt at a reasonable tutorial on how to create a custom login extension for MySQL databases. This tutorial assumes you already have a MySQL database setup with at least one table and some data in it. It also assumes the database you’re using is jdbc accessible.

As always you can download the working files
but you’ll need to read the tutorial to get SFS setup and using them properly.

1. Setup the MySQL Database Driver

  1. Login to the SFS admin panel.
  2. Go to the Zone Configurator.
  3. Click on the zone you want to setup the database for.
  4. At the bottom of the screen click on the pencil to edit the zone.
  5. Find the Database Manager tab.
  6. Make sure you switch the Active slider to ON.
  7. In the Database Driver class type in: org.gjt.mm.mysql.Driver
  8. In the Connection String type in: jdbc:mysql://[localhost or IP address to the server]/[database name you want to use]
  9. Enter in your username and password necessary to connect to the database you entered in the connection string
  10. Put in a simple SQL query into the test SQL box. This isn’t required but SFS will notify you that there was a connection problem if you leave this blank. Something like SELECT id FROM users LIMIT 1 is a good query to enter assuming you have a users table on the database you’re using and it has some data in it.
  11. Press the submit button to save your changes.
  12. One thing to note, you can also change all of these settings if you go to the installation directory of SFS2x, find the Zones folder, then edit the [zonename].xml file. You’ll end up with something that looks like this:

<databaseManager active=”true”>
<driverName>org.gjt.mm.mysql.Driver</driverName>
<connectionString>jdbc:mysql://localhost/testDatabase</connectionString>
<userName>Jade</userName>
<password>somethingNoOneWillGuess</password>
<testSql>SELECT id FROM users LIMIT 1</testSql>
<maxActiveConnections>10</maxActiveConnections>
<maxIdleConnections>10</maxIdleConnections>
<exhaustedPoolAction>FAIL</exhaustedPoolAction>
<blockTime>3000</blockTime>
</databaseManager>

2. Create The Login Extension File

  1. Open your favorite Java IDE. I use Netbeans but any one will work.
  2. Create a new Java project. Name the project whatever you want, the project name isn’t important but the class names will be later.
  3. Create a new class with a file name of LoginExtension. This is case sensitive!
  4. When it asks for a package enter the following: sfs2x.extension.[whatever you want to call this extension].src
  5. Note that any extension you make MUST start with the blue colored portion above. If it doesn’t SFS won’t be able to find the .JAR file you’ll be creating later.
  6. In the red colored portion above you can enter whatever your want the name of this extension to be. I named mine login. This is important later as this is what you’ll give SFS so it knows which extension it’s supposed to be loading.
  7. The green .src is optional however I find that SFS sometimes has problems loading extensions if you don’t put the files in another level. This may also be something IDE related with how NetBeans is exporting the .JAR. Either way I would recommend it so if you have people working with different IDEs you won’t run into problems later.
  8. Next you need to import the SmartFoxServer java libraries. Where this is located will vary depending on the IDE you use, but generally you’ll find it under project > options > libraries. Click the button that says Add JAR/Folder or Add External JARS or something to that effect. Navigate to where you installed SFS and find the LIB folder (not the _LIB_ folder under extensions). Locate the sfs2x.jar and the sfs2x_core.jar files and add them to your project.
  9. In your class file enter the following then save your changes:
package sfs2x.extension.login.src;

import com.smartfoxserver.v2.extensions.SFSExtension;
import com.smartfoxserver.v2.core.SFSEventType;

public class LoginExtension extends SFSExtension {

 @Override
 public void init()
 {
 trace("Login extension starting.");

 // Register the login event
 addEventHandler(SFSEventType.USER_LOGIN, LoginHandler.class);
 }

 @Override
 public void destroy()
 {
 trace("Login extension stopped.");
 super.destroy();
 }
}

3. Create the Login Request Handler File

  1. Create another class called LoginHandler in the same project. It should have the same package as the last file you made.
  2. In this file you’ll need to enter the following:
package sfs2x.extension.login.src;

import java.sql.SQLException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.PreparedStatement;
import com.smartfoxserver.bitswarm.sessions.ISession;
import com.smartfoxserver.v2.entities.data.SFSArray;
import com.smartfoxserver.v2.core.SFSEventParam;
import com.smartfoxserver.v2.core.ISFSEvent;
import com.smartfoxserver.v2.exceptions.SFSException;
import com.smartfoxserver.v2.exceptions.SFSLoginException;
import com.smartfoxserver.v2.exceptions.SFSErrorData;
import com.smartfoxserver.v2.exceptions.SFSErrorCode;
import com.smartfoxserver.v2.extensions.BaseServerEventHandler;
import com.smartfoxserver.v2.extensions.ExtensionLogLevel;

public class LoginHandler extends BaseServerEventHandler {

   @Override
   public void handleServerEvent(ISFSEvent event) throws SFSException
   {
        String username = (String) event.getParameter(SFSEventParam.LOGIN_NAME);
        String password = (String) event.getParameter(SFSEventParam.LOGIN_PASSWORD);

        ISession session = (ISession)event.getParameter(SFSEventParam.SESSION);

        try {
            //get a connection to the database
            Connection conn = getParentExtension().getParentZone().getDBManager().getConnection();

            //This will strip potential SQL injections
            PreparedStatement sql = conn.prepareStatement("SELECT id, password FROM members WHERE username = ?");
            sql.setString(1, username);

            // Obtain ResultSet
            ResultSet result = sql.executeQuery();

            //Put the result into an SFSobject array
            SFSArray row = SFSArray.newFromResultSet(result);

            //make sure there is a password before you try to use the checkSecurePassword function
            if (password.equals(""))
            {
                SFSErrorData data = new SFSErrorData(SFSErrorCode.LOGIN_BAD_PASSWORD);
                data.addParameter(username);
                throw new SFSLoginException("You must enter a password.", data);
            }

           //SFS always encrypts passwords before sending them so you need to decrypt the password
           //received from the database and compare that to what they entered in flash
           if (!getApi().checkSecurePassword(session, row.getSFSObject(0).getUtfString("password"), password))
           {
                SFSErrorData data = new SFSErrorData(SFSErrorCode.LOGIN_BAD_PASSWORD);

                data.addParameter(username);

                throw new SFSLoginException("Login failed for user: "  + username, data);
            }

            //this was in one of the SFS examples so I left it in there for testing purposes
            if (username.equals("Gonzo") || username.equals("Kermit"))
            {

                // Create the error code to send to the client
                SFSErrorData errData = new SFSErrorData(SFSErrorCode.LOGIN_BAD_USERNAME);
                errData.addParameter(username);

                // Fire a Login exception
                throw new SFSLoginException("Gonzo and Kermit are not allowed in this Zone!", errData);
            }

            //make sure you close the database connection when you're done with it, especially if you've
            //set a low number of maximum connections
            conn.close();

            //at this point you could trigger an joinRoom request if you wanted to, otherwise
            //this will return success to your LOGIN event listener
            trace("Login successful, joining room!");

        } catch (SQLException e) {
            trace(ExtensionLogLevel.WARN, " SQL Failed: " + e.toString());
        }
    }
}

4. Create the .JAR Executable

  1. Now that you have both extension files ready to go it’s time to setup the project for building a .JAR
  2. Return to your project > options and find the Build/Compile settings. Make sure your .JAR is set to export with class name warnings/errors (if the option is available) and that it’s set to compress the file. A smaller file means faster runtime.
  3. Build your project. If you have any errors your linker will let you know. You need a successful build to get a .JAR. Sometimes your project isn’t set to build .JAR files until execution. This is also a setting in your IDE that you can toggle somewhere.
  4. Last but not least, it’s time to find where your .JAR file was created. You’re going to need this file for the next step.

5. Configure SFS to Use the Login Extension

  1. Before you can run your extension you have to make your extension .JAR file available to SFS and then configure your zone to load the extension and attach it to your zone. (you can also put extensions on a room level if you need to).
  2. Start by going to the location of where you installed SFS. Locate the Extensions folder. Now create a new folder that matches the name of your extension. In my example I used login as the name of my extension so I would create a folder called login.
  3. Next copy the .JAR you created and paste it into the folder you just created.
  4. Go back to the SFS Admin console — you can also do this by going to the zone’s xml file.
  5. Now go to the Zone Configuration and edit the same zone that you setup your database connection on. This time click on the Zone Extension tab.
  6. In the name field enter the name of your extension. In my example I called my extension login and I created a login folder so I would enter the word login into this box.
  7. Our extension is a .JAR so we’re going to leave the type at JAVA.
  8. In the File box enter the package and filename for your main extension file like so: sfs2x.extension.login.src.LoginExtension
  9. Now click on the general tab and turn on the Use Custom login. Even if you have the extension setup properly SFS will continue to use it’s built in login functionality if this is not turned on.
  10. This completes the extension portion of the tutorial. Now let’s build a .SWF file to test our extension and make sure it’s working properly.

6. Restart SFS

Make sure you restart SmartFox before testing your extensions. This will load in the .JAR files you placed in the extensions folder and check to make sure your database configuration is setup properly. Additionally you should check the SFS console for any errors it encounters as it tries to test your database connection and load your extension.

7. Create A .SWF to Test Your Extension

Since I’ve created a .zip with the .fla and .swf already created for you I’m not going to go into detail here. In a nutshell this file connects to SFS then attempts to use the login extension you just created. If you have it setup properly:

  • you’ll get an error message if you leave the password blank
  • you’ll get an error message if you have a username of Gonzo
  • you’ll get an error if the username and password you’ve supplied don’t match a username/password found in your database
  • Otherwise you’ll get a successful LOGIN event triggered and you can go from there.

Troubleshooting &
Frequently Asked Questions

Why doesn’t my login work  even though my extension is setup correctly?

  • Make sure you have a record in the database table you’re referencing and that the correct username/password information exists for that user.
  • Make sure you’re using the correct database and accessing the correct table.
  • Make sure SFS is connecting to your database. To do that shut down SFS then restart it again using the SFS console. You’ll see a message at the top concerning your database connection if the test SQL query you entered in the SFS admin panel fails.

Why do I get null object errors?

  • I found these happen for a wide variety of reasons. One may be that you’re not checking for an empty password string when you use the checkSecurePassword function. Another may be that your result set isn’t returning any data. I’ve also found this happens if your database connection isn’t configured properly. Sorry but that’s all the help I have to offer for this one.

Why do I get extension files not found errors?

  • I believe this has something to do with how your IDE is building the .JAR file. Refer back to the login extension we made above. If you put your LoginExtension and LoginHandler files in package extension sfs2x.extension.login you may get this error. Try changing the package extension on both files to sfs2x.extension.login.src. Rebuild your .JAR file and replace the old one in your extension/login folder.
  • Check to make sure you’ve entered the correct package path in the File box on your SFS admin panel. If you have a typo in the name it won’t be able to use your .JAR.

Why do I get  invalid path directory errors?

  • When you create an extension you have to create a folder with the extension name and place it into your extension folder wherever you installed SFS.  In our example above I created an extension called login. So in my extensions folder I create a new folder called login and place the .JAR file I created inside.
  • Your .java files have the wrong package name.  Make sure your package name is formatted as follows with the blue part being required, the red part changed to your extension name and the green part is optional: sfs2x.extension.name_of_your_extension.src

Why do I get the .JAR cannot be found errors?

  • Your .JAR file hasn’t been placed in the right location. Go to where you’ve installed SFS, then find the extensions folder. You should have created a folder inside of the SFS extensions folder with the name of your extension. Your  .JAR file should be placed here and not in the _LIB_ folder like most of their website tells you to do (weird huh?). If anyone has an explanation for this one and cares to comment or elaborate about this oddity then please do.

Why aren’t my changes to my .JAR  going into effect?

  • If you re-build your .JAR file then you have to copy/paste it back into the extensions/your_extension_name folder. If you don’t do that SFS will never get an updated version of your code.
package sfs2x.extension.login.src;import java.sql.SQLException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.PreparedStatement;
import com.smartfoxserver.bitswarm.sessions.ISession;
import com.smartfoxserver.v2.entities.data.SFSArray;
import com.smartfoxserver.v2.core.SFSEventParam;
import com.smartfoxserver.v2.core.ISFSEvent;
import com.smartfoxserver.v2.exceptions.SFSException;
import com.smartfoxserver.v2.exceptions.SFSLoginException;
import com.smartfoxserver.v2.exceptions.SFSErrorData;
import com.smartfoxserver.v2.exceptions.SFSErrorCode;
import com.smartfoxserver.v2.extensions.BaseServerEventHandler;
import com.smartfoxserver.v2.extensions.ExtensionLogLevel;public class LoginHandler extends BaseServerEventHandler {@Override
public void handleServerEvent(ISFSEvent event) throws SFSException
{
String username = (String) event.getParameter(SFSEventParam.LOGIN_NAME);
String password = (String) event.getParameter(SFSEventParam.LOGIN_PASSWORD);ISession session = (ISession)event.getParameter(SFSEventParam.SESSION);

try {
//get a connection to the database
Connection conn = getParentExtension().getParentZone().getDBManager().getConnection();

PreparedStatement sql = conn.prepareStatement(“SELECT id, password FROM members WHERE username = ?”);
sql.setString(1, username);

// Obtain ResultSet
ResultSet result = sql.executeQuery();

//Put the result into an object array
SFSArray row = SFSArray.newFromResultSet(result);

if (password.equals(“”))
{
SFSErrorData data = new SFSErrorData(SFSErrorCode.LOGIN_BAD_PASSWORD);
data.addParameter(username);
throw new SFSLoginException(“You must enter a password.”, data);
}

if (!getApi().checkSecurePassword(session, row.getSFSObject(0).getUtfString(“password”), password))
{
SFSErrorData data = new SFSErrorData(SFSErrorCode.LOGIN_BAD_PASSWORD);

data.addParameter(username);

throw new SFSLoginException(“Login failed for user: ”  + username, data);
}

if (username.equals(“Gonzo”) || username.equals(“Kermit”))
{

// Create the error code to send to the client
SFSErrorData errData = new SFSErrorData(SFSErrorCode.LOGIN_BAD_USERNAME);
errData.addParameter(username);

// Fire a Login exception
throw new SFSLoginException(“Gonzo and Kermit are not allowed in this Zone!”, errData);
}

conn.close();
trace(“Login successful, joining room!”);

} catch (SQLException e) {
trace(ExtensionLogLevel.WARN, ” SQL Failed: ” + e.toString());
}
}
}

Flash AS3 Tutorial: Embedding Symbols From External .swf Files

Leave a comment Standard

This is one of my favorite features in flash but the documentation is pretty much non-existent and what little I’ve found is completely crappy. In developing a large flash game you’ll find you have a TON of symbols, buttons and images that you need to use in various classes throughout your game. So the question is, how can you put all of those assets into a .swf file and just reference them when necessary? Embedding is the answer. I’ve created a little clicking game to show you how it’s done.

First You’ll Need To
Download the Embedding Symbols Tutorial Game Code

Create & Organize Your Assets

Create an assets.fla file. This will hold all of your graphics, buttons, screens and user interface symbols. If you have a lot of these I suggest you break them into several different files (ie by level, scene or type) so  loading doesn’t take quite so long. I typically put all of the .swf files in a graphics or assets folder so they’re easy to find and manage later on down the road.

Now in your assets.fla file create a new MovieClip symbol. Inside this symbol draw a square. When you’re done right click on the symbol in your library > select properties > then export the square for actionscript as.

Create two more symbols, both of them Buttons. One button will start the game and another will restart the game.

Now create one last MovieClip symbol. This will be your interface for the little game we’re making. Add both of your buttons somewhere in the interface symbol. In the properties panel give each of them an instance name so we can reference them later.

Next we want a way to keep score of how many times our shape has been clicked. Add two text fields somewhere on the screen. One of them should contain static textfield that says the word “Score:” and the other should be a dynamic text field that will hold the user’s score as they play. Make sure the dynamic textfield has an instance name so we can reference it later on.

Exporting Your Assets

Unfortunately we can’t embed a .fla file so before we can use the graphics in our assets.fla file we need to export them to a .swf.  Any time you update your assets.fla file you will need to re-export it to a .swf file in order to see the changes. Once we have our assets.swf file we’re ready to start building our game.

Create Your Main .fla File

Before we can start putting our game together we need to create another flash file that will import our game classes, create a game instance, add our game to the stage and then start rendering our game. Create a file called embedding.fla.  Import your main game class, create an instance of it, then call the run function once it’s been added to the stage. You’ll end up with the following:

//import your game logic class
import com.design1online.puzzle.GameLogic;

//create the game instance
var blockGame = new GameLogic();
//check to see if the game has been added to the stage before you run it
//otherwise you'll get errors
blockGame.addEventListener(Event.ADDED_TO_STAGE, init);

//add the game to the stage
addChild(blockGame);

//once the game has been added to the stage the event listener
//will call this init function
function init(e:Event)
{
    //now we start our game logic
    blockGame.run();
}

Create Your Game Logic & Embed Your Files

So this little game I made up is nothing fancy. All it does is take a block and randomly place it around the screen with random alpha values. Each time you click on the square it places it at a new random location and increases your score.  It’s nothing fancy, it’s just to show you how everything fits together.

/**
* File: com.design1online.puzzle.GameLogic.as
* Author: jade@design1online.com
* Created: 12/19/2010
* Purpose: game logic for a demo puzzle game
*    in order to show how embedding works
**/
package com.design1online.puzzle {

 import flash.display.Bitmap;
 import flash.display.MovieClip;
 import flash.display.SimpleButton;
 import flash.events.Event;
 import flash.events.MouseEvent;
 import flash.text.TextField;

 public class GameLogic extends MovieClip {

 /**
 * Source: the path to the file containing our square symbol
 *     which must is relative to where this GameLogic.as file is located
 * Symbol: contains the name you've given the symbol when you chose to
 *    export it for actionscript
 * Public Var {name}: Finally we associate this symbol to a class named
 *    block. You can call your class whatever you want but you must have a
 *    different class name for each symbol you're embedding.
 **/
 [Embed(source='../graphics/assets.swf', symbol='squareBlock')] public var Square:Class;
 [Embed(source='../graphics/assets.swf', symbol='interfaceUI')] public var Interface:Class;

 public var block = new Square();
 public var ui = new Interface();
 public var score:int;

 /**
 * Default Constructor
 **/
 public function GameLogic()
 {
   score = 0;
 }

 public function run()
 {
   //add the user interface
   ui.x = 400;
   ui.y = 200;
   ui.btnReset.visible = false;
   ui.addEventListener(MouseEvent.CLICK, mouseClick);
   addChild(ui);

   //format the block if necessary
   block.alpha = Math.random();
   block.visible = true;
   block.x = 340;
   block.y = 150;
   block.alpha = 1;
   block.width = block.height = 34;
   block.name = "squareBlock";

   //you can even add event listeners to the embedded object
   block.addEventListener(MouseEvent.CLICK, mouseClick);

   //now display the block on the screen
   addChild(block);
 }

 private function mouseClick(e:Event)
 {
   switch (e.target.name)
   {
   /**
   * If they click on the block increase their score
   * and update the score text box in the embedded InterfaceUI object
   * then reset the block
   **/
   case "squareBlock":
   //check to see if the instructions are still up
   if (ui.instructions_txt.visible)
   {
     score = 0;
     ui.instructions_txt.visible = false;
     ui.btnStart.visible = false;
     ui.btnReset.visible = true;
     resetBlock();
    }
    //they are actively playing the game
    else
    {
      score++;
      ui.score_txt.text = score;
      resetBlock();
    }
    break;

    /**
    * If they hit the reset button on the ui screen
    * it will be caught here and restart the game
    **/
    case "btnReset":
    score = 0;
    ui.score_txt.text = score;
    resetBlock();
    break;

    /**
    * If they hit the start button or the instructions screen hide
    * the instructions screen and start the game
    **/
    case "btnStart":
    ui.instructions_txt.visible = false;
    ui.btnStart.visible = false;
    ui.btnReset.visible = true;
    resetBlock();
    break;
   }
 }

 /**
 * Purpose: scramble the blocks opacity, size and position
 **/
 private function resetBlock()
 {
   block.x = (Math.random() * 600);
   block.y = (Math.random() * 400);
   block.alpha = Math.random();
 }

 }
}

Troubleshooting &
Frequently Asked Questions

Why do I get Error #2044: Unhandled ioError?

You have the incorrect path to your assets.swf file. You must embed the files relative to where you’re using the [Embed] command. For this reason I typically include the assets in com.design1online.graphics folder which is only one level removed from my game logic folder.

Why do I get Unable to Transcode errors?

Sometimes Flash CS4 has a small memory leak and when you export your assets.fla file to get assets.swf it doesn’t show you the compiler errors. Other times your assets.swf file is corrupted. Regardless of which is happening you need to restart Flash and re-export your assets.fla to get a clean/uncorrupted assets.swf file.

Why does it say I’m missing something from the Flex SDK? I’m not using Flex.

Embedding is a part of the Flex SDK. Even if you aren’t using Flex you need to have the Flex SDK in your library path in order for embedding to work correctly.  Sometimes you’ll be prompted to add the correct application path when you save your main .fla file but you can always  add it manually by doing the following:

Go to Document > Preferences. Click on the Settings… button next to the Actionscript 3.0 in the flash version drop down box. Click on the Library path tab. Click on the plus sign at the bottom and add the following:

($AppConfig)/Actionscript 3.0/libs/flex_sdk_3/

I’ve embedded my symbol but it still doesn’t show up. What’s wrong?

  1. Check to make sure you have the correct path to your assets.swf file.
  2. Make sure you’re embedding a .swf file and not a .fla file.
  3. Make sure your symbol is visible. You can use instanceName.visible = true to force it to show up.
  4. Make sure your symbol is on a visible part of the stage. Try setting the x and y values to the middle of the stage.
  5. Make sure your symbol has a height and a width property. It may be showing up but it’s just not visible to the naked eye.
  6. Make sure your symbol has an alpha value higher than 0.
  7. Make sure you’re referencing the correct name in your symbol=”symbolNameHere”. In your assets.fla file make sure the symbol has symbolNameHere in the export link identifier. Otherwise you need to export your symbol for actionscript.

How do I make an embedded symbol publicly accessible to all functions in a class?

Once you embed the symbol you need to define a public variable that instantiates your symbols class. This instantiated variable will then be accessible to all class functions. For instance:

package.name.here {

  public class.name {

    [Embed(source='../graphics/assets.swf', symbol='squareBlock')] public var Square:Class;
    private var mySquare = new Square();

    //default constructor has access to mySquare
    public function class.name():void {

       var myNewSquare = new Square();

       addChild(mySquare);
       addChild(myNewSquare);

       resize(50);
    }

     //all other function also have access to mySquare
     private function resize(amount:int):void {
       mySquare.height += amount;
       mySquare.width += amount;

       /* this will not work, myNewSquare is out of scope
       myNewSquare.height += amount;
       myNewSquare.width += amount;
       */

       /* this will not work, Square is not instantiated, it's just a class definition
       Square.height += amount;
       Square.width += amount;
       */

    } //end resize
  } //end class
} //end package

Why do I get Class Is Not A Compiled Type errors?

Embedded symbols use a dynamic class, meaning the class is created at compile time. If you try to create a variable with a type of your symbol’s class name you’ll get an error. The way around that is to declare your variable without a type association. Then it can be dynamically bound.

For instance, this is incorrect:

package.name.here {

  public class.name {

    [Embed(source='../graphics/assets.swf', symbol='squareBlock')] public var Square:Class;
    private var mySquare:Square = new Square();

    //default constructor has access to mySquare
    public function class.name():void {
    }
  } //end class
} //end package

This is correct:

package.name.here {

  public class.name {

    [Embed(source='../graphics/assets.swf', symbol='squareBlock')] public var Square:Class;
    private var mySquare = new Square();

    //default constructor has access to mySquare
    public function class.name():void {
    }
  } //end class
} //end package

Do I need a new class name for every symbol I embed?

Yes. You’ll get  class definition conflicts if you try to give two embedded symbols the same class name.

How do I access symbols within my embedded symbol?

First take a look at the interface in the tutorial files. You’ll notice that it has several different symbols within it. Each of these symbols has been given an instance name in the assets.fla file while only the InstanceUI symbol is being exported to actionscript.

In order to access symbols within embedded symbols they must have an instance name. Then you can access them via dot syntax using their instance name.

package.name.here {

  public class.name {

    [Embed(source='../graphics/assets.swf', symbol='interfaceUI')] public var Interface:Class;
    private var ui = new Interface();

    //default constructor hides the reset button symbol inside of the embedded interface symbol
    public function class.name():void {
        /**
        * Notice that in assets.fla the reset button is not being
        * exported for actionscript. instead it has an instance
        * name of resetBtn
        **/
        ui.btnReset.visible = false;
    }
  } //end class
} //end package