T3Cast zu DEV3: Eclipse basierte FLOW3- und TYPO3-Entwicklung

T3Cast zu DEV3: Eclipse basierte FLOW3- und TYPO3-Entwicklung: „David Brühlmeier ist Robert Lemke per Skype aus einem Park in Zürich zugeschaltet. In knapp 20 Minuten zeigt Brühlmeier Robert Lemke beispielhaft, wie die von ihm im Rahmen seiner Masterarbeit geschaffene Entwicklungsumgebung DEV3 zu bedienen ist.

Gezeigt werden alle für die Arbeit notwendigen Schritte: Nach der eigentlichen Installation des Plugins wird die weitere Einrichtung gezeigt. Darüber hinaus geben Robert Lemke und David Brühlmeier einen Einblick in die Arbeit mit DEV3.

Das Projekt DEV3 verfolgt das Ziel, Entwicklern eine auf Eclipse und den PHP Development Tools (PDT) basierende Entwicklungsumgebung für TYPO3 zur Verfügung zu stellen.

Entstanden ist DEV3 aus den zuvor unabhängig gestarteten Projekten tyClipse von Sebastian Böttger und Eckhard M. Jäger sowie FLOW3DE von David Brühlmeier. Auf Anraten von TYPO3 5.0– und FLOW3-Entwicklungsleiter Robert Lemke haben sich die Projekte zur gemeinsamen Arbeit entschlossen.“

(Via t3n.yeebase.com – Open Source, Web & TYPO3.)

Open-Source-Plattform für Social Networks: Elgg v1.0 startet

Open-Source-Plattform für Social Networks: Elgg v1.0 startet: „Elgg ist eine Open-Source-Social-Network-Plattform, die Blogging, Networking, Messaging, Communitys, RSS-Feeds und Filesharing miteinander verbindet. Die webbasierte Anwendung wurde auf der Grundlage von LAMP (Linux, Apache, MySQL, PHP) entwickelt.

Ein wesentlicher Bestandteil von Elgg sind die ‚Views‘. Damit werden die einzelnen Seiten für unterschiedliche Anwendungsfelder aufbereitet. Neben Standard-HTML sind beispielsweise Views für mobiles Internet, iPhone oder als eingebettetes Widget möglich.

Das Konzept von Elgg beinhaltet die Erweiterung der Plattform über Plugins. Damit diese Möglichkeit einfach und schnell umsetzbar wird, wurde das Framework von Elgg so geschrieben, dass viele Komponenten eines Plugins schon enthalten sind, wie beispielsweise ein Benachrichtigungssystem, Import/Export-Filter, Sprachanpassung und eine API.

Die Möglichkeit zum Datentransport zwischen unterschiedlichen Social Networks wurde in der nahen Vergangenheit immer wieder gefordert und von einigen Netzwerken auch schon angegangen. Elgg präsentiert in diesem Bereich mit der openData Definition (ODD) schon zum Start ein fertiges Konzept, mit dem die Nutzer in der Lage sein sollen, ihre persönlichen Daten von einem Netzwerk in ein anderes zu kopieren.

Die Social-Network-Plattform Elgg verfügt über einen hohen Funktionsumfang und ist als webbasierte Anwendung crossplattformfähig. Das vom Start weg enthaltene Konzept zur Data Portability macht Elgg zukunftssicher und hält eventuell vorhandene Einstiegshürden niedrig. Die vereinfachte Möglichkeit zur Entwicklung von Plugins sorgt zudem für eine zusätzliche Anpassungsfähigkeit der mit Elgg entwickelten Social Networks.

Heute (18.08) startet Elgg nun die finale Version 1.0. Einen ersten Eindruck kann man sich mit einer Testseite von Elgg verschaffen.“

(Via t3n.yeebase.com – Open Source, Web & TYPO3.)

A Closer Look at YUI 3.0 PR 1: Dav Glass’s Draggable Portal Example

A Closer Look at YUI 3.0 PR 1: Dav Glass’s Draggable Portal Example: „

YUI 3.0 Preview Release 1 was made available on Wednesday, and with it we provided a look at how the next major iteration of YUI is taking shape. Among the elements we shipped with the preview is a new example from Dav Glass, the Draggable Portal, which exercises a broad cross section of the preview’s contents.

The Portal Example in the YUI 3.0 preview release.

