Archive for category Flash

Sizing the buttons on the NumericStepper

So your working on a new RIA in Flash and you want to use the built in NumericStepper, or any other Flash component for that matter but you aren’t happy with the skin. You’ve already seen Customizing the NumericStepper component by Adobe and you’re ready to move past changing the color of the component and want to update the buttons. Every time I updated the component skin after it has been added to the Library in Flash and tested the Movie, the smaller button graphics I created get stretched and distorted. It was always 21 pixels wide and 12 pixels tall! The Adobe documentation on the NumericStepper didn’t provide any help in resizing these buttons that control the increase and decrease for the NumericStepper component.

What you need to do is open up the source and take a look to figure out what was going on. I found the source files here C:\Program Files (x86)\Adobe\Adobe Flash CS4\Common\Configuration\Component Source\ActionScript 3.0\User Interface\fl\controls\NumericStepper.as on my system. I found out what was going wrong by doing a quick search for that pesky 21 pixel width and found my answer starting on line 527.

527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
override protected function configUI():void {
	super.configUI();
 
	upArrow = new BaseButton();
	copyStylesToChild(upArrow, UP_ARROW_STYLES);
	upArrow.autoRepeat = true;
	upArrow.setSize(21, 12);
	upArrow.focusEnabled = false;
	addChild(upArrow);
 
	downArrow = new BaseButton();
	copyStylesToChild(downArrow, DOWN_ARROW_STYLES);
	downArrow.autoRepeat = true;
	downArrow.setSize(21, 12);
	downArrow.focusEnabled = false;
	addChild(downArrow);
 
	inputField = new TextInput();
	copyStylesToChild(inputField, TEXT_INPUT_STYLES);
	inputField.restrict = "0-9\\-\\.\\,";
	inputField.text = _value.toString();
	inputField.setSize(21, 24);
	inputField.focusTarget = this as IFocusManagerComponent;
	inputField.focusEnabled = false;
	inputField.addEventListener(FocusEvent.FOCUS_IN, passEvent);
	inputField.addEventListener(FocusEvent.FOCUS_OUT, passEvent);
	addChild(inputField);
 
	inputField.addEventListener(Event.CHANGE, onTextChange, false, 0, true);
	upArrow.addEventListener(ComponentEvent.BUTTON_DOWN, stepperPressHandler, false, 0, true);
	downArrow.addEventListener(ComponentEvent.BUTTON_DOWN, stepperPressHandler, false, 0, true);
}

Ah ha! They set the size of the buttons when the component is initialized on the stage. You can’t edit this file to solve your problem though you’ll need to extend the fl.controls.NumericStepper class and override the configUI function to change the size of your buttons. I suspect there are several other instances of hard-coded component sizes in the Flash component library but you just need to look to the source they provided to extend the components to your liking.

, , ,

No Comments

Blocking IP addresses by country on IIS shared hosting

On a shared hosting environment you often won’t have access to ban IP addresses on the IIS level and my shared host didn’t offer the Firewall module for Plesk so I had to come up with a programmatic way of blocking large blocks of IPs. You can setup in your web.config file something called a HTTPModule that works before the page is delivered to the client computer. For this sample I added a key and value to my web.config file that holds my comma separated IP list that I want to block. Since I’m running a site that is focused on the United States there isn’t much overlap on the /24 block area 255.255.255.* so I am only checking the first 3 digit blocks for matches. When a request comes in IpTwentyFourBlockingModule will check the users IP address against the key value blockiptwentyfour to see if there is a match and if it is a match will return 403 forbidden to the client browser, banned!

Coming up with a IP list is another problem. I found IP Location Tools that gives out an API that generates a updated list of IPs for a given country. The problem is the list gets broken out into IP blocks other than /24, you’ll see all ranges of IP blocks that get very complicated very fast and more than I wanted to try and pull off in a days work. I wrote a Flash ActionScript 3 application to consume this data and give me a list of unique IPs 255.255.255 that I could then drop in as the value for blockiptwentyfour. I then added IP tracking for new users and have had to ban some rogue /24 blocks that escaped this list but its kept them at bay and more manageable for now. I’ve already had a colleague suggest that this is still only a stopgap at best and I should develop some kind of throttling system to help prevent spam when I’m not around to watch the site like a hawk.

web.config

1
2
3
4
5
6
7
8
9
10
<configuration>
  <appSettings>
    <add key="blockiptwentyfour" value="41.210.29,41.210.28" />
  </appSettings>
  <system.web>
    <httpModules>
      <add name="IpTwentyFourBlockingModule" type="IpTwentyFourBlockingModule" />
    </httpModules>
  </system.web>
</configuration>

IpTwentyFourBlockingModule.cs – put this is in your App_Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#region Using
 
using System;
using System.Web;
using System.Configuration;
using System.Collections.Specialized;
 
#endregion
 
/// <summary>
/// Block the response to certain IP addresses
/// </summary>
public class IpTwentyFourBlockingModule : IHttpModule
{
 
    #region IHttpModule Members
 
    void IHttpModule.Dispose()
    {
        // Nothing to dispose; 
    }
 
