FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Textual Encoding
Goto page Previous  1, 2, 3, 4, 5, 6, 7  Next
 
Post new topic   Reply to topic     Forum Index -> Mango
View previous topic :: View next topic  
Author Message
kris



Joined: 27 Mar 2004
Posts: 1494
Location: South Pacific

PostPosted: Mon Dec 19, 2005 8:28 pm    Post subject: Reply with quote

I think it's also worth noting that the very example(s) we've been discussing are perhaps the least suited for a UniversalString. That is, an XML parser should not be creating String classes to house XML elements, attribute lists, and so on. Instead, for the sake of efficiency, it should probably choose one particular encoding and pass slices of the (possibly transcoded) input around. That is, an XML parser is a very good case of where you'd likely want explicit control over the transcoding, and where minimal memory allocation should perhaps be a priority?

Where a UniversalString has potential value is in much more ad-hoc type applications, though I can't think of one right now ... anyone?
Back to top
View user's profile Send private message
teqdruid



Joined: 11 May 2004
Posts: 390
Location: UMD

PostPosted: Mon Dec 19, 2005 8:29 pm    Post subject: Reply with quote

kris wrote:
For the sake of argument, one could envisage a scenario where transcoding is performed at the I/O barrier only. Assuming the internal and external encodings match, there would be zero transcoding taking place.

That's the problem, however. It's not a homogenous world, so that's not a valid assumption. If there was just one encoding, everything would be real easy!

kris wrote:
At very worst there would be two transcodings (input and output). One could argue that the end-result there is cleaner and more efficient. No? For me, UniversalString has to offer something really compelling before I'd use it ~ partly because it hides the transcoding barrier Smile

Hides? I would disagree with that. I'm not trying to hide the transcoding, I'm trying to make it automatic. One of the things I like about Mango is that it gives people like you the option to optimize the application at even the lowest level, which still making the higher level available.

kris wrote:
There are often very good reasons for maintaining explicit control over the transcoding aspect. In those worlds, why should I use UniversalString? What benefit does it bring to the table that can't be achieved through other means? And, at what cost?

In my opinion is brings more effience and cleaner code (I find templates to be ugly if they have to be used throughout an application, and arbitrary choice of encoding to be just a revolting) in applications to be used in heterogeneous areas (I.E.: Any application that has to interact with real world stuff)

kris wrote:
That's not to say what you've done with UniversalString ain't cool ~ it is ... I'm just having a hard time identifying any use-case where I'd actually use it Sad

I should note that I'm personally a bit of a stickler for efficiency in code, so there's definately a bias there.

I don't see how using the universal string is any less efficient. It doesn't make sense to have two different and incompatible types of Strings in Mango, and I'd rather provide both. My goal was to provide a higher-level string that one could use, in addition to still allowing lower level access- using a UtfXString class, in my module. If you keep all the encodings the same, there shouldn't be any performance difference between your stuff and mine.

Here's my problem with your stuff. If I use it for, say, my new SAX parser, then everywhere I've got a String, the entire class needs to be templated. This would be the entire package, and sub-package. Then, all of the clients using the SAX parser either need to be templated, or choose an encoding. If an application is to be kept encoding neutral- as I would desire all of my applications to be, the templates would end up being perpetuated throughout the application, not to mention Mango.

Also keep in mind the toll on Mango. Wherever a String was to be accepted as a parameter, would require three different methods: one for each templated string, unless they're going to immediatly convert to a Xchar array, thus defeating the purpose of a string.

In the end, I providing a universal string doesn't necessarily hide the encoding (just abstracts it) and doesn't necessarily degrade performance. It provides a higher-level option for people like me, and a lower-level option for performance sticklers.

You also mention that you are a performance stickler, but I'm still confident that a universal string will perform faster than the templated strings in a heterogeneous environment, and identically in the homogeneous environment. Is there a particular reason you think otherwise?

~John
Back to top
View user's profile Send private message Send e-mail AIM Address
kris



Joined: 27 Mar 2004
Posts: 1494
Location: South Pacific

PostPosted: Mon Dec 19, 2005 9:05 pm    Post subject: Reply with quote

Perhaps we need to slow down a wee bit here? After all, we're just discussing alternatives; yes?

So far, I haven't seen any detractions from being able to easily convert from one encoding to another. So we might assume for now that's something nice to have?
Back to top
View user's profile Send private message
teqdruid