The Draggable Portal is a common design pattern in which content modules on the page can be repositioned, minimized, removed, and re-added to the page. The state of the modules persists in the background, so a reload of the page or a return to the page calls up the modules in their most recently positioned state. You see variations of this design pattern on many personlizable portals like My Yahoo, NetVibes, and iGoogle.

In this article, we’ll take a look under the hood of this example to get a richer sense of YUI’s 3.x codeline and the idioms and patterns it establishes. We’re just pulling out some specific code snippets to examine here, but you can review the full code source for this exampleand for 66 others — on the YUI 3 website.

(more…)

(Via Yahoo! User Interface Blog.)

YUI 3.0 Preview Release 1

YUI 3.0 Preview Release 1: „

YUI 3.0 Preview 1 website.The YUI team is pleased to announce the public availability of YUI 3.0 Preview Release 1, an early look at what we’re working on for the next generation of the YUI Library. Documentation for YUI 3.0 is on the YUI website; the download is available on the YUI project area on SourceForge; you can find us with questions or comments on the YUI 3.x discussion forum. Keep in mind that this is an early preview, not a production-quality (or even a beta) release. This release is not suitable for production use, but it will give you an idea of what we’re working on, and it should provide a good framework for conversation about the future of the library.

Five Goals for YUI 3:

We’ve talked to thousands of YUI users over the past 30 months, and based on that feedback we’ve set five design goals for the next generation of the library. What you’ve told us is that YUI 3.0 should be:

  • lighter (less K-weight on the wire and on the page for most uses)
  • faster (fewer http requests, less code to write and compile, more efficient code)
  • more consistent (common naming, event signatures, and widget APIs throughout the library)
  • more powerful (do more with less implementation code)
  • more securable (safer and easier to expose to multiple developers working in the same environment; easier to run under systems like Caja or ADsafe)

With this early release, we’ve made progress toward most of these objectives — and we believe we have the right architecture in place to meet all five as we move to GA over the next few quarters.

What’s New in YUI 3.0?

When you start to write code using YUI 3.0, you’ll notice some changes in structure and style. Here’s a taste:

Snippet: What it does:
YUI().use('node', function(Y) {
    Y.get('#demo').addClass('enabled');
});
Creates a YUI instance with the node module (and any dependencies) and adds the class ‚enabled‘ to the element with the id of ‚demo‘.
YUI().use('dd-drag', function(Y) {
        var dd = new Y.DD.Drag({
        node: '#demo'
    });
});
Creates an instance of YUI with basic drag functionality (a subset of the dd module), and makes the element with the id of ‚demo‘ draggable.
Y.all('.demo').addClass('enabled');
Adds the class ‚enabled‘ to the all elements with the className ‚demo‘.
Y.all('.demo').set('title', 'Ready!').removeClass('disabled');
Sets the title attribute of all elements with the className ‚demo‘ and removes the class ‚disabled‘ from each.
Y.get('#demo').plug(Y.Plugin.Drag, {
    handles: 'h2'
});
Adds the Drag plugin to the element with the id ‚demo‘, and enables all of its h2 children drag as handles.
Y.on('click', function(e) {
    e.preventDefault();
    e.target.query('em').set('innerHTML', 'clicked');
}, '#demo a');
Attaches a DOM event listener to all anchor elements that are children of the element with the id ‚demo‘. The event handler prevents the anchor from navigating and then sets a value for the innerHTML of the first em element of the clicked anchor.

What’s different here?

  • Sandboxing: Each YUI instance on the page can be self-contained, protected and limited (YUI().use()). This segregates it from other YUI instances, tailors the functionality to your specific needs, and lets different versions of YUI play nicely together.
  • Modularity: YUI 3 is architected to use smaller modular pieces, giving you fine-grained control over what functionality you put on the page. If you simply want to make something draggable, you can include the dd-drag submodule, which is a small subset of the Drag & Drop Utility.
  • Self-completing: As long as the basic YUI seed file is in place, you can make use of any functionality in the library. Tell YUI what modules you want to use, tie that to your implementation code, and YUI will bring in all necessary dependencies in a single HTTP request before executing your code.
  • Selectors: Elements are targeted using intuitive CSS selector idioms, making it easy to grab an element or a group of elements whenever you’re performing an operation.
  • Custom Events++: Custom Events are even more powerful in YUI 3.0, with support for bubbling, stopping propagation, assigning/preventing default behaviors, and more. In fact, the Custom Event engine provides a common interface for DOM and API events in YUI 3.0, creating a consistent idiom for all kinds of event-driven work.
  • Nodes and NodeLists: Element references in YUI 3.0 are mediated by Node and NodeList facades. Not only does this make implementation code more expressive (Y.Node.get('#main ul li').addClass('foo');), it makes it easier to normalize differences in browser behavior (Y.Node.get('#promo').setStyle('opacity', .5);).
  • Chaining: We’ve paid attention throughout the new architecture to the return values of methods and constructors, allowing for a more compressed chaining syntax in implementation code.

