Mozilla

Articles by Robert Nyman [Editor]

Sort by:

View:

  1. Wercker – Continuous Delivery Made Easy – a webFWD project

    There is a great quote by Marc Andreessen who said that “software is eating the world”. What Marc means by this is that software is defining every industry we know; we’re no longer buying records at our local retailer but stream them via Rdio or Spotify. Skype is now the largest telecommunications provider and we’re even talking about the software-defined data-center.

    The cloud has become the defacto distribution mechanism for these software services, but has also allowed for disruptive change in how these services are delivered and consumed. Whereas it used to be the case that you would have to purchase a new version of your favorite word processing software at your local retailer, with the cloud, updates can be pushed out incrementally.

    Introducing wercker

    The key enabler for this new way of developing software is continuous delivery. Software is eating the world, and wercker makes it taste better.

    There are several successful companies out there which are big proponents of continuous delivery such as Netflix and Etsy. It is wercker’s mission to democratize continuous delivery for every developer and was founded on this very same premise in the beginning of last year by me, Micha Hernandez van Leuffen, and my cofounder Wouter Mooij out of frustration with existing solutions.

    This video introduces wercker and presents our vision on the product:

    How it works

    Wercker’s flow is simple; it integrates with popular version controls platforms such as Github and Bitbucket on one end and Infrastructure-as-a-Service providers and Platform clouds like Heroku on the other end.

    We run any unit tests you might have included in your project and subsequently present the results on a comprehensive dashboard.

    You are able to define different environments or deploy targets for, for instance staging or production to which you can deploy your project with a push of a button.

    Software is better developed together so wercker also captures the social dynamics that are paired with continuous delivery. The activity feed showcases who in your team broke the build or deployed to which environment. This increases transparency and trust within your team.

    Open Source

    Apart from offering wercker for free to open source projects we are also in the process of opening up wercker’s build environments. These environments are similar to Heroku’s buildpacks, allowing developers to define not only their own programming stack that they would like to use on wercker, but also the various build and test steps that they want to run.

    New languages and frameworks can be integrated with ease as we’ve built these environments upon Chef cookbooks which can subsequently be used for both provisioning and deployment as well. Cookbooks and recipes are already a very big open source movement, which we’re stimulating even more.

    The Future

    We’re very excited that we’ve raised a seed round led by Shamrock Ventures, Amsterdam-based MicroVC Vitulum Ventures and Greylock Partners. The funding will help us grow our platform and expand our operations.

    If you are a developer, sign up for the beta at http://beta.wercker.com. We are also interested in hearing what programming stacks developers are leveraging for their applications and to which environments they are deploying.

  2. Getting started with Open Web Apps – why and how

    We’ve been talking a lot about Open Web Apps, Firefox OS and more here lately, and I wanted to cover both how to get started, and, maybe more importantly, why.

    Why a web app?

    If we look at the climate for mobile development, it has usually come down to a choice where developers had to pick their platform and skill. Maybe do iOS and Objective-C, or Android and Java.

    The big challenge here, of course, is that if you want to deliver your content on several platforms, you’ve had a few choices:

    • Pick one platform, and ignore the others
    • Learn a number of programming languages
    • Have separate development teams for each platform

    For major organizations, having multiple teams has been something they could do, while many other have struggled with that. And naturally, many mobile apps are in addition to a company/service web site, just adding more and more on top of the things that need to be maintained, supported and developed.

    Therefore, for reasons like saving costs, simplicity of one development language and more, many developers have jumped on the options like PhoneGap, Titanium and more, thus developing with HTML5 and JavaScript, and then packaging it for various mobile operating systems.

    This has been a good and interesting approach, but probably far from optimal in most cases. We at Mozilla want you to be able to use your existing skills as a web developer, but instead of having you jump through hoops to make it work, we want the platforms to evolve and give you more possibilities and power.

    This is accomplished by giving you as a developer access to a large amount of WebAPIs, Web Activities and more, to make the web layer as powerful a platform as it deserves to be.

    The idea with Open Web Apps is not to make you choose a new platform or, worse, excluding others – on the contrary, it’s about giving you means to reuse your existing code and, if desired, make small additions to make it installable as an app.

    Should I build an app?

    While many other platforms have a strong interest in getting you tied into their platform, delivering to their app store etc, I would rather say that the first question you need to ask yourself is:

    Do I really need to make an app out of this?

    In some cases, yes, definitely! But in other cases, you need to be professional and come to the conclusion that it is probably not likely to add any extra value – a few use cases where you don’t need to do an app have been outlined in articles like No, I’m not going to download your bullshit app and Packaged HTML5 Apps: Are we emulating failure?.

    I don’t want to trick you into making an app just for the sake of it, or that you’ll do it just because others do. I would rather see you make a fair assessment, and if your app idea has something additional to offer to the end user and overall user experience, then you should consider doing an app.

    So, what could those cases be? A few of them might be:

    • You want to offer a richer experience than you could offer from a web page, e.g. accessing some WebAPIs specific to the platform/device
    • You need to store a lot of information in localStorage or IndexedDB
    • The user wants to have a real installation
    • The user wants a nice icon on their home screen/desktop for easier accessibility

    Types of Open Web Apps

    There are basically two types of Open Web Apps you can install:

    • Hosted apps
    • Packaged apps

    Hosted apps

    Hosted apps are apps running from a URL, but in an app context. This means that you need to be online to run it, and all resources (e.g. files, images etc) will reside on your server and where you will host it.

    One option to avoid the need for connectivity is make sure your app works offline. This is done by adding an appcache file with listings of assets to be made available offline, and then refer to it from your main page:

    HTML file

    <html manifest="manifest.appcache">

    Appcache file

    CACHE MANIFEST
    # Version 1.0
     
    index.html
    css/base.css
    js/base.js
    js/webapp.js
    js/offline.js
     
    NETWORK:
    *
     
    FALLBACK:
    / fallback.html

    For learning more about offline support and caveats, I strongly recommend looking into these resources:

    Pros

    • You completely control the update process
    • Just run/reuse currently existing code

    Cons

    • Requires connectivity (if offline support isn’t implemented)
    • Doesn’t have as much access to APIs as a packaged app

    Packaged apps

    Packaged apps are where you put all your assets in a ZIP file, and then offer that as a complete package to be installed. This makes these files available at all times, and it also gives you elevated privileges – i.e. you can access more APIs – since all the code can be security cleared before install.

    Pros

    • Available offline by default
    • More API access

    Cons

    • More difficult to maintain
    • Update process for getting new versions out

    At the end of the day, you need to evaluate your needs, workflow, APIs you need to work with and more to make a good decision whether you want to do a hosted or a packaged app.

    Getting started with Open Web Apps

    After all that talk, what do you actually need to build an Open Web App? Not much, as it turns out. We’ve documented it on MDN in Getting started with making apps but I’d like to give you a quick run-down here as well.

    image

    Basically, all you need to do is take an existing web site/service you have and add a manifest file. Voilà, that’s it! Yes, really. And to get it installed, of course.

    The manifest file

    A manifest file describes your app, with things like name, icons, developer and such, but also localization support, path to launch, permission request for certain APIs and more. All manifest fields are available in App manifest on MDN.

    A simple manifest could look like this:

    {
        "version": "1",
        "name": "Firefox OS Boilerplate App",
        "launch_path": "/Firefox-OS-Boilerplate-App/index.html",
        "description": "Boilerplate Firefox OS app with example use cases to get started",
        "icons": {
            "16": "/Firefox-OS-Boilerplate-App/images/logo16.png",
            "32": "/Firefox-OS-Boilerplate-App/images/logo32.png",
            "48": "/Firefox-OS-Boilerplate-App/images/logo48.png",
            "64": "/Firefox-OS-Boilerplate-App/images/logo64.png",
            "128": "/Firefox-OS-Boilerplate-App/images/logo128.png"
        },
        "developer": {
            "name": "Robert Nyman",
            "url": "http://robertnyman.com"
        },
        "installs_allowed_from": ["*"],
        "default_locale": "en"
    }

    Save this file with a .webapp extension, for instance, manifest.webapp. One very important thing to note here is that this file needs to be served with the Content-type: application/x-web-app-manifest+json.

    This is something you need to set up on your server, e.g. through an .htaccess file in Apache:

    AddType application/x-web-app-manifest+json .webapp

    Once you have your manifest, make sure to validate your app to see that it has the correct format.

    image

    Installing the app

    Now that your manifest is in order and served with the right Content-type, let’s offer a way to install it. In your web page, you can add an install button that calls this code:

    var installApp = navigator.mozApps.install(manifestURL);
     
    // Successful install
    installApp.onsuccess = function(data) {
        console.log("Success, app installed!");
    };
     
    // Install failed
    installApp.onerror = function() {
        console.log("Install failed\n\n:" + installApp.error.name);
    };

    Make sure that the URL to the manifest is absolute – a simple way to do this is to extract the URL from the current page with the install button, and to have the manifest file in the same location:

    var manifestURL = location.href.substring(0, location.href.lastIndexOf("/")) + "/manifest.webapp";

    Optionally, you can also provide a second parameter to the install method, receipts, which is a JSON object. More on that in the documentation for the install method.

    Installing a packaged app

    The above solution, with a manifest file and an install call, works well with hosted apps. With Packaged apps, you need to go through some extra steps:

    ZIP all app content

    Make sure to ZIP all the files (not the containing folder), including the regular manifest file. The manifest file has to be named manifest.webapp

    Create a mini manifest

    Create another manifest file, for instance named package.webapp, and make sure the package_path is absolute to where the ZIP file is located.

    Also, developer name and info has to match between mini manifest and the regular one in the ZIP file.

    {
        "name": "Firefox OS Boilerplate App",
        "package_path" : "http://localhost/Firefox-OS-Boilerplate-App/Firefox-OS-Boilerplate-App.zip",
        "version": "1",
        "developer": {
            "name": "Robert Nyman",
            "url": "http://robertnyman.com"
        }
    }

    Installing a package

    Instead of using the regular install method, you now call the installPackage method, which points to the mini manifest, which in turn points to the ZIP file/package:

    var manifestURL = location.href.substring(0, location.href.lastIndexOf("/")) + "/package.webapp";
    var installApp = navigator.mozApps.installPackage(manifestURL);

    Turning on Developer Mode

    For this to work in the Firefox OS Simulator, you need to turn on the Developer Mode:

    Settings > Device Information > More Information > 
    Developer > Developer mode
    

    Note: this is a work in progress, and the availability of this option might vary, and not be available in your version of the Simulator or an actual Firefox OS device.

    All the releases and pre-releases of the Firefox OS Simulator are available on Mozilla’s FTP.

    Specifying permissions

    If you plan on using some APIs that only Packaged apps have access to, you need to add a couple of things to your regular (manifest.webapp) file:

    • Add type property (e.g. “type” : “privileged”)
    • Specify permission access
    "permissions": {
        "contacts": {
            "description": "Required for autocompletion in the share screen",
            "access": "readcreate"
        },
        "alarms": {
            "description": "Required to schedule notifications"
        }
    }

    There is also an interesting option, in the form of packaged-app-server, which offers zipping the files as a package when they get requested at run time.

    $ cd ~/myapp
    $ python ~/serve_packaged_apps.py

    An example app

    As an example app – if you want to check out something easy to dissect, tweak and get started with – feel free to test the Firefox OS Boilerplate App. It supports:

    • An install button, offering you to install it as a hosted app
    • Web Activities – lots of examples and use cases
    • WebAPIs in action
    • Offline support (disabled by default)
    • Packaged apps – install your app as a ZIP file

    image

    Which platforms are supported?

    Let’s look at where we are right now with Open Web Apps. They are supported in:

    Firefox OS

    You can install an Open Web App in Firefox OS (the Simulator or on a device) and most WebAPIs and Web Activities will work.

    image

    Firefox on Android

    In Firefox on Android you can install an app, and have it installed on your home screen with the correct icon. However, it doesn’t support the WebAPIs and Web Activities.

    image

    Nightly/Aurora versions on Desktop

    You can install and run a stand-alone app in Firefox Nightly/Firefox Aurora, but it doesn’t have access to many WebAPIs and no Web Activities.

    image

    The initial strong focus at the moment is support on mobile, but the hope and goal is that Open Web Apps will work on all platforms and devices, by adding support to needed APIs and more.

    Marketplace

    When it comes to Open Web Apps, you can use or install them from anywhere. Completely up to you.However, if you are interested in being listed, hosted and much more, I recommend taking a look at the Firefox Marketplace.

    image

    You can also visit the Developer Hub for a lot more information about app development.

    image

    Conclusion

    Open Web Apps aren’t here to change your developing ways – they are here to give you the option to install your existing web solutions as apps, access device-specific APIs and more.

    Don’t reinvent the wheel – just make it a bit more powerful!

  3. Hello Chrome, it’s Firefox calling!

    Mozilla is excited to announce that we’ve achieved a major milestone in WebRTC development: WebRTC RTCPeerConnection interoperability between Firefox and Chrome. This effort was made possible because of the close collaboration between the open Web community and engineers from both Mozilla and Google.

    RTCPeerConnection (also known simply as PeerConnection or PC) interoperability means that developers can now create Firefox WebRTC applications that make direct audio/video calls to Chrome WebRTC applications without having to install a third-party plugin. Because the functionality is now baked into the browser, users can avoid problems with first-time installs and buggy plugins, and developers can deploy their apps much more easily and universally.

    To help celebrate this momentous milestone, we thought it would be fun to call up our friends at Google to discuss it with them. Check out this Firefox-Chrome demonstration call between Mozilla’s Chief Innovation Officer, Todd Simpson, and Google’s Director of Product Management, Hugh Finnan, and read what Google had to say about this momentous occasion in their blog post.

    This milestone builds on an earlier demo we showed late last year of WebRTC integrated with Social API. There we demonstrated an industry first with our implementation of DataChannels, a powerful component of WebRTC that can combined with an audio/video chat to allow users to share almost anything on their computer or device. Send vacation photos, memorable videos, links news stories etc., simply by dragging the item into your video chat window. Look out for more on this to come.

    The purpose of WebRTC, an open standard being defined jointly at the W3C and IETF standards organizations, is to provide a common platform for all user devices to communicate and share audio, video and data in real-time. This is a first step toward that vision of interoperability and true, open, real-time communication on the web.

    Posted by:
    Serge Lachapelle, Chrome Product Manager and Maire Reavy, Firefox Media Product Lead

    Start Developing Using RTCPeerConnection in Firefox

    For JavaScript developers who haven’t tried RTCPeerConnection in Firefox yet (since it is a brand new feature for us), you can try this out using the most recent Firefox Nightly by setting the media.peerconnection.enabled pref to “true” (browse to about:config and search for the media.peerconnection.enabled pref in the list of prefs). Here is a snippet of code from a sample app that shows off how to initiate, accept, and end a WebRTC call in Firefox using RTCPeerConnection:

    function initiateCall(user) {
      document.getElementById("main").style.display = "none";
      document.getElementById("call").style.display = "block";
     
      // Here's where you ask user permission to access the camera and microphone streams
      navigator.mozGetUserMedia({video:true, audio:true}, function(stream) {
        document.getElementById("localvideo").mozSrcObject = stream;
        document.getElementById("localvideo").play();
        document.getElementById("localvideo").muted = true;
     
        // Here's where you set up a Firefox PeerConnection
        var pc = new mozRTCPeerConnection();
        pc.addStream(stream);
     
        pc.onaddstream = function(obj) {
          log("Got onaddstream of type " + obj.type);
          document.getElementById("remotevideo").mozSrcObject = obj.stream;
          document.getElementById("remotevideo").play();
          document.getElementById("dialing").style.display = "none";
          document.getElementById("hangup").style.display = "block";
        };
     
        pc.createOffer(function(offer) {
          log("Created offer" + JSON.stringify(offer));
          pc.setLocalDescription(offer, function() {
            // Send offer to remote end.
            log("setLocalDescription, sending to remote");
            peerc = pc;
            jQuery.post(
              "offer", {
                to: user,
                from: document.getElementById("user").innerHTML,
                offer: JSON.stringify(offer)
              },
              function() { console.log("Offer sent!"); }
            ).error(error);
          }, error);
        }, error);
      }, error);
    }
     
    function acceptCall(offer) {
      log("Incoming call with offer " + offer);
      document.getElementById("main").style.display = "none";
      document.getElementById("call").style.display = "block";
     
      // Here's where you ask user permission to access the camera and microphone streams
      navigator.mozGetUserMedia({video:true, audio:true}, function(stream) {
        document.getElementById("localvideo").mozSrcObject = stream;
        document.getElementById("localvideo").play();
        document.getElementById("localvideo").muted = true;
     
        // Here's where you set up a Firefox PeerConnection
        var pc = new mozRTCPeerConnection();
        pc.addStream(stream);
     
        pc.onaddstream = function(obj) {
          document.getElementById("remotevideo").mozSrcObject = obj.stream;
          document.getElementById("remotevideo").play();
          document.getElementById("dialing").style.display = "none";
          document.getElementById("hangup").style.display = "block";
        };
     
        pc.setRemoteDescription(JSON.parse(offer.offer), function() {
          log("setRemoteDescription, creating answer");
          pc.createAnswer(function(answer) {
            pc.setLocalDescription(answer, function() {
              // Send answer to remote end.
              log("created Answer and setLocalDescription " + JSON.stringify(answer));
              peerc = pc;
              jQuery.post(
                "answer", {
                  to: offer.from,
                  from: offer.to,
                  answer: JSON.stringify(answer)
                },
                function() { console.log("Answer sent!"); }
              ).error(error);
            }, error);
          }, error);
        }, error);
      }, error);
    }
     
    function endCall() {
      log("Ending call");
      document.getElementById("call").style.display = "none";
      document.getElementById("main").style.display = "block";
     
      document.getElementById("localvideo").mozSrcObject.stop();
      document.getElementById("localvideo").mozSrcObject = null;
      document.getElementById("remotevideo").mozSrcObject = null;
     
      peerc.close();
      peerc = null;
    }

    You’ll notice that Firefox still prefixes the RTCPeerConnection API call as mozRTCPeerConnection because the standards committee is not yet done defining it. Chrome prefixes it as webkitRTCPeerConnection. Once the standards committee finishes its work, we will remove the prefixes and use the same API, but in the meantime, you’ll want to support both prefixes so that your app works in both browsers.

    Trying Interop Yourself

    For those eager to give interop a try, here are instructions and information about “trying this at home”.

    This is Firefox’s and Chrome’s first version of PeerConnection interoperability. As with most early releases, there are still bugs to fix, and interop isn’t supported yet in every network environment. But this is a major step forward for this new web feature and for the Web itself. We thank the standards groups and every contributor to the WebRTC community. While there’s more work to do, we hope you’ll agree that the Web is about to get a lot more awesome.

  4. Remote Debugging Firefox OS with Weinre

    If you’ve wanted to contribute to Gaia, or have been writing a webapp for Firefox OS, one of the pain points you probably ran into, when using either B2G desktop or testing on a device, is the lack of developer tools to inspect and debug your HTML, CSS and JavaScript.

    Currently we have two tracking bugs, go ahead an vote on them to bump their priority, to track the work going into developing a native remote inspector and style editor for Firefox OS but, I have some pretty exciting news. You can have access to a remote debugger today.

    And how is this possible I hear you ask? Well, one word: Weinre. Weinre is a project of the Apache Foundation and stands for WEb INspector REmote and is exactly what it’s name suggests, a tool in the same vein as Firebug or Webinspector but, able to run and debug web pages remotely. So, if you have used tools such as the Firefox Developer Tools or Chrome Dev Tools, using Weinre will be second nature. But enough talk, let’s get this up and running.

    Setting Up Weinre

    As Weinre runs on top of Node.js your first port of call would be to install Node.js. Node.js comes with NPM (Node Package Manager) bundled nowadays and this is then then what we are going to use to install Weinre. From a terminal run the following:

    npm -g install weinre

    NOTE: The -g flag is used to install Weinre as a global Node.js module for command line goodness but, on Linux and Mac, this means you most likely are going to need to run the above by prepending sudo to the above command.

    Once the installation process is complete, we are ready to use Weinre to debug. But first, let’s make absolutely sure that Weinre was indeed installed successfully. In your terminal, run the following:

    $ weinre --boundHost 127.0.0.1 --httpPort 9090
    2013-01-28T10:42:40.498Z weinre: starting server at http://127.0.0.1:9090

    If you see a line similar to the last line above, your installation was a success and the Weinre server us up and running. With that, fire up a browser (NOTE: The UI for Weinre is built specifically for Webkit based browsers so, while it might work to some degree in other browsers, I would suggest you use Chrome) and point it to http://127.0.0.1:9090

    Above then is the landing page for the Weinre server giving you access to the documentation, some other trinkets, as well as the Weinre client, the page we really want to head to so, go ahead and click on the debug client link.

    From the above you can see that we have one connected client, this is the current instance of the web inspector, some general properties of our server but, no targets. Let’s get our target set-up.

    NOTE: If the UI of winery looks very familiar that’s because Winery uses the same UI code as the web inspector in Chrome and Safari.

    Setting Up A Weinre Target

    In Weinre targets are the web pages or apps that you want to debug, and in order for the target to be able to connect, we need to add a one liner to the relevant file of our app. For this post, let’s inspect the Calendar app. Go ahead and open up gaia -> apps -> calendar -> index.html and scroll right to the bottom. Just before the closing body tag, insert the following line:

    <script src="http://127.0.0.1:9090/target/target-script-min.js#anonymous"></script>

    Before we can launch B2G Desktop and try this out however, there is one more step. Gaia uses a Content Security Policy and as part of that scripts are said to only be allowed to load, if from the same origin as the application. So, if we were to try and load the Calendar now, the script from above would be blocked as it is not being loaded from the specified origin.

    To overcome this, we need to temporarily disable CSP. To do this, open up gaia -> build -> preferences.js and add the following line, around line 24:

    prefs.push(["security.csp.enable", false]);

    Debugging Using Weinre and B2G Desktop

    Now we are ready to test Weinre. If you are not already inside the Gaia root directory, change into it now and execute:

    DEBUG=1 make

    Once the profile is built, launch B2G desktop:

    /Applications/B2G.app/Contents/MacOS/b2g-bin -profile /Users/username/mozilla/projects/gaia/profile

    Once B2G launches, unlock the screen, swipe two screens to the right and click on the Calendar icon to launch the Calendar app. Once the app launches, you will see a new item appear on Weinre’s client dashboard:

    As you can see, the Calendar has successfully connected and is now listed as one of our targets. Go ahead and click on the ‘Elements’ tab.

    Listed here is the HTML of our app on the left and our CSS on the right! You can go right ahead and edit either the HTML or the CSS as you normally would and see the changes reflect live. Note that even though the CSS looks grayed out and disabled, it if fully editable. You can also add completely new styles to the current element using the empty element.style block or amending existing rules. You will also notice you have access to the computed styles as well as metrics of the current element.

    Working With The Console

    The next tab of interest to us is the Console tab. Here you can code away and run any JavaScript you want directly against the current app or execute code exposed by the app. To see how this works, let’s interact with the call log portion of the Dialer.

    First step then is to move our script import from Calendar to Dialer. Grab the code from Calendar and then open up gaia -> apps – > communication -> dialer -> index.html and paste the code. Next rebuild your profile using ‘make’ and finally relaunch B2G desktop.

    Once it is launched again, click on the Dialer icon at the bottom left of the home screen. Once loaded, confirm that the communication channels are open to Weinre by opening http://127.0.0.1:9090/client/#anonymous and confirming that the target now looks as follows:

    127.0.0.1 [channel: t-7 id: anonymous] - app://communications.gaiamobile.org/dialer/index.html#keyboard-view

    With the dialer open, click on the call log icon, bottom left. Currently the call log is already populated with some dummy data but, let’s create our own. Click over to the Console tab in Weinre, type the following and press enter.

    RecentsDBManager.deleteAll();

    If you look at the view on desktop now, it would seem that nothing has happened but wait, there is more. Type in the following and press enter:

    Recents.refresh();

    Aha! As you can see, our call log is empty. Next step then, is to add an entry back. To do this, we will create a dummy call entry Object and then pass this to the add function of the RecentsDBManager to store it:

    // Dummy entry
    var recentCall = {
        type: 'incoming-refused',
        number: '555-6677',
        date: new Date()
    };
    RecentsDBManager.add(recentCall);
    Recents.refresh();

    And as you can see now, the entry we just created has been added to storage, IndexedDB to be exact, and is visible in the call log view. As you might very well have noticed, another of the great features that comes with the console is auto-complete which will further speed up development.

    The combination of features that this exposes already opens new doors and will make working on Firefox OS, or writing apps for the OS, much easier with less time spent between building profiles, tearing down and relaunching B2G. Which all makes for happier developers.

    But hey wait a second, what about debugging on the device? This will work exactly the same as the above with one small difference, the IP. When you want to debug on the device you first need to know the IP address of your host computer. Then you need to start up Weinre using this IP as the buondHost and also as the IP when including the script into you target documents.

    On Mac and Linux you can get this address using ifconfig and on Windows it is ipconfig. Once you have the new IP, just stop the current instance of Weinre and then do the following:

    weinre --boundHost 192.168.1.1 --httpPort 9090

    Then inside you target document add:

    <script src="http://192.168.1.1:9090/target/target-script-min.js#anonymous"></script>

    Make and push your Gaia profile to the device using:

    make install-gaia

    Launch your target app and you are in business!

    Conclusion

    While this solution is not perfect, you need to remember to undo your changes before committing anything to source control, having to manually add the script every time is not ideal and then there are also some things that do not work 100%, such as, highlighting DOM elements as you hover over the HTML source and debugging JavaScript with breakpoints and such, this does go a long way towards improving the lives of developers both working directly on Gaia as well as those writing exciting new apps for Firefox OS.

    But there is already some light at the end of the tunnel with regards to managing the injection of the script manually, disabling CSP and ensuring things are cleaned up before pushing to source control. Jan Jongboom has opened a pull request against the Gaia repo that looks extremely promising and will alleviate a lot of this so, go on and give him a hand and let’s get this merged into Gaia. Happy Hacking!

    An important note: None of the above would have happened if it was not for Kevin Grandon who remembered using Weinre and sent out the email that set the ball rolling. Thanks Kevin!

  5. Introducing the Firefox OS Boilerplate App

    When coming to a new platform or context, it’s always good to get a peek at some code and examples how to make things work. With Firefox OS and app development, it’s just the web with a few additions.

    Before here at Mozilla Hacks, we’ve covered a few ways to get started with building apps for Firefox OS:

    My experiences

    Lately I’ve been fortunate enough to give and take part in a number of workshops around Firefox OS, to see developers trying to build things for it, port their existing web apps and much more.

    This has been a fantastic learning lesson for me, and it’s been crucial to see where people might need pointers, help or examples!

    The Firefox OS Boilerplate App

    This led to me creating the Firefox OS Boilerplate App. As the name implies, it’s there to provide you with the most basic features to get started with building an app from scratch, or tools to port your existing web app.

    The idea is also to avoid any dependency on external libraries or resources, but rather be self-contained.

    It contains:

    • An install button, offering you to install it as a hosted app
    • Web Activities – lots of examples and use cases
    • WebAPIs in action
    • Offline support (disabled by default)
    • Packaged apps – install your app as a ZIP file

    It’s available on GitHub:

    How to use it

    The easiest way to get started, installing it and testing the various features, is to navigate to the Firefox OS Boilerplate App in the web browser on a Firefox OS device or in the Firefox OS Simulator.

    Alternatively, install it in the Firefox OS Simulator Dashboard by providing either of these URLs:

    Running it locally

    Once you’re ready to get started developing, download the code and run it on a web server, or point out your local version of the Firefox OS Boilerplate App in the Firefox OS Simulator.

    Note: make sure that the paths in the manifest file are valid on your localhost – bear in mind that these paths are relative to the root of the web site they are being served at.

    Also make sure to configure your server to send the manifest file with the right Content-type: application/x-web-app-manifest+json.

    This is, for instance, easy to set up in an .htaccess file in Apache:

    AddType application/x-web-app-manifest+json .webapp

    Offline support

    I’ve provided an .appcache file for enabling offline support (it’s disabled by default).

    To enable offline capabilities, just add this to the index.html file:

    <html manifest="manifest.appcache">

    Please make sure to do your homework before enabling offline support, to avoid possible initial issues:

    Remember that the .appcache file has to be served as a text/cache-manifest file:

    AddType text/cache-manifest .appcache

    Packaged apps

    When you develop web apps, by default they are being delivered from a server, thus needing online connectivity or offline support to be enabled, to work as expected.

    You do have another option, though, which is packaged apps. Basically, what this is, is putting all the files of your app into a ZIP file, making them available directly on the device itself.

    Packaged apps can also request an elevated access to certain WebAPIs in Firefox OS that aren’t available to hosted apps (we’ll go more into the differences in a later post here on Mozilla Hacks).

    There are a couple of files included in the Firefox Boilerplate OS App to help you get started, if you are interested in this.

    To create and install a packaged app, you need to go through a few steps:

    • ZIP all app content (not containing folder), including regular manifest
    • Create a mini manifest (the package.manifest file) and make sure the “package_path” is absolute to where the ZIP is located
    • Developer name and info has to match between mini manifest and the regular one in the ZIP file
    • Have an installPackage call in JavaScript pointing to the mini manifest (instead of the regular install one) – this is shown in comments in the base.js file
    • Turn on Developer Mode in the Firefox OS Simulator (Settings > Device Information > More Information > Developer > Developer mode)
    • Add type property (e.g. "type" : "privileged") in the manifest if you want access to certain APIs

    Work in progress

    The Firefox OS Boilerplate App is a work in progress, meaning that it’s likely to change over time. I believe, however, that it gives you a good head start and look into what’s possible with web apps in Firefox OS.

    Hope you like it, and please let me know what you think!

  6. Websecurify – Experiences & Technology Choices

    When I launched @websecurify years ago I wrote a lot of JavaScript, native code and XUL but today the technology combo that I use in Websecurify is made of a custom language compiled to JavaScript that sits on top of the modern HTML5 stack that runs inside your normal browser. Sounds crazy but it somehow feels the right thing to do.

    Websecurify default application launcher.

    Coming to the realisation that HTML5 was ready for Websecurify’s goals wasn’t an easy step. We were entering unexplored land full of dangers and tradeoffs. No one was attempting to do what we wanted to do and it was sort of scary place to be. Websecurify did not start out of nothing. It was primarily a desktop application and over the years we built a solid framework, wrote thousands of lines of code and spent enormous amount of hours fixing and tracking bugs in our own algorithms and the JavaScript interpreters of the time.

    There was also this question in the air whether it was actually possible to write a full-blown security testing framework with just browser technologies – something that browsers were really never meant to do for a range of reasons. We did succeed at the end and here are some of the things that made us take HTML5 on board and the things that we’ve learned during the process.

    JavaScript And Its Role

    We need to start the story with JavaScript – the language that moves the Web. It is funny how predominant this language has become over the years. It feels like it was yesterday when JavaScript was used just to create fancy rollover buttons and popups. We chose JavaScript for our vulnerability testing platform not because we knew that it was a great language but because it was native to Mozilla’s Xulrunner, which looked like a solid cross-platform desktop application framework at the time.

    Over the years we’ve learned a few nasty truths about JavaScript as a general purpose programming language. To start with, JavaScript is a scripting language – meaning it is good for writing scripts. If the aim is to glue things together than use JavaScript. For serious applications, expanding to thousands of lines of code, you will need a proper programming language with static compilation, type system and all that jazz. One of the obstacle we had with JavaScript was around garbage collection. As you program in JavaScript you tend to think with closures in mind. Almost everything is inlined as a function. Due to this style of programming, during the first months of our scanning technology we were constantly running into js interpreter quirks, which were difficult to debug. It was either the interpreter or our own code not keeping enough references around and causing all kinds of unexpected bugs.

    Sometimes it was not the garbage collection effect but the opposite – memory leaks. All of the sudden we were allocating far too much memory than we wanted to use. The dynamic nature of the language was also an obstacle as it was never possible to tell if the state of all objects was correct at any given point in time. The immediate solution to this problem was to write unit tests, which we happily started doing but solved the problem only to an extend. Even after thousands of lines of unit tests JavaScript felt short to our expectations.

    A Custom Language

    During one of the miserable periods of dealing with unexpected bugs we decided to replace JavaScript with a custom language that provided enough robustness for our needs and programming ideals. It was an experiment and it was done out of desperation. I believe we were one of the first to start thinking of JavaScript more or less like an assembler than an actual general purpose programming language. We spent 3 months developing the first prototype and the results were remarkable. The first incarnation of our JavaScript compiler was essentially a glorified grep. Things started looking good because at the time we had for the first time a proper web application security framework that runs in its entirety on standard JavaScript interpreters. Our web security scanning technology matured and we rolled out several versions of our desktop product plus a security testing tool for iOS built with a custom compiler for Objective-C.

    If it wasn’t for the lack of support for Xulrunner and XUL, we would have never looked at HTML5 as a replacement. That is right. XUL is amazing framework but it is Mozilla-centric (almost like Java, Flash, Silverlight, ActiveX and other) and lacks any support because it was never meant to be used outside of Firefox. XUL was built all around the design principles behind separation of concerns. Internationalization files, styles, structure and code were all kept separately and overlays provided the most powerful way to extend things as you wish. I still believe that XUL and XPCOM is an awesome combination and perhaps the most powerful desktop programming framework ever made but it was never meant to be.

    The Mozilla community was betting hugely on HTML5 as the next generation of programming platform and after having a look at some ongoing projects such as B2G (now Firefox OS), the Chromeless browser experiment, Firefox for Android (completely native) we started to realise that XUL might be soon deprecated and we had to think for the future. We decided to go with HTML5 which was a serious gamble. In fact, it was down crazy.

    Going With HTML5

    HTML5 happened to be a bit difficult initially. It does lacks any native look and feel but after going over this thought for a while, we realised that this is actually an advantage rather than a disadvantage. HTML5 lacks internationalisation support. It lacks the theming and overlaying features of XUL and initially it felt as being quite immature and dull. It lacks XBL. It is certainly not a XML language. When you are programming in HTML5 the only way is to build everything yourself and compose your application from the ground up in whichever way you desire.

    It was difficult to envision how that will translate to our needs but we did it. The UI was built from scratch and all the application elements were encapsulated into a small framework. Can we extend the UI in the same way we used to do with XUL? Definitely not! However, it was simpler and less confusing. HTML5 rendering turned out to be quite fast and very robust for both Firefox and Chrome and for once we saw potential.

    We had all the bits that we started with we developed our desktop software but the next big problem to tackle was really about how to deliver a web application security scanner as a modern web app. That was the difficult question. It was difficult because in order for the scanner to work you have to break out of the security model that the browser employes and that is not something browsers allow you to do. We were not lost because we already knew that worse come-to-worse, we will simply embed a browser rendering engine and write the rest of the code natively but we hoped to make our next generation product a first class citizen in both Firefox and Chrome.

    Adding Our Own API

    For sure, we couldn’t do it with the standard API provided by browsers so we decided to do what the B2G folks did with Firefox OS and add our own API that enables our applications to do what we wanted them to do while still remaining web apps by definition. These augmentations, as we like to call them, were delivered as extensions which provided a thin layer between the browser and Websecurify, our own code delivered as a web app. The mechanics behind the extensions are difficult to describe so I will skip this part. However, it is enough to say that our extensions turned out to be maintainable and provide the functionalities that we required from browsers to support in order for our in-browser web application security suite to work in the same way you would expect it to work as a desktop app.

    Websecurify operating as a proxy using the Firefox extension.

    Websecurify Httpview with full access to browser HTTP trafic provided by the Websecurify Firefox Extension.

    The HTML5 app plus a browser extension turned out to be a good combo. The HTML5 app takes care of the delivery mechanism, which as you know, it is over the Web. It also simplified the updates because we no longer had to wait for months before we roll them out because we could do them on daily basis as we go (something that we still do today). The HTML5 app that we wrote also meant that we were future-proof and here to stay as a technology company being able to adopt, pioneer and innovate in previously unexplored field. On the other hand the browser extensions that we delivered provided this much needed support to go beyond what modern browsers are capable of without compromising the user experience or security. The result is tremendous.

    Conclusion

    Until this point you must be thinking why I am writing all these things. What is this guy’s agenda? When we started writing our XUL-based app we always wanted to contribute our framework back to Mozilla while keeping our scanning technology to ourselves. We felt it was a good compromise. Now when we no longer develop for Xulrunner due to all the reasons explained above, the only thing we can share is our experience and I believe there is a lot to learn from it. We are still trying to figure out the best way to make the old XUL framework public.

    The main point I want to make is that although both JavaScript and HTML5 have their own hurdles we find them mature enough to write first-class web applications that go beyond data-entry. It is a proof that web apps are mature enough for all kinds of applications including blockbuster games, complex software which is usually only available for various native platforms and others. I am quite excited to see what the future holds and I bet it will be exhilarating.

  7. Power Polygon – HTML5 slides with theming and much more

    Since 2007 or so, I’ve been giving talks on my web browser, although browsers did not offer much of the current technology back then! Of course, each talk of mine was based on a new HTML page which isn’t very practical! Power Polygon was then born! And died a few months after that! I kept it working and used it in many of my talks, but I knew it needed some special updates.

    In 2012, with BrazilJS Foundation, which I’m a co-founder, and all the mess with those many presentation tools out there, I decided to reopen the project and BrazilJS became the foster father of the project, which you can find in the BrazilJS’s projects page and on BrazilJS Foundation’s github page.

    This new version of Power Polygon was entirely re-written and was based on statements of some of the best speakers we know of, putting the identified useful tools together!

    Want to see it working? First, you can watch a short video with an overview of these features:

    Now, you can check on the following demos:

    Why Power Polygon?

    Well, the first thing is that all the existing presentation tools work by themselves and following their own formats or “fixed” themes and results! The main idea of Power Polygon is to keep it open as the web!
    In Power Polygon, there may be addons, themes, transactions and customisations as you need! Even extra JavaScript and CSS or HTML elements can be added.

    Your talks in Power Polygon can count on some interesting tools, besides the addons, to help you presenting them, as well as to publish them and making it easier for users to see it afterwards.

    Plus, you can change languages of your slides, share it or even profile your talk for different audiences. Once this new version of Power Polygon was born from the knowledge and experience of great speakers and their living situations, you know it is being prepared and maintained to fit such needs!

    Power Polygon is open source under MIT license, although, you can create your theme or addon and use its own license, as well as your talks. We believe that being free, means you should be able to CHOOSE what you want to keep for free or not! Still, the Power Polygon core is and will be kept Open Source.

    Using it

    You can simply load the jquery and power-polygon scripts to your page, and then every section element will become an slide!
    All you gotta do is to add, in the end of your HTML code, the following line:

    PPW.init();

    This will set all the default settings to your talk! So, you can easily copy your slides from a tool to another, as well as copying them from one presentation to another! You can pass your own settings to the .init method and change everything!

    Another way of using Power Polygon, is to have all your slides saved in individual HTML files…you can even have different directories for each slides and then, put their images inside each respective folder, Power Polygon will load them for you as you define the slides property in your settings, like this:

    PPW.init({
        slides: [
            { id: "myFirstSlide", type: "opening"},
            { id: "anotherSlideOfMine", type: "content"},  // default type, if type is not defined
            { id: "anotherSubject", type: "section"}, // slides of type section look like slide titles
            { id: "anotherSlide", type: "content", notes: ["remember the milk!", "drink water!"]},
            { id: "theLastOne", type: "closing"} // the closing slide is the end of your talk
        ]
    });

    As you see, your slides may have notes and different types. By defining your slides on the init method, PPW(Power Polygon Web) will look for section elements with the respective IDs in your HTML document, if it is not found, PPW looks for it on a customisable directory.

    External slides do not need to have the section element, once PPW will create it for each external slide, giving it the slide id.

    You can see more in the full definition of the available settings, and there’s more info in general in the wiki documentation.

    Some features

    Power Polygon offers all the features we and the many speakers who have helped us building it, realized that would be useful for speakers to use, as well as to the audience to follow. You can easily change the font-size of your slides, the language of your texts(you can create your slides specifying as many different languages as you need), apply new themes, load addons, use CSS3 animations besides the jQuery animations…

    Plus, you can see the thumbs of your slides, search into slides and use a group of default shortcuts, or create your own set of shortcuts. You can use some zooming features and add actions to your slides, as well. The presentation tool will let you know about the notes you wrote for each slide, the time left and what slide is next. Also, be alerted as the time passes and you can use the social addon here to see your mentions on twitter during your talk.

    You can open your camera to the audience quite easily, so you can show them a device in your hand or anything else, re-sizing, dragging the video, or setting it to full screen. It is also easy for you to test the resolution, colors and font sizes before you start your talk, using the splash screen.
    Many other features will be added and you can give us more ideas!

    Feel free to submit new issues on our github repository!

    Actions and animations

    Besides the animations you will already be able to do by using jQuery on your talk, you will also be able to use the PPW.animate() method. The difference here is that the PPW.animate method applies animations using CSS3, instead of JavaScript, and also offers a bunch of different, more complex set of animations, like bouncing or light-effect.

    To add actions to a slide, all you gotta do is adding a script INSIDE your slide, either external or not, calling the method PPW.addAction(). This will allow you to create a timming action, or to define what and how it is done, and undone.

    Addons and themes

    You can also load or create your own addons, so you can add more features to your talk. Among the addons, you can use, for example, the syntax highlight addon, which shows better source codes on your talks, and even allows you to focus on specific lines of code, in case the speaker is a developer.

    Another addon can load the mentions you are receiving on twitter, and show them to you on your presentation tool while you are giving your talk! Another example of addon is the remote-control, which allows you to control your talk via cellphone or any mobile device, but not only go forward and backward with your slides, but also to show a pointer or a focus spot area on the current slide! You can even draw on the slide using the screen of your mobile device.

    Power Polygon - addons and plugin support.

    Everything that happens in Power Polygon triggers an event that can be listened by using the PPW.addListener() method. You can see the list of available events on the API page.

    What is next?

    We want the communities, not only from Brazil, to contribute to Power Polygon, to make it more useful for both speakers and attendees! We want the presentations to be creative and open as the web itself, and by that, I mean your talks should be different, should be creative, should be YOURS!

    Therefore, we want to have a talk repository, where you can publish your talks, embed them everywhere, and also have them indexed by search engines. Another huge step we want, is to build a great new interface for you to create your talk, create themes or even addons! Also, feel free to contribute to it, as well!

    We will be offering a repository with all the published addons, themes and transitions.

    We need you!

    Power Polygon was created to exist as the web! Open, creative and help people to reach their goals! I know we can’t do it alone, so we need you! Power Polygon can be a much more useful tool with your ideas, contributions, and why not, addons, themes or even pull requests on github!

    Also, feel free to submit new issues on our github repository!

    By the way, BrazilJS has a bunch of useful, cool projects that may need your initiative! You will be VERY welcome to contribute to our projects and to be at our conference!

    I hope you like Power Polygon and look forward to hearing new ideas and feedback from you!

  8. Introducing Web Activities

    One of the more powerful things lately for apps on various mobile phones have been intents. Register your app for handling certain types of actions, or specify in your app what kind of support you are looking for, for the thing you are trying to do.

    This is especially important in the case of Firefox OS. No matter how good your web app is to begin with, what really takes it to the next level is interaction with other apps and activities on the device.

    This is where Web Activities come into place.

    It is basically one of the new WebAPIs we’ve been working on to make the web even more powerful as a platform, and the idea is to have a simple API to both specify intent with your activity, but also declare that your app will be able to handle actions from other apps.

    If you haven’t looked into web apps yet, by the way, the best thing is probably to read Getting started with making apps. In their simplest form, a web app is just HTML5, CSS and JavaScript, with an app manifest added.

    Getting started with Web Activities

    There are a few ways you can work with Web Activities:

    • Call an activity and get presented with apps that can handle that
    • Register your activity support for your web app in the manifest file
    • Register activity support on-the-fly
    • Attach a handler to your app for when that activity occurs

    Calling an activity

    Let’s say you have a button in your app, and you want to be able to get a picture – either from the Gallery, Camera or any other app in Firefox OS that supports that activity. You can then call the pick activity, like this:

    var pick = new MozActivity({
       name: "pick",
       data: {
           type: ["image/png", "image/jpg", "image/jpeg"]}
    });

    In this example, we specify the name pick and the data to be PNG or JPEG images. You will then be presented with a menu of available activities in Firefox OS:

    As a user, you choose the app you want to pick an image from – or take a picture with the Camera – and once you’ve done so, the result will be posted back to the requesting app (Note: it is chosen from within the app handling the activity what, and if, something will be returned).

    Handling the response

    For most WebAPIs, including Web Activities, you will have onsuccess and onerror event handlers. In the case of an image/file you will get a blob back. You can then represent that returned image visually directly in your app:

    pick.onsuccess = function () {// Create image and set the returned blob as the src
        var img = document.createElement("img");
        img.src = window.URL.createObjectURL(this.result.blob);
     
        // Present that image in your app
        var imagePresenter = document.querySelector("#image-presenter");
        imagePresenter.appendChild(img);
    };
     
    pick.onerror = function () {// If an error occurred or the user canceled the activity
        alert("Can't view the image!");
    };

    Register your app for an activity

    As mentioned above, you can also set your app as a handler for certain activities. There are two ways to do that:

    Through the manifest file – declaration registration

    {
        "name": "My App",
        "description": "Doing stuff",
        "activities": {
           "view": {
                "filters": {
                    "type": "url",
                    "url": {
                        "required": true, 
                        "regexp":"/^https?:/"
                    }
                }
            }
        }
    }

    Register an activity handler – dynamic registration

    var register = navigator.mozRegisterActivityHandler({
        name: "view", 
        disposition: "inline", 
        filters: {
            type: "image/png"
        }});
     
    