Joined: 11 May 2004
Posts: 390
Location: UMD

PostPosted: Mon Dec 19, 2005 9:28 pm    Post subject: Reply with quote

kris wrote:
Perhaps we need to slow down a wee bit here? After all, we're just discussing alternatives; yes?

So far, I haven't seen any detractions from being able to easily convert from one encoding to another. So we might assume for now that's something nice to have?


Sorry if I seem like I'm getting defensive- I suppose that I am. For for clarity's sake, when it comes to debating design decisions, I am frequently defensive of my idea, but I _never_ take detractions from them personally.

And yes, the toUtfX methods are a good thing to have at a minimum.
Back to top
View user's profile Send private message Send e-mail AIM Address
teqdruid



Joined: 11 May 2004
Posts: 390
Location: UMD

PostPosted: Mon Dec 19, 2005 9:36 pm    Post subject: Reply with quote

pragma wrote:
In the case of Mango, XML and other related technologies, we are in a position to *dictate* a "Lingua Franca" of sorts and say "use this encoding for optimal performance"


And in fact that's what I've done with the current DOM library, that's exactly what I'm not happy about.

Anytime when the encoding is set at compile time (as it would have to be if templates are used), some apps are going to experience efficiency problems due to unnecessary conversions.

Quote:
I think it's also worth noting that the very example(s) we've been discussing are perhaps the least suited for a UniversalString. That is, an XML parser should not be creating String classes to house XML elements, attribute lists, and so on. Instead, for the sake of efficiency, it should probably choose one particular encoding and pass slices of the (possibly transcoded) input around. That is, an XML parser is a very good case of where you'd likely want explicit control over the transcoding, and where minimal memory allocation should perhaps be a priority?


There's nothing stopping Strings from doing precisely that. The only memory allocations that are done are new'ing the Classes themselves- they're not copying the data, or even transcoding it. In fact, an encoding IS implicitly choosen before the parsing starts, but the big important point is that it's choosen at runtime by whatever encoding the first String fed to it is in.
Back to top
View user's profile Send private message Send e-mail AIM Address
teqdruid



Joined: 11 May 2004
Posts: 390
Location: UMD

PostPosted: Mon Dec 19, 2005 9:46 pm    Post subject: Reply with quote

kris wrote:
So far, I haven't seen any detractions from being able to easily convert from one encoding to another. So we might assume for now that's something nice to have?


I also haven't seen any specific detractions from the universal string... and perhaps the name seems too over-ambitious. It's more like encoding-choosen-at-runtime string.

What about it doesn't have y'all convinced? Since I haven't seen any specific detrations, I'm thinking that you both are reacting with your guts. Usually I believe strongly in a gut reaction, but in this case, my gut tells me that being able to determine the encoding at run time is a much better idea.

Do you think that it's inheriently slower? I don't see why, since you can choose the encoding, and potentially never do any conversions.

Do you think it would use more memory?

Do you feel that you'd be giving up too much control? If so, I think more control can be given.

Do you think that it doesn't encourage programmers to program efficiently, but be lazy about it?

Am I correct in assuming that the real difference of opinion is encoding being determined at compile time vs. runtime?

If you believe that it's technically pheasable, I don't see a reason *not* to do it, and have the encoding specific classes extend it, since having two different String hierarchies isn't the best idea.

~John
Back to top
View user's profile Send private message Send e-mail AIM Address
kris



Joined: 27 Mar 2004
Posts: 1494
Location: South Pacific

PostPosted: Tue Dec 20, 2005 1:52 am    Post subject: Anonymous strings Reply with quote

Specific detractions: there are various examples cited within this topic. Most recently there's issue of hashing and the lack of casting. You may not feel these are worth considering, but I do.

Technically feasible: that doesn't give it the right to exist Smile

Two different String hierarchies: that's making some fairly stark assumptions, since we don't even have one at this time.


I'm going to try and tease one or two things apart. Let's take a look at the notion of

Anonymous Strings:

John has noted some benefits in avoiding a fixed-type of String. For the sake of discussion, here's one way to achieve that:

Code:
class AnonymousString
{
     private int type;
     private void[] content;

     set (char[]) {}
     set (wchar[]) {}
     set (dchar[]) {}