And that’s just the beginning. Dive into the examples to learn more and to see the preview release in action, including some hidden gems like full A-Grade cross-domain requests. Our resident metahacker Dav Glass created a nice multi-component example, the draggable portal, that will give you some sense of what’s included in today’s preview.

Is YUI 3.0 Backward Compatible with YUI 2.x?

No. YUI 3.0 builds off of the YUI 2.x codeline, but we’ve evolved most of the core APIs in working toward the five key goals described above. As a result, migrating from YUI 2.x to 3.x will require effort at the implementation level.

We know that ease-of-migration will be a critical factor for all YUI users. We’re taking two important steps to facilitate the transition as it arrives:

  • Limited compatibility layer: YUI 3.0 will ship with a limited compatibility layer for the current YUI Core (Yahoo Global Object, Dom Collection, and Event Utility). This will allow you to run many of your YUI 2.x-based implementations on top of YUI 3.0. We’re not shipping the compatibility layer with today’s preview, but you’ll see it appear in a future preview or beta release prior to GA.
  • Full parallel compatibility: YUI 3.0 can be run in parallel to YUI 2.x with no side effects for either version. If you choose to make the transition in stages, you can run the full 2.x stack and 3.x stack together as needed.

Even with these provisions in place, we know that an API change (along with new concepts and idioms) has a real cost for everyone involved. We’re convinced that this change is both necessary and worth the effort, and obviously we’re going to work hard to make the value proposition compelling.

What’s Next?

YUI 3.0 is a work in progress. The common widget framework for 3.0 is not included in this preview and we’re continuing to work on refinements to the core — including optimizations to the package structure to minimize base K-weight. We anticipate the next two releases coming up as follows:

  • October 2008 — PR2: Widget Framework, sample widgets, additional utilities.
  • December 2008 — Beta 1: Final mix of module structures, API completion, full complement of utilities.

We have some great stuff to share as we move further along in this process. We’ve never been more excited about YUI and its future — and we think YUI 3.0 will have a big role to play in that future.

(Via Yahoo! User Interface Blog.)

Ad-Server OpenX 2.6 mit API und schnelleren AdTags

OpenX hat mit der Version 2.6 seines gleichnamigen freien Ad-Servers veröffentlicht, die wesentliche neue Funktionen mitbringt, darunter ein API und schnellere Ad-Tags. OpenX hieß einst phpAdsNews, später dann OpenAds und heute OpenX.
Dank des neuen API in OpenX 2.6 soll es deutlich einfacher sein, OpenX in bestehende Systeme zu integrieren und beispielsweise an CRM-Software anzubinden. Zudem können Entwickler so eigene Applikationen schreiben um neue Kampagnen anzulegen, Statistikdaten empfangen oder eine größere Zahl an Werbemitteln hochladen.

Neu ist auch das Dashboard, das auf Wünsche aus der OpenX-Community zurückgeht. Es fasst die wichtigsten Statistiken zu den genutzten Ad-Servern zusammen und kann um Widgets erweitert werden, die Daten zu laufenden Kampagnen zeigen.

Ein neues Ad-Tag verspricht eine schnellere Auslieferung der Werbung, denn der Browser muss damit künftig nur noch eine Anfrage an den Ad-Server senden, auch wenn mehr als ein Werbemittel angezeigt werden muss. Es sind vor allem diese via JavaScript abgewickelten Aufrufe, die Webseiten langsam erscheinen lassen, da das Rendern der Seite dadurch in manchen Browsern behindert wird. Das Laden der eigentlichen Banner ist eher unproblematisch.

