JSFL Changes to selection Array Don’t Prompt for Save

When you use JSFL to do something to the selection array, such as

MMExecute("fl.getDocumentDOM().selection[0].x += 50;");

If that’s all you do, saving flash then closing the file won’t keep your changes.
However, modifying objects on stage using things other than selection can provoke a change.

MMExecute("fl.getDocumentDOM().moveSelectionBy({x:0, y:0})");

Is an excellent workaround originally posted at kirupa

Refresh Music Library on Android Phones

I know what you’re thinking, “I just downloaded a new mp3 audiobook and I want to listen to it!” Well, let me tell you, I know it’s there, you know it’s there, but does the music player? No. Even stopping the service doesn’t help. What does help?

Open Settings
Go to SD card & phone storage
Unmount the SD Card
Re-mount the SD card
Re-open music

This should do it

SayMedia is Hiring

My job is an amazing place to work. We build online advertising and much of the problems I’ve posted about here are the result of my work at Say Media. We’re using Javascript, PHP, and Actionscript to produce a fast, stable, simple UI system that couples to a backend produced by Hadoop and Hive, Perl, Python and Django. Our daily problems range from dealing with scale (billions of viewers) to usability.

As a company, we’re still growing by leaps and bounds, but have good people at the helm. I can’t think of another job I’ve enjoyed more from the technical aspects, and the people here are the best I’ve ever worked with.

Send me your resume and I’ll do my best to get you an interview.

For our list of jobs, check out http://saymedia.com/jobs.php

PHP DateTime and NOW() vs UTC_TIMESTAMP()

In a previous post, I complained about the lack of connection of dates from AS3 to PHP. This is partially due to incompatible formats, but also may have had something to do with server vs. local time.

AS3 always returns the local time of the user. PHP always returns the local time of the server. This can cause all sorts of problems when using mysql to bridge the two. The obvious solutions are to have your computers in the same time zone OR to use unix epoch time.

I’ve always used NOW() as a mysql system to add the date, but this provides local server time.

UTC_TIMESTAMP() instead provides the GMT time, which is what Unix epoch time is based upon. This should be more consistent and more easily converted.

Keep in mind, however, that storing a unix timestamp in an int field is still a bit more simple to understand, easier to sort, and just as easy to convert.

CS5 Classic Dynamic TextField Font Embedding

Here’s the concept:
In a file that’s publishing to Flash 9, create a textfield, give it an instance name of “tf1″, set the font to comic sans, and make it dynamic.
In the actionscript, do the following:

tf1.text = "this text is normal";
tf1.rotation = 30;

when you compile, you should get an error like
Fonts should be embedded for any text that may be edited at runtime, other than text with the "Use Device Fonts" setting. Use the Text > Font Embedding command to embed fonts.
This is solved by embedding the fonts, but when you’ve got one font with multiple states, things get a little weird.
Duplicate your textfield and set the instance name to tf2
Set the font to comic sans bold
Click the Embed button. Comic Sans Bold will be added. Choose the typical settings for embedding, Upper, Lower, Numbers, Punctuation and hit ok.
Click your other textfield and hit Embed. The second font, Comic Sans Regular will be added. Choose the typical settings for embedding, Upper, Lower, Numbers, Punctuation and hit ok.
Set your actionscript to

tf1.text = "this text is normal";
tf1.rotation = 30;
tf2.text = "this text is bold";
tf2.rotation = 30;

An odd thing happens. Whichever font we embedded first seems to be the only one that’s used. This is fixed in one of two ways:

Okay way:
Use htmlText with italic and bold indicators to produce the effect you want.

tf1.text = "this text is normal";
tf1.rotation = 30;
tf2.htmlText = "<b>this text is bold</b>";
tf2.rotation = 30;

Better way:
use getTextFormat and setTextFormat

var format:TextFormat = tf1.getTextFormat();
tf1.text = "this text is normal";
tf1.setTextFormat(format);
tf1.rotation = 30;
format = tf2.getTextFormat();
tf2.text = "this text is bold";
tf2.setTextFormat(format);
tf2.rotation = 30;

this can also be done more dynamically using functions:

function setText(txt, val)
{
	var format:TextFormat = txt.getTextFormat();
	txt.text = val;
	txt.setTextFormat(format);
}
setText(tf1, "this text is normal");
setText(tf2, "this text is bold");
tf1.rotation=30;
tf2.rotation=30;

cs5_font_embedding.fla

Remove Unnecessary PHP GET Variables

When building PHP forms, I often use fields to produce my get vars. Some forms don’t need all of the fields filled in, and when that happens, you get a lot of empty variables that don’t mean anything. If you’re providing a URL that people will want to copy and paste, removing those extra variables can make your URLs look a LOT cleaner. Here’s a really simple way to do that in PHP.

I’ve also included an example of how to remove default vars as well. I’ve assumed you have a GET var called myvar and the defaultvalue is “default”