     char[] toUtf8() {}
     char[] toUtf16() {}
     char[] toUtf32() {}
}


There's definately value there. I can certainly see where that could be used. What's perhaps not immediately obvious is the fact that it is (or could be made) stateless. This means that it can be reused.

Going back to our XML parser example, the parser can use a single instance of AnonymousString as a vehicle for delivering content to user methods. This is quite different from something like a String aggregate, where it's infinitely harder to make an argument about statelessness, or ownership. In the String case, one might be creating hundreds (perhaps thousands) of String instances just to carry a content slice across a contract boundary Shocked

In contrast, library components can utilize this anonymous notion whilst being very frugal re heap activity.

I think we need to make a clear distinction between the two notion ~ AnonymousString is effectively stateless, whilst the String we've been working with is not. The implications are far-reaching and worth noting.

(please note that AnonymousString and UtfString are synonymous)

Is AnonymousString or fixed-type "better"?

This is surely application-specific? I will state that, IMO, fixed-type has the potential to always be faster, since an environment can make certain guarantees about slices. The same guarantees cannot, in general, be made via AnonymousString. Thus the latter will almost always involve heap-activity, with the potential to be truly heap aggressive. It all depends on the application.

Transcoding Tradeoffs

Transcoding is generally pretty fast but, in Mango, it is not tuned for short bits of text. Quite the contrary. To give a vague indication of performance, current heap allocation is often slower than transcoding (and the heap perfomance will rapidly deteriorate where there's thread contention). Thus, from a performance perspective, it's much, much better to avoid heap activity. Additionally, it's generally better to trade lots of short transcodings for a handful of larger ones.
Back to top
View user's profile Send private message
teqdruid



Joined: 11 May 2004
Posts: 390
Location: UMD

PostPosted: Tue Dec 20, 2005 3:18 am    Post subject: Re: Anonymous strings Reply with quote

kris wrote:
Specific detractions: there are various examples cited within this topic. Most recently there's issue of hashing and the lack of casting. You may not feel these are worth considering, but I do.


Well, the hashing issue isn't so much a huge issue. One can always just convert to a specific Utf and always hash that. I'm hoping that there's a faster way to do it, however.

As for the casting issue- it depends on how you look at it. Not being able to cast from a MutableUtf8String to a Utf8String is only an issue if you're exclusively using Utf8, so if you need some of the methods only in Utf8String, and you've got a MutableUtf8String, you're outta luck. The reason I don't see this as a huge issue, however, is that a) all of the Utf8String's methods are in MutableUtf8String as well, and b) if you really, really can only use Utf8String, just construct a new one with a slice of the MutableUtf8String's data.... The only heap cost is that of the new class, and c) there shouldn't be a whole of of methods in Utf8String that aren't in String anyway. Yes, it's not the greatest situation, but it's not the worst hack that I've seen.

Quote:
In the String case, one might be creating hundreds (perhaps thousands) of String instances just to carry a content slice across a contract boundary