OpenX ist Open Source und steht unter der GPLv2. Die Version 2.6 kann ab sofort unter openx.org/download heruntergeladen werden. Laut OpenX wird die Software auf mehr als 100.000 Websites eingesetzt und monatlich mehr als 250 Milliarden Werbemittel über OpenX-Server ausgeliefert. Das Unternehmen selbst bietet auch eine gehostete Version des Ad-Servers an. (via Golem.de)

Using GnuPG with PHP

Using GnuPG with PHP: „

GnuPG is open-source software that makes it possible to encrypt your email and other messages so that they can only be read by the intended recipient (not unlike Jim Phelps and his briefing book). Unlike cleartext messages, which are unprotected and can be read by anyone who intercepts them, GnuPG-encrypted messages are ‘locked’ through cryptographic techniques and may be viewed only by a person with the correct ‘key’; everyone else will merely see gibberish. In today’s day and age, when hacking and phishing is common, such encryption plays an important role in protecting sensitive data like user names, passwords or credit-card information.

(Via Zend Developer Zone.)

W3C Releases Mobile Web Best Practices

W3C Releases Mobile Web Best Practices: „

The World Wide Web Consortium (W3C) today released the 1.0 version of their Mobile Web Best Practices document. The guidelines offer mobile web developers a consistent set of best practices to apply when creating content for consumption on mobile devices. ‘The principal objective is to improve the user experience of the Web when accessed from [mobile web] devices,’ according to the W3C.

In Japan, there are already more mobile web users than PC users, and the rest of the world is catching up. Jupiter Research expects that mobile Web 2.0 revenues will hit $22.4 billion by 2014, with the biggest growth areas in mobile social networking and user generated content.

Developing content across such a wide array of mobile devices and creating a consistent and enjoyable user experience is not an easy task. The W3C hopes that its new mobile best practices guidelines will make it easier for developers to create content and applications for cell phones and other mobile devices.

‘Mobile Web content developers now have stable guidelines and maturing tools to help them create a better mobile Web experience,’ said Dominique Hazaël-Massieux, W3C Mobile Web Activity Lead in a press release. ‘In support of the W3C mission of building One Web, we want to support the developer community by providing tools to enable a great mobile Web user experience.’

The W3C also announced the release of the XHTML Basic 1.1 Recommendation today as the preferred markup language for the best practices document. ‘Until today, content developers faced an additional challenge: a variety of mobile markup languages to choose from,’ said the W3C. ‘With the publication of the XHTML Basic 1.1 Recommendation today, the preferred format specification of the Best Practices, there is now a full convergence in mobile markup languages, including those developed by the Open Mobile Alliance (OMA).’“

(Via SitePoint Blogs.)

»Drizzle« – Abspaltung von MySQL für Webanwendungen

Unter dem Namen „Drizzle“ haben MySQL-Entwickler eine neue Version der freien Datenbank angekündig, die sich auf die aus ihrer Sicht wesentlichen Aspekte konzentriert. Brian Aker nennt in seinem Blog als Einsatzmöglichkeiten dieses abgespeckten MySQL-Servers Webanwendungen, Datenbanken ohne eingebaute Geschäftsprozesse, Cloud-Umgebungen und Multi-Core-Architekturen.
Anzeige

Viele Features, die in den letzten Jahren auf Druck von MySQL-Nutzern aus Unternehmen hinzukamen, fehlen in Drizzle: Stored Procedures, Trigger, Prepared Statements und Views. Auch der Query Cache fällt weg; er beschleunigt das wiederholte Ausführen derselben SQL-Befehle. Möglicherweise würden in Zukunft einige dieser Funktionen wieder eingeführt, es sei jedoch keine vollständige Kompatibilität mit MySQL geplant. Wichtiger sei es, Drizzle als echtes Open-Source-Projekt zu betreiben. Die Entwickler wollen wann immer möglich freie Bibliotheken benutzen; als Datenbank-Engine soll das transaktionsfähige InnoDB zum Einsatz kommen.

MySQL verharrt seit Längerem bei der Versionsnummer 5.0, die 2005 als Produktionsversion erschien. Seit zweieinhalb Jahren arbeiten die Entwickler an dem Nachfolger 5.1, der bislang wegen zahlreicher Fehler nicht zum Produktionseinsatz freigegeben ist. Vor Kurzem rief der Chef-Entwickler Monty Widenius MySQL-Anwender zur Hilfe bei der Fehlersuche auf. Parallel zur Arbeit an 5.1 verläuft seit Mitte letzten Jahres die an Version 6, die die selbstentwickelte transaktionsfähige Storage-Engine Falcon enthält. Deren Chef-Architekt Jim Starkey hat das Projekt jedoch vor Kurzem verlassen.