<?php
//First, we get the main URL of the page, without the get vars
$mainurl = "http://".$_SERVER['SERVER_NAME'];
//set up an empty var for vars
$vars="";
//we assume no changes need to be made until we see any
$change=false;
//for each get var
foreach($_GET AS $key => $value)
{
	//if it's not something we've set as a default and it's not empty
	if($value!=""&&!($key=="myvar"&&$value=="default"))
	{
		//if it's the first one
		if($vars == "")
		{
			$vars .= "?";
		}
		else
		{
			$vars .= "&";
		}
		//attach the var to the end again
		$vars.="$key=$value";
	}
	else
	{
		//if something existed before and is left out now, 
		//we mark this as changed and reload the page with 
		//the new headers
		$change=true;
	}
}
 
if($change)
{
	//reload the page with the new location, nice and clean. 
	header("Location: " . $mainurl.$vars);
}
else
{
	//include the main file
	include("main.php");
}
?>

PHP and SSH and SCP – exec, backtics, popen, or proc_open

I can SSH into a server using an ssh key I was given. It’s pretty simple, I just open a terminal and type in

ssh -i key.ssh me@myserver.com cms

and then it opens up like it’s a local box. I can mkdir, rm, and cp all I want. The problem is, what if I want to do similar functionality in PHP? There’s at least 4 ways to execute a command, but while some of them will work for some things, I’ve only succeeded in calling ssh one way. Here’s what I’ve learned.
SCP
Using backtics seems like the simplest solution and seems to work fine.

$scp = "scp -i key.ssh";
$scp .= "sourcefile.zip ";
$scp .= "me@myserver.com:/www/export/destfile.zip";
$scp_exec = `$scp`;

using ` around your command causes it to execute.

SSH
There’s only one way I’ve actually succeeded in running SSH commands on my server. There’s plenty of blog posts out there about how you might do it, but ultimately, they’re vague or incomplete. I hope this helps someone.

//build the array that indicates which part of the call does what
$descriptorspec = array(
0 => array("pipe", "r"), // stdin is a pipe that the child will read
1 => array("pipe", "w"), // stdout is a pipe that the child will write
2 => array("pipe", "w") // stderr is a pipe that the child will write
);
$mkdir = "ssh -i key.ssh me@myserver.com 'mkdir -v www/export/newfolder'"';
$mkdir_handler = proc_open($mkdir, $descriptorspec, $pipes);
$mkdir_write = stream_get_contents($pipes[1]);
$mkdir_result = "mkdir result: \n" . $pipes[1];
proc_close($mkdir_handler);

As far as I know, the ssh call is only executed when stream_get_contents is called. The result of this call is placed into the pipes array in the 1th item. Don’t forget to close your session!

‘$var’ won’t resolve in single quotes

Ahh the little nuances of PHP. The more I use it, the more I wonder who decided some of these “features” were a good idea.
Usually you can evaluate variables in your strings in the following way:

$years = 15;
echo "I am $years years old.";
//produces: I am 15 years old.

but the moment you do this, it fails:

$years = 15;
echo 'I am $years years old.';
//produces: I am $years years old.

See the difference? One uses ‘ and one uses ” to create the string.

My friend Steve just informed me that this also does fun things with escape characters like
“\n” and ‘\n’
but apparently if you don’t need the extra happy usefulness of double quotes, single quotes are faster.

Using Flash’s Date Class in AMF PHP to MySQL

So you’re trying to rectify your dates, eh? Here’s a little funbit. If you want to take a Flash Date, transfer it to AMF, convert it to a PHP date, then insert that into a MySQL database as a DATETIME, you’re in for one hell of a headache. How does flash store it’s date class anyway? How can PHP read it? What about that whole milliseconds to seconds thing? No worries, my friends, I have a solutions for you.

Actionscript:

var d:Date = new Date()

This creates a new date. This can then be passed to AMF using whatever means you feel work best. I’m using a codeigniter port with AMF as the model that was built by my pal, Steve.

PHP to make a DATE in MySQL:
I have passed in an FP object that contains my Date object.

$date = $fp['d']/1000;
$date = date("Y-m-d","$date");

This will output your date as something like 2010-10-18. You can modify the output to be anything you like, such as:
How does it work? Flash automatically encodes Dates as the number of milliseconds since the Unix Epoch. This means that to convert it to the typical date structure in PHP, you have to convert it to seconds, which involves division by 1000. From there we can turn it into a date, but it has to be turned into a string, hence the quotes.

$date = $fp['d']/1000;
$date = date("Y-m-d H:i:s","$date");

This would give you something like 2010-10-18 15:45:30
This number can be used to insert into or compare against MySQL DATETIME entries.

fl.browseForFileURL won’t work across hard drives

In JSFL, when you use fl.browseForFileURL it returns a URI pointing to the file or folder you’ve chosen. On OX, however, the reference is wrong when you choose a file on a hard drive other than your primary.

Example: I have a hard drive on my mac named HD2. If I browse to a file on there, the URI returned will be

file:///HD2/myFile.txt

If you then immediately try a

FLfile.exists('file:///HD2/myFile.txt')

it returns false. This is due to OSX’s referencing system. the correct location is

file:///Volumes/HD2/myFile.txt

so all we have to do is add the word “Volumes/” to the string and the reference will be correct.

public static function browseForFileURI( title:String = "", type:String = "open" ):String
{
   var ar:Array = MMExecute( "fl.browseForFileURL('" + type + "','" + title + "');" ).split("/");
   ar[2] = "/Volumes";
   return ar.join("/");
}