register.onerror = function () {
        console.log("Failed to register activity");}

    and then handle the activity:

    navigator.mozSetMessageHandler("activity", function (a) {var img = getImageObject();

        img.src = a.source.url;/*
          Call a.postResult() or a.postError() if 

          the activity should return a value

        */
    });

    Available activities

    The available activities to choose from at this time are:

    • configure
    • costcontrol/balance
    • costcontrol/data_usage
    • costcontrol/telephony
    • dial
    • new (e.g. type: “websms/sms”, “webcontacts/contact”)
    • open
    • pick (e.g. type: “image/png”)
    • record
    • save-bookmark
    • share
    • test
    • view

    A few examples:

    Dial

    var call = new MozActivity({
        name: "dial",
        data: {
            number: "+46777888999"
        }
    });

    New SMS

    var sms = new MozActivity({
        name: "new",
        data: {
            type: "websms/sms",
            number: "+46777888999"
        }
    });

    New Contact

    var newContact = new MozActivity({
        name: "new",
        data: {
            type: "webcontacts/contact",
            params: { // Will possibly move to be direct properties under "data"
                giveName: "Robert",
                familyName: "Nyman",
                tel: "+44789",
                email: "robert@mozilla.com",
                address: "Sweden",
                note: "This is a note",
                company: "Mozilla"
            }
        }
    });

    View URL

    var openURL = new MozActivity({
        name: "view",
        data: {
            type: "url", // Possibly text/html in future versions
            url: "http://robertnyman.com"
        }
    });

    Save bookmark

    var savingBookmark = new MozActivity({
        name: "save-bookmark",
        data: {
            type: "url",
            url: "http://robertnyman.com",
            name: "Robert's talk",
            icon: "http://robertnyman.com/favicon.png"}
    });

    Try it out now!

    You can try this out right now, by putting together a web app and calling web activities. You can then test it in the Firefox OS Simulator!

    Work in progress

    Web Activities are a work in progress, and the activity names, data types etc are subject to change. However, currently most of the above works right now (with the exception for mozRegisterActivityHandler and mozSetMessageHandler, that haven’t been implemented yet).

    I hope you share my excitement with all the possibilities Web Activities are offering us, and can probably think of a number of use cases, making your app much more powerful through interaction with other apps!

  9. Firefox Development Highlights – H.264 & MP3 support on Windows, scoped stylesheets + more

    Time for the first look this year into the latest developments with Firefox. This is part of our Bleeding Edge and Firefox Development Highlights series, and most examples only work in Firefox Nightly (and could be subject to change).

    H.264 & MP3 support on Windows

    Firefox for Android and Firefox OS already support H.264 and MP3. We are also working on bringing these formats to Firefox Desktop. On Windows 7 and above, you can already test it by turning on the preference media.windows-media-foundation.enabled in about:config. Decoding is done on the OS side (no decoder included in Firefox source code, not like WebM or Ogg Theora). For Linux and Mac, work is in progress.

    The new Downloads panel has been enabled

    We have now enabled the new Downloads panel:

    Scoped style attribute

    It’s now possible to define scoped style elements. Usually, when we write a stylesheet, we use <style>...</style>, and CSS code is applied to the whole document. If the <style> tag is nested inside a node (let’s say a <div>), and the <style> tag includes the scoped attribute (<style scoped>), then the CSS code will apply only to a subtree of the document, starting with the parent node of the <style> element. The root of the subtree can also be referred via the :scope pseudo-class.

    Demo

    Scoped style demo support on JS Bin.

    Our friends over at HTML5Rocks have also written about it in A New Experimental Feature: scoped stylesheets.

    @supports and CSS.supports

    In Firefox 17, we shipped the @supports CSS at-rule. This lets you define specific CSS code only if some features are supported. For example:

    @supports not (display: flex) {
      /* If flex box model is not supported, we use a different layout */
      #main {
          width: 90%;
      }
    }

    In Firefox 20, it’s now possible to do the same thing, but within JavaScript:

    if (CSS.supports("display", "flex")) {
      // do something relying on flexbox
    }