Bislang gibt es keine produktionsreife Version von Drizzle. Interessenten können sich den Code von Launchpad herunterladen. Zu den Entwicklern gehören neben Brian Aker Zak Greant, Monty Taylor und Jay Pipes. „Drizzle“ ist das englische Wort für Nieselregen, der besonders häufig in Akers Heimatstadt Seattle auftreten soll.

Via heise online

Non-blocking JavaScript Downloads

Non-blocking JavaScript Downloads:

External JavaScript files block downloads and hurt your page performance, but there is an easy way to work around this problem: use dynamic scripts tags and load scripts in parallel, improving the page loading speed and the user experience.

The problem: scripts block downloads

Let’s first take a look at what the problem is with the script downloads. The thing is that before fully downloading and parsing a script, the browser can’t tell what’s in it. It may contain document.write() calls which modify the DOM tree or it may even contain location.href and send the user to a whole new page. If that happens, any components downloaded from the previous page may never be needed. In order to avoid potentially useless downloads, browsers first download, parse and execute each script before moving on with the queue of other components waiting to be downloaded. As a result, any script on your page blocks the download process and that has a negative impact on your page loading speed.

Here’s how the timeline looks like when downloading a slow JavaScript file (exaggerated to take 1 second). The script download (the third row in the image) blocks the two-by-two parallel downloads of the images that follow after the script:

Timeline - Blocking behavior of JavaScript files

Here’s the example to test yourself.

Problem 2: number of downloads per hostname

Another thing to note in the timeline above is how the images following the script are downloaded two-by-two. This is because of the restriction of how many components can be downloaded in parallel. In IE <= 7 and Firefox 2, it’s two components at a time (following the HTTP 1.1 specs), but both IE8 and FF3 increase the default to 6.

You can work around this limitation by using multiple domains to host your components, because the restriction is two components per hostname. For more information of this topic check the article ‘Maximizing Parallel Downloads in the Carpool Lane’ by Tenni Theurer.

The important thing to note is that JavaScripts block downloads across all hostnames. In fact, in the example timeline above, the script is hosted on a different domain than the images, but it still blocks them.

Scripts at the bottom to improve user experience

As Yahoo!’s Performance rules advise, you should put the scripts at the bottom of the page, towards the closing </body> tag. This doesn’t really make the page load faster (the script still has to load), but helps with the progressive rendering of the page. The user perception is that the page is faster when they can see a visual feedback that there is progress.

Non-blocking scripts

It turns out that there is an easy solution to the download blocking problem: include scripts dynamically via DOM methods. How do you do that? Simply create a new <script> element and append it to the <head>:

var js = document.createElement('script');
js.src = 'myscript.js';
var head = document.getElementsByTagName('head')[0];
head.appendChild(js);

Here’s the same test from above, modified to use the script node technique. Note that the third row in the image takes just as long to download, but the other resources on the page are loading simultaneously:

Non-blocking JavaScript timeline

Test example

As you can see the script file no longer blocks the downloads and the browser starts fetching the other components in parallel. And the overall response time is cut in half.

Dependencies

A problem with including scripts dynamically would be satisfying the dependencies. Imagine you’re downloading 3 scripts and three.js requires a function from one.js. How do you make sure this works?

