Andy Oakley

  • Workspaces standalone client updated for 1.2

    I made a few tweaks to WksAlone, the GotDotNet Workspaces standalone client, this afternoon to bring it in line with the recent v1.2 feature release.

    Download it here http://workspaces.gotdotnet.com/wksalone

    Changes:

    • Installation/setup package for easy deployment.
    • Improved Passport handling. Fixed a handful of Windows Server 2003 compatibility issues.
    • Changed the usage flow around signin and Workspace selection.
  • Farewell Craig

    Alas, Craig, it’s sad to see you go. I do appreciate the constructive feedback however as it’s always really helpful to hear different perspectives.

    Going through your points in turn:

    Reliability:

    This one really worries me. Clearly a source control system that loses changes is only marginally better (or arguably slightly worse) than none at all. Of course we test as many different scenarios as we can and random data loss while doing typical operations would be a very large red flag to me. I have heard so few reports of this that I’m suspecting some odd interaction with something on your particular system – I’ll follow up on that with you separately if you’re willing. If anyone else reading this has just been angrily cursing at data loss and keeping quiet, please let me know.

    Tooling:

    It sounds like there are two issues here – the software and the interaction paradigm.

    I think it’s fair to say CVS has a head start with a good ten years more experience on the software front. OK, so some of the GUI-based interfaces are a bit younger, but still, Workspaces is a mere infant by comparison :). Yes, the backend we’re using is well-proved but the front-end interfaces (Windows Forms, HTML, VS.NET plugin) were all built from nothing, based around the web services architecture Workspaces created. These tools will improve with time, but I have to ask for patience. Likewise, integration with build systems, unit tests and other such marvels are all things that are possible in the future.

    The lock-modify-unlock (LMU) model was picked for both its simplicity (it’s relatively easy to pick up and understand if you’ve no previous source control experience) and its familiarity for users comfortable with Visual SourceSafe. The exclusive checkout enforcement is something I’d like to relax as it definitely can be overly restrictive at times. Of course, that requires some merge/diff logic in the clients which again takes time. Allowing multiple checkouts of the same file brings things far closer to the CVS-like copy-modify-merge (CMM) approach you’re more comfortable with.

    Performance:

    This, I’m pleased to say, is due to change. With an increasing number of Workspaces and activity, performance has notably degraded. We’re taking some immediate measures to improve database performance (which should have a visible effect on the GotDotNet.com site, as well as Workspaces’ source control) in the next couple of weeks.

    Believe it or not, we really do care about site downtime. Earlier this week, we suffered some hardware-related failures with our database server; thankfully our backup practices and redundancy avoided any data loss, but it has certainly kept us very busy. We do try to mitigate such problems as much as possible, but as I’m sure everyone who works with computers knows, the occasional tantrum habits of the machine get you sooner or later.

    Later this year (think July), we’ll be making some big changes in the Workspaces world but it won’t be a feature release. Instead, we’re reworking much of the infrastructure for performance and availability – no more 30 second delays viewing the directory or apparent hanging while syncing a folder. More details on that in time.

     

    In the bigger picture, Workspaces is more than just a source control system. It turns out that different people have different needs – some look at it as a source control service with extra frills, other projects don’t use source control at all and rely on the bug tracking and other collaboration features. Balancing these requests to steer a course that provides the most needed features for the most is the challenge, but we’re working on it.

    Yes, things are moving forwards, and you’ll be welcomed back as and when :)

  • Changes in the Workspaces releases area

    As I mentioned last week, the Workspaces on GotDotNet are going to see a few changes tomorrow. There will be some downtime while the modifications are made across the site but expect all data to remain intact.

    Some of the changes on the way in the releases section:

    • Per-release download count. See how many people are downloading your releases.
    • No more zero-byte/corrupt downloads. While 308090 remains, we've changed the download page to work around these problems.
    • No more Passport sign-in for downloads. Get to the bits right away. 
    • Off-site hosting of releases. If you're running up against the release quota limit or need to link to another product primarily hosted elsewhere, try this out.
  • Workspaces bug tracker changes coming soon

    Watch out for some improvements in the Workspaces bug tracker next week (Tuesday 3/16/04).

    Find that bug

    It’s true, the querying power in today’s bug tracker leaves somewhat to be desired. As the bug count rises, it can become increasingly difficult to track down a particular bug, even though you know so many details about it. That’s about to change.

    The new query builder lets you construct a query from basic clauses. Using boolean AND and OR operators, you can create marvelously detailed queries that define just the view into the bugs list that shows you what you need to see. Queries can be saved in a Workspace so frequently used queries can easily be reused or shared with other Workspace participants.

    Who does this belong to?

    Don’t know who should own a bug? Assign it to ‘[Unassigned]’ so it doesn’t fill up your list. Of course, it’s always a good idea to check that someone is sifting through unassigned bugs on a regular basis to make sure that they are routed to their rightful owner.

    My project doesn’t have milestones, but we do like to record build numbers…

    How convenient! Up to now, the bug tracker has had two ‘non-core’ fields, namely milestone and area. Common to many projects, these allow bugs to be separated into different functional components and periods of time. But of course, you couldn’t filter by these fields, nor display them in the bug list, or perhaps they just didn’t quite suit the project workflow.

    The custom fields feature allows up to thirty custom fields to be defined in the bug tracker area. Each custom field appears in every bug and can be used in filters and results lists. Custom fields can either stand as free text or be constrained to a set of options.

    How would you like to see your bugs today?

    Sometimes it helps to see the values of the various fields in the bug tracker. Customize the display of the bugs list by adding (or hiding) certain columns of interest. An overview query might include the AssignedTo field to give a feel for bug distribution; meanwhile, if you’re looking at just your own bugs, it’s probably a good opportunity to give that column a rest.

    Analyze this

    While the web interface lets all Workspace members manage and browse through the bug database, the interface isn’t always conducive to in-depth analysis. Next week, with the ability to export bug lists to XML, reporting becomes far easier using any manner of tools of your choice, from a hand-written XML parser to the ever useful Microsoft Excel.

    File attachments

    Sometimes words just can’t say enough. Why not save a thousand or so and attach a screenshot of a bug manifestation or maybe your artist’s impression of the UI of the future?  Debug logs, trace files and XML configuration files can all be attached to individual bugs to give some context for your Workspace colleagues.

    And there’s more, stay tuned..

  • Drag and drop file uploads in IE with .NET

    I've received a couple of requests lately about how to implement drag-and-drop multiple file uploads in Internet Explorer from within managed code. Fortunately for me, someone else has already taken the liberty of writing an article on the subject at large: Host Secure, Lightweight Client-Side Controls in Microsoft Internet Explorer. Just a couple of tweaks and it'll be accepting files via drag and drop too.

    In MultiUploadCtrl.cs, we need to enable drag and drop processing in the user control. Setting AllowDrop=True handles that in one swoop, now all that's left is the plumbing to handle the dropped files. For the events, DragEnter and DragDrop, the following should work well:

    private void MultiUploadCtrl_DragEnter(object sender, System.Windows.Forms.DragEventArgs e)
    {
     
    if (e.Data.GetDataPresent("FileDrop"))
       
    e.Effect = DragDropEffects.Copy;
     
    else
       
    e.Effect = DragDropEffects.None;
    }

    private void MultiUploadCtrl_DragDrop(object sender, System.Windows.Forms.DragEventArgs e)
    {
     
    new FileIOPermission(PermissionState.Unrestricted).Assert();
     
    foreach (string fileListItem in (e.Data.GetData("FileDrop") as string[]))
     
    {
       
    if (!fileTable.Contains(fileListItem))
       
    {
         
    AddFile(fileListItem);
       
    }
     
    }
     
    CodeAccessPermission.RevertAssert();
     
    UpdateFileSizeDescription();
    }

  • wksalone updated

    Thanks to Omar Shahine for updating wksalone, now with built-in Workspace selection and stored window size/position preferences.
  • RSS Bandit moving on

    Dare posts about RSS Bandit leaving GotDotNet Workspaces. Workspaces is still a relatively young application and is something that continues to grow. Does it provide everything the community project developer needs? Not yet, but we're working on it.

    Looking at a few of Dare's points in loose order:

    1. Doesn't require people have Passport accounts to download the RSS Bandit installer.

    2. We get download and page load statistics.

    We hear you. We've consistently heard this feedback and these are among just a few of the changes we'll be putting in place in the new few months. 

    3. Bug reports can have file attachments. This is great since a lot of the time we end up wishing people would attach their error.log or feedlist.xml file with their bug reports.

    5. Separate databases for features vs. bugs.

    8. Bug tracker remembers your queries and the default query is more useful to me (all open bugs) than GDN's (all bugs assigned to me even closed ones).

    There are a number of big changes coming in the bug tracker. I'll be making a blog post about some of them later this week. In brief, watch out for:

    •  user-defined custom fields (Milestone, Feature/Bug, ToBeFixedBy, WasFixedIn, might all be examples)
    • flexible queries (based on boolean combination of multiple fields, customizable by each user)
    • file attachments
    • export to XML functionality

    6. Source code can be browsed over HTTP via ViewCVS without having to install any software

    There's an HTML interface to the Source Control area that doesn't involve any software either. Its functionality is limited to basic viewing of files and history, but does also provide check in and check out on a per file basis. The interface selection page can be reached by using the "Interface selection" link in the menu on any Source Control page.

    7. Larger quotas on how much you can store on their servers.

    Any Workspace owners are welcome to use the quota request form to ask for extra space or additional members. Provided requests are being made for an active project, they will be checked and approved.

    9. Activity score more accurately reflects activity of the project (on GDN, BlogX is scored at having 99% activity score even though the project has been dead for all intents and purposes for several months).

    Interesting, I was talking about activity metrics just the other day. BlogX is definitely on its way down the list, but it still receives hits. That, combined with its strong activity rating from earlier times when it was under active development, help to keep its high rating. Despite being a dead project, it's not the policy of GotDotNet to tweak these metrics; time should balance this one out as people move on.

    10. With SourceForge we get to use the BSD licence.

    The Workspaces licensing system allows for any license to be submitted at Workspace creation time. As a Workspace owner, you first accept the 'Use Agreement', which covers the overall usage of the application, and then proceed to pick a license to cover the content. As a suggestion, you can use a Shared Source license, although any licenses are welcome. As owner, you'll want to make sure that you have the sufficient rights to apply such a license to the content.

    Sure, there are still a few areas where Workspaces is lacking but things are changing. As has always been the case, feedback sent through the GotDotNet site, posts to message boards, even blog entries (thank you Feedster!) all gets read and placed together into a tracking system. As a small team, we're not able to reply to everything individually, but we are listening.

  • Workspaces activity metrics

    In the Workspaces directory, what is the activity number and how is it calculated?

    The activity percentile assigned to each Workspace is calculated on a nightly basis and gives an idea of the relative activity of different Workspaces. As a percentile, a Workspace with a score of 90.0 can be understood to be more 'active' than 90% of the other Workspaces hosted on GotDotNet.

    Activity is, however, a rather general word. The ranking is determined in a batch job that compares the 'point scores' for each Workspace over both the previous day and the Workspace's standing the night before. Whenever something happens in a Workspace, be it a check in, a message board post, a release download or even a page view, some points are added to a running total for that Workspace on that day. Note that that list is not exhaustive and that different events can add different numbers of points to the total (for example, a release submission is more significant than a simple page view).

    As with any system involving ranking, there is always a risk of abuse whereby undeserving candidates could artificially elevate their position. The GotDotNet team maintains a general watch over the highly ranked Workspaces to make sure that their positioning remains fair. So far, the top Workspaces really are the ones that are seeing a significant amount of either development or release download activity and there no weighting currently involved in calculating these metrics.

    So how to get your Workspace to the top? Well, community projects with broad appeal (to both contributors and users) are the best candidates; those that are generating a cross-section of traffic in terms of source control actions, downloads and message board discussion will tend to float to the top of the list. Good luck!

  • O'Reilly on Annotations

    Ian Griffiths over at O’Reilly has put together a great article on the Longhorn SDK annotations and how O'Reilly put together the first independent feed. It’s a good read.

  • 'The Compressed (zipped) Folder is invalid or corrupted'

    Some people have reported problems downloading releases from the Workspaces application; either they find a 0 byte file, or are presented with the message 'The Compressed (zipped) Folder is invalid or corrupted'. Either way, not fun.

    From the list of late-breaking issues:
    On downloading a release, the error message "The Compressed (zipped) Folder is invalid or corrupted." is shown
    This corresponds to a known problem in the way Internet Explorer downloads compressed files. For more information, see KB 308090. As suggested in that article, this problem can be worked around by first saving the compressed folder to disk, and opening the release from the saved location.

    So, the KB has background and the workaround is to save to disk. What if you never have that option? You may have (inadvertantly) configured your machine to always open ZIP files, without asking you first. To fix this, open up any Windows Explorer window, Tools/Folder Options, then on the File Types tab find ZIP files and click Advanced. Finally, make sure the 'Confirm open after download' box is checked.

    All fixed.

  • Passport exceptions in wkssync and wksalone

    (Just posted to the news sections in these Workspaces)

    If you're running wkssync or wksalone on a machine that's not previously been used with the VS.NET provider for Workspaces, you need to do one of the following

    • Run the VS.NET provider installation package

    or

    • Create the registry key 'SOFTWARE\Microsoft\Windows\CurrentVersion\\Internet Settings\Passport' and add a string value titled 'LoginServerURL' that points to 'https://login.passport.com/login2.srf?lc=1033'

    That should resolve any exceptions being thrown during the passport authentication stages.

    Thanks Ethan!

  • Workspaces 1.1

    Not to be left out, GotDotNet Workspaces has also seen a few changes recently. We’ve fixed a handful of problems and introduced a number of new features. Changes to watch out for:

    • Access control system
    • Notifications for Workspaces events
    • Customization capabilities, including the ability to upload documents and images
    • Workspace ‘alias’ support for shorter URLs

    Access control gives Workspace owners the ability to organize members of their Workspace into any number of groups. These groups can then be granted permissions to do various things within a Workspace. For example, in some cases I may want anyone (literally ‘anyone with a browser’) to be able to open bugs, any Workspace member to be able to edit them, and only people in the ‘Testers’ group able to close them. No problem. With a complex code tree checked in to Source Control, it’s also easy to control who has read and write access to separate parts of the tree.

     

    Notifications are now available for many more Workspace events than previously. Introducing the idea of ‘watching’, members can elect to be notified when certain changes are made to a bug, file or folder, as well as message boards and news.

     

    The alias support is so simple, why mention it? Well, try memorizing a GUID, or speaking one over the phone, and all of a sudden it becomes obvious. Now, easy to remember: http://workspaces.gotdotnet.com/alias/. 

     

    As always, the best way to learn more about Workspaces is to explore..

  • wksalone

    Just published: wksalone, a little wrapper that hosts the GotDotNet Workspaces Windows Forms interface in a standalone app, rather than Internet Explorer.

    Beware, this application is trivial and contains no pretty interface for selecting a Workspace or an type of error handling. Use at your own risk.

  • Safely displaying untrusted HTML

    One of the challenges in importing external RSS feeds for the annotations aggregator is how to safely display untrusted HTML. Enter the SECURITY attribute of the IFRAME, a great way of instructing the browser to render the contents of the frame in the Restricted Sites zone, thus (by default) limiting the capabilities of HTML in that frame to markup and not much else.

     

    To cut a long story short, the client-side component encodes the incoming HTML from the RSS feed and ships it around in that HtmlEncoded state through a series of transforms to provide sorting, create borders and generally beautify. Just before it’s rendered in the browser, there’s a final decoding step to decode that content back into HTML so that the markup is interpreted for display to the end user.

     

    Since there’s no built-in client side implementation, here’s a rendition of Server.HtmlDecode in Javascript:

     

    // HtmlDecode http://lab.msdn.microsoft.com/annotations/htmldecode.js

    //   client side version of the useful Server.HtmlDecode method

    //   takes one string (encoded) and returns another (decoded)

    function HtmlDecode(s)

    {

          var out = "";

          if (s==null) return;

     

          var l = s.length;

          for (var i=0; i<l; i++)

          {

                var ch = s.charAt(i);

               

                if (ch == '&')

                {

                      var semicolonIndex = s.indexOf(';', i+1);

                     

                if (semicolonIndex > 0)

                {

                            var entity = s.substring(i + 1, semicolonIndex);

                            if (entity.length > 1 && entity.charAt(0) == '#')

                            {

                                  if (entity.charAt(1) == 'x' || entity.charAt(1) == 'X')

                                        ch = String.fromCharCode(eval('0'+entity.substring(1)));

                                  else

                                        ch = String.fromCharCode(eval(entity.substring(1)));

                            }

                        else

                          {

                                  switch (entity)

                                  {

                                        case 'quot': ch = String.fromCharCode(0x0022); break;

                                        case 'amp': ch = String.fromCharCode(0x0026); break;

                                        case 'lt': ch = String.fromCharCode(0x003c); break;

                                        case 'gt': ch = String.fromCharCode(0x003e); break;

                                        case 'nbsp': ch = String.fromCharCode(0x00a0); break;

                                        case 'iexcl': ch = String.fromCharCode(0x00a1); break;

                                        case 'cent': ch = String.fromCharCode(0x00a2); break;

                                        case 'pound': ch = String.fromCharCode(0x00a3); break;

                                        case 'curren': ch = String.fromCharCode(0x00a4); break;

                                        case 'yen': ch = String.fromCharCode(0x00a5); break;

                                        case 'brvbar': ch = String.fromCharCode(0x00a6); break;

                                        case 'sect': ch = String.fromCharCode(0x00a7); break;

                                        case 'uml': ch = String.fromCharCode(0x00a8); break;

                                        case 'copy': ch = String.fromCharCode(0x00a9); break;

                                        case 'ordf': ch = String.fromCharCode(0x00aa); break;

                                        case 'laquo': ch = String.fromCharCode(0x00ab); break;

                                        case 'not': ch = String.fromCharCode(0x00ac); break;

                                        case 'shy': ch = String.fromCharCode(0x00ad); break;

                                        case 'reg': ch = String.fromCharCode(0x00ae); break;

                                        case 'macr': ch = String.fromCharCode(0x00af); break;

                                        case 'deg': ch = String.fromCharCode(0x00b0); break;

                                        case 'plusmn': ch = String.fromCharCode(0x00b1); break;

                                        case 'sup2': ch = String.fromCharCode(0x00b2); break;

                                        case 'sup3': ch = String.fromCharCode(0x00b3); break;

                                        case 'acute': ch = String.fromCharCode(0x00b4); break;

                                        case 'micro': ch = String.fromCharCode(0x00b5); break;

                                        case 'para': ch = String.fromCharCode(0x00b6); break;

                                        case 'middot': ch = String.fromCharCode(0x00b7); break;

                                        case 'cedil': ch = String.fromCharCode(0x00b8); break;

                                        case 'sup1': ch = String.fromCharCode(0x00b9); break;

                                        case 'ordm': ch = String.fromCharCode(0x00ba); break;

                                        case 'raquo': ch = String.fromCharCode(0x00bb); break;

                                        case 'frac14': ch = String.fromCharCode(0x00bc); break;

                                        case 'frac12': ch = String.fromCharCode(0x00bd); break;

                                        case 'frac34': ch = String.fromCharCode(0x00be); break;

                                        case 'iquest': ch = String.fromCharCode(0x00bf); break;

                                        case 'Agrave': ch = String.fromCharCode(0x00c0); break;

                                        case 'Aacute': ch = String.fromCharCode(0x00c1); break;

                                        case 'Acirc': ch = String.fromCharCode(0x00c2); break;

                                        case 'Atilde': ch = String.fromCharCode(0x00c3); break;

                                        case 'Auml': ch = String.fromCharCode(0x00c4); break;

                                        case 'Aring': ch = String.fromCharCode(0x00c5); break;

                                        case 'AElig': ch = String.fromCharCode(0x00c6); break;

                                        case 'Ccedil': ch = String.fromCharCode(0x00c7); break;

                                        case 'Egrave': ch = String.fromCharCode(0x00c8); break;

                                        case 'Eacute': ch = String.fromCharCode(0x00c9); break;

                                        case 'Ecirc': ch = String.fromCharCode(0x00ca); break;

                                        case 'Euml': ch = String.fromCharCode(0x00cb); break;

                                        case 'Igrave': ch = String.fromCharCode(0x00cc); break;

                                        case 'Iacute': ch = String.fromCharCode(0x00cd); break;

                                        case 'Icirc': ch = String.fromCharCode(0x00ce ); break;

                                        case 'Iuml': ch = String.fromCharCode(0x00cf); break;

                                        case 'ETH': ch = String.fromCharCode(0x00d0); break;

                                        case 'Ntilde': ch = String.fromCharCode(0x00d1); break;

                                        case 'Ograve': ch = String.fromCharCode(0x00d2); break;

                                        case 'Oacute': ch = String.fromCharCode(0x00d3); break;

                                        case 'Ocirc': ch = String.fromCharCode(0x00d4); break;

                                        case 'Otilde': ch = String.fromCharCode(0x00d5); break;

                                        case 'Ouml': ch = String.fromCharCode(0x00d6); break;

                                        case 'times': ch = String.fromCharCode(0x00d7); break;

                                        case 'Oslash': ch = String.fromCharCode(0x00d8); break;

                                        case 'Ugrave': ch = String.fromCharCode(0x00d9); break;

                                        case 'Uacute': ch = String.fromCharCode(0x00da); break;

                                        case 'Ucirc': ch = String.fromCharCode(0x00db); break;

                                        case 'Uuml': ch = String.fromCharCode(0x00dc); break;

                                        case 'Yacute': ch = String.fromCharCode(0x00dd); break;

                                        case 'THORN': ch = String.fromCharCode(0x00de); break;

                                        case 'szlig': ch = String.fromCharCode(0x00df); break;

                                        case 'agrave': ch = String.fromCharCode(0x00e0); break;

                                        case 'aacute': ch = String.fromCharCode(0x00e1); break;

                                        case 'acirc': ch = String.fromCharCode(0x00e2); break;

                                        case 'atilde': ch = String.fromCharCode(0x00e3); break;

                                        case 'auml': ch = String.fromCharCode(0x00e4); break;

                                        case 'aring': ch = String.fromCharCode(0x00e5); break;

                                        case 'aelig': ch = String.fromCharCode(0x00e6); break;

                                        case 'ccedil': ch = String.fromCharCode(0x00e7); break;

                                        case 'egrave': ch = String.fromCharCode(0x00e8); break;

                                        case 'eacute': ch = String.fromCharCode(0x00e9); break;

                                        case 'ecirc': ch = String.fromCharCode(0x00ea); break;

                                        case 'euml': ch = String.fromCharCode(0x00eb); break;

                                        case 'igrave': ch = String.fromCharCode(0x00ec); break;

                                        case 'iacute': ch = String.fromCharCode(0x00ed); break;

                                        case 'icirc': ch = String.fromCharCode(0x00ee); break;

                                        case 'iuml': ch = String.fromCharCode(0x00ef); break;

                                        case 'eth': ch = String.fromCharCode(0x00f0); break;

                                        case 'ntilde': ch = String.fromCharCode(0x00f1); break;

                                        case 'ograve': ch = String.fromCharCode(0x00f2); break;

                                        case 'oacute': ch = String.fromCharCode(0x00f3); break;

                                        case 'ocirc': ch = String.fromCharCode(0x00f4); break;

                                        case 'otilde': ch = String.fromCharCode(0x00f5); break;

                                        case 'ouml': ch = String.fromCharCode(0x00f6); break;

                                        case 'divide': ch = String.fromCharCode(0x00f7); break;

                                        case 'oslash': ch = String.fromCharCode(0x00f8); break;

                                        case 'ugrave': ch = String.fromCharCode(0x00f9); break;

                                        case 'uacute': ch = String.fromCharCode(0x00fa); break;

                                        case 'ucirc': ch = String.fromCharCode(0x00fb); break;

                                        case 'uuml': ch = String.fromCharCode(0x00fc); break;

                                        case 'yacute': ch = String.fromCharCode(0x00fd); break;

                                        case 'thorn': ch = String.fromCharCode(0x00fe); break;

                                        case 'yuml': ch = String.fromCharCode(0x00ff); break;

                                        case 'OElig': ch = String.fromCharCode(0x0152); break;

                                        case 'oelig': ch = String.fromCharCode(0x0153); break;

                                        case 'Scaron': ch = String.fromCharCode(0x0160); break;

                                        case 'scaron': ch = String.fromCharCode(0x0161); break;

                                        case 'Yuml': ch = String.fromCharCode(0x0178); break;

                                        case 'fnof': ch = String.fromCharCode(0x0192); break;

                                        case 'circ': ch = String.fromCharCode(0x02c6); break;

                                        case 'tilde': ch = String.fromCharCode(0x02dc); break;

                                        case 'Alpha': ch = String.fromCharCode(0x0391); break;

                                        case 'Beta': ch = String.fromCharCode(0x0392); break;

                                        case 'Gamma': ch = String.fromCharCode(0x0393); break;

                                        case 'Delta': ch = String.fromCharCode(0x0394); break;

                                        case 'Epsilon': ch = String.fromCharCode(0x0395); break;

                                        case 'Zeta': ch = String.fromCharCode(0x0396); break;

                                        case 'Eta': ch = String.fromCharCode(0x0397); break;

                                        case 'Theta': ch = String.fromCharCode(0x0398); break;

                                        case 'Iota': ch = String.fromCharCode(0x0399); break;

                                        case 'Kappa': ch = String.fromCharCode(0x039a); break;

                                        case 'Lambda': ch = String.fromCharCode(0x039b); break;

                                        case 'Mu': ch = String.fromCharCode(0x039c); break;

                                        case 'Nu': ch = String.fromCharCode(0x039d); break;

                                        case 'Xi': ch = String.fromCharCode(0x039e); break;

                                        case 'Omicron': ch = String.fromCharCode(0x039f); break;

                                        case 'Pi': ch = String.fromCharCode(0x03a0); break;

                                        case ' Rho ': ch = String.fromCharCode(0x03a1); break;

                                        case 'Sigma': ch = String.fromCharCode(0x03a3); break;

                                        case 'Tau': ch = String.fromCharCode(0x03a4); break;

                                        case 'Upsilon': ch = String.fromCharCode(0x03a5); break;

                                        case 'Phi': ch = String.fromCharCode(0x03a6); break;

                                        case 'Chi': ch = String.fromCharCode(0x03a7); break;

                                        case 'Psi': ch = String.fromCharCode(0x03a8); break;

                                        case 'Omega': ch = String.fromCharCode(0x03a9); break;

                                        case 'alpha': ch = String.fromCharCode(0x03b1); break;

                                        case 'beta': ch = String.fromCharCode(0x03b2); break;

                                        case 'gamma': ch = String.fromCharCode(0x03b3); break;

                                        case 'delta': ch = String.fromCharCode(0x03b4); break;

                                        case 'epsilon': ch = String.fromCharCode(0x03b5); break;

                                        case 'zeta': ch = String.fromCharCode(0x03b6); break;

                                        case 'eta': ch = String.fromCharCode(0x03b7); break;

                                        case 'theta': ch = String.fromCharCode(0x03b8); break;

                                        case 'iota': ch = String.fromCharCode(0x03b9); break;

                                        case 'kappa': ch = String.fromCharCode(0x03ba); break;

                                        case 'lambda': ch = String.fromCharCode(0x03bb); break;

                                        case 'mu': ch = String.fromCharCode(0x03bc); break;

                                        case 'nu': ch = String.fromCharCode(0x03bd); break;

                                        case 'xi': ch = String.fromCharCode(0x03be); break;

                                        case 'omicron': ch = String.fromCharCode(0x03bf); break;

                                        case 'pi': ch = String.fromCharCode(0x03c0); break;

                                        case 'rho': ch = String.fromCharCode(0x03c1); break;

                                        case 'sigmaf': ch = String.fromCharCode(0x03c2); break;

                                        case 'sigma': ch = String.fromCharCode(0x03c3); break;

                                        case 'tau': ch = String.fromCharCode(0x03c4); break;

                                        case 'upsilon': ch = String.fromCharCode(0x03c5); break;

                                        case 'phi': ch = String.fromCharCode(0x03c6); break;

                                        case 'chi': ch = String.fromCharCode(0x03c7); break;

                                        case 'psi': ch = String.fromCharCode(0x03c8); break;

                                        case 'omega': ch = String.fromCharCode(0x03c9); break;

                                        case 'thetasym': ch = String.fromCharCode(0x03d1); break;

                                        case 'upsih': ch = String.fromCharCode(0x03d2); break;

                                        case 'piv': ch = String.fromCharCode(0x03d6); break;

                                        case 'ensp': ch = String.fromCharCode(0x2002); break;

                                        case 'emsp': ch = String.fromCharCode(0x2003); break;

                                        case 'thinsp': ch = String.fromCharCode(0x2009); break;

                                        case 'zwnj': ch = String.fromCharCode(0x200c); break;

                                        case 'zwj': ch = String.fromCharCode(0x200d); break;

                                        case 'lrm': ch = String.fromCharCode(0x200e); break;

                                        case 'rlm': ch = String.fromCharCode(0x200f); break;

                                        case 'ndash': ch = String.fromCharCode(0x2013); break;

                                        case 'mdash': ch = String.fromCharCode(0x2014); break;

                                        case 'lsquo': ch = String.fromCharCode(0x2018); break;

                                        case 'rsquo': ch = String.fromCharCode(0x2019); break;

                                        case 'sbquo': ch = String.fromCharCode(0x201a); break;

                                        case 'ldquo': ch = String.fromCharCode(0x201c); break;

                                        case 'rdquo': ch = String.fromCharCode(0x201d); break;

                                        case 'bdquo': ch = String.fromCharCode(0x201e); break;

                                        case 'dagger': ch = String.fromCharCode(0x2020); break;

                                        case 'Dagger': ch = String.fromCharCode(0x2021); break;

                                        case 'bull': ch = String.fromCharCode(0x2022); break;

                                        case 'hellip': ch = String.fromCharCode(0x2026); break;

                                        case 'permil': ch = String.fromCharCode(0x2030); break;

                                        case 'prime': ch = String.fromCharCode(0x2032); break;

                                        case 'Prime': ch = String.fromCharCode(0x2033); break;

                                        case 'lsaquo': ch = String.fromCharCode(0x2039); break;

                                        case 'rsaquo': ch = String.fromCharCode(0x203a); break;

                                        case 'oline': ch = String.fromCharCode(0x203e); break;

                                        case 'frasl': ch = String.fromCharCode(0x2044); break;

                                        case 'euro': ch = String.fromCharCode(0x20ac); break;

                                        case 'image': ch = String.fromCharCode(0x2111); break;

                                        case 'weierp': ch = String.fromCharCode(0x2118); break;

                                        case 'real': ch = String.fromCharCode(0x211c); break;

                                        case 'trade': ch = String.fromCharCode(0x2122); break;

                                        case 'alefsym': ch = String.fromCharCode(0x2135); break;

                                        case 'larr': ch = String.fromCharCode(0x2190); break;

                                        case 'uarr': ch = String.fromCharCode(0x2191); break;

                                        case 'rarr': ch = String.fromCharCode(0x2192); break;

                                        case 'darr': ch = String.fromCharCode(0x2193); break;

                                        case 'harr': ch = String.fromCharCode(0x2194); break;

                                        case 'crarr': ch = String.fromCharCode(0x21b5); break;

                                        case 'lArr': ch = String.fromCharCode(0x21d0); break;

                                        case 'uArr': ch = String.fromCharCode(0x21d1); break;

                                        case 'rArr': ch = String.fromCharCode(0x21d2); break;

                                        case 'dArr': ch = String.fromCharCode(0x21d3); break;

                                        case 'hArr': ch = String.fromCharCode(0x21d4); break;

                                        case 'forall': ch = String.fromCharCode(0x2200); break;

                                        case 'part': ch = String.fromCharCode(0x2202); break;

                                        case 'exist': ch = String.fromCharCode(0x2203); break;

                                        case 'empty': ch = String.fromCharCode(0x2205); break;

                                        case 'nabla': ch = String.fromCharCode(0x2207); break;

                                        case 'isin': ch = String.fromCharCode(0x2208); break;

                                        case 'notin': ch = String.fromCharCode(0x2209); break;

                                        case 'ni': ch = String.fromCharCode(0x220b); break;

                                        case 'prod': ch = String.fromCharCode(0x220f); break;

                                        case 'sum': ch = String.fromCharCode(0x2211); break;

                                        case 'minus': ch = String.fromCharCode(0x2212); break;

                                        case 'lowast': ch = String.fromCharCode(0x2217); break;

                                        case 'radic': ch = String.fromCharCode(0x221a); break;

                                        case 'prop': ch = String.fromCharCode(0x221d); break;

                                        case 'infin': ch = String.fromCharCode(0x221e); break;

                                        case 'ang': ch = String.fromCharCode(0x2220); break;

                                        case 'and': ch = String.fromCharCode(0x2227); break;

                                        case 'or': ch = String.fromCharCode(0x2228); break;

                                        case 'cap': ch = String.fromCharCode(0x2229); break;

                                        case 'cup': ch = String.fromCharCode(0x222a); break;

                                        case 'int': ch = String.fromCharCode(0x222b); break;

                                        case 'there4': ch = String.fromCharCode(0x2234); break;

                                        case 'sim': ch = String.fromCharCode(0x223c); break;

                                        case 'cong': ch = String.fromCharCode(0x2245); break;

                                        case 'asymp': ch = String.fromCharCode(0x2248); break;

                                        case 'ne': ch = String.fromCharCode(0x2260); break;

                                        case 'equiv': ch = String.fromCharCode(0x2261); break;

                                        case 'le': ch = String.fromCharCode(0x2264); break;

                                        case 'ge': ch = String.fromCharCode(0x2265); break;

                                        case 'sub': ch = String.fromCharCode(0x2282); break;

                                        case 'sup': ch = String.fromCharCode(0x2283); break;

                                        case 'nsub': ch = String.fromCharCode(0x2284); break;

                                        case 'sube': ch = String.fromCharCode(0x2286); break;

                                        case 'supe': ch = String.fromCharCode(0x2287); break;

                                        case 'oplus': ch = String.fromCharCode(0x2295); break;

                                        case 'otimes': ch = String.fromCharCode(0x2297); break;

                                        case 'perp': ch = String.fromCharCode(0x22a5); break;

                                        case 'sdot': ch = String.fromCharCode(0x22c5); break;

                                        case 'lceil': ch = String.fromCharCode(0x2308); break;

                                        case 'rceil': ch = String.fromCharCode(0x2309); break;

                                        case 'lfloor': ch = String.fromCharCode(0x230a); break;

                                        case 'rfloor': ch = String.fromCharCode(0x230b); break;

                                        case 'lang': ch = String.fromCharCode(0x2329); break;

                                        case 'rang': ch = String.fromCharCode(0x232a); break;

                                        case 'loz': ch = String.fromCharCode(0x25ca); break;

                                        case 'spades': ch = String.fromCharCode(0x2660); break;

                                        case 'clubs': ch = String.fromCharCode(0x2663); break;

                                        case 'hearts': ch = String.fromCharCode(0x2665); break;

                                        case 'diams': ch = String.fromCharCode(0x2666); break;

                                        default: ch = ''; break;

                                  }

                            }

                            i = semicolonIndex;

                      }

                }

               

                out += ch;

          }

     

          return out;

         

    }

  • Annotations content from O'Reilly

More Posts Next page »

This Blog

Syndication

News

The posts on this weblog are provided “AS IS” with no warranties, and confer no rights. The opinions expressed herein are my own personal opinions and do not represent my employer’s view in any way.

My personal blog is updated more frequently.

© 2009 Microsoft Corporation. All rights reserved. Terms of Use  |  Trademarks  |  Privacy Statement
Microsoft
Page view tracker