Runtime Font Embedding in AS3. There is no need to embed the entire fontset anymore.
Well, pulled a few more hairs out today. Hard to believe I have any left. I am working on a multi-lingual application that needs embeded fonts. As most of you know, loading every character in a given fontset equates to one big ass swf. For example, if you want to embed a regular and bold Japanese font you’re looking at approx. 13 megs, and depending on the quality of the font you could be close to 20 megs. That’s a lot of font. In an ideal world the Flash Player would allow for dynamic runtime shared font libraries that allow for only a subset of characters to be embeded.
In AS2 there were a few ways (hacks) to load font libraries at runtime. Unfortunately none of the AS2 hacks work in Flash CS3 using AS3. However, there is an answer. In Flex you can embed fonts at compile time using the [Embed] metadata tag in your Actionscript. And the best part is you can use the unicodeRange attribute to define a subset of characters you want to embed. Below is a class I created that compiles a swf that contains all Latin I characters in the Arial font.
package {
import flash.display.Sprite;
public class _Arial extends Sprite {
[Embed(source='C:/WINDOWS/Fonts/ARIAL.TTF', fontName='_Arial', unicodeRange='U+0020-U+002F,U+0030-U+0039,U+003A-U+0040,U+0041-U+005A,U+005B-U+0060,U+0061-U+007A,U+007B-U+007E')]
public static var _Arial:Class;
}
}
A couple things to point out here. The fontName attribute value can not be the same name as a device font. If I were to change my code to use fontName=’Arial’ the compiler throws the following warning “the embedded font ‘Arial’ may shadow a device font of the same name. Use fontName to alias the font to a different name”. To get around this I simply added an underscore before the name. From this point on you must reference the _Arial in your TextFormats or CSS. Now if you compile that it will create a swf named _Arial.swf.
Ok, great, now what? Well, now you have to load the font into the application. Here is a sample class that loads in the font and displays some rotated text just to prove that it is embeded.
package {
import flash.display.Loader;
import flash.display.Sprite;
import flash.events.Event;
import flash.net.URLRequest;
import flash.text.*;
public class FontLoader extends Sprite {
public function FontLoader() {
loadFont("_Arial.swf");
}
private function loadFont(url:String):void {
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, fontLoaded);
loader.load(new URLRequest(url));
}
private function fontLoaded(event:Event):void {
var FontLibrary:Class = event.target.applicationDomain.getDefinition("_Arial") as Class;
Font.registerFont(FontLibrary._Arial);
drawText();
}
public function drawText():void {
var tf:TextField = new TextField();
tf.defaultTextFormat = new TextFormat("_Arial", 16, 0);
tf.embedFonts = true;
tf.antiAliasType = AntiAliasType.ADVANCED;
tf.autoSize = TextFieldAutoSize.LEFT;
tf.border = true;
tf.text = "Scott was here\nScott was here too\nblah scott...:;*&^% ";
tf.rotation = 15;
addChild(tf);
}
}
}
And there you have it. Run time embeded fonts. The key lines to look at here are
var FontLibrary:Class = event.target.applicationDomain.getDefinition("_Arial") as Class;
The getDefinition method returns a reference to the _Arial class loaded in through the swf (event.target). The next line:
Font.registerFont(FontLibrary._Arial);
registers the loaded in _Arial font in the global font list. If you were to trace out the results of Font.enumerateFonts() you will now see _Arial at the top of the list.
Now lets say your site was in a few different languages you may add the following line to the FontLoader constructor to load language specific fonts at runtime.
public function FontLoader() {
var langManager:LanguageManager = LanguageManager.getInstance();
var langID:String = langManager.getLanguageCode(); //returns jp
loadFont(langID + "_Arial.swf");
}
Instead of loading in _Arial.swf the application will load in jp_Arial.swf. jp_Arial.swf would be another generated font swf like the _Arial example above but this time the unicodeRange would only include the Japanese fonts you need. All you have to do now is create a CSS file and fonts for each language, store the proper language code somewhere within the application and use that language code when loading your CSS files and fonts.
You may not know this but Adobe has supplied us with sample unicodeRanges in the following file “\Applications\Adobe\Flex Builder 2\Flex SDK 2\frameworks\flash-unicode-table.xml”. You can either use one of the supplied ranges or create your own. You may only need to embed a few characters, if so just list the unicode values of the characters you want each seperated by a comma.
Sounds pretty straight forward eh? Or is it????
In doing this I ran into a huge bug using Flex Builder to generate the font swfs. When I was experimenting with the unicodeRanges my compiled versions did not contain the proper character ranges that I specified. For example I would define a range that only contained Uppercase characters. In my test font loading app I would only see numbers. Only if I removed the unicodeRange attribute would I see all my characters. This led me to believe that Adobe had documented something that really wasn’t part of the compiler. I tried deleting files, I was checking timestamps, nothing. Then I tried to clean my project before compiling (In FlexBuilder select Project > Clean). It worked! The subset of characters I defined in my unicodeRange only loaded into my test app. YAY! Then I tried switching the unicodeRange again. DOH! nothing. Cleaned project again and BINGO!
Lesson learned: Whenever you change your unicodeRange clean your project before you compile or else your change may not be compiled properly.
I haven’t tried this in Flex 3 yet to see if the bug has been addressed. I did look at the Flex 3 bug system and didn’t see it listed. Either it has been fixed or no one has run into this issue yet. It is pretty obscure I guess.
64 Responses so far
xmpcray
June 18th, 2007
8:51 pm
Interesting, I am working on a similar app and will try this.
Can you point to similar hack(?!) for AS2…?
Cheers!
Scott
June 18th, 2007
8:52 pm
http://sharedfonts.com/eng/index.html
is one.
http://www.flashextensions.com/products/fontastic.php
is another. I know there are others out there but these are the 2 that come to mind.
Scott Morgan
Kelvin Luck
June 19th, 2007
8:52 pm
Thanks for the info, this will undoubtedly come in useful at some point…
@xmpcray – I did another writeup on dynamically loading fonts into AS2 here:
http://kelvinluck.com/article/dynamic-shared-fonts-in-flash
Ben
June 19th, 2007
8:53 pm
Great article Scott. Definitely submit the bug to the bugbase. I submitted an enhancement request the other day and it was quickly assigned to an engineer and properly classified. Doesn’t guarantee they’ll fix it but shows they’re definitely taking community-submitted items seriously.
xmpcray
June 21st, 2007
8:53 pm
Thanks Scott and Kelvin. Very useful info. Immense help
Felix
June 23rd, 2007
8:54 pm
Hi,
here’s some more info about runtime font loading in AS3 and Flash CS3. You may find this useful if you’re compiling with the Flash IDE:
http://www.betriebsraum.de/blog/2007/06/22/runtime-font-loading-with-as3-flash-cs3-not-flex/
RedB
June 27th, 2007
8:55 pm
Hello Scott,
Good article, very handy stuff. I find myself with a problem when compiling your stuff in flex 3 beta for eclipse: The swf for the font class does not get created. What are you compiling this with and do i need to create a css and compile it as SWF or should building the project make one from the class automatically? i feel i’m missing something here.
Cheers
Scott
June 27th, 2007
8:55 pm
Hi RedB,
I have not tried this method yet in Flex 3. I used FlexBuilder 2. Make sure you set the font class as a default application and compile it seperatly from the FontLoader class.
RedB
June 27th, 2007
8:56 pm
Ah that did the trick, setup a separate project for font files and output to a font swfs dump. Works like a charm.
Thanks again for the help.
Anthony
July 9th, 2007
8:56 pm
Hey there, I\’m trying to compile the _Arial class. I set up a separate project and imported the path to the _Arial class. but I stop right there because I\’m not sure what else I should do. I see you have a static prop, should I call it like any other static prop?
Wan
July 13th, 2007
8:57 pm
Hi, I want to learn flash. Do you guys know where I can take flash class in bay area?
RedB
August 28th, 2007
8:57 pm
Hey there,
Been using this technique since first reading it and its been great. However i recently noticed something i had overlooked before due to the fact that i wasnt reading the content of the text displayed in the embedded font (its just testing stuff right?). Anyways, the problem is that when generating the SWFs with flexbuilder 2.0.1, it seems to create graphic artifacts and deformations depending on the original font file. Following link show an image of some characters being deformed after the embed. Those are for Arial but after testing with multiple fonts its pretty much an acrosse the board thing for most font files i tried. Am i missing something or is this something you noticed too?
Link to example:
http://coresplit.com/test.jpg
RedB
August 28th, 2007
8:58 pm
ooops wrong link. this is right:
http://coresplit.com/files/test.jpg
Claudia
October 25th, 2007
4:17 pm
Very helpful 411!…Thanks!
How would you implement a multiple word named font, for ex: Trebuchet MS?
How would you also implement that font’s bold version, for ex: Trebuchet MS Bold?
Thanks again!
Vlado
December 5th, 2007
9:28 am
Heh, tnx.
I searching for this for while.
Scotter
December 19th, 2007
8:21 am
Great article on runtime embedding fonts!
I’m creating an “online logo-maker” application.
I want to (a) have a “library” of bitmap & vector objects a user can drag onto the “work area”; and (b) have user-specific libraries. I’m planning on using PhP or ASP for the user to be able to upload bitmap & vector images to the server (they will be converted on the fly to WMF). I want the Flash (cs3) application to be able to reference that folder of images so the user can also drag those onto his “work area”. Is this a runtime possibility? I don’t even know where to get started so if you have ideas, please share!
Thanks!
Ian
January 22nd, 2008
11:55 pm
I have run into an issue with embedding fonts that are “extra bold” or “black” rather than just simply “bold” or “italic”. When it goes to compile, mxmlc reports that it can’t find the font with the properties specified. I fixed it by modifying the TrueType subfamily name to “Normal” using a Perl script. It’s a bad hack but it works. Now I can load my font even if it doesn’t match a “standard” weight or style.
Adam Miles
January 30th, 2008
9:20 am
I am having trouble at this line
var FontLibrary:Class = event.target.applicationDomain.getDefinition(“_Arial”) as Class;
I can’t seem to get a swf file with the font embedded in it. could you post or send the flex / flash files?
Thanks so much
Adam
xerode
April 30th, 2008
5:19 am
I’m having the exact same problem as Adam above, it falls over with:
ReferenceError: Error #1065: Variable _Arial is not defined.
at flash.system::ApplicationDomain/getDefinition()
at net.xerode.test::FontTest/fontLoaded()
I’m using CS3 to publish and not Flex, would this be an issue?
Nishant
May 5th, 2008
3:14 am
Hey,
I get “VerifyError: Error #1014: Class IFlexAsset could not be found” just as soon as the font file created by the above method finishes loading
Any ideas?
Steve Schelter
May 6th, 2008
5:11 pm
Scott,
I like where you’re going with this, but from a design stand-point, I have suggestion.
If you set up an interface to your _Arial class like IFontFactory, you can set it up like this:
interface IFontFactory{
function getRegularFontClass():Class;
function getBoldFontClass():Class;
function getItalicsFontClass():Class;
}
Then you can change your fontLoaded method to look more like this:
var FontLibrary:Class = IFontFactory(evt.target.content).getRegularFontClass();
Font.registerFont(FontLibrary);
This way, you can abstract the font registration process.
Then again…perhaps you could just make the Font.registerFont() call in the constructor of _Arial in the first place? I’ll have to play around with that
Alastair
May 7th, 2008
11:03 am
For those getting ‘Variable _Arial is not defined’ I had the same error because my _Arial.as file was in a package like com.mydomain.myproject.resources.fonts so when you get the definition it should be like so…
var FontLibrary:Class = e.target.applicationDomain.getDefinition(“com.mydomain.myproject.resources.fonts._Arial”) as Class;
Nishant
May 8th, 2008
2:48 am
Well,
Quite disappointing that you don’t respond to questions from people about the very subjects you so expertly write about.
tripleaxis.com » Dynamic font loading in AS3
May 14th, 2008
1:32 pm
[...] http://www.betriebsraum.de/…runtime-font-loading-with-as3/ http://www.mikechambers.com/…class-reference-by-class-name/ http://www.scottgmorgan.com/…runtime-font-embedding-in-as3/ [...]
Jipe
May 21st, 2008
5:07 am
Works like a charm, thanks!!!
tilda
June 2nd, 2008
1:49 am
I use FlashCS3 and Flex3 . It works only in the debug version of flashplayer
Brian
June 20th, 2008
8:58 am
Scott,
Spent the last day or so trying to figure this out. I generated the font swf file using flex builder, but when i load that swf using flash cs3 i get “The SWF file … contains invalid data.” when it tries to register the font. Have you tried publishing using flash cs3 or just flex?
Cheers.
Brian
June 20th, 2008
9:10 am
Sigh, nevermind, i figured it out. Thanks for this write up.
jocce
July 2nd, 2008
1:04 am
Hi,
Sweet stuff.
But i have ran into a problem when trying to make this dynamical, as im making a multilanguage site and japanees aint the favorit one for embaded fonts. So I’m sending in two variables, the url to the font swf and the font name.
public class FontLoader extends Sprite {
var _fontName:String;
public function FontLoader(fontUrl:String, fontName:String) {
trace(“FontLoader”);
_fontName = fontName;
loadFont(fontUrl);
}
… all thigns works fine down to here:..
private function fontLoaded(event:Event):void {
var FontLibrary:Class = event.target.applicationDomain.getDefinition(_fontName) as Class;
trace(typeof(FontLibrary)); // traces object
trace(typeof(FontLibrary._fontName)); // traces string , should trace object to work i guess.
Font.registerFont(FontLibrary._fontName); // creates the error: 1067: Implict coercion of a value of type String to an unrelated type Class.
drawText();
}
…
}
Btw, I’m kind of new to AS3, so any of you have a solution/suggestion on how to solve this?
jocce
July 4th, 2008
12:22 am
I think i have solved it now.
I changed the code in flex 3, so that i registrer the font there and looks like its workin.
package {
import flash.display.Sprite;
import flash.text.Font;
public class _arial extends Sprite {
[Embed(source='C:/WINDOWS/Fonts/ARIAL.TTF', fontName='_arial', unicodeRange='U+0020-U+002F,U+0030-U+0039,U+003A-U+0040,U+0041-U+005A,U+005B-U+0060,U+0061-U+007A,U+007B-U+007E')]
public static var _arial:Class;
Font.registerFont(_arial)
}
}
then in my FontLoader.as all i needed in the fontLoaded function is the drawText
private function fontLoaded(event:Event):void {
drawText();
}
So now i can start trying to load multiple fonts and font variants.
TS Larusso » Blog Archive » Embedding Fonts mit AS3
July 28th, 2008
12:03 pm
[...] Der meißt bequemste Weg geht hier über das [EMBED] Tag der leider nur mit der Flex-Compiler Shell funktioniert. Dieses Tag ermöglicht es die gewünschte Schrift einfach in die SWF zu compilieren. Die Dateigröße wird dabei zwar beachtlich größer, aber dafür gibt es die Möglichkeit einige UNICODE Sets zu Filtern. Damit nicht der volle Zeichensatz importiert werden muss. [Embed(source='C:/WINDOWS/Fonts/arial.ttf', fontName='_Arial')] public static var _Arial:Class; Scott Morgan hat auf seinen blog ein kleines tutorial geschrieben wie eine erweiterte Klasse das Laden von externen Schriften ermöglicht Runtime Font Embedding in AS3. There is no need to embed the entire fontset anymore. [...]
MikeyAction
August 7th, 2008
7:54 am
Anybody got any thoughts on how to embed a suitcase font using this method?
flashape
September 10th, 2008
1:08 pm
MikeyAction – extract the individual fonts from the suitcase, there are a bunch of freeware programs that do that.
flashape
September 10th, 2008
1:08 pm
MikeyAction – extract the individual fonts from the suitcase, there are a bunch of freeware programs that do that.
Flash: Runtime Font Sharing Embedding with only Partial Character sets: How To. : TroyWorks
September 12th, 2008
2:43 am
[...] me realize the ability to limit the unicode. The more readable one on the yahoo labs, and the authors blog with many comments. The solution he and others presented didn’t work for me, and I think the [...]
Runtime font embedding in AS3 « moogtone
September 18th, 2008
1:19 am
[...] 8:19 am Filed under: Actionscript 3 | Tags: AS3, Flash, font Scott Morgan has a nice post about font embedding at his blog. No Comments so far Leave a comment RSS feed for comments on this post. [...]
saul
October 9th, 2008
8:31 pm
Guess what your not alone. I’m down to a single hair. No, i’m not kidding. Flex newbies be aware. Its the coaster you can’t get off. I’m just glad flex will never be installed on say a fly by wire system otherwise you may as well just slit your throat before you get on the plane. lol, NOT!
Example of Embedding font in an ActionScript project with external XML, CSS and html formatted text | Samuel’s Blog
October 16th, 2008
9:41 am
[...] quite indepth and useful post here about embedding only the glyphs you [...]
madhu
February 20th, 2009
6:48 am
This is issue is also in flex builder 3,
thanks for solution.
Tehsin
March 23rd, 2009
1:59 pm
Hey Scott
You are still helping me even after leaving Innovasium!
Thanks for the write up…
For the people asking questions on how to embed multiple fonts.. and btw with CS4, you can do this as well (using the Flex 3 Library Path).
So for multiple font embedding, you can simply do something like this in your class file
[Embed(source="C:/windows/Fonts/HelveticaNeueLTStd-Cn.otf", fontName="HelveticaNeueLTStdCn", mimeType="application/x-font-opentype",unicodeRange="U+0041-U+005A,U+00C0-U+00DE")]
public static var HelveticaNeueLTStdCn:Class;
[Embed(source="C:/windows/Fonts/HelveticaLTStd-Roman.otf", fontName="HelveticaLTStdRoman", mimeType="application/x-font-opentype",unicodeRange="U+0041-U+005A")]
public static var HelveticaLTStdRoman:Class;
And then register both fonts:
Font.registerFont(HelveticaNeueLTStdCn);
Font.registerFont(HelveticaLTStdRoman);
Thanks again Scott..
Regards,
Tehsin
sheetal
March 25th, 2009
11:35 pm
Hello,
I am doin it in Flex3,and i am using it in an mxml.i mean loading the _Arial.swf in my application.I am getting the same error- Error #1065: Variable _Arial is not defined.
Also my _Arial class is in the src folder and know more packages.Plz help.
Thomas Brady
April 17th, 2009
9:59 am
I implemented this as a Flex Component. Check it out.
Flex/Flash Runtime Fonts with HTML « Here’s how I did it…
April 27th, 2009
9:50 am
[...] out there on how to dynamically load font libraries at runtime in Flex. here are just a few: scottmorgan.com, undefined-type.com, [...]
asja
May 13th, 2009
9:27 pm
Has this changed recently, I added the unicodeRange bit in to my font loader to try to decrease the size and it actually increased!
Gary
May 28th, 2009
2:54 am
I chose exactly which character glyphs to compile into my swf by deleting all the unnecessary ones from the TrueType font file using http://www.high-logic.com/fontcreator.html. It cut the swf file size in half.
Another tip, Flash Optimizer http://www.flashoptimizer.com/ works really well with an embedded font, reducing its size by about 30%. This may make it worth the $99 price tag.
Hope this info helps someone!
schjlatah
June 3rd, 2009
5:01 pm
I too was experiencing what #12 was with regards to the glyph errors. I filed a bug with Adobe about it and they suggested that I try compiling my app using a different font manager: http://bugs.adobe.com/jira/browse/SDK-14955
There is only one thing wrong with this method; they do not support embedding Post Script fonts from Flex/ActionScript/mxmlc… pretty much anything other than Flash CS3/4: http://bugs.adobe.com/jira/browse/SDK-1500
Otherwise it works great!
Nick
June 11th, 2009
1:53 pm
Thanks a lot, the need to clean the project bug exists in Flex builder 3 as well. I would have lost a lot of time learning that if I didn’t see your blog.
enrico penzo
June 15th, 2009
2:44 am
thanks,
very useful
Taj
June 23rd, 2009
1:06 pm
Hi,
can u please the send me the sample in Action Script 2.0
b’coz I am using the AS2.0 only, I seen the “shared fonts manager” and download the (source)zip file, but the source in Action script1.0. Please Help me. Thanx in Advance.
danny
July 15th, 2009
1:30 pm
I am having a problem with this. I can only get it to work when the static var name is the same name as the class name. For example if my class name is _Arial and I embed the Arial font and give the static var a name of _Arial it works great. But if I change the name of the static var to something else (and update my embed code’s fontName accordingly) I don’t get errors on the font register or load but I don’t see any text on screen. Has anyone had this issue? I have seen examples where the name of that var is different from the class and it works fine. Could anyone help???:S
henkie
August 13th, 2009
8:07 am
After trying everything I still cant get a single textfield to display both bold and regular characters. Everything is embedded, all fonts are on the stage and wherever I could place them. All variations are embedded, but nothing works.
Josh Noble
September 3rd, 2009
7:08 am
This was a massive help on a recent project you are a super star thanks for sharing.
easyMind
October 5th, 2009
5:20 am
Hi, isn’t it possible to use Flash to make the font swfs? I still want to use these fonts in flex, but creating the fonts swfs in flash will reduce the file size since the flex framework is not compiled. But maybe just compiling the framework seperatly has the same result…
easyMind
October 5th, 2009
8:34 am
Ok, so you want normal, bold and italic also…
Just add those fonts to your swf class like this:
[Embed(source='C:/WINDOWS/Fonts/ARIAL.TTF', fontName='_Arial')]
public static var _Arial:Class;
[Embed(source='C:/WINDOWS/Fonts/ARIALBD.TTF', fontWeight='bold', fontName='_Arial')]
public static var _ArialB:Class;
[Embed(source='C:/WINDOWS/Fonts/ARIALI.TTF', fontStyle='italic', fontName='_Arial']
public static var _ArialI:Class;
[Embed(source='C:/WINDOWS/Fonts/ARIALBI.TTF', fontWeight='bold', fontStyle='italic', fontName='_Arial']
public static var _ArialBI:Class;
As you can see, you have to set the proper fontstyle and fontweight values. Also keep the same fontName…
Now when loading the font make sure to register all 4 fonts in your class… I do this like this:
var FontLibrary:Class = event.target.applicationDomain.getDefinition(‘_Arial’) as Class;
var fl:Object = ObjectUtil.copy(FontLibrary);
for(var i:Object in fl)
Font.registerFont(FontLibrary[i]);
parker
December 1st, 2009
8:33 am
wondeerful post Scott. many thanks, exactly what I needed! :- )
Raji
December 24th, 2009
5:46 am
very Nice Tutorial..
Blake Ferm
February 4th, 2010
3:24 pm
This is an awesome tutorial. Got it working in eclipse w/FDT. Very cool! Thanks for sharing.
Blake
duza
February 12th, 2010
11:25 am
hello,
thanks for sharing this.
I’ve managed to get the _Arial font class in my swf and use it. I works fine. Thus, i have some problems: I can’t make my Text Fild to desplay special chars (like È).
The weird thing is that in Flex I see this chars without any problem (by creating a TextField).
So I suppose that Flash lose them somehow,
Have somebody had the same problem or something close?
Thanks!
john piere jones
February 12th, 2010
1:44 pm
what about on a mac jack?
adampasz
February 21st, 2010
8:35 am
I’m having trouble with this technique. Specifically, it appears that it is not possible to control advanced anti-aliasing settings (via the TextRenderer class) when fonts are embedded in this way. I was wondering whether anyone else had run into this issue..?
Flash字体嵌入方法总结—(4)进阶篇【转载kevincao】 | Catfly猫脸爬
April 19th, 2010
9:27 pm
[...] Runtime Font Embedding in AS3. There is no need to embed the entire fontset anymore. [...]
Steef
August 17th, 2010
6:32 am
Hi there,
I’am working on dynamic font embedding, and it works fine. But only if the font.swf is standing in the same folder als the app.swf.
My SWF files with the fonts are on a remote server, so instead of “Arial,swf” i point to “http://myserver/fontCache/Arial.swf”
If i put Arial.swf in mij app-folder, YEAY, it works. If i point to a remote (or even a c:/blah/arial.swf) it wont work.
Anyone an idea?
Ashish
August 26th, 2010
2:37 am
Thanks Scott!
Very useful hack
munkychop
August 5th, 2011
11:40 am
This Is a great article, but, it is missing one CRUCIAL UPDATE…
If you are publishing to Flash Player 10+ and using the TextField class then you need to explicitly set the newly added ‘embedAsCFF’ property to false, as if you don’t then this method will only work with the new TextLayoutFramework.
This confused me for hours and hours, so please add it to the article if possible.
[CODE]
[Embed(source='C:/WINDOWS/Fonts/ARIAL.TTF', fontName='_Arial', embedAsCFF='false', unicodeRange='U+0020-U+007E')]
[/CODE]
Hope that helps somebody, some day
Leave a comment