Page 1 of 2 12 Last
  • Jump to page:
    #1
  1. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Oct 2011
    Posts
    12
    Rep Power
    0

    Display GeoLocation with Flash/AS/Javascript?


    Hello,

    I am trying to make a flash movie display the Geo-location of the user (city and state), just like those JavaScripts that you see everywhere that say something like: "welcome to my page, from CITY NAME, STATE NAME."

    After much searching, I believe that I may have found a solution, but I do not know how to implement it. It requires the use of a ".as" file, which I have no idea what to do with. Here is where I am at:

    I am not allowed to post URLs, but you can google the phrase "flash geoip javascript" and it's the first link. -MaxMind GS WebService

    That URL shows the javascripts to use (which are easy enough to implement by themselves), but at the very bottom of that page is a link to an "ActionScript wrapper" which allegedly facilitates usage with Flash. I just don't know what do with with the "ActionScript wrapper" or where to go from here.

    I'm using Flash 8. Any help is very much appreciated! thanks!
  2. #2
  3. No Profile Picture
    Gotta get to the next screen..
    Devshed Supreme Being (6500+ posts)

    Join Date
    Nov 2003
    Location
    Legion of Dynamic Discord
    Posts
    6,678
    Rep Power
    3165
    Hi, I followed the trail and have the source file. To use it you will need to create three directories in the same one as the fla.
    • com
    • Then inside that: quilix
    • Then inside that: maxmind
    • Then move the GeoIP.as file into the "maxmind" directory from the last step.

    Now create a new fla file or use one you already have ready.

    It would be a good idea if you now open the GeoIP.as file by dragging it into the Flash window. It should open in a code view. That is because a .as file is just a plain text file used to hold ActionScript. Opening in the Flash IDE means you get indenting and syntax highlighting. If you look at the file you will see large blocks that are in grey. These are comments and if you read them you will see the author actually left examples of how to use the class.

    I took it upon myself to rewrite his class slightly to make it a bit easier for you to use. Open the GeoIP.as file and replace everything inside it with the following:
    Code:
    /**
     * Copyright (c) 2009 Rick Winscot www.quilix.com
     * Modified 9th Ocotober 2011 by Tann San to use new URL and remove dependance on flex SDK.
     *
     * 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.
     */
    package
       {
          import flash.events.Event;
          import flash.events.IOErrorEvent;
          import flash.events.SecurityErrorEvent;
          import flash.net.URLLoader;
          import flash.net.URLRequest;
    
          /**
          * Utility class used to geocode via captured IP address; a service provided
          * by MaxMind. If you use this... make sure to give them credit!
          *
          * @see http://www.maxmind.com
          *
          * @example Typical usage for the Maxmind GeoIP class.
          * <listing>
          *
          *
          * // Call into the static method with your result and fault handlers
          * GeoIP.getGeospatialInfos( handleResult, handleFault );
          *
          * private function handleResult( xml:XML ):void
          * {
          *     // Process XML result here...
          *     Trace( "Your Region: " + xml.geoip_region );
          * }
          *
          * private function handleFault():void
          * {
          *     // Some fault stuffs here...
          *     Trace("Maxmind not responding.");
          * }
          *
          * </listing>
          */
          public class GeoIP
             {
                /**
                * @private
                * Function reference passed by caller for result return.
                */
                private static var _resultCallback:Function = null;
    
                /**
                * @private
                * Function reference passed by called for fault return.
                */
                private static var _faultCallback:Function = null;
    
                /**
                * Provides geospatial information (geocode-by-IP) for HTTP traffic. A result
                * or fault is passed back the caller.
                *
                * @param rr <code>Function</code> provided by the caller that will be used
                * as a result handler.
                *
                * @param rf <code>Function</code> provided by the caller that will be used
                * as a fault handler.
                */
                public static function getGeospatialInfos( rr:Function, rf:Function = null ):void
                {
                   _resultCallback = rr;
                   _faultCallback = rf;
    
                   var url:String = "http://www.maxmind.com/app/geoip.js";
                   var req:URLRequest = new URLRequest( url );
                   var loader:URLLoader = new URLLoader( req );
    
                   loader.addEventListener( Event.COMPLETE, handleRegionInfosLoaded, false, 0, true );
                   loader.addEventListener(IOErrorEvent.IO_ERROR, handleRegionInfosIOError, false, 0, true );
                   loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, handleRegionInfosSecurityError, false, 0, true );
                }
    
                /**
                * @private
                *
                * MaxMind provides a great service for geocoding by ip. They do
                * this by dynamically generating JavaScript for remote execution.
                *
                * Hitting this url...
                * http://j.maxmind.com/app/geoip.js
                *
                * Produces something like this in a browser window...
                *
                * function geoip_country_code() { return 'US'; }
                * function geoip_country_name() { return 'United States'; }
                * function geoip_city()         { return 'State College'; }
                * function geoip_region()       { return 'PA'; }
                * function geoip_region_name()  { return 'Pennsylvania'; }
                * function geoip_latitude()     { return '40.7912'; }
                * function geoip_longitude()    { return '-77.8746'; }
                * function geoip_postal_code()  { return '16802'; }
                *
                * ...which can open a sandbox can of worms if you are going to try
                * remote JavaScript execution. If only this service returned XML!
                *
                * MaxMind already has a crossdomain.xml in place.
                *
                * http://j.maxmind.com/crossdomain.xml
                *
                * So, use a loader to retrieve the JavaScript as text. Given the fact
                * that the JavaScript is dynamically generated and that this is an
                * established API... it should be safe to use string replacement to
                * convert the output to XML. My approach yields the following results.
                *
                * <maxmind>
                * 	  <geoip_country_code value="US"/>
                * 	  <geoip_country_name value="United States"/>
                * 	  <geoip_city value="State College"/>
                * 	  <geoip_region value="PA"/>
                * 	  <geoip_region_name value="Pennsylvania"/>
                * 	  <geoip_latitude value="40.7912"/>
                * 	  <geoip_longitude value="-77.8746"/>
                * 	  <geoip_postal_code value="16802"/>
                * 	</maxmind>
                */
                private static function handleRegionInfosLoaded( event:Event ):void
                   {
                      event.target.removeEventListener( Event.COMPLETE, handleRegionInfosLoaded );
                      event.target.removeEventListener( IOErrorEvent.IO_ERROR, handleRegionInfosIOError );
                      event.target.removeEventListener( SecurityErrorEvent.SECURITY_ERROR, handleRegionInfosSecurityError );
    
                      var result:String = event.target.data as String;
                      var rxp:RegExp = new RegExp( "g" );
                      result = result.replace( new RegExp( "{ return ", "g" ), "value=" );
                      result = result.replace( new RegExp( "function ", "g" ), "<" );
                      result = result.replace( new RegExp( "; }", "g" ), "/>" );
                      result = result.replace( /\(/g, "" );
                      result = result.replace( /\)/g, "" );
                      result = "<maxmind>" + result + "</maxmind>";
    
                      var xml:XML = new XML( result );
    
                      if ( _resultCallback != null )
                         _resultCallback( xml );
                   }
    
                /**
                * @private
                * Give Mr. Scrooge a stale bisquit.
                */
                private static function handleRegionInfosIOError( event:IOErrorEvent ):void
                   {
                      event.target.removeEventListener( Event.COMPLETE, handleRegionInfosLoaded );
                      event.target.removeEventListener( IOErrorEvent.IO_ERROR, handleRegionInfosIOError );
                      event.target.removeEventListener( SecurityErrorEvent.SECURITY_ERROR, handleRegionInfosSecurityError );
    
                      if ( _faultCallback != null )
                         _faultCallback(event.toString());
                   }
    
                /**
                * @private
                * Give Mr. Scrooge a stale bisquit.
                */
                private static function handleRegionInfosSecurityError( event:SecurityErrorEvent ):void
                   {
                      event.target.removeEventListener( Event.COMPLETE, handleRegionInfosLoaded );
                      event.target.removeEventListener( IOErrorEvent.IO_ERROR, handleRegionInfosIOError );
                      event.target.removeEventListener( SecurityErrorEvent.SECURITY_ERROR, handleRegionInfosSecurityError );
    
                      if ( _faultCallback != null )
                         _faultCallback(event.toString());
                   }
             }
       }
    Now, to use the class you would copy and paste the following code onto the ActionScript tab of a keyframe in an fla file:
    Code:
    import com.quilix.maxmind.GeoIP;
    
    GeoIP.getGeospatialInfos( handleResult, handleFault );
     
    function handleResult( xml:XML ):void
       {
          // Process XML result here...
          trace("Your Region:\n" + xml.toXMLString() );
       }
     
    function handleFault(message:String):void
       {
          // Some fault stuffs here...
          trace(message);
       }
    Last edited by Tann San; October 9th, 2011 at 01:04 PM.
    Quis custodiet ipsos custodes?
  4. #3
  5. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Oct 2011
    Posts
    12
    Rep Power
    0
    Hey Tann,

    Thanks VERY much for your help, I can tell you spent a bit of time on that.. but it seems there is still a piece of the puzzle missing for me.

    I have created the directory structure like you have suggested, and placed your modified GeoIP.as class file in the appropriate folder. I placed your other bit of code in the ActionScript tab of a keyframe as you described.

    When I try to test the movie online, it is blank. It seems like there should be some kind of text field (dynamic?) on the stage of my FLA somewhere, in which the output (city and state) text would appear.. possibly labeled with a certain instance name that I should use..?

    Also, there was 17 errors in my Flash8 output when publishing the FLA with the new script in the keyframe. Not sure if that matters or not..

    And I really did try to read the grey blocks of the author's comments and "examples" on using the class before posting.. it is a bit above my current skill set, though. He may as well have been speaking Martian. beep bop boop..
  6. #4
  7. No Profile Picture
    Gotta get to the next screen..
    Devshed Supreme Being (6500+ posts)

    Join Date
    Nov 2003
    Location
    Legion of Dynamic Discord
    Posts
    6,678
    Rep Power
    3165
    You don't need a text field on the stage. The trace command will output messages to the output window directly. I would say the reason it is not doing that is because of all the errors you are getting. Post the errors or one of them if they all seem the same.
    Quis custodiet ipsos custodes?
  8. #5
  9. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Oct 2011
    Posts
    12
    Rep Power
    0
    **Error** C:\Documents and Settings\user\Desktop\geotest\com\quilix\maxmind\GeoIP.as: Line 24: ActionScript 2.0 class scripts may only define class or interface constructs.
    {

    **Error** C:\Documents and Settings\user\Desktop\geotest\com\quilix\maxmind\GeoIP.as: Line 58: Attribute used outside class.
    public class GeoIP

    **Error** C:\Documents and Settings\user\Desktop\geotest\com\quilix\maxmind\GeoIP.as: Line 59: The class being compiled, 'GeoIP', does not match the class that was imported, 'com.quilix.maxmind.GeoIP'.
    {

    **Error** C:\Documents and Settings\user\Desktop\geotest\com\quilix\maxmind\GeoIP.as: Line 82: ')' or ',' expected
    public static function getGeospatialInfos( rr:Function, rf:Function = null ):void

    **Error** C:\Documents and Settings\user\Desktop\geotest\com\quilix\maxmind\GeoIP.as: Line 88: The class or interface 'flash.net.URLRequest' could not be loaded.
    var req:URLRequest = new URLRequest( url );

    **Error** C:\Documents and Settings\user\Desktop\geotest\com\quilix\maxmind\GeoIP.as: Line 89: The class or interface 'flash.net.URLLoader' could not be loaded.
    var loader:URLLoader = new URLLoader( req );

    **Error** C:\Documents and Settings\user\Desktop\geotest\com\quilix\maxmind\GeoIP.as: Line 139: The class or interface 'flash.events.Event' could not be loaded.
    private static function handleRegionInfosLoaded( event:Event ):void

    **Error** C:\Documents and Settings\user\Desktop\geotest\com\quilix\maxmind\GeoIP.as: Line 145: Syntax error.
    var result:String = event.target.data as String;

    **Error** C:\Documents and Settings\user\Desktop\geotest\com\quilix\maxmind\GeoIP.as: Line 146: The class or interface 'RegExp' could not be loaded.
    var rxp:RegExp = new RegExp( "g" );

    **Error** C:\Documents and Settings\user\Desktop\geotest\com\quilix\maxmind\GeoIP.as: Line 150: Operator '=' must be followed by an operand
    result = result.replace( /\(/g, "" );

    **Error** C:\Documents and Settings\user\Desktop\geotest\com\quilix\maxmind\GeoIP.as: Line 151: Operator '=' must be followed by an operand
    result = result.replace( /\)/g, "" );

    **Error** C:\Documents and Settings\user\Desktop\geotest\com\quilix\maxmind\GeoIP.as: Line 164: The class or interface 'flash.events.IOErrorEvent' could not be loaded.
    private static function handleRegionInfosIOError( event:IOErrorEvent ):void

    **Error** C:\Documents and Settings\user\Desktop\geotest\com\quilix\maxmind\GeoIP.as: Line 178: The class or interface 'flash.events.SecurityErrorEvent' could not be loaded.
    private static function handleRegionInfosSecurityError( event:SecurityErrorEvent ):void

    **Error** C:\Documents and Settings\user\Desktop\geotest\com\quilix\maxmind\GeoIP.as: Line 83: This statement is not permitted in a class definition.
    {

    **Error** C:\Documents and Settings\user\Desktop\geotest\com\quilix\maxmind\GeoIP.as: Line 188: ActionScript 2.0 class scripts may only define class or interface constructs.
    }

    **Error** Scene=Scene 1, layer=Layer 1, frame=1:Line 5: A type identifier is expected after the ':'.
    function handleResult( xml:XML ):void

    **Error** Scene=Scene 1, layer=Layer 1, frame=1:Line 11: A type identifier is expected after the ':'.
    function handleFault(message:String):void

    Total ActionScript Errors: 17 Reported Errors: 17



    It is being published using ActionScript 2.0, if that helps any.
    thanks again!
  10. #6
  11. No Profile Picture
    Gotta get to the next screen..
    Devshed Supreme Being (6500+ posts)

    Join Date
    Nov 2003
    Location
    Legion of Dynamic Discord
    Posts
    6,678
    Rep Power
    3165
    The file you linked to is an ActionScript 3 file and the error message you posted indicates you have the project set to use ActionScript 2. Easy to change:

    File->Publish Settings->Flash (tab)

    There should be an ActionScript dropdown. Change this from ActionScript 2 to 3 and then try to publish again.
    Quis custodiet ipsos custodes?
  12. #7
  13. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Oct 2011
    Posts
    12
    Rep Power
    0
    My version of Flash 8 only has options for ActionScript1 or ActionScript2. There is no option to publish in ActionScript 3.
  14. #8
  15. No Profile Picture
    Gotta get to the next screen..
    Devshed Supreme Being (6500+ posts)

    Join Date
    Nov 2003
    Location
    Legion of Dynamic Discord
    Posts
    6,678
    Rep Power
    3165
    ah, well, kinda screwed then! You could port it all over to the ActionScript 2 equivalents and see how that works out. You can stop using the external .as file for now as we will be writing new code and you might as well just do it in ActionScript panel directly. Even though we're not using the external AS file anymore we will still be doing the same process:
    • Calling the remote script which generates a file with all the geo IP data in it.
    • That file is a dynamically generated JavaScript file. It contains 6 functions, each one simply returning the value such as City, Country etc.
    • We then need to parse that data into a nice XML structure we can use.

    In the external file they use an URLLoader instance to load the remote JavaScript file. URLLoader does not exist in ActionScript 2 but you could use the XML class which does something similar. You can read about how to use that here.

    Also, there is no regex support in AS2 but we can get around that by just using some String parsing functions.

    One thing we do have to do with the XML class is listen for two events. The first is the onData event. This happens when the external data has been read in but is still just seen as a raw string. Internally, that string is then parsed into a proper XML object. Then the onLoad event is fired and we read that XML object. We need to hijack the onData event and do our own parsing as the external file is not an XML file.

    Sounds tricky but it's not reallly. I was just going to give you a few snippets but then I ended up writing it all anyhow. This does what the AS3 version does.

    Copy and paste this into the ActionScript 2 panel of your file. Replace the code we had there from before.
    Code:
    var info_xml = new XML();
    info_xml.onData = function(raw:String)
       {
          if (raw == undefined)
             {
                this.onLoad(false);
             }
          else
             {
                // Normally onData would just do this:
                // this.parseXML(raw);
                // But we need to replace that with our own parsing:
    		  
                // This is the start of the fake XML string we are going to be making up.
                var parsed:String = "<maxmind>\n";		  
    		  
                // Split each of the "function" lines into it's own string.  
                var lines:Array = raw.split("\n");
    		  
                // Remove the last one because that is a blank line.
                lines.pop();
    		  
                // Replace all the Regex functions from the external class since the Regex class does not exist in AS2.
                // All we're doing is chopping out two parts of each string and creating a fake XML node.
                // We cut the function name and make that into the XML node name, then we cut the returned value and set that to be the nodes "value".
                for(var i:Number = 0; i < lines.length; i++)
                   {
                      parsed += "   <" + lines[i].slice(9, lines[i].indexOf("()")) + " value=\"" + lines[i].slice(lines[i].indexOf("'") + 1, lines[i].lastIndexOf("'")) + "\" />\n";
                   }
    		  
                // Now parse the string into a true XML object.
                this.parseXML(parsed + "</maxmind>");
    				  
                // Back to normal loading.
                this.loaded = true;
                this.onLoad(true);
             }
       }
    
    info_xml.onLoad = function(success:Boolean)
       {
          if (success)
             {
                trace('Remote File Loaded.  Contents are:\n' + this.toString());
             }
          else
             {
                trace("There was a problem loading the remote file.");         
             }
       };
    
    info_xml.load('http://www.maxmind.com/app/geoip.js');
    Quis custodiet ipsos custodes?
  16. #9
  17. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Oct 2011
    Posts
    12
    Rep Power
    0
    OK, I now have removed the entire directory structure that we were using for the class file. I created a new FLA with ONLY the new code you listed in your last post in the first (and only) keyframe of my movie.

    There were no errors while publishing.

    When trying to load it online, it seems to get stuck, saying "transferring data from maxmind..." in the status bar. It seems like it's trying, but it never displays anything.


    thanks again for all your help!
  18. #10
  19. No Profile Picture
    Gotta get to the next screen..
    Devshed Supreme Being (6500+ posts)

    Join Date
    Nov 2003
    Location
    Legion of Dynamic Discord
    Posts
    6,678
    Rep Power
    3165
    It works for me. It probably won't work if you just try and run the html file on your local machine as the Flash player will be in the wrong security sandbox for it to work. If you pick a Windows or Mac projector file in the publish settings and try that locally it should work. Also, the html+swf should work when uploaded to a web server. I just did it as a test and it works for me. I added a textfield to the stage and changed the trace statements so they write to that instead of the output panel so I could see what is going on.

    I recommend you do the same so you can actually see what is happening under the hood. The trace statements won't show up when you are using it in the browser (unless you install the debug flash player plugin).

    Another way to test it out is to use a HTTP sniffer like Fiddler. That will let you see what is happening in the background between your file and the remote server.
    Quis custodiet ipsos custodes?
  20. #11
  21. No Profile Picture
    Gotta get to the next screen..
    Devshed Supreme Being (6500+ posts)

    Join Date
    Nov 2003
    Location
    Legion of Dynamic Discord
    Posts
    6,678
    Rep Power
    3165
    Also, remember that you are relying on a third party service "maxmind.com" so if they change the JS code you are pulling then you will have to change your code to match. Also, if their service goes down then your app will also no longer function. If this was a commercial product I would say don't worry about it but since it appears to be a free service, well, it's up to them then.
    Quis custodiet ipsos custodes?
  22. #12
  23. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Oct 2011
    Posts
    12
    Rep Power
    0
    Hmm I started from scratch and tried again, and it still doesn't work; same result as before. The status bar gets stuck saying "transferring data from maxmind..". The movie seems to load ok.

    What I did:

    1. Create new FLA
    2. Click on frame1 and paste your latest bit of code in the scripting area.
    2. Save and publish to html and SWF.
    3. Put both files online and test HTML.
    4. movie appears, but no region info.

    Yeah, I'm testing online live on my liquidweb VPS. I would PM you the URL if you would like, but I would rather not post it publicly.

    I don't know how to change the trace statements to write to a text field, although that sounds like what I was originally trying to do.

    I have not tried using "Fiddler" yet, but I may give it a go..
  24. #13
  25. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Oct 2011
    Posts
    12
    Rep Power
    0
    Is there anything at all on the stage of your movie? I don't understand how the output text is supposed to be displayed on the stage. With no text field, and only that bit of code you supplied, how will it know where on the stage to put it, or what font/font color/size?
  26. #14
  27. No Profile Picture
    Gotta get to the next screen..
    Devshed Supreme Being (6500+ posts)

    Join Date
    Nov 2003
    Location
    Legion of Dynamic Discord
    Posts
    6,678
    Rep Power
    3165
    Yes, that's what I (clearly badly) explained in the last post. For testing online you would have to create a text field on the stage to output the text to, otherwise you would not know if it worked or not.

    I created a TextField on the stage that took up most of the viewing area. I set it to be a "Dynamic Text" type of textfield and gave it the Instance Name of tf_debug.

    Then I changed the onLoad event handler to use that instead of the traces:
    Code:
    info_xml.onLoad = function(success:Boolean)
       {
          if (success)
             {
                _root.tf_debug.text += 'Remote File Loaded.  Contents are:\n' + this.toString() + "\n";
             }
          else
             {
                _root.tf_debug.text += "There was a problem loading the remote file.\n";         
             }
       };
    Quis custodiet ipsos custodes?
  28. #15
  29. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Oct 2011
    Posts
    12
    Rep Power
    0
    Super awesome! It works now

    I don't suppose I could bother you one more time to ask how to display only a couple of the final output values, instead of the entire code-looking output.

    For example, I would like my visitors to just see the nice pretty output of "CITY NAME", and "STATE NAME".. instead of "geoip_city value="CITY NAME", with all of that code-looking gobbledy-gook.

    I tried to give you Rep, but it says I have 0 rep to give.. sorry, but feel free to point me to your paypal "buy me a beer" button, or whatever.

    thanks again!
Page 1 of 2 12 Last
  • Jump to page:

IMN logo majestic logo threadwatch logo seochat tools logo