Yes, that's true... But that's going to be a problem whether you're using fixed-type string or an anonymous string. What do you think about a delivery mechanism such as the following:
Code:
struct Slice {
String getOwner(); //Returns the larger string
char[] toUtfX(); //Returns just the slice's content
String toString(); //Creates a String from the content
MutableString copy(MutableString); //Copy the content into a mutable string
bool equals();
int opCmp();
... Other useful methods

This way no heap space is used, but the reciever has the option of moving it into a full blown String, or copying it into a MutableString if they really want to do something with it.

I would suggest that a MutableString be used, and casted to a String for the reciever to use, but even if the ownership is documented (that the caller owns the String) it wouldn't help- nobody reads the documentation if they think it's clear what they're doing.

Quote:
Is AnonymousString or fixed-type "better"?

This is surely application-specific? I will state that, IMO, fixed-type will always be faster since an environment can make certain guarantees about slices. The same guarantees cannot, in general, be made via AnonymousString. Thus the latter will almost always involve heap-activity, with the potential to be truly heap aggressive. It all depends on the application.

Why? Can you elaborate on this? I certainly agree that heap-allocation is the devil when it comes to fast text processing, but I don't understand why there is more heap-allocation inheriently involved in an anonymous string.

I would imagine that your reasoning is that an anonymous string will inheriently have more transcoding associated with it, and thus will be copying data instead of just slicing it.

Yes, it's certainly easier to ensure that transcoding is kept to a minimum with a fixed-type string since all transcoding is done explicitly and you know, at compile time, at which points in your application transcoding is going to take place.

So you mentioned slicing: when a fixed-type string slices, there's no transcoding involved. Same is true for the anonymous string, too though. It just slices the current encoding. The only challenge is that you probably don't wanna use indexes for the slices but a more abstract method.

I guess I've been rambling a bit, but I agree with you on minimizing heap usage, and would like to know why you think anonymous strings would inheriently use more heap space than fixed-type strings.

~John

BTW, thanks for your cogent and cohesive remarks. They certainly show a stark contrast to my brain dumps and rambling.
Back to top
View user's profile Send private message Send e-mail AIM Address
teqdruid



Joined: 11 May 2004
Posts: 390
Location: UMD

PostPosted: Thu Dec 22, 2005 7:07 pm    Post subject: Thinking lately Reply with quote

So obviously this topic has died down a lot lately but I've still been thinking about it a lot. I still think that a universal string is the most elegant method, but given a lot of the problems I've been having programming it, I'm not sure it's worth it. OTOH, a templated string in which the AbstractString only has three transcoding methods is kinda slim pickings... We can at least do better than that. I also think that my idea for a "ConstantString" has some merit.

So, what do you all think of the following:
Code:

abstract class String: IWritable
{
   abstract char[] utf8  (char[]  dst = null);
   abstract wchar[] utf16 (wchar[] dst = null);
   abstract dchar[] utf32 (dchar[] dst = null);
   abstract TypedString!(char)  utf8String  (MutableTypedString!(char) dst = null);
   abstract TypedString!(wchar) utf16String (MutableTypedString!(wchar) dst = null);
   abstract TypedString!(dchar) utf32String (MutableTypedString!(dchar) dst = null);
   
   abstract Type getEncoding();
   
   abstract bool equals (char[] other);
   abstract bool equals (wchar[] other);
   abstract bool equals (dchar[] other);
   abstract bool equals (String other);

   abstract void copy (MutableStringTemplate!(char) dst);
   abstract void copy (MutableStringTemplate!(wchar) dst);
   abstract void copy (MutableStringTemplate!(dchar) dst);
   
   abstract Pointer startBindPointer(Pointer); //Binds a pointer to index zero
   abstract Pointer endBindPointer(Pointer); //Binds a pointer to the last code-unit
   
   abstract uint toHash(); //This one's still a problem (to do efficiently) but I think it's solvable
   
   private abstract GenericSlice getSlice(uint start, uint end);
}

class Pointer
{
   abstract bindTo(String s);
   abstract Pointer advance(uint count=0);
   abstract Pointer retreat(uint count=0);
   abstract bool hasMore();
   abstract GenericSlice slice(); //Returns a slice from the pointer to the end of it's String.
   abstract GenericSlice sliceTo(Pointer other); //Returns a slice from this pointer to the next
   abstract bool equals(ConstantString cs); //Compares the current code-unit and up to the ones in the ConstantString
   abstract bool seek(ConstantString cs); //Advances the Pointer to a substring.  Returns false if substring not found
   //Perhaps more cool searching stuff
}

class TypedPointer(T): Pointer
{
   T get(); //Get the current code-unit
   abstract bool seek(T[] str);
   abstract Slice!(T) typedSlice();
   abstract Slice!(T) typedSliceTo(Pointer other);
   //Probably more type-specific Pointer stuff
}

struct GenericSlice
{
   char[]  utf8  (char[]  dst = null);
   wchar[] utf16 (wchar[] dst = null);
   dchar[] utf32 (dchar[] dst = null);
   TypedString!(char)  utf8String  (MutableTypedString!(char) dst = null);
   TypedString!(wchar) utf16String (MutableTypedString!(wchar) dst = null);
   TypedString!(dchar) utf32String (MutableTypedString!(dchar) dst = null);
   
   Type getEncoding();
   
   bool equals (char[] other);
   bool equals (wchar[] other);
   bool equals (dchar[] other);
   bool equals (String other);
   
   bool startsWith (char[] other);
   bool startsWith (wchar[] other);
   bool startsWith (dchar[] other);
   bool startsWith (String other);
   