Well, the simplest thing is to have only one file, this way not only avoiding the problem, but also improving performance by minimizing the number of HTTP requests (performance rule #1).

If you do need several files though, you can attach a listener to the script’s onload event (this will work in Firefox) and the onreadystatechange event (this will work in IE). Here’s a blog post that shows you how to do this. To be fully cross-browser compliant, you can do something else instead: just include a variable at the bottom of every script, as to signal ‘I’m ready’. This variable may very well be an array with elements for every script already included.

Using YUI Get utility

The YUI Get Utility makes it easy for you to use script includes. For example if you want to load 3 files, one.js, two.js and three.js, you can simply do:

var urls = ['one.js', 'two.js', 'three.js'];
YAHOO.util.Get.script(urls);

YUI Get also helps you with satisfying dependencies, by loading the scripts in order and also by letting you pass an onSuccess callback function which is executed when the last script is done loading. Similarly, you can pass an onFailure function to handle cases where scripts fail to load.

var myHandler = {
    onSuccess: function(){
        alert(':))');
    },
    onFailure: function(){
        alert(':((');
    }
};

var urls = ['1.js', '2.js', '3.js'];
YAHOO.util.Get.script(urls, myHandler);

Again, note that YUI Get will request the scripts in sequence, one after the other. This way you don’t download all the scripts in parallel, but still, the good part is that the scripts are not blocking the rest of the images and the other components on the page. Here’s a good example and tutorial on using YUI Get to load scripts.

YUI Get can also include stylesheets dynamically through the method
YAHOO.util.Get.css() [example].

Which brings us to the next question:

And what about stylesheets?

Stylesheets don’t block downloads in IE, but they do in Firefox. Applying the same technique of dynamic inserts solves the problem. You can create dynamic link tags like this:

var h = document.getElementsByTagName('head')[0];
var link = document.createElement('link');
link.href = 'mycss.css';
link.type = 'text/css';
link.rel = 'stylesheet';
h.appendChild(link);

This will improve the loading time in Firefox significantly, while not affecting the loading time in IE.

Another positive side effect of the dynamic stylesheets (in FF) is that it helps with the progressive rendering. Usually both browsers will wait and show blank screen until the very last piece of stylesheet information is downloaded, and only then they’ll start rendering. This behavior saves them the potential work of re-rendering when new stylesheet rules come down the wire. With dynamic <link>s this is not happening in Firefox, it will render without waiting for all the styles and then re-render once they arrive. IE will behave as usual and wait.

But before you go ahead and implement dynamic <link> tags, consider the violation of the rule of separation of concerns: your page formatting (CSS) will be dependent on behavior (JS). In addition, this problem is going to be addressed in future Firefox versions.

Other ways?

There are other ways to achieve the non-blocking scripts behavior, but they all have their drawbacks.

Method Drawback
Using defer attribute of the script tag IE-only, unreliable even there
Using document.write() to write a script tag
  1. Non-blocking behavior is in IE-only
  2. document.write is not a recommended coding practice
XMLHttpRequest to get the source then execute with eval().
  1. eval() is evil’
  2. same-domain policy restriction
XHR request to get the source, create a new script tag and set its content
  1. more complex
  2. same-domain policy
Load script in an iframe
  1. complex
  2. iframe overhead
  3. same-domain policy

Future

Safari and IE8 are already changing the way scripts are getting loaded. Their idea is to download the scripts in parallel, but execute them in the sequence they’re found on the page. It’s likely that one day this blocking problem will become negligible, because only a few users will be using IE7 or lower and FF3 or lower. Until then, a dynamic script tag is an easy way around the problem.

Summary

  • Scripts block downloads in FF and IE browsers and this makes your pages load slower.
  • An easy solution is to use dynamic <script> tags and prevent blocking.
  • YUI Get Utility makes it easier to do script and style includes and manage dependencies.
  • You can use dynamic <link> tags too, but consider the separation of concerns first.

(Via Yahoo! User Interface Blog.)

Conditional Comments for HTML Email

Conditional Comments for HTML Email: „

Take a look at this:

<!--[if gte mso 9]>

<![endif]-->

Chances are the general syntax will be instantly familiar — it’s a conditional comment, useful for feeding specific content only to Windows versions of Internet Explorer. But did you know they work for Office applications too?

Neither did I … until recently.

We’ve just overhauled the HTML templates for our email newsletters … a painful process to be sure — if you think that web browsers are harsh task-masters, you should try coding to suit email clients! A recent article, How to Code HTML Email Newsletters, spells out just how convoluted it can be, and how arcane are the techniques you have to resort to, to produce a decent layout in the most popular email clients. And the issue has been further complicated by the fact that one of the most popular Windows clients — Outlook — no longer uses Internet Explorer for HTML rendering, it uses Word!

And it was while perusing the franken-code that passes for ‘Save as Web Page’ output from a Word document, that I first saw these little nuggets — exactly what we needed to hide bits of content from Outlook that were just too mangled to leave.

So there you go. If you’re publishing HTML email and struggling with Outlook’s rendering, here’s an extra little tool for the kit. The syntax even implies that it can be used for granular targetting of Office versions all the way back; but I haven’t tested this, so any information is gratefully received :)

(Via SitePoint Blogs.)