Mozilla

Standards Articles

Sort by:

View:

  1. Mozilla and Web Components: Update

    Editor’s note: Mozilla has a long history of participating in standards development. The post below shows a real-time slice of how standards are debated and adopted. The goal is to update developers who are most affected by implementation decisions we make in Firefox. We are particularly interested in getting feedback from JavaScript library and framework developers.

    Mozilla has been working on Web Components — a technology encompassing HTML imports, custom elements, and shadow DOM — for a while now and testing this approach in Gaia, the frontend of Firefox OS. Unfortunately, our feedback into the standards process has not always resulted in the changes required for us to ship Web Components. Therefore we decided to reevaluate our stance with members of the developer community.

    We came up with the following tentative plan for shipping Web Components in Firefox and we would really appreciate input from the developer community as we move this forward. Web Components changes a core aspect of the Web Platform and getting it right is important. We believe the way to do that is by having the change be driven by the hard learned lessons from JavaScript library developers.

    • Mozilla will not ship an implementation of HTML Imports. We expect that once JavaScript modules — a feature derived from JavaScript libraries written by the developer community — is shipped, the way we look at this problem will have changed. We have also learned from Gaia and others, that lack of HTML Imports is not a problem as the functionality can easily be provided for with a polyfill if desired.
    • Mozilla will ship an implementation of custom elements. Exposing the lifecycle is a very important aspect for the creation of components. We will work with the standards community to use Symbol-named properties for the callbacks to prevent name collisions. We will also ensure the strategy surrounding subclassing is sound with the latest work on that front in JavaScript and that the callbacks are sufficiently capable to describe the lifecycle of elements or can at least be changed in that direction.
    • Mozilla will ship an implementation of shadow DOM. We think work needs to be done to decouple style isolation from event retargeting to make event delegation possible in frameworks and we would like to ensure distribution is sufficiently extensible beyond Selectors. E.g Gaia would like to see this ability.

    Our next steps will be working with the standards community to make these changes happen, making sure there is sufficient test coverage in web-platform-tests, and making sure the specifications become detailed enough to implement from.

    So please let us know what you think here in the comments or directly on the public-webapps standards list!

  2. Introducing the JavaScript Internationalization API

    Firefox 29 issued half a year ago, so this post is long overdue. Nevertheless I wanted to pause for a second to discuss the Internationalization API first shipped on desktop in that release (and passing all tests!). Norbert Lindenberg wrote most of the implementation, and I reviewed it and now maintain it. (Work by Makoto Kato should bring this to Android soon; b2g may take longer due to some b2g-specific hurdles. Stay tuned.)

    What’s internationalization?

    Internationalization (i18n for short — i, eighteen characters, n) is the process of writing applications in a way that allows them to be easily adapted for audiences from varied places, using varied languages. It’s easy to get this wrong by inadvertently assuming one’s users come from one place and speak one language, especially if you don’t even know you’ve made an assumption.

    function formatDate(d)
    {
      // Everyone uses month/date/year...right?
      var month = d.getMonth() + 1;
      var date = d.getDate();
      var year = d.getFullYear();
      return month + "/" + date + "/" + year;
    }
     
    function formatMoney(amount)
    {
      // All money is dollars with two fractional digits...right?
      return "$" + amount.toFixed(2);
    }
     
    function sortNames(names)
    {
      function sortAlphabetically(a, b)
      {
        var left = a.toLowerCase(), right = b.toLowerCase();
        if (left > right)
          return 1;
        if (left === right)
          return 0;
        return -1;
      }
     
      // Names always sort alphabetically...right?
      names.sort(sortAlphabetically);
    }

    JavaScript’s historical i18n support is poor

    i18n-aware formatting in traditional JS uses the various toLocaleString() methods. The resulting strings contained whatever details the implementation chose to provide: no way to pick and choose (did you need a weekday in that formatted date? is the year irrelevant?). Even if the proper details were included, the format might be wrong e.g. decimal when percentage was desired. And you couldn’t choose a locale.

    As for sorting, JS provided almost no useful locale-sensitive text-comparison (collation) functions. localeCompare() existed but with a very awkward interface unsuited for use with sort. And it too didn’t permit choosing a locale or specific sort order.

    These limitations are bad enough that — this surprised me greatly when I learned it! — serious web applications that need i18n capabilities (most commonly, financial sites displaying currencies) will box up the data, send it to a server, have the server perform the operation, and send it back to the client. Server roundtrips just to format amounts of money. Yeesh.

    A new JS Internationalization API

    The new ECMAScript Internationalization API greatly improves JavaScript’s i18n capabilities. It provides all the flourishes one could want for formatting dates and numbers and sorting text. The locale is selectable, with fallback if the requested locale is unsupported. Formatting requests can specify the particular components to include. Custom formats for percentages, significant digits, and currencies are supported. Numerous collation options are exposed for use in sorting text. And if you care about performance, the up-front work to select a locale and process options can now be done once, instead of once every time a locale-dependent operation is performed.

    That said, the API is not a panacea. The API is “best effort” only. Precise outputs are almost always deliberately unspecified. An implementation could legally support only the oj locale, or it could ignore (almost all) provided formatting options. Most implementations will have high-quality support for many locales, but it’s not guaranteed (particularly on resource-constrained systems such as mobile).

    Under the hood, Firefox’s implementation depends upon the International Components for Unicode library (ICU), which in turn depends upon the Unicode Common Locale Data Repository (CLDR) locale data set. Our implementation is self-hosted: most of the implementation atop ICU is written in JavaScript itself. We hit a few bumps along the way (we haven’t self-hosted anything this large before), but nothing major.

    The Intl interface

    The i18n API lives on the global Intl object. Intl contains three constructors: Intl.Collator, Intl.DateTimeFormat, and Intl.NumberFormat. Each constructor creates an object exposing the relevant operation, efficiently caching locale and options for the operation. Creating such an object follows this pattern:

    var ctor = "Collator"; // or the others
    var instance = new Intl[ctor](locales, options);

    locales is a string specifying a single language tag or an arraylike object containing multiple language tags. Language tags are strings like en (English generally), de-AT (German as used in Austria), or zh-Hant-TW (Chinese as used in Taiwan, using the traditional Chinese script). Language tags can also include a “Unicode extension”, of the form -u-key1-value1-key2-value2..., where each key is an “extension key”. The various constructors interpret these specially.

    options is an object whose properties (or their absence, by evaluating to undefined) determine how the formatter or collator behaves. Its exact interpretation is determined by the individual constructor.

    Given locale information and options, the implementation will try to produce the closest behavior it can to the “ideal” behavior. Firefox supports 400+ locales for collation and 600+ locales for date/time and number formatting, so it’s very likely (but not guaranteed) the locales you might care about are supported.

    Intl generally provides no guarantee of particular behavior. If the requested locale is unsupported, Intl allows best-effort behavior. Even if the locale is supported, behavior is not rigidly specified. Never assume that a particular set of options corresponds to a particular format. The phrasing of the overall format (encompassing all requested components) might vary across browsers, or even across browser versions. Individual components’ formats are unspecified: a short-format weekday might be “S”, “Sa”, or “Sat”. The Intl API isn’t intended to expose exactly specified behavior.

    Date/time formatting

    Options

    The primary options properties for date/time formatting are as follows:

    weekday, era
    "narrow", "short", or "long". (era refers to typically longer-than-year divisions in a calendar system: BC/AD, the current Japanese emperor’s reign, or others.)
    month
    "2-digit", "numeric", "narrow", "short", or "long"
    year
    day
    hour, minute, second
    "2-digit" or "numeric"
    timeZoneName
    "short" or "long"
    timeZone
    Case-insensitive "UTC" will format with respect to UTC. Values like "CEST" and "America/New_York" don’t have to be supported, and they don’t currently work in Firefox.

    The values don’t map to particular formats: remember, the Intl API almost never specifies exact behavior. But the intent is that "narrow", "short", and "long" produce output of corresponding size — “S” or “Sa”, “Sat”, and “Saturday”, for example. (Output may be ambiguous: Saturday and Sunday both could produce “S”.) "2-digit" and "numeric" map to two-digit number strings or full-length numeric strings: “70” and “1970”, for example.

    The final used options are largely the requested options. However, if you don’t specifically request any weekday/year/month/day/hour/minute/second, then year/month/day will be added to your provided options.

    Beyond these basic options are a few special options:

    hour12
    Specifies whether hours will be in 12-hour or 24-hour format. The default is typically locale-dependent. (Details such as whether midnight is zero-based or twelve-based and whether leading zeroes are present are also locale-dependent.)

    There are also two special properties, localeMatcher (taking either "lookup" or "best fit") and formatMatcher (taking either "basic" or "best fit"), each defaulting to "best fit". These affect how the right locale and format are selected. The use cases for these are somewhat esoteric, so you should probably ignore them.

    Locale-centric options

    DateTimeFormat also allows formatting using customized calendaring and numbering systems. These details are effectively part of the locale, so they’re specified in the Unicode extension in the language tag.

    For example, Thai as spoken in Thailand has the language tag th-TH. Recall that a Unicode extension has the format -u-key1-value1-key2-value2.... The calendaring system key is ca, and the numbering system key is nu. The Thai numbering system has the value thai, and the Chinese calendaring system has the value chinese. Thus to format dates in this overall manner, we tack a Unicode extension containing both these key/value pairs onto the end of the language tag: th-TH-u-ca-chinese-nu-thai.

    For more information on the various calendaring and numbering systems, see the full DateTimeFormat documentation.

    Examples

    After creating a DateTimeFormat object, the next step is to use it to format dates via the handy format() function. Conveniently, this function is a bound function: you don’t have to call it on the DateTimeFormat directly. Then provide it a timestamp or Date object.

    Putting it all together, here are some examples of how to create DateTimeFormat options for particular uses, with current behavior in Firefox.

    var msPerDay = 24 * 60 * 60 * 1000;
     
    // July 17, 2014 00:00:00 UTC.
    var july172014 = new Date(msPerDay * (44 * 365 + 11 + 197));

    Let’s format a date for English as used in the United States. Let’s include two-digit month/day/year, plus two-digit hours/minutes, and a short time zone to clarify that time. (The result would obviously be different in another time zone.)

    var options =
      { year: "2-digit", month: "2-digit", day: "2-digit",
        hour: "2-digit", minute: "2-digit",
        timeZoneName: "short" };
    var americanDateTime =
      new Intl.DateTimeFormat("en-US", options).format;
     
    print(americanDateTime(july172014)); // 07/16/14, 5:00 PM PDT

    Or let’s do something similar for Portuguese — ideally as used in Brazil, but in a pinch Portugal works. Let’s go for a little longer format, with full year and spelled-out month, but make it UTC for portability.

    var options =
      { year: "numeric", month: "long", day: "numeric",
        hour: "2-digit", minute: "2-digit",
        timeZoneName: "short", timeZone: "UTC" };
    var portugueseTime =
      new Intl.DateTimeFormat(["pt-BR", "pt-PT"], options);
     
    // 17 de julho de 2014 00:00 GMT
    print(portugueseTime.format(july172014));

    How about a compact, UTC-formatted weekly Swiss train schedule? We’ll try the official languages from most to least popular to choose the one that’s most likely to be readable.

    var swissLocales = ["de-CH", "fr-CH", "it-CH", "rm-CH"];
    var options =
      { weekday: "short",
        hour: "numeric", minute: "numeric",
        timeZone: "UTC", timeZoneName: "short" };
    var swissTime =
      new Intl.DateTimeFormat(swissLocales, options).format;
     
    print(swissTime(july172014)); // Do. 00:00 GMT

    Or let’s try a date in descriptive text by a painting in a Japanese museum, using the Japanese calendar with year and era:

    var jpYearEra =
      new Intl.DateTimeFormat("ja-JP-u-ca-japanese",
                              { year: "numeric", era: "long" });
     
    print(jpYearEra.format(july172014)); // 平成26年

    And for something completely different, a longer date for use in Thai as used in Thailand — but using the Thai numbering system and Chinese calendar. (Quality implementations such as Firefox’s would treat plain th-TH as th-TH-u-ca-buddhist-nu-latn, imputing Thailand’s typical Buddhist calendar system and Latin 0-9 numerals.)

    var options =
      { year: "numeric", month: "long", day: "numeric" };
    var thaiDate =
      new Intl.DateTimeFormat("th-TH-u-nu-thai-ca-chinese", options);
     
    print(thaiDate.format(july172014)); // ๒๐ 6 ๓๑

    Calendar and numbering system bits aside, it’s relatively simple. Just pick your components and their lengths.

    Number formatting

    Options

    The primary options properties for number formatting are as follows:

    style
    "currency", "percent", or "decimal" (the default) to format a value of that kind.
    currency
    A three-letter currency code, e.g. USD or CHF. Required if style is "currency", otherwise meaningless.
    currencyDisplay
    "code", "symbol", or "name", defaulting to "symbol". "code" will use the three-letter currency code in the formatted string. "symbol" will use a currency symbol such as $ or £. "name" typically uses some sort of spelled-out version of the currency. (Firefox currently only supports "symbol", but this will be fixed soon.)
    minimumIntegerDigits
    An integer from 1 to 21 (inclusive), defaulting to 1. The resulting string is front-padded with zeroes until its integer component contains at least this many digits. (For example, if this value were 2, formatting 3 might produce “03”.)
    minimumFractionDigits, maximumFractionDigits
    Integers from 0 to 20 (inclusive). The resulting string will have at least minimumFractionDigits, and no more than maximumFractionDigits, fractional digits. The default minimum is currency-dependent (usually 2, rarely 0 or 3) if style is "currency", otherwise 0. The default maximum is 0 for percents, 3 for decimals, and currency-dependent for currencies.
    minimumSignificantDigits, maximumSignificantDigits
    Integers from 1 to 21 (inclusive). If present, these override the integer/fraction digit control above to determine the minimum/maximum significant figures in the formatted number string, as determined in concert with the number of decimal places required to accurately specify the number. (Note that in a multiple of 10 the significant digits may be ambiguous, as in “100” with its one, two, or three significant digits.)
    useGrouping
    Boolean (defaulting to true) determining whether the formatted string will contain grouping separators (e.g. “,” as English thousands separator).

    NumberFormat also recognizes the esoteric, mostly ignorable localeMatcher property.

    Locale-centric options

    Just as DateTimeFormat supported custom numbering systems in the Unicode extension using the nu key, so too does NumberFormat. For example, the language tag for Chinese as used in China is zh-CN. The value for the Han decimal numbering system is hanidec. To format numbers for these systems, we tack a Unicode extension onto the language tag: zh-CN-u-nu-hanidec.

    For complete information on specifying the various numbering systems, see the full NumberFormat documentation.

    Examples

    NumberFormat objects have a format function property just as DateTimeFormat objects do. And as there, the format function is a bound function that may be used in isolation from the NumberFormat.

    Here are some examples of how to create NumberFormat options for particular uses, with Firefox’s behavior. First let’s format some money for use in Chinese as used in China, specifically using Han decimal numbers (instead of much more common Latin numbers). Select the "currency" style, then use the code for Chinese renminbi (yuan), grouping by default, with the usual number of fractional digits.

    var hanDecimalRMBInChina =
      new Intl.NumberFormat("zh-CN-u-nu-hanidec",
                            { style: "currency", currency: "CNY" });
     
    print(hanDecimalRMBInChina.format(1314.25)); // ¥ 一,三一四.二五

    Or let’s format a United States-style gas price, with its peculiar thousandths-place 9, for use in English as used in the United States.

    var gasPrice =
      new Intl.NumberFormat("en-US",
                            { style: "currency", currency: "USD",
                              minimumFractionDigits: 3 });
     
    print(gasPrice.format(5.259)); // $5.259

    Or let’s try a percentage in Arabic, meant for use in Egypt. Make sure the percentage has at least two fractional digits. (Note that this and all the other RTL examples may appear with different ordering in RTL context, e.g. ٤٣٫٨٠٪ instead of ٤٣٫٨٠٪.)

    var arabicPercent =
      new Intl.NumberFormat("ar-EG",
                            { style: "percent",
                              minimumFractionDigits: 2 }).format;
     
    print(arabicPercent(0.438)); // ٤٣٫٨٠٪

    Or suppose we’re formatting for Persian as used in Afghanistan, and we want at least two integer digits and no more than two fractional digits.

    var persianDecimal =
      new Intl.NumberFormat("fa-AF",
                            { minimumIntegerDigits: 2,
                              maximumFractionDigits: 2 });
     
    print(persianDecimal.format(3.1416)); // ۰۳٫۱۴

    Finally, let’s format an amount of Bahraini dinars, for Arabic as used in Bahrain. Unusually compared to most currencies, Bahraini dinars divide into thousandths (fils), so our number will have three places. (Again note that apparent visual ordering should be taken with a grain of salt.)

    var bahrainiDinars =
      new Intl.NumberFormat("ar-BH",
                            { style: "currency", currency: "BHD" });
     
    print(bahrainiDinars.format(3.17)); // د.ب.‏ ٣٫١٧٠

    Collation

    Options

    The primary options properties for collation are as follows:

    usage
    "sort" or "search" (defaulting to "sort"), specifying the intended use of this Collator. (A search collator might want to consider more strings equivalent than a sort collator would.)
    sensitivity
    "base", "accent", "case", or "variant". This affects how sensitive the collator is to characters that have the same “base letter” but have different accents/diacritics and/or case. (Base letters are locale-dependent: “a” and “ä” have the same base letter in German but are different letters in Swedish.) "base" sensitivity considers only the base letter, ignoring modifications (so for German “a”, “A”, and “ä” are considered the same). "accent" considers the base letter and accents but ignores case (so for German “a” and “A” are the same, but “ä” differs from both). "case" considers the base letter and case but ignores accents (so for German “a” and “ä” are the same, but “A” differs from both). Finally, "variant" considers base letter, accents, and case (so for German “a”, “ä, “ä” and “A” all differ). If usage is "sort", the default is "variant"; otherwise it’s locale-dependent.
    numeric
    Boolean (defaulting to false) determining whether complete numbers embedded in strings are considered when sorting. For example, numeric sorting might produce "F-4 Phantom II", "F-14 Tomcat", "F-35 Lightning II"; non-numeric sorting might produce "F-14 Tomcat", "F-35 Lightning II", "F-4 Phantom II".
    caseFirst
    "upper", "lower", or "false" (the default). Determines how case is considered when sorting: "upper" places uppercase letters first ("B", "a", "c"), "lower" places lowercase first ("a", "c", "B"), and "false" ignores case entirely ("a", "B", "c"). (Note: Firefox currently ignores this property.)
    ignorePunctuation
    Boolean (defaulting to false) determining whether to ignore embedded punctuation when performing the comparison (for example, so that "biweekly" and "bi-weekly" compare equivalent).

    And there’s that localeMatcher property that you can probably ignore.

    Locale-centric options

    The main Collator option specified as part of the locale’s Unicode extension is co, selecting the kind of sorting to perform: phone book (phonebk), dictionary (dict), and many others.

    Additionally, the keys kn and kf may, optionally, duplicate the numeric and caseFirst properties of the options object. But they’re not guaranteed to be supported in the language tag, and options is much clearer than language tag components. So it’s best to only adjust these options through options.

    These key-value pairs are included in the Unicode extension the same way they’ve been included for DateTimeFormat and NumberFormat; refer to those sections for how to specify these in a language tag.

    Examples

    Collator objects have a compare function property. This function accepts two arguments x and y and returns a number less than zero if x compares less than y, 0 if x compares equal to y, or a number greater than zero if x compares greater than y. As with the format functions, compare is a bound function that may be extracted for standalone use.

    Let’s try sorting a few German surnames, for use in German as used in Germany. There are actually two different sort orders in German, phonebook and dictionary. Phonebook sort emphasizes sound, and it’s as if “ä”, “ö”, and so on were expanded to “ae”, “oe”, and so on prior to sorting.

    var names =
      ["Hochberg", "Hönigswald", "Holzman"];
     
    var germanPhonebook = new Intl.Collator("de-DE-u-co-phonebk");
     
    // as if sorting ["Hochberg", "Hoenigswald", "Holzman"]:
    //   Hochberg, Hönigswald, Holzman
    print(names.sort(germanPhonebook.compare).join(", "));

    Some German words conjugate with extra umlauts, so in dictionaries it’s sensible to order ignoring umlauts (except when ordering words differing only by umlauts: schon before schön).

    var germanDictionary = new Intl.Collator("de-DE-u-co-dict");
     
    // as if sorting ["Hochberg", "Honigswald", "Holzman"]:
    //   Hochberg, Holzman, Hönigswald
    print(names.sort(germanDictionary.compare).join(", "));

    Or let’s sort a list Firefox versions with various typos (different capitalizations, random accents and diacritical marks, extra hyphenation), in English as used in the United States. We want to sort respecting version number, so do a numeric sort so that numbers in the strings are compared, not considered character-by-character.

    var firefoxen =
      ["FireFøx 3.6",
       "Fire-fox 1.0",
       "Firefox 29",
       "FÍrefox 3.5",
       "Fírefox 18"];
     
    var usVersion =
      new Intl.Collator("en-US",
                        { sensitivity: "base",
                          numeric: true,
                          ignorePunctuation: true });
     
    // Fire-fox 1.0, FÍrefox 3.5, FireFøx 3.6, Fírefox 18, Firefox 29
    print(firefoxen.sort(usVersion.compare).join(", "));

    Last, let’s do some locale-aware string searching that ignores case and accents, again in English as used in the United States.

    // Comparisons work with both composed and decomposed forms.
    var decoratedBrowsers =
      [
       "A\u0362maya",  // A͢maya
       "CH\u035Brôme", // CH͛rôme
       "FirefÓx",
       "sAfàri",
       "o\u0323pERA",  // ọpERA
       "I\u0352E",     // I͒E
      ];
     
    var fuzzySearch =
      new Intl.Collator("en-US",
                        { usage: "search", sensitivity: "base" });
     
    function findBrowser(browser)
    {
      function cmp(other)
      {
        return fuzzySearch.compare(browser, other) === 0;
      }
      return cmp;
    }
     
    print(decoratedBrowsers.findIndex(findBrowser("Firêfox"))); // 2
    print(decoratedBrowsers.findIndex(findBrowser("Safåri")));  // 3
    print(decoratedBrowsers.findIndex(findBrowser("Ãmaya")));   // 0
    print(decoratedBrowsers.findIndex(findBrowser("Øpera")));   // 4
    print(decoratedBrowsers.findIndex(findBrowser("Chromè")));  // 1
    print(decoratedBrowsers.findIndex(findBrowser("IË")));      // 5

    Odds and ends

    It may be useful to determine whether support for some operation is provided for particular locales, or to determine whether a locale is supported. Intl provides supportedLocales() functions on each constructor, and resolvedOptions() functions on each prototype, to expose this information.

    var navajoLocales =
      Intl.Collator.supportedLocalesOf(["nv"], { usage: "sort" });
    print(navajoLocales.length > 0
          ? "Navajo collation supported"
          : "Navajo collation not supported");
     
    var germanFakeRegion =
      new Intl.DateTimeFormat("de-XX", { timeZone: "UTC" });
    var usedOptions = germanFakeRegion.resolvedOptions();
    print(usedOptions.locale);   // de
    print(usedOptions.timeZone); // UTC

    Legacy behavior

    The ES5 toLocaleString-style and localeCompare functions previously had no particular semantics, accepted no particular options, and were largely useless. So the i18n API reformulates them in terms of Intl operations. Each method now accepts additional trailing locales and options arguments, interpreted just as the Intl constructors would do. (Except that for toLocaleTimeString and toLocaleDateString, different default components are used if options aren’t provided.)

    For brief use where precise behavior doesn’t matter, the old methods are fine to use. But if you need more control or are formatting or comparing many times, it’s best to use the Intl primitives directly.

    Conclusion

    Internationalization is a fascinating topic whose complexity is bounded only by the varied nature of human communication. The Internationalization API addresses a small but quite useful portion of that complexity, making it easier to produce locale-sensitive web applications. Go use it!

    (And a special thanks to Norbert Lindenberg, Anas El Husseini, Simon Montagu, Gary Kwong, Shu-yu Guo, Ehsan Akhgari, the people of #mozilla.de, and anyone I may have forgotten [sorry!] who provided feedback on this article or assisted me in producing and critiquing the examples. The English and German examples were the limit of my knowledge, and I’d have been completely lost on the other examples without their assistance. Blame all remaining errors on me. Thanks again!)

  3. CSS Variables in Firefox Nightly

    As reported by Cameron McCormack, Firefox Nightly (version 29) now supports CSS variables. You can get a quick overview in this short screencast:

    You can define variables in a context with a var- prefix and then implement them using the var() instruction. For example:

    :root {
      var-companyblue: #369;
      var-lighterblue: powderblue;
    }
     
    h1 {
      color: var(companyblue);
    }
    h2 {
      color: var(lighterblue);
    }
    <h1>Header on page</h1>
    <h2>Subheader on page</h2>

    This defines the two variables companyblue and lighterblue for the root element of the document which results in (you can try it here using Firefox Nightly):

    Variables are scoped, which means you can overwrite them:

    :root {
      var-companyblue: #369;
      var-lighterblue: powderblue;
    }
    .partnerbadge {
      var-companyblue: #036;
      var-lighterblue: #cfc;
    }
     
    h1 {
      color: var(companyblue);
    }
    h2 {
      color: var(lighterblue);
    }
    <h1>Header on page</h1>
    <h2>Subheader on page</h2>
     
    <div class="partnerbadge">
      <h1>Header on page</h1>
      <h2>Subheader on page</h2>
    </div>

    Using these settings, headings inside an element with a class of partnerbadge will now get the other blue settings:

    Variables can be any value you want to define and you can use them like any other value, for example inside a calc() calculation. You can also reset them to other values, for example inside a media query. This example shows many of these possibilities.

    :root {
      var-companyblue: #369;
      var-lighterblue: powderblue;
      var-largemargin: 20px;
      var-smallmargin: calc(var(largemargin) / 2);
      var-borderstyle: 5px solid #000;
      var-headersize: 24px;
    }
    .partnerbadge {
      var-companyblue: #036;
      var-lighterblue: #369;
      var-headersize: calc(var(headersize)/2);
      transition: 0.5s;
    }
     
    @media (max-width: 400px) {
      .partnerbadge {
         var-borderstyle: none;
         background: #eee;
      }
    }
     
    /* Applying the variables */
    body {font-family: 'open sans', sans-serif;}
     
    h1 {
      color: var(companyblue);
      margin: var(largemargin) 0;
      font-size: var(headersize);
    }
    h2 {
      color: var(lighterblue);
      margin: var(smallmargin) 0;
      font-size: calc(var(headersize) - 5px);
    }
     
    .partnerbadge {
      padding: var(smallmargin) 10px;
      border: var(borderstyle);
    }

    Try resizing the window to less than 400 pixels to see the mediaQuery change in action.

    An initial implementation of CSS Variables has just landed in Firefox Nightly, which is currently at version 29 and after the February 3 merge, in Firefox Aurora. There are still a few parts of the specification which still need to be supported before the can go into the release cycle of Firefox Beta and Firefox. Cameron has the details on that:

    The only part of the specification that has not yet been implemented is the CSSVariableMap part, which provides an object that behaves like an ECMAScript Map, with get, set and other methods, to get the values of variables on a CSSStyleDeclaration. Note however that you can still get at them in the DOM by using the getPropertyValue and setProperty methods, as long as you use the full property names such as "var-theme-colour-1".

    The work for this feature was done in bug 773296, and my thanks to David Baron for doing the reviews there and to Emmanuele Bassi who did some initial work on the implementation. If you encounter any problems using the feature, please file a bug!

    For now, have fun playing with CSS variables in Nightly and tell us about issues you find.

  4. Web Payments with PaySwarm: Assets and Listings (part 2 of 3)

    The Promise of Web Payments

    The first article in this series on PaySwarm outlined how the technology is designed to transmit and receive funds with the same ease as sending and receiving an email. It went on to explain how taking the tools that have been traditionally only available to banks, Wall Street, and large corporations and making them available to everyone can reshape financial systems in a very positive way. The goal is not just one-click payments, but also to enable crowdfunding innovation, help Web developers earn a living through the Web, boost funding rounds for start-ups, and more.

    This article is the second in a three part series on buying and selling content using the PaySwarm specification. It will review some basic concepts covered in the first article and then explain how to list things for sale using PaySwarm.

    Review: Web Keys and JSON-LD

    As explained in part one, the Web Keys specification provides a simple, decentralized identity solution for the Web based on public key cryptography. It enables Web applications to send messages that are both protected from snooping and verifiable via digital signatures.

    The messages are marked up using the JavaScript Object Notation for Linking Data (JSON-LD). As the name suggests, JSON-LD is a way of expressing Linked Data in JSON. Both HTML documents and JSON-LD documents describe things and have links to other documents on the Web. The primary benefit with JSON-LD is that the entire document is understandable by a machine to the point that it can extract and perform basic reasoning without placing a huge burden on the developer writing the JSON markup.

    Web Keys coupled with JSON-LD provide the underlying messaging and product markup mechanism used by PaySwarm to perform Web Payments.

    Decentralized Products and Services

    One design requirement of a Web Payments system is that the identity mechanism (Web Keys) must be decentralized. Another requirement is that the data markup mechanism (JSON-LD) must be capable of expressing decentralized resources like people, places, events, goods/services, and a variety of other data that will likely exist on 3rd party websites.

    Similarly, PaySwarm does not require that products and services be listed in a central location on the Web. Instead, it allows content creators and developers to be in control of their own product descriptions and prices in addition to giving them the option to delegate this responsibility to an App Store or large retail website. PaySwarm has the following requirements when it comes to listing products and services for sale:

    • The listings must be able to be decentralized, which reduces the possibility of monopolistic behavior among retailers.
    • The product being sold must be separable from the terms under which the sale occurs, enabling different prices to be associated with different licenses, affiliate sales, and business models like daily deals.
    • The creator of the product must be able to specify restrictions on pricing, resellers, validity periods, and a variety of other properties associated with the sale of the product. This ensures that the product creator is in control of her product at all times.
    • It must support decentralized extensibility, which enables applications to add application-specific data to the product description and terms of sale.
    • It must be secure, such that the risk of tampering with product descriptions and prices is mitigated.
    • It must be non-repudiable, such that the creator of the listing cannot dispute the fact that they created it.

    Assets and Listings

    There are two concepts that are core to understanding how products and services are listed for sale via PaySwarm.

    The first is the asset. An asset is a description of a product or service. Examples of assets include web pages, ebooks, groceries, concert tickets, dog walking services, donations, rights to transmit on a particular radio frequency band, and invoices for work performed. In general, anything of value can be modeled as an asset.

    An asset typically describes something to be sold, who created it, a set of restrictions on selling it, and a validity period. Since the asset is expressed using JSON-LD, a number of other application-specific properties can be associated with it. For example, a 3D printing store could include the dimensions of the asset when physically printed, the materials to be used to print the asset, and a set of assembly instructions. Upon purchase of the asset, a digital receipt with a description of the asset is generated. This receipt can be given to a printer to produce a physical representation of the asset.

    The second concept that is key to understanding how products and services are sold in PaySwarm is the listing. A listing is a description of the specific terms under which an asset is offered for sale. These terms include: the exact asset being sold, the license that will be associated with the purchase, the list of people or organizations to be paid for the asset, and the validity period for the listing. Like an asset, a listing may include other application-specific properties.

    This tutorial elaborates on creating an asset and listing and publishing them to a website, as shown briefly in the video below:

    Code from the payswarm.js node module will be used throughout this tutorial. Specifically, it utilizes the asset publishing example. The payment processor will be the PaySwarm Developer Sandbox and asset hosting service will be the PaySwarm Developer Listing Service.

    Creating an Asset

    As mentioned previously, an asset is described using JSON-LD. An asset is built in a programming language the same way one would build data to be published as a JSON document. Typically, this involves using an object (in JavaScript), a dictionary (in Python), an associative array (in PHP), or a hash (in Ruby). Here is the code to create an asset in JavaScript. Pay particular attention to the comments as they will explain what each key-value pair means. Let’s try a simple example first:

    // create a PaySwarm asset
    var asset = {
      // the @context is a hint to a JSON-LD processor on how to interpret the
      // key-value pairs in the document
      '@context': 'https://w3id.org/payswarm/v1',
      // this is the global identifier for the asset
      id: 'http://listings.dev.payswarm.com/mozhacks/demo#asset',
      type: ['Asset'],
      // this is the person who created the asset
      creator: { fullName: 'Developer Joe' },
      title: 'Mozilla Hacks Demo Asset',
      // this is typically the link to the paid content
      assetContent: 'http://listings.dev.payswarm.com/mozhacks/demo#asset',
      // this is the entity that has rights to the asset (or owns it)
      assetProvider: 'https://dev.payswarm.com/i/YOUR_IDENTITY_HERE'
    };

    The code above is a working example of an asset description in about seven lines of code (without comments). It describes an asset called Mozilla Hacks Demo Asset, which can be sold by anyone. The idea is that you would express this data on a website, either as a separate JSON-LD document or directly in an HTML5 page using RDFa markup. Any PaySwarm-compatible payment processor could then get your document and know exactly what you have created and what the sale restrictions are.

    Let’s take a look at a more complex example. The asset below specifies a song with a twist on how it can be sold. It can be resold by anyone, with 80% of the proceeds, or a minimum of $0.50, going to the band that created the song.

    // create a PaySwarm asset
    var asset = {
      // the @context is a hint to a JSON-LD processor on how to interpret the
      // key-value pairs in the document
      '@context': 'https://w3id.org/payswarm/v1',
      // this is the global identifier for the asset
      id: 'http://listings.dev.payswarm.com/mozhacks/html5-me-song#asset',
      type: ['Asset', 'schema:MusicRecording'],
      // this is the person who created the asset
      creator: { fullName: 'The Webdevs' },
      title: 'HTML5 Me, Baby',
      // this is the link to the paid content
      assetContent: 'http://listings.dev.payswarm.com/mozhacks/paid/html5-me-song',
      // this is the entity that has rights to the asset (the artist in this case)
      assetProvider: 'https://dev.payswarm.com/i/the-webdevs',
      // these are restrictions under which the asset can be sold
      listingRestrictions: {
        // validity dates so that the price information below doesn't
        // last forever (you may want to change your price)
        validFrom: payswarm.w3cDate(validFrom),
        validUntil: payswarm.w3cDate(validUntil),
        payee: [{
          // this is an entity that should be paid when the asset is sold
          type: 'Payee',
          // when the asset is sold, put the money for the asset provider here
          destination: 'https://dev.payswarm.com/i/the-webdevs/accounts/royalties',
          // the name of the group determines how this particular payee's rate comes
          // out of the total price of the sale
          payeeGroup: ['assetProvider'],
          // next 6 lines: the greater of 80% of the vendor's price or $0.50 should go
          // to the content creator
          payeeRate: '80',
          payeeRateType: 'Percentage',
          payeeApplyType: 'ApplyInclusively',
          payeeApplyGroup: ['vendor'],
          minimumAmount: '0.50',
          currency: 'USD',
          // show this to the buyer as one of the line items in the digital receipt
          comment: 'Payment to The Webdevs for creating the HTML5 Me, Baby song'
        }],
        payeeRule: [{
          // next 2 lines: allow the payment processor (the PaySwarm Authority) to add
          // a fee for processing the transaction
          type: 'PayeeRule',
          payeeGroupPrefix: ['authority']
        }, {
          // next 4 lines: vendors can only specify a flat fee for reselling the song
          // from their website
          type: 'PayeeRule',
          payeeGroup: ['vendor'],
          payeeRateType: 'FlatAmount',
          payeeApplyType: 'ApplyExclusively'
        }]
      }
    };

    The code above is a more comprehensive example of an asset description in approximately 30 lines of code (without comments). It describes an asset, which is a song, called HTML5 Me, Baby that can be sold by anyone who complies with the other restrictions set forth. A content creator who describes an asset this way on the web creates an incentive for their fan base to blog about and resell the content on their personal blogs. Imagine a WordPress plugin that allows you to review and resell your favorite bands songs directly from your blog. The artist is always guaranteed to get paid, regardless of which blog sells it or which PaySwarm Authority processes the payment. In this particular example, the asset provider has enabled their fans to take a 20% cut of the sale.

    When a sale of the song above occurs, 80% of the sale price, or a minimum of $0.50 USD, is transferred to the asset provider. The PaySwarm Authority may add a fee for processing payment for the asset. A vendor may set a flat price for the song. For example, if the song is sold for $1.00, then $0.80 goes to The Webdevs (80% of final price restriction kicks in). If the song is sold for $0.60 USD, then $0.50 goes to The WebDevs ($0.50 USD minimum restriction kicks in). As you can see, the listing restrictions provide a great deal of power to the asset provider to specify exactly how their product should be sold.

    Once the asset has been created, the developer can then use her private key to digitally sign the asset:

    payswarm.sign(asset, {
      publicKeyId: publicKey.id,
      privateKeyPem: privateKey.privateKeyPem
    }, function(err, signedAsset) {
      // do something with the signed asset
    });

    Digitally signing the asset ensures that no one can change any of the information associated with it. This is important because, at a minimum, a content creator wouldn’t want to be removed from the list of people who should be paid when the asset is sold. The digital signature also guarantees, to a buyer, that the content creator did in fact describe the asset and its sale restrictions as seen.

    The next step in preparing the asset for sale is to create a special identifier for the asset so that it can be accurately referenced by the listing. This identifier is called a cryptographic hash and is generated using the payswarm.js library’s hash() function:

    // generate a hash for the signed asset
    payswarm.hash(signedAsset, function(err, assetHash) {
      // do something with the signed asset hash
    });

    Once we have the signed asset and the signed asset hash, we can create the listing that will be used to purchase the asset.

    Creating a Listing

    As mentioned earlier in this article, a listing is a description of the terms under which an asset is offered for sale. A listing, like an asset, is expressed in JSON-LD. The listing below specifies which license to associate with the asset being sold as well as who should get paid for the sale of the asset. It also specifies restrictions on certain payees, such as how much a PaySwarm Authority can charge for processing a payment. Pay particular attention to the comments above each line as they explain what the line does:

    // create the listing
    var listing = {
      // the @context is a hint to a JSON-LD processor on how to interpret the
      // key-value pairs in the document
      '@context': 'https://w3id.org/payswarm/v1',
      // this is the identifier for the listing
      id: 'http://listings.dev.payswarm.com/mozhacks/html5-me-song#listing',
      type: ['Listing'],
      // the identity offering the item for sale is The WebDevs
      vendor: 'https://dev.payswarm.com/i/the-webdevs',
      payee: [{
        type: 'Payee',
        // payment should be deposited into this financial account
        destination: 'https://dev.payswarm.com/i/the-webdevs/accounts/royalties',
        // this is used to determine how fees are applied to the final price
        payeeGroup: ['vendor'],
        // the next 4 lines: Sell the song for $1.00
        payeeRateType: 'FlatAmount',
        payeeRate: '1.00',
        currency: 'USD',
        payeeApplyType: 'ApplyExclusively',
        // this should be displayed for the line item in the digital receipt
        comment: 'Payment to The Webdevs for creating the HTML5 Me, Baby song'
      }],
      // the next 6 lines: The payment processor cannot take more than 5% of
      // the total sale price.
      payeeRule : [{
        type: 'PayeeRule',
        payeeGroupPrefix: ['authority'],
        payeeRateType: 'Percentage',
        maximumPayeeRate: '5',
        payeeApplyType: 'ApplyInclusively'
      }],
      // this is the ID of the asset being sold
      asset: 'http://listings.dev.payswarm.com/mozhacks/html5-me-song#asset',
      assetHash: assetHash,
      // this is the license that should be associated with the asset upon sale
      license: 'https://w3id.org/payswarm/licenses/personal-use',
      licenseHash: 'urn:sha256:' +
        'd9dcfb7b3ba057df52b99f777747e8fe0fc598a3bb364e3d3eb529f90d58e1b9',
      // the offer of sale is only valid between these two times
      validFrom: payswarm.w3cDate(validFrom),
      validUntil: payswarm.w3cDate(validUntil)
    };

    The code above states that the song HTML5 Me, Baby is for sale for $1.00 and a payment processor can’t charge more than 5% of the total sale price in transaction processing fees. The song is licensed for personal use, with the full text of the license available at the provided URL. Once the listing has been created, it must be digitally signed:

    payswarm.sign(listing, {
      publicKeyId: cfg.publicKey.id,
      privateKeyPem: cfg.publicKey.privateKeyPem
    }, function(err, signedListing) {
      // do something with the signed listing
    });

    The listing is digitally signed for the same reason that the asset is: to prevent tampering and for non-repudiation. Once both the asset and the listing are signed, they are ready to be published. This could be done by publishing them as two different documents or as a single document. The easiest way to publish them as a single document in JSON-LD is to use the ‘@graph’ keyword, which essentially states that you want to combine two independent objects into the same JSON-LD document.

    var assetAndListing = {
      '@context': 'https://w3id.org/payswarm/v1',
      '@graph': [signedAsset, signedListing]
    };

    Publishing an Asset and Listing

    The final step in the publication process is to take the signed asset and listing document and publish it to the Web. Since PaySwarm is decentralized, we can publish our signed asset and listing to any website. Since the assets are digitally signed, the website doesn’t have to be protected by Transport Layer Security (TLS), more commonly known as HTTPS. The digital signature guarantees that no one can modify the data without invalidating the signature on the asset and listing. In the following example, we use the payswarm.js library’s postJsonLd() function to upload the asset and listing to a public PaySwarm listing service.

    var url = 'http://listings.dev.payswarm.com/mozhacks/html5-me-song';
    payswarm.postJsonLd(url, assetAndListing, function(err, result) {
      // if result is a 200, then your listing has been published
    });

    After the asset and listing have been uploaded, the asset can be purchased by any PaySwarm client. Note that while the asset and listing information was expressed as JSON-LD, it could have just as easily been published as HTML5+RDFa. PaySwarm Authorities are capable of interpreting both JSON-LD and RDFa. While we won’t go into the details in this blog post, a future blog post will address how to take the asset and listing Linked Data expressed above and publish it as HTML5+RDFa.

    Next: Purchasing an Asset

    This is the second article in a three part series on developing PaySwarm-aware Web applications to engage in commerce. The next article will explain how to purchase the asset that was created in this tutorial and retrieve the digital receipt of the sale.

  5. Web Payments with PaySwarm: Identity (part 1 of 3)

    The Promise of Web Payments

    The Web has fundamentally transformed the way we publish and interact with information. However, the way we reward people for creating that content has not changed. The Web’s foundation was not built to transmit and receive funds with the same ease as sending and receiving an email.

    Making payments on the Web simpler and more accessible has more than superficial advantages. By taking the tools that have been traditionally only available to banks, Wall Street, and large corporations and making them available to everyone, we can reshape the world’s financial system. The goal is not to just simply enable one click payments, but also to enable crowdfunding innovation, help Web developers earn a living through the Web, boost funding rounds for world-changing start-ups, and more.

    Whilst bringing new or powerful tools to the general public will breed competition and innovation, open Web payments can also bring about much more basic and societal changes. 2.5 billion people around the world don’t have bank accounts and thus have no ability to save money due to banking corruption and/or high fees. When a family has no way of saving for the future, it greatly limits their chances of pulling themselves out of poverty. The promise of Web payments is about more than just an exciting future, it is about a more egalitarian one.

    So, how do we get from where we are today, to a future where sending an receiving funds on the Web is as easy as clicking a button?

    Web Payment Requirements

    One of the primary drivers of innovation on the Web is that it is decentralized. You don’t have to ask permission to publish your creation. Open standards such as TCP/IP, HTTP, HTML, CSS, JavaScript, and JSON ensure interoperability between applications. Thus, a solution for payments on the Web must have at least the following traits:

    • It must be decentralized.
    • It must be an open, patent and royalty-free standard.
    • It must be designed to work with Web architecture like URLs, HTTP, and other Web standards.
    • It must allow anyone to implement the standard and interoperate with others that implement the standard.

    In addition to these basic characteristics of a successful Web technology, a successful Web Payments technology must also do the following:

    • It must enable choice among customers, vendors, and payment processors, in order to drive healthy market competition.
    • It must be extensible in a decentralized way, allowing application-specific extensions to the core protocol without coordination.
    • It must be flexible enough to perform payments as well as support higher order economic behaviors like crowdfunding and executing legal contracts.
    • It must be secure, using the latest security best practices to protect the entire system from attack.
    • It must be currency agnostic, supporting not only the US Dollar, the Euro, and the Japanese Yen, but also supporting virtual currencies like Bitcoin and Ven.
    • It must be easy to develop for and integrate into the Web.

    Fortunately, the Web Payments group at the World Wide Web Consortium (W3C) has created a set of specifications called PaySwarm that addresses all of the requirements listed above. The group is currently in contact with Mozilla and is trying to converge with the mozPay() API as well as Persona to provide a truly excellent Web Payments experience. There is even a commercial launch of the technology using real money, which means you can use it to send and receive funds today.

    This is the first blog post in a three part series that will explore the PaySwarm specifications and demonstrate, using code examples and video, how to build a fully functional PaySwarm client in Node.js.

    Decentralized Identity

    A decentralized payment system for the Web means that, ultimately, the identity mechanism must be decentralized as well. There are a number of identity solutions today that are decentralized. OpenID, WebID, Web Keys, and BrowserID/Persona are among some of the more well-known, decentralized identity mechanisms that are designed for the Web. Identity for Web Payments brings in an additional set of requirements on top of the normal set of requirements for a Web identity solution. The following is a brief list of these requirements:

    • It must be decentralized.
    • It must support discoverability by using a resolvable address, like a URL or email address.
    • It must support, with authorization, arbitrary machine-readable information being attached to the identity by 3rd parties.
    • It must be able to provide both public and private data to external sites, based on who is accessing the resource.
    • It must provide a secure digital signature and encryption mechanism.

    The solution we ended up settling on is called Web Keys. It enables secure, decentralized, discoverable, controlled access to arbitrary machine-readable information associated with an identity. This identity mechanism and the functionality it enables is at the heart of the PaySwarm work.

    Web Keys

    For reasons that we don’t have time to go into in this blog post, OpenID, WebID, and OAuth were considered but ultimately did not make the cut because they don’t provide at least one of the features above. At the time, BrowserID, which was later rebranded as Persona, was still too early in the design stage to consider as a viable solution. The Web Payments group is currently working with the Persona team to see if all of the features above could be integrated into Persona to support Web Payments, but it is not certain that it will happen.

    In the end, we had to create a minimal identity solution for Web Payments because one did not exist that met all of the requirements above. So, let’s dive into using the Web Keys technology to establish an identity online for the purposes of making decentralized Web Payments.

    This tutorial will use code from the payswarm.js node module. Specifically, it will use code snippets from the Web Key registration example. The tutorial will also use the PaySwarm Developer Sandbox as our Web Key host and payment processor.

    The following video shows what we will be building throughout the rest of this tutorial:

    Generating a Key

    The Web Keys specification is built on top of a technology called public-key cryptography. We don’t have time to go into how this technology works in detail in this blog post, so what follows is a quick overview for those that are unfamiliar with the technology.

    Public key cryptography is used to secure traffic on the Web. If you have ever seen a padlock icon when doing a purchase online, you’re using public key cryptography. When you generate these keys, you are given two of them: a public key and a private key. Together the keys can be used to do two major operations that are important in Web Payments. The first is that the private key can be used to digitally sign a purchase request. The public key can be used to verify the digital signature on the purchase request, proving that you, and only you, wish to make a purchase. The second is that the public key can be used to encrypt information so that only the holder of the private key can read that information. Together these keys can be used to prove your identity online to others and to encrypt messages sent to you so that only you can read them.

    To generate the pair of keys in PaySwarm, you can do the following:

    var payswarm = require('payswarm-client');
    ...
    payswarm.createKeyPair({keySize: 2048}, function(err, pair) {
      if(err) {
        console.log('Oops, something went wrong:', err);
      }
      else {
        var publicKeyPem = pair.publicKey;
        var privateKeyPem = pair.privateKey;
    ...
      }
    });

    In the code above, the PaySwarm library’s createKeyPair() function is used to create a 2048-bit key pair. The more bits that are used for the key pair, the harder it is to do a brute-force attack against it. At present (April 2013), a key length of 2048 bits is considered very secure for PaySwarm transactions. You should never use a key length below 2048 bits; it should be rejected by the financial network. Once the key pair is created, both the public key and the private key are returned to you. It is up to the application to then store the keys. The private key must be stored very securely, preferably encrypting the key with a long passphrase before writing it to disk. The public key should be published in a way that other people can use it to verify your digital signatures and send encrypted data to you that only you will be able to read. The process of publishing the public key to the web will be covered in the next section.

    Registering a Key

    The Web Keys specification details how an application can associate a public key with an identity. Associating a Web Key with an identity consists of a multi-step process:

    1. Discover the Web Key server’s key registration base URL.
    2. Generate a key registration URL.
    3. Register the key via a web browser.

    The steps above are demonstrated in the code snippet below:

    async.waterfall([
    ...
      function(callback) {
        // Step #1: Fetch the Web Keys endpoint from the PaySwarm Authority.
        payswarm.getWebKeysConfig('dev.payswarm.com', callback);
      }, function(endpoints, callback) {
        // Step #2: Generate the key registration URL
        var registrationUrl = URL.parse(endpoints.publicKeyService, true, true);
        registrationUrl.query['public-key'] = publicKeyPem;
        registrationUrl.query['response-nonce'] =
          new Date().getTime().toString(16);
        delete registrationUrl.search;
        registrationUrl = URL.format(registrationUrl);
        callback(null, registrationUrl)
      },
      function(registrationUrl, callback) {
        // Step #3: Register the key via a web browser.
        console.log('Register your key here: ', registrationUrl);
    ...

    A PaySwarm client running the code above will fetch the Web Keys configuration for the dev.payswarm.com site first. The URL used when retrieving the Web Keys configuration via the getWebKeysConfig() function will be https://dev.payswarm.com/.well-known/web-keys. The result is a JSON-LD document, which can be used as a JSON document. The JSON key that holds the registration endpoint is publicKeyService. A registration URL is then constructed by adding URL parameters to the registration endpoint URL. First, the public key that was generated by the application is added. Then, a single-use response nonce is added, which is used to prevent replay attacks. The response from the server will include the response nonce, so be sure to store it somewhere. It is very important that the response nonce is tracked by the application and never used more than once. If an application detects that a response nonce has been used more than once when receiving a message from the server, you may be under attack and must ignore the message. Messages in PaySwarm are transient in nature, so nonces may only need to be stored for a limited period of time, simplifying certain implementations.

    What the PaySwarm Authority does when the browser goes to the registration URL is implementation specific. The only requirement is that it provides a permanent URL location for the public key and the URL for the owner of the public key being registered. Note that the URL for the owner must also be deferenceable, so it can provide information that indicates the owner does, in fact, own the public key. The response will be encrypted using the public key provided and can only be decrypted by the application’s private key. The next section will cover handling the registration response from the PaySwarm Authority.

    The Registration Response

    The last step in registering a Web Key is receiving the encrypted response from the PaySwarm Authority. Finalizing the registration of a Web Key consists of the following two steps:

    1. Receive the encrypted key registration response.
    2. Decode the key registration response.

    The steps above are demonstrated in the code snippet below:

    async.waterfall([
    ...
        // step #1: receive the encrypted key registration response
    ...
      function(encryptedMessage, callback) {
        // step #2: decode the key registration response
        payswarm.decrypt(encryptedMessage, {privateKey: privateKeyPem}, callback);
      },
      function(message, callback) {
        var publicKeyUrl = message.publicKey;
        var publicKeyOwnerUrl = message.owner;
        var financialAccountUrl = message.destination;
        callback();
      },
    ...

    When registering a public key, the application will ask you to go to a URL on your PaySwarm Authority. If your application is a console application, the final step of the registration process will provide an encrypted message that you can copy and paste into your application. If your application is a Web application, you can provide a callback URL that the encrypted message will be sent to after registration. That encrypted message is the input to the JavaScript code above. The PaySwarm library uses a function called decrypt() that will take the encrypted message and the application’s private key, which was generated earlier in the tutorial, and provide the unencrypted message that was sent to you by the PaySwarm Authority.

    The unencrypted message will contain, at a minimum, the URL for the public key and the identity URL for the owner of the public key. The Web Payments specification also requires that a financial account is associated with the public key, which is useful when you need to tell another application where to send funds. Once the application has this information, it should store it in a safe place, preferably password protected, along with the private key data.

    Browser-based Web Key Registration

    This tutorial covered the basics of creating a console-based Web Key client for the purposes of registering a public key. Typically a Web Key client will be built into software running on a public website that is accessed using a Web browser. An example of the experience provided by a purely browser-based Web Key workflow is shown below:

    Next: Listing an Asset for Sale

    This is the first article in a three part series on using the PaySwarm specifications which can be used to send and receive funds via the Web in a decentralized way. The next article in the series will explain how to create an Asset, such as an article, song, or movie, and list it for sale on the Web. The beauty of PaySwarm is that a customer on your site does not need to use the same payment processor as you, just as you don’t need to care which payment processor the customer uses. With PaySwarm, the money just flows to the appropriate place.

  6. Welcoming the new kid: Web Platform Docs

    Documenting the open Web and Web standards is a big job! As Mozillians, we’re well aware of this — documenting the open Web has been the mission of the Mozilla Developer Network for many years. Anything we can do to further the cause of a free and open Web is a worthwhile endeavor. With so many different groups involved in the design and development of new Web standards, it can be tricky to figure out the current right way to use them. That’s why we’re excited to be able to share this news with you.

    Introducing Web Platform Docs

    Mozilla, along with a group of major Web-related organizations convened by the World-Wide Web Consortium (W3C), has announced the start of Web Platform Docs (WPD), a new documentation site for Web standards documentation, which will be openly-licensed and community-maintained. The supporting organizations, known as the “stewards,” have contributed an initial batch of content to the site from their existing resources. The body of content is very much in an alpha state, as there is much work to be done to integrate, improve, and augment that content. to achieve the vision of WPD as a comprehensive and authoritative source for Web developer documentation. The stewards want to open the site for community participation as early as possible. With your help, WPD can achieve its vision being a comprehensive and authoritative source for Web developer documentation.

    Web Platform Docs has a similar goal to MDN: to help web developers improve their ability to make sites and applications using web standards. Mozilla welcomes this effort and joins with the other stewards in financially supporting the Web Platform Docs project, and in providing seed content for it. This new project is very much aligned with Mozilla’s mission to promote openness, innovation, and opportunity on the Web.

    What does this mean for MDN?

    MDN already provides a wealth of information for Web developers and for developers who use or contribute to Mozilla technology. That isn’t going to change. Some members of the MDN community, including both paid staff and volunteers, are actively involved with the Web Platform Docs project. Web Platform Docs incorporates some seed content from MDN, namely tutorial and guide content. Anyone is welcome to use MDN content under its Creative Commons Attribution-ShareAlike license (CC-BY-SA), whether on WPD or elsewhere.

    Licensing issues

    Licensing is where things get a little bit complicated. MDN and WPD use different contributor agreements and different licenses for reuse. By default, WPD contributors grant W3C the ability to relicense their original content under an open license (Creative Commons Attribution (CC-BY)). MDN content is licensed by the contributors under CC-BY-SA. The copyright belongs to the contributors, not to Mozilla, so we don’t have the right to change the license. Therefore, content that originates from MDN must be specially marked and attributed when it appears on WPD. If you create an account on WPD and create a new page, you’ll see that there is an option to indicate that the content you’re contributing came from MDN, and to provide the original URL on MDN. If you do copy MDN content (and we would be happy if you did so), we ask that you comply with the license requirements. There is also a way on WPD to mark sections of articles as coming from MDN, for cases where they get merged into CC-BY content.

    Get involved

    We encourage all Mozillians to visit the Web Platform Docs site, take a look, and get involved. By working with the other stewards to jointly build a complete, concise, and accurate suite of documentation of and for Web standards, we can help make the future of the World Wide Web brighter than ever!

  7. It's Opus, it rocks and now it's an audio codec standard!

    In a great victory for open standards, the Internet Engineering Task Force (IETF) has just standardized Opus as RFC 6716.

    Opus is the first state of the art, free audio codec to be standardized. We think this will help us achieve wider adoption than prior royalty-free codecs like Speex and Vorbis. This spells the beginning of the end for proprietary formats, and we are now working on doing the same thing for video.

    There was both skepticism and outright opposition to this work when it was first proposed in the IETF over 3 years ago. However, the results have shown that we can create a better codec through collaboration, rather than competition between patented technologies. Open standards benefit both open source organizations and proprietary companies, and we have been successful working together to create one. Opus is the result of a collaboration between many organizations, including the IETF, Mozilla, Microsoft (through Skype), Xiph.Org, Octasic, Broadcom, and Google.

    A highly flexible codec

    Unlike previous audio codecs, which have typically focused on a narrow set of applications (either voice or music, in a narrow range of bitrates, for either real-time or storage applications), Opus is highly flexible. It can adaptively switch among:

    • Bitrates from 6 kb/s to 512 kb/s
    • Voice and music
    • Mono and stereo
    • Narrowband (8 kHz) to Fullband (48 kHz)
    • Frame sizes from 2.5 ms to 60 ms

    Most importantly, it can adapt seamlessly within these operating points. Doing all of this with proprietary codecs would require at least six different codecs. Opus replaces all of them, with better quality.
    Illustration of the quality of different codecs
    The specification is available in RFC 6716, which includes the reference implementation. Up-to-date software releases are also available.

    Some audio standards define a normative encoder, which cannot be improved after it is standardized. Others allow for flexibility in the encoder, but release an intentionally hobbled reference implementation to force you to license their proprietary encoders. For Opus, we chose to allow flexibility for future encoders, but we also made the best one we knew how and released that as the reference implementation, so everyone could use it. We will continue to improve it, and keep releasing those improvements as open source.

    Use cases

    Opus is primarily designed for use in interactive applications on the Internet, including voice over IP (VoIP), teleconferencing, in-game chatting, and even live, distributed music performances. The IETF recently decided with “strong consensus” to adopt Opus as a mandatory-to-implement (MTI) codec for WebRTC, an upcoming standard for real-time communication on the web. Despite the focus on low latency, Opus also excels at streaming and storage applications, beating existing high-delay codecs like Vorbis and HE-AAC. It’s great for internet radio, adaptive streaming, game sound effects, and much more.

    Although Opus is just out, it is already supported in many applications, such as Firefox, GStreamer, FFMpeg, foobar2000, K-Lite Codec Pack, and lavfilters, with upcoming support in VLC, rockbox and Mumble.

    For more information, visit the Opus website.

  8. Talking web standards with Microsoft part 1 – Building for real standards

    I just returned from a recording session with Microsoft for their Channel 9 feature. Rey Bango (ex-Mozilla and also ex-Ajaxian) had invited us to chat about a few web development topics on video. The recordings are being edited now but you can get the presentations and the code examples right now.

    Rey and Chris

    The first session we recorded was about “Building for real standards”. In this we talk about what a standard means, how this applies to HTML5 and discuss problems and pitfalls to avoid. The slides are available on Slideshare and there is also a version with presenter notes.

    As part of the Mozilla Evangelism Reps Program we also make the slides with presenter notes as PDF, Keynote and PPT available and additionally release the code examples with tips on how to present them.

    You can get all of this on GitHub in case you want to give this presentation yourself.

    In the second (and last) part of the series we talked in detail about Progressive Enhancement, Graceful Degradation and Responsive design. The slides and code examples will be up here tomorrow.

  9. CSS 3D transformations in Firefox Nightly

    When the first 3D transformations in CSS got support on Webkit browsers people got incredibly excited about them. Now that they have matured we also support 3D CSS in Firefox. To see it for yourself, check out one of the latest nightly builds.

    You can see them in action in this demo of a rotating HTML5 logo and the screencast below:

    This means now that we need your support in trying out CSS 3D examples in Firefox and add other extensions than -webkit- to your CSS 3D products and demos. To show that this is possible, we took the well-known webkit-only “poster circle” demo and made it work with Firefox nightly by adding the -moz- (and of course the other prefixes and one set of instructions without browser prefixes). Here is a slight excerpt:

    -webkit-transform-style: preserve-3d;
    -moz-transform-style: preserve-3d;
    -o-transform-style: preserve-3d;
    -ms-transform-style: preserve-3d;
    transform-style: preserve-3d;

    You can see this in action in the screencast below alongside Chrome and you try the demo out yourself. The slight jerkiness is actually my MacBook Air impersonating a starting jet every time I use ScreenFlow and not the browser.

    To celebrate the release and to show how CSS 3D can be applied as subtle effect, have a game of pairs using your favourite browsers (and a cat) :

    browser pairs

    Oleg Romashin also spent some time to convert a few CSS 3D demos to work with Mozilla and you can check the 3D city for more “wow”.

    If you are new to CSS 3D transformations here’s a good beginner course and a tool to create them.

    The rotating HTML5 logo demo also shows how you can check if the currently used browser supports 3D transforms. Instead of repeating the animation frames for all the prefixes we test in JavaScript and create the CSS on the fly:

    function checksupport() {
      var props = ['perspectiveProperty', 'WebkitPerspective',
                   'MozPerspective', 'OPerspective', 'msPerspective'],
          i = 0,
          support = false;
      while (props[i]) {
        if (props[i] in form.style) {
          support = true;
          pfx = props[i].replace('Perspective','');
          pfx = pfx.toLowerCase();
          break;
        }
        i++;
      }
      return support;
    }
    if (checksupport()) {
      var s = '';
      styles = document.createElement('style');
      s += '#stage{-'+ pfx +'-perspective: 300px;}'+
           '#logo{-'+ pfx +'-transform-style: preserve-3d;position:relative;}'+
           '#logo.spin{-'+ pfx +'-animation: spin 3s infinite linear;}'+
           '@-'+ pfx +'-keyframes spin {'+
           '0% {'+
           '-'+ pfx +'-transform: rotateX(0deg) rotateY(0deg) rotateZ(0deg);'+
           '}'+
           '100% {'+
           '-'+ pfx +'-transform: rotateX(0deg) rotateY(360deg)'+
           ' rotateZ(360deg);'+
           '}}';
      styles.innerHTML = s;
      document.querySelector('head').appendChild(styles);
    }

    For more information on creating your own pages that use 3D transformations, take a look at the draft specification

    As always, If you find any bugs, please report them at bugzilla.mozilla.org!

    So please reward our hard work bringing the third dimension to Firefox’s CSS engine by supporting and testing. Cheers!

  10. More details about the WebAPI effort

    As we’ve hoped, there has been a lot of interest in the newly announced WebAPI effort. So I figured that I should explain in more detail some of my thinking around what we’re hoping to do and the challenges that are ahead of us.

    Goal

    The goal of this effort is to create APIs to expand what the Web can do. We don’t want people to end up choosing to develop for a proprietary platform just because the Web is lacking some capability.

    The main effort, at least initially, is to enable access to hardware connected to the device, and data which is stored or available to the device. As for hardware, we want to make the full range of hardware that people use available to the web platform. From common hardware like cameras, to more rarely used (but no less awesome) hardware like USB-driven Nerf cannons. We also want to enable communication hardware like Bluetooth and NFC.

    For data stored on the device, the most commonly discussed data today is contacts and calendar. This includes the ability to both read and write data. That is, we both want the Web platform to be able to enumerate contacts stored on the device, and read their details, as well as add and remove contacts. In short, we want it to be possible to create a Web page or Web app which lets the user manage his contact list. Same thing for calendar events and other types of data stored on devices.

    Security and Privacy

    One big reason these types of APIs haven’t been developed for the Web platform yet is because of their security and privacy implications. I would obviously not want every single Web page out there to be able to mess around with my contact list or my calendar. And being able to issue any commands to any USB device that I happen to have plugged in would likely result in everyone’s computer immediately being zombified.

    So as we are developing these APIs, we always have to develop a security model to go along with them. In some cases simply asking the user, which is how we currently do Geolocation, might work. In others, where security implications are scarier or where describing the risk to the user is harder, we’ll have to come up with better solutions.

    I really want to emphasize that we don’t yet know what the security story is going to be, but that we’re absolutely planning on having a solid security solution before we ship an API to millions of users.

    Robert O’Callahan has a really great post about permissions for Web applications.

    Standards

    Mozilla has always had a strong commitment to Web standards. This is of course not something we’re changing! All of the APIs that we are developing will be developed with the goal of being standardized and implemented across both browsers and devices.

    But it’s important to ensure that standards are good standards. This takes experimenting. Especially in areas which are as new to the Web, and as security sensitive, as these are.

    Standards organizations aren’t a good place to do research. This is why we want to experiment and do research outside the standards organizations first. But always in the open, and always listening to feedback. We’re also going to clearly prefix any APIs as to indicate that they are experiments and might change once they get standardized.

    Once we have a better understanding of what we think makes a good API we will create a proposal and bring to working groups like the Device API group at W3C, WAC and WHATWG.

    Throughout this process we will of course be in contact with other interested parties, such as other browser vendors and web developers. This is part of the normal research and making sure that an API is a good API.

    Mozilla always has and always will be a good steward of the open Web. We are not interested in creating a Mozilla-specific Web platform. We are interested in moving the open Web platform forward.

    High Level vs. Low Level

    One thing that often comes up with API design is whether we should do high level or low level APIs. For example, do we provide a low-level USB API, or a high-level API for cameras?

    There are pros and cons with both. High level means that we can create more developer-friendly APIs. We can also provide a better security model since we can ensure that the page won’t issue any unexpected USB commands, and we can ensure that no privacy-sensitive access is made without user approval. But high level also means that developers can’t access a type of device until we’ve added support for it. So until we’ve added an API for Nerf cannons, there will be no way to talk to them.

    Exposing a low-level USB API on the other hand, means that web pages can talk to any USB device in existence, with no need for us to add an explicit API for them. However it also requires developers to get their hands dirty with the details of the USB protocol and differences between devices.

    The approach we’re planning on taking is to do both high-level and low-level APIs, as well as give people the proper incentives to use the one that is best for the user. But a very important point is to provide low-level APIs early to ensure that Mozilla isn’t on the critical path for innovation. Over time, we can add high-level APIs where that makes sense.

    How you can join

    As with all things Mozilla, we’re planning on doing all our work in the open. In fact, we’ll be relying on your help to make this successful! As to keep discussions focused, we’re going to use the a new mozilla.dev.webapi discussion forum for all communication. This means that you can participate through email, newsgroups, or the web-based google group UI.

    You can subscribe to the mailing list at https://lists.mozilla.org/listinfo/dev-webapi

    For other methods go to: http://www.mozilla.org/about/forums/#dev-webapi

    We also use the #webapi IRC channel on irc.mozilla.org.

    We’ll also be tracking progress on the wiki page https://wiki.mozilla.org/WebAPI

    Looking forward to hearing from you to help build the next stage for the web platform!

    Hiring developers

    Edit: Forgot to mention, we are hiring several full time engineers for working on the WebAPI team! Read the job description and apply.