   bool endsWith (char[] other);
   bool endsWith (wchar[] other);
   bool endsWith (dchar[] other);
   bool endsWith (String other);
   
   uint toHash ();
   
   void write (IWriter input);
}

struct Slice(T)
{
   //All of the stuff from GenericSlice, but with more type-specific stuff.
}

class ConstantString
{
   this(char[] cstr, wchar[] wstr, dchar[] dstr);
   //Implement methods from String
}

class TypedString!(T)
{
   //These two in addition to the two from String that have to be implemented
   abstract TypedPointer startBindPointer(TypedPointer); //Binds a pointer to index zero
   abstract TypedPointer endBindPointer(TypedPointer); //Binds a pointer to the last code-unit

   //Methods from Kris' current StringTemplate:
           opApply (int delegate(inout T) dg);
                T get (uint index);
                uint toHash ();
                uint length ();
                bool endsWith (T[] other);
                bool endsWith (String other);
                bool startsWith (T[] other);
                bool startsWith (String other);
                uint indexOf (T c, uint start=0);
                uint indexOf (T[] chars, uint start=0);
                uint indexOf (String other, uint start=0);
                uint lastIndexOf (T c, uint start=uint.max);
                uint lastIndexOf (T[] chars, uint start=uint.max);
                uint lastIndexOf (String other, uint start=uint.max);
                T[] copy (T[] dst, uint start=0, uint len=uint.max);
                MutableString copy (MutableString dst, uint start=0, uint len=uint.max);
}

class MutableTypedString!(T): TypedString(T)
{
   //Keeps a list of Pointers and updates them when data is inserted, essentially just running the indexes they contain through pinIndex
   //Methods from Kris' current MutableStringTemplate:
           T[] aliasOf ();
                MutableString trim ();
                MutableString append (int value);
                MutableString append (long value);
                MutableString append (double value);
                MutableString append (char[] other);
                MutableString append (wchar[] other);
                MutableString append (dchar[] other);
                MutableString append (T chr, uint count=1);
                MutableString append (String other, uint start=0, uint len=uint.max);
                MutableString format (T[] format, ...);
                MutableString layout (T[] layout ...);
                MutableString set    (T chr, uint index);
                MutableString setTo  (T[] chars, bool mutable=true);
                MutableString setTo  (String other, bool mutable=true);
                MutableString setTo  (String other, uint start, uint len, bool mutable=true);
                MutableString insert (T[] other, uint index=0);
                MutableString insert (String other, uint index=0);
                MutableString insert (T other, uint index=0, uint count=1);
                MutableString remove (uint start, uint length=uint.max);
                MutableString truncate (uint length=0);
}


This isn't fully flushed out, but I think it gives the right idea. The point is that you can do a lot with a string even if you don't know the encoding. For instance, with this structure I can parse an entire XML document via SAX without ever doing any transcoding and no heap allocations. The desired lack of heap allocations is the reason for Slice and GenericSlice being structs- classes with inheritance would be nicer, but then heap allocations would be required.

It'd be nice to have a universal mutable string (and this might be an appropriate wrapper class in the future), but it's also perfectly reasonable to have to know an encoding when you're manipulating it.

Thoughts?
~John
Back to top
View user's profile Send private message Send e-mail AIM Address
kris



Joined: 27 Mar 2004
Posts: 1494
Location: South Pacific

PostPosted: Thu Dec 22, 2005 8:10 pm    Post subject: Reply with quote

I've though a lot about this also, and for the upcoming release I'd prefer to go with something simple that can made compatable with ICU. It will have all the features required to build highly efficient text-processing engines (e.g. zero or minimal heap & transcoding activity). The main thing missing will be the ability to execute lookups or tests across mixed UTF encodings ~ I'm not convinced of the value there, or whether the tradeoffs are worthwhile.

I think we should revisit this topic after some gaining some practical usage experience.
Back to top
View user's profile Send private message
teqdruid



Joined: 11 May 2004
Posts: 390
Location: UMD

PostPosted: Thu Dec 22, 2005 8:14 pm    Post subject: Reply with quote

kris wrote:
I've though a lot about this also, and for the upcoming release I'd prefer to go with something simple that can made compatable with ICU. It will have all the features required to build highly efficient text-processing engines (e.g. zero or minimal heap & transcoding activity). The main thing missing will be the ability to execute lookups or tests across mixed UTF encodings ~ I'm not convinced of the value there, or whether the tradeoffs are worthwhile.


So what you mean by this is that it will be lacking a way for me to use it to create a non-templated, encoding neutral SAX parser?

That's really all I'm looking to do.

~John
Back to top
View user's profile Send private message Send e-mail AIM Address
kris



Joined: 27 Mar 2004
Posts: 1494
Location: South Pacific

PostPosted: Thu Dec 22, 2005 8:52 pm    Post subject: Reply with quote

teqdruid wrote:
kris wrote:
I've though a lot about this also, and for the upcoming release I'd prefer to go with something simple that can made compatable with ICU. It will have all the features required to build highly efficient text-processing engines (e.g. zero or minimal heap & transcoding activity). The main thing missing will be the ability to execute lookups or tests across mixed UTF encodings ~ I'm not convinced of the value there, or whether the tradeoffs are worthwhile.


So what you mean by this is that it will be lacking a way for me to use it to create a non-templated, encoding neutral SAX parser?

That's not what it means at all Smile

You can certainly build a non-templated, encoding-neutral, SAX parser ~ it just won't have the seek(), append(), or equals() methods available in a neutral manner. There are alternate, language-supported, mechanisms that are arguably more efficient and more appropriate for handling application-specific requirements (such as hash-tables for XML element/attribute identification). Plus, one can make application-specific extensions to the provided classes, if necessary.

After building a text-processing engine, we might find there's some additional things that should be generalized ~ surely that's covered by the suggestion to revisit after some practical usage?
Back to top
View user's profile Send private message
kris



Joined: 27 Mar 2004
Posts: 1494
Location: South Pacific

PostPosted: Thu Dec 22, 2005 9:06 pm    Post subject: Reply with quote

teqdruid wrote:
That's really all I'm looking to do.

If it turns out there's a stumbling block due to lack of functionality, we should address it then? I think you'll be able to get by without every bit of the String/MutableString functionality in a SAX parser, but I could easily be quite wrong. How about we just see what happens?
Back to top
View user's profile Send private message
teqdruid



Joined: 11 May 2004
Posts: 390
Location: UMD

PostPosted: Thu Dec 22, 2005 9:13 pm    Post subject: Reply with quote

kris wrote:
teqdruid wrote:
That's really all I'm looking to do.

If it turns out there's a stumbling block due to lack of functionality, we should address it then? I think you'll be able to get by without all of the String/MutableString functionality in a SAX parser, but I could easily be quite wrong. How about we just see what happens?


I'm not too worried about the parser itself as much as I am the SAXHandler interface:
Code:
interface ISAXHandler {
   void startDocument();
   void endDocument();
   void processingInstruction(UText target, UText data);
   void startElement(UText name, Map!(UText, UText) attributes);
   void endElement(UText name);
   void characterData (UText data);
   void comment(UText text);
}


(BTW... The Map for attributes is going to replaced with something not requiring any heap-usage Smile

I find the UTexts to be clunky and I want to replace them. The question is, what do I replace them with- keeping in mind that I want it to be encoding neutral and I'd rather not template the interface. With the current String.d, I'd have to use a ConvertingString, but, honestly, that's a rather useless class.
Back to top
View user's profile Send private message Send e-mail AIM Address
kris



Joined: 27 Mar 2004
Posts: 1494
Location: South Pacific

PostPosted: Thu Dec 22, 2005 9:33 pm    Post subject: Reply with quote

teqdruid wrote:
The question is, what do I replace them with- keeping in mind that I want it to be encoding neutral and I'd rather not template the interface. With the current String.d, I'd have to use a ConvertingString, but, honestly, that's a rather useless class.

It's value is in the encoding-neutrality alone.

With one exception, I strongly suspect the other String methods would prove to be of little value for this scenario. For example, as a SAX client, I can't see myself ever using append(), format(), truncate(), remove(), or seek() ~ there's just no clear value in them within that use-case. But let's find out ... you can always extend the basic class as necessary.

The exception: If the client is processing CDATA (or something like that) then they may want the string functionality. At that point, the client will be encoding-specific, so it could leverage the relevant String template as desired.
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic     Forum Index -> Mango All times are GMT - 6 Hours
Goto page Previous  1, 2, 3, 4, 5, 6, 7  Next
Page 5 of 7

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group