    void IHttpModule.Init(HttpApplication context)
    {
        context.BeginRequest += new EventHandler(context_BeginRequest);
    }
 
    #endregion
 
    /// <summary>
    /// Checks the requesting IP address in the collection
    /// and block the response if it's on the list.
    /// </summary>
    private void context_BeginRequest(object sender, EventArgs e)
    {
        string ip = HttpContext.Current.Request.UserHostAddress;
        string[] tempIpArray = ip.Split('.');
        string iptwentyfour = tempIpArray[0] + "." + tempIpArray[1] + "." + tempIpArray[2];
 
        if (_IpAdresses.Contains(iptwentyfour))
        {
            HttpContext.Current.Response.StatusCode = 403;
            HttpContext.Current.Response.End();
        }
    }
 
    private static StringCollection _IpAdresses = FillBlockedIps();
 
    /// <summary>
    /// Retrieves the IP addresses from the web.config
    /// and adds them to a StringCollection.
    /// </summary>
    /// <returns>A StringCollection of IP addresses.</returns>
    private static StringCollection FillBlockedIps()
    {
        StringCollection col = new StringCollection();
        string raw = ConfigurationManager.AppSettings.Get("blockiptwentyfour");
 
        foreach (string ip in raw.Split(','))
        {
            col.Add(ip.Trim());
        }
 
        return col;
    }
}

collectipaddresses.as

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import flash.events.*;
import flash.net.*;
 
var myRequest:URLRequest = new URLRequest("http://iplocationtools.com/country_query.php?country=CI,SN,GH,NA,NG")
var loader:URLLoader = new URLLoader();
 
loader.dataFormat = URLLoaderDataFormat.TEXT;
loader.addEventListener(Event.COMPLETE, handleComplete);
loader.load(myRequest);
 
function handleComplete(event:Event):void
{
	var loader:URLLoader = URLLoader(event.target);
	//trace(loader.data.replace(/\n/g, "|"));
	var ipArray:Array = loader.data.replace(/\n/g, "|").split("|");
	trace(ipArray.length);
	setTwentyFourBlock(ipArray);
}
 
function setTwentyFourBlock(ipArray:Array)
{
    var	shortIpArray:Array = new Array();
 
	var	lastUniqueIp:String = "";
 
	for each(var ip:String in ipArray)
	{
		var tempIpArray:Array = ip.split(".");
		var stringCurrentIp:String = tempIpArray[0]+"."+tempIpArray[1]+"."+tempIpArray[2]+".0";
		if(stringCurrentIp != lastUniqueIp)
		{
			lastUniqueIp = stringCurrentIp;
			shortIpArray.push(stringCurrentIp);
		}
	}
 
	trace(shortIpArray.length);
	trace(shortIpArray.join(','));
}

All of this work has really kept my free online dating site almost spam free for now but I’m adding IP blocks I’ve missed from time to time.

, , , , ,

No Comments

Weddingtracker launched!

Weddingtracker launched on June 12th around 2:30PM CST and it has been about 8 long months of development and battle to get it out the door. With over 18,000 lines of code, over 400 files and 64mb in size this has been by far my most complicated Flash project ever. You can see the 13 template files in action on the Weddingtracker sample sites page. We did not design the sites so be sure to look past the front-end user interface when continuing through this post. I want to detail some of the finer points of the production and elements that I am happy with.

The entire project was coded using ActionScript 3.0 and the underlying framework that was used was PureMVC for Flash CS3. It was very stable once we got comfortable with working in its rather verbose arena. Each of the components that made up a users website existed in external files. Template layout, page type content, template colors, menu types, custom media display files and embedded font resource files. All of this makes for an extremely extensible code base that will allow for much more complicated designs without endangering the underlining controller code that sets up how the user interacts with the different pages.

All of the colors and text formatting are loaded in from CSS files that are defined in the initial XML file loading process. These CSS classes are accessed by the different page type controllers when they format themselves. Placeholder movieclips are used in the template resource files to define the location and size of the page type elements. The first class in the CSS files defines a list of used embedded font files required for accurate rendering. These font files are loaded from external SWF files and then registered to the Flash application for usage on embedded TextFields. Many of the ideas that made up this runtime font loader came from this post Runtime font loading with AS3 Flash CS3 not Flex.

I think that this code base is a great start to what could be an excellent product with some more attention to the design and user interface components. I expect to be working on it for the next couple of weeks for post launch issues and into the future when new templates are designed. All of the work over the last 8 months will be extremely helpful when it comes to fixing bugs or making improvements in the future.

I wanted to say thank you to everyone who helped code this impressive project and see it through launch. Susannah was with me in development from the very beginning and the project would not have launched without her help. Andres and Hal came in at the end of the project and worked two weekends in a row to get the template css and skin files setup for me while I finished the components and Susannah worked on custom template elements. I am already looking forward to my next major project but needed to reflect on over half a years work and a successful launch. Congratulations to everyone who worked on this project in the .NET development, all the HTML and CSS work and thank you to the IT project manager for being there from beginning to end of the marathon project.

No Comments