mirror of
				https://github.com/fog/fog.git
				synced 2022-11-09 13:51:43 -05:00 
			
		
		
		
	remove docs and related, they now live at fog/fog.github.com
This commit is contained in:
		
							parent
							
								
									289dcc3f03
								
							
						
					
					
						commit
						1cfd2c5546
					
				
					 35 changed files with 0 additions and 10585 deletions
				
			
		
							
								
								
									
										5
									
								
								Rakefile
									
										
									
									
									
								
							
							
						
						
									
										5
									
								
								Rakefile
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -106,7 +106,6 @@ task :release => :build do
 | 
			
		|||
  sh "git push origin master"
 | 
			
		||||
  sh "git push origin v#{version}"
 | 
			
		||||
  sh "gem push pkg/#{name}-#{version}.gem"
 | 
			
		||||
  Rake::Task[:docs].invoke
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
task :build => :gemspec do
 | 
			
		||||
| 
						 | 
				
			
			@ -151,7 +150,3 @@ end
 | 
			
		|||
 | 
			
		||||
require "tasks/changelog_task"
 | 
			
		||||
Fog::Rake::ChangelogTask.new
 | 
			
		||||
 | 
			
		||||
require "tasks/documentation_task"
 | 
			
		||||
Fog::Rake::DocumentationTask.new
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,39 +0,0 @@
 | 
			
		|||
safe:        false
 | 
			
		||||
auto:        false
 | 
			
		||||
server:      false
 | 
			
		||||
server_port: 4000
 | 
			
		||||
 | 
			
		||||
source:      .
 | 
			
		||||
destination: ./_site
 | 
			
		||||
plugins:     ./_plugins
 | 
			
		||||
 | 
			
		||||
future:      true
 | 
			
		||||
lsi:         false
 | 
			
		||||
pygments:    false
 | 
			
		||||
markdown:    maruku
 | 
			
		||||
permalink:   none
 | 
			
		||||
 | 
			
		||||
maruku:
 | 
			
		||||
  use_tex:    false
 | 
			
		||||
  use_divs:   false
 | 
			
		||||
  png_engine: blahtex
 | 
			
		||||
  png_dir:    images/latex
 | 
			
		||||
  png_url:    /images/latex
 | 
			
		||||
 | 
			
		||||
rdiscount:
 | 
			
		||||
  extensions: []
 | 
			
		||||
 | 
			
		||||
kramdown:
 | 
			
		||||
  auto_ids: true,
 | 
			
		||||
  footnote_nr: 1
 | 
			
		||||
  entity_output: as_char
 | 
			
		||||
  toc_levels: 1..6
 | 
			
		||||
  use_coderay: false
 | 
			
		||||
  
 | 
			
		||||
  coderay:
 | 
			
		||||
    coderay_wrap: div
 | 
			
		||||
    coderay_line_numbers: inline
 | 
			
		||||
    coderay_line_numbers_start: 1
 | 
			
		||||
    coderay_tab_width: 4
 | 
			
		||||
    coderay_bold_every: 10
 | 
			
		||||
    coderay_css: style
 | 
			
		||||
| 
						 | 
				
			
			@ -1,111 +0,0 @@
 | 
			
		|||
<!doctype html>
 | 
			
		||||
 | 
			
		||||
<!--[if lt IE 7 ]> <html lang="en" class="no-js ie6"> <![endif]-->
 | 
			
		||||
<!--[if IE 7 ]>    <html lang="en" class="no-js ie7"> <![endif]-->
 | 
			
		||||
<!--[if IE 8 ]>    <html lang="en" class="no-js ie8"> <![endif]-->
 | 
			
		||||
<!--[if IE 9 ]>    <html lang="en" class="no-js ie9"> <![endif]-->
 | 
			
		||||
<!--[if (gt IE 9)|!(IE)]><!--> <html lang="en" class="no-js"> <!--<![endif]-->
 | 
			
		||||
<head>
 | 
			
		||||
  <meta charset="utf-8">
 | 
			
		||||
  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
 | 
			
		||||
 | 
			
		||||
  <title>fog - {{ page.title }}</title>
 | 
			
		||||
  <meta name="description" content="">
 | 
			
		||||
  <meta name="author" content="">
 | 
			
		||||
 | 
			
		||||
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
 | 
			
		||||
 | 
			
		||||
  <!--
 | 
			
		||||
    <link rel="shortcut icon" href="/public/favicon.ico">
 | 
			
		||||
    <link rel="apple-touch-icon" href="/public/apple-touch-icon.png">
 | 
			
		||||
  -->
 | 
			
		||||
 | 
			
		||||
  <link rel="stylesheet" href="/public/css/style.css?v=2">
 | 
			
		||||
  <link rel="stylesheet" href="/public/css/fog.css?v=2">
 | 
			
		||||
  <script src="/public/js/libs/modernizr-1.6.min.js"></script>
 | 
			
		||||
 | 
			
		||||
</head>
 | 
			
		||||
 | 
			
		||||
<body>
 | 
			
		||||
 | 
			
		||||
  <div id="container">
 | 
			
		||||
    <header>
 | 
			
		||||
      <a href="/"><img src="/public/images/fog.png" title="fog" /></a>
 | 
			
		||||
      <h1>{{ page.title }}</h1>
 | 
			
		||||
      <dl>
 | 
			
		||||
        <dt>version</dt><dd>vX.Y.Z</dd>
 | 
			
		||||
        <dt>install</dt><dd><code>gem install fog</code></dd>
 | 
			
		||||
        <dt>source</dt><dd><a href="http://github.com/fog/fog">fog/fog</a></dd>
 | 
			
		||||
      </dl>
 | 
			
		||||
    </header>
 | 
			
		||||
 | 
			
		||||
    <nav>
 | 
			
		||||
      <ul>
 | 
			
		||||
        <li><a href="/">Home</a></li>
 | 
			
		||||
        <li><a href="/about/structure.html">Structure</a></li>
 | 
			
		||||
        <li><a href="/about/getting_started.html">Getting Started</a></li>
 | 
			
		||||
        <li> </li>
 | 
			
		||||
        <li><a href="/storage">Storage</a></li>
 | 
			
		||||
        <li><a href="/compute">Compute</a></li>
 | 
			
		||||
        <li><a href="/dns">DNS</a></li>
 | 
			
		||||
        <li><a href="/cdn">CDN</a></li>
 | 
			
		||||
      </ul>
 | 
			
		||||
    </nav>
 | 
			
		||||
 | 
			
		||||
    <div id="main">
 | 
			
		||||
 | 
			
		||||
      {{ content }}
 | 
			
		||||
 | 
			
		||||
      <h2>About</h2>
 | 
			
		||||
      <ul>
 | 
			
		||||
        <li><a href="/">Home</a></li>
 | 
			
		||||
        <li><a href="/about/contributing.html">Contributing</a></li>
 | 
			
		||||
        <li><a href="/about/press.html">Press</a></li>
 | 
			
		||||
        <li><a href="/about/supported_services.html">Supported Services</a></li>
 | 
			
		||||
        <li><a href="/about/users.html">Users</a></li>
 | 
			
		||||
      </ul>
 | 
			
		||||
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <footer>
 | 
			
		||||
      sponsored by
 | 
			
		||||
      <img height="20px" src="/public/images/engineyard.png" title="engineyard" />
 | 
			
		||||
    </footer>
 | 
			
		||||
  </div> <!-- end of #container -->
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  <script src="//ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.js"></script>
 | 
			
		||||
  <script>!window.jQuery && document.write(unescape('%3Cscript src="public/js/libs/jquery-1.4.2.js"%3E%3C/script%3E'))</script>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  <!-- scripts concatenated and minified via ant build script-->
 | 
			
		||||
  <script src="public/js/plugins.js"></script>
 | 
			
		||||
  <script src="public/js/script.js"></script>
 | 
			
		||||
  <!-- end concatenated and minified scripts-->
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  <!--[if lt IE 7 ]>
 | 
			
		||||
    <script src="public/js/libs/dd_belatedpng.min.js"></script>
 | 
			
		||||
    <script> DD_belatedPNG.fix('img, .png_bg'); </script>
 | 
			
		||||
  <![endif]-->
 | 
			
		||||
 | 
			
		||||
  <!-- yui profiler and profileviewer - remove for production -->
 | 
			
		||||
  <script src="public/js/profiling/yahoo-profiling.min.js"></script>
 | 
			
		||||
  <script src="public/js/profiling/config.js"></script>
 | 
			
		||||
  <!-- end profiling code -->
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  <!-- change the UA-XXXXX-X to be your site's ID -->
 | 
			
		||||
  <script>
 | 
			
		||||
   var _gaq = [['_setAccount', 'UA-301159-7'], ['_trackPageview']];
 | 
			
		||||
   (function(d, t) {
 | 
			
		||||
    var g = d.createElement(t),
 | 
			
		||||
        s = d.getElementsByTagName(t)[0];
 | 
			
		||||
    g.async = true;
 | 
			
		||||
    g.src = ('https:' == location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
 | 
			
		||||
    s.parentNode.insertBefore(g, s);
 | 
			
		||||
   })(document, 'script');
 | 
			
		||||
  </script>
 | 
			
		||||
 | 
			
		||||
</body>
 | 
			
		||||
</html>
 | 
			
		||||
| 
						 | 
				
			
			@ -1,229 +0,0 @@
 | 
			
		|||
---
 | 
			
		||||
layout: default
 | 
			
		||||
title:  Contributing
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
First off, high five for coming to visit this page.  You are my new hero.
 | 
			
		||||
 | 
			
		||||
## Overview
 | 
			
		||||
 | 
			
		||||
* Organize your patches by keeping all related changes together in a topic branch.
 | 
			
		||||
* Rebase your branch against master before submitting a pull request (and squish any 'oops' or work in progress commits).
 | 
			
		||||
* Ensure your changes work with both Ruby 1.8.7 and 1.9! We support both!
 | 
			
		||||
* Submit changes as pull requests describing what the changes should cover and referencing issues (if any).
 | 
			
		||||
* Use 'tags' in your commits to indicate the scope, so things like '\[aws|compute\] fixed something'.
 | 
			
		||||
* Write and run tests.  Tests should follow through usage workflows and ought to pass both with mocking on and off.
 | 
			
		||||
 | 
			
		||||
## Deep dive
 | 
			
		||||
 | 
			
		||||
Now then, some of the what makes it tick and why. For simplicity let's pretend you want to implement a new service, from scratch. I will walk through the requisite pieces and important things to keep in mind as you go.
 | 
			
		||||
 | 
			
		||||
But, before I dive too deep, I'll leave you with an out.  Other great ways to contribute are fixing bugs, writing documentation or helping port other projects to use fog. That way everybody wins!
 | 
			
		||||
 | 
			
		||||
## The Service
 | 
			
		||||
 | 
			
		||||
First and foremost you'll need to create a service, which should start from something like:
 | 
			
		||||
 | 
			
		||||
    module Fog
 | 
			
		||||
      class TheService < Fog::Service
 | 
			
		||||
 | 
			
		||||
        requires :necessary_credential
 | 
			
		||||
 | 
			
		||||
        model_path 'path/to/models'
 | 
			
		||||
        collection 'name_of_collection'
 | 
			
		||||
        model 'name_of_model'
 | 
			
		||||
 | 
			
		||||
        request_path 'path/to/requests'
 | 
			
		||||
        request 'name_of_request'
 | 
			
		||||
 | 
			
		||||
        class Mock
 | 
			
		||||
          include Collections
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        class Real
 | 
			
		||||
          include Collections
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
### Highlights:
 | 
			
		||||
* we segregate between real and mock so it is easier to add stuff to one or the other later.
 | 
			
		||||
* this is where any shared stuff will go, like making/signing requests
 | 
			
		||||
 | 
			
		||||
## Requests
 | 
			
		||||
 | 
			
		||||
The next thing to bite off are the requests. fog is all about making cloud services easier to use and move between, but requests are not where this happens. Requests should map closely to the actual api requests (you should be able to directly reference the api docs and vice versa). In particular, try to keep the output of any data parsing as close to the actual format as possible. This makes implementation and maintenance much easier and provides a solid foundation for models to build nice things on top of. I generally end up working on stuff to get/list details first and then filling in create/destroy pairs and other requests.
 | 
			
		||||
You start with something like this:
 | 
			
		||||
 | 
			
		||||
<pre>
 | 
			
		||||
module Fog
 | 
			
		||||
  class TheService
 | 
			
		||||
 | 
			
		||||
    class Real
 | 
			
		||||
 | 
			
		||||
      def request(*args)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    class Mock
 | 
			
		||||
 | 
			
		||||
      def request(*args)
 | 
			
		||||
        Fog::Mock.not_implemented
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
</pre>
 | 
			
		||||
 | 
			
		||||
### Highlights:
 | 
			
		||||
* You should define the method twice, once for the real implementation and once for mocked (they should take the same arguments).
 | 
			
		||||
* The mock versions should just start out by raising a not implemented error, you can come back and fill this in later.
 | 
			
		||||
* The real version should make a request, probably by a method defined on the real class in the service you defined earlier.
 | 
			
		||||
* Each request should either return an Excon::Response (with a parsed body where appropriate) or raise an error.
 | 
			
		||||
 | 
			
		||||
## Tests
 | 
			
		||||
 | 
			
		||||
Now would be a good time to write some tests to make sure what you have written works (and will continue to). I've tried a couple variations on testing in the past, but have settled on consolidated lifetime testing. These vary enough that its hard to give a single simple example, but you can see many examples in "tests/compute/requests/aws":https://github.com/fog/fog/tree/master/tests/compute/requests/aws/.
 | 
			
		||||
 | 
			
		||||
### Highlights:
 | 
			
		||||
* Reuse the same objects and take them through their whole life cycle (this is much faster, and most of the time if one portion fails the others would anyway).
 | 
			
		||||
* Test the format of the output to ensure parsers match expectations (check the provider's api docs) and that mocks return matching data.
 | 
			
		||||
* Test common failure cases and their behavior, you'll need to know how the service acts in these cases to make better mocks.
 | 
			
		||||
 | 
			
		||||
## Models
 | 
			
		||||
 | 
			
		||||
You could also skip to the mocks here if you wanted, but I usually find the more time I spend working with the service the easier it is to build mocks. The models are the real pay dirt, you have slogged through low level requests that map to the provider api and now you want a nice interface. This is where models and collections come in. Collections provide access to lists of data on the provider and for creating new objects. Models represent the individual objects.
 | 
			
		||||
 | 
			
		||||
If you know which object you'd like to represent you should start with the collection. When naming, please refer to the names that have been chosen for other services. I haven't standardized all nouns yet, but a few are already shared (Flavor, Image, Server)
 | 
			
		||||
An example servers collection:
 | 
			
		||||
 | 
			
		||||
    require 'fog/collection'
 | 
			
		||||
    require 'fog/theservice/models/server'
 | 
			
		||||
    module Fog
 | 
			
		||||
      class TheService
 | 
			
		||||
 | 
			
		||||
        class Servers < Fog::Collection
 | 
			
		||||
 | 
			
		||||
          model Fog::TheService::Server
 | 
			
		||||
 | 
			
		||||
          def all
 | 
			
		||||
            # get list of servers
 | 
			
		||||
            load(data) # data is an array of attribute hashes
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
          def get(identity)
 | 
			
		||||
            # get server matching id
 | 
			
		||||
            new(data) # data is an attribute hash
 | 
			
		||||
          rescue Excon::Errors::NotFound
 | 
			
		||||
            nil
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
### Highlights
 | 
			
		||||
* First make an accessor in the Collections model so it will be included in Real and Mock.
 | 
			
		||||
* `#model` will take a reference to the class that will be instantiated to represent individual objects.
 | 
			
		||||
* `#all` should get a list of servers from the provider and pass an array of attribute hashes, one per server, to load.
 | 
			
		||||
* `#get` should take an identity reference and instantiate a new model object with an attribute hash returned from the remote server, or return nil of no such object exists.
 | 
			
		||||
 | 
			
		||||
Models handle remapping attributes into friendlier names and providing the rest of the interface.
 | 
			
		||||
An example model:
 | 
			
		||||
 | 
			
		||||
    require 'fog/model'
 | 
			
		||||
    module Fog
 | 
			
		||||
      module TheService
 | 
			
		||||
 | 
			
		||||
        class Server << Fog::Model
 | 
			
		||||
 | 
			
		||||
          identity  :id
 | 
			
		||||
 | 
			
		||||
          attribute :state, 'StatusValue'
 | 
			
		||||
 | 
			
		||||
          def destroy
 | 
			
		||||
            requires :identity
 | 
			
		||||
            connection.destroy_server(identity)
 | 
			
		||||
            true
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
          def ready?
 | 
			
		||||
            state == 'running'
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
          def save
 | 
			
		||||
            requires ...
 | 
			
		||||
            connection.create_server(options)
 | 
			
		||||
            true
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
### Highlights
 | 
			
		||||
* `#identity` captures the id/name that the objects are identified by and takes the same arguments as attribute.
 | 
			
		||||
* `#attribute` takes the name to make a variable available as and one or more aliases that parsers/requests will return this value as.
 | 
			
		||||
* `#destroy` will require the identity of the model and should destroy it and return true.
 | 
			
		||||
* `#ready?` should return whether the object has finished being initialized (where appropriate).
 | 
			
		||||
* `#save` should take any required objects and instantiate the object on the provider's service.
 | 
			
		||||
* These models just rely on underlying collections and requests, so it should not be necessary at this level to distinguish between Real and Mock methods.
 | 
			
		||||
 | 
			
		||||
## Mocks
 | 
			
		||||
 | 
			
		||||
Mocks provide a powerful tool for users of fog to experiment with their implementations much more quickly and without incurring costs. I usually save these for last, as implementing the requests and models provide some necessary context to finally put the mocks together. Your services mock class should have a data method that will return mocked data like so:
 | 
			
		||||
 | 
			
		||||
    module Fog
 | 
			
		||||
      module TheService
 | 
			
		||||
 | 
			
		||||
        class Mock
 | 
			
		||||
          def self.data
 | 
			
		||||
            @data ||= Hash.new do |hash, key|
 | 
			
		||||
              hash[key] = {}
 | 
			
		||||
            end
 | 
			
		||||
          end
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
The keys in this hash should represent a unique identifier of the user accessing the data and the value assigned should contain any default data that a new user might have. Any implemented mock requests should then return data retrieved from here or raise an error.
 | 
			
		||||
For instance:
 | 
			
		||||
 | 
			
		||||
    module Fog
 | 
			
		||||
      module TheService
 | 
			
		||||
 | 
			
		||||
        class Mock
 | 
			
		||||
 | 
			
		||||
          def destroy_server(server_identity)
 | 
			
		||||
            if data = self.data[:servers].delete(server_identity)
 | 
			
		||||
              response = Excon::Response.new
 | 
			
		||||
              response.status = 202
 | 
			
		||||
              response.body   = data
 | 
			
		||||
              response
 | 
			
		||||
            else
 | 
			
		||||
              raise Fog::TheService::NotFound
 | 
			
		||||
            end
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
### Highlights
 | 
			
		||||
* Mock requests should return the same type of data as an already parsed real response or should return the same error as a real problem.
 | 
			
		||||
* By mocking at this low level, higher level functions are automatically mocked out for you.
 | 
			
		||||
* The extra rigorous tests related to output formatting and error messages should help keep you honest, and each should pass in both mocked and unmocked modes.
 | 
			
		||||
 | 
			
		||||
## Summary
 | 
			
		||||
 | 
			
		||||
That provides a lot more detail than you will probably need right away, but hopefully you can refer back to different sections as you need them. If you have any questions send me a github message or email me (address is on my profile). You should always start development by creating your own fork. When you feel confident about your fork, send me a pull request. Be forewarned that I may edit some things before it gets to master, but I'll do my best to take care of this in a timely manner.
 | 
			
		||||
 | 
			
		||||
Thanks again for your interest and let me know if there is anything else I can do to help.
 | 
			
		||||
| 
						 | 
				
			
			@ -1,108 +0,0 @@
 | 
			
		|||
---
 | 
			
		||||
layout: default
 | 
			
		||||
title:  Getting Started
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
First off, install the gem:
 | 
			
		||||
 | 
			
		||||
    $ gem install fog
 | 
			
		||||
 | 
			
		||||
## Setting Up Local Storage
 | 
			
		||||
 | 
			
		||||
We will be using Local storage in the example.  Local storage provides the same api that cloud storage services in fog do, but without the bother of needing to signup for stuff or pay extra money.
 | 
			
		||||
 | 
			
		||||
First, make a local directory to hold your data.
 | 
			
		||||
 | 
			
		||||
    $ mkdir ~/fog
 | 
			
		||||
 | 
			
		||||
Now we can start writing our script, first off we should require fog.
 | 
			
		||||
 | 
			
		||||
    require 'rubygems'
 | 
			
		||||
    require 'fog'
 | 
			
		||||
 | 
			
		||||
Now in order to play with our data we need to setup a storage connection.
 | 
			
		||||
 | 
			
		||||
    storage = Fog::Storage.new({
 | 
			
		||||
      :local_root => '~/fog',
 | 
			
		||||
      :provider   => 'Local'
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
`storage` will now contain our storage object, configured to use the Local provider from our specified directory.
 | 
			
		||||
 | 
			
		||||
## Storing Data
 | 
			
		||||
 | 
			
		||||
Now that you have cleared the preliminaries you are ready to start storing data. Storage providers in fog segregate files into `directories` to make it easier to organize things. So lets create a directory so we can see that in action.
 | 
			
		||||
 | 
			
		||||
    directory = storage.directories.create(
 | 
			
		||||
      :key => 'data'
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
To make sure it was created you can always check in your filesystem, but we can also check from inside fog.
 | 
			
		||||
 | 
			
		||||
    storage.directories
 | 
			
		||||
 | 
			
		||||
Progress! Now it is time to actually create a file inside our new directory.
 | 
			
		||||
 | 
			
		||||
    file = directory.files.create(
 | 
			
		||||
      :body => 'Hello World!',
 | 
			
		||||
      :key  => 'hello_world.txt'
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
We should now have our file, first we can open it up and make sure we are on the right track.
 | 
			
		||||
 | 
			
		||||
    $ open ~/fog/hello_world.txt
 | 
			
		||||
 | 
			
		||||
It is much more likely that you will want to see what files you have from inside fog though.
 | 
			
		||||
 | 
			
		||||
    directory.files
 | 
			
		||||
 | 
			
		||||
Now that we have run through all the basics, lets clean up our mess.
 | 
			
		||||
 | 
			
		||||
    file.destroy
 | 
			
		||||
    directory.destroy
 | 
			
		||||
 | 
			
		||||
After that you should be able to check your directory list in fog or your filesystem and see you are safely back to square one.
 | 
			
		||||
 | 
			
		||||
## Next Steps
 | 
			
		||||
 | 
			
		||||
Using the same interface you can also practice working against a real provider (such as Amazon S3). Rather than worrying about signing up for an account right away though, we can use mocks to simulate S3 while we practice.
 | 
			
		||||
 | 
			
		||||
This time we will turn on mocking and then, just like before, we will need to make a connection.
 | 
			
		||||
 | 
			
		||||
    Fog.mock!
 | 
			
		||||
    storage = Fog::Storage.new({
 | 
			
		||||
      :aws_access_key_id      => 'fake_access_key_id',
 | 
			
		||||
      :aws_secret_access_key  => 'fake_secret_access_key',
 | 
			
		||||
      :provider               => 'AWS'
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
You may notice that we used bogus credentials, this is fine since we are just simulating things. To use real S3 you can simply omit Fog.mock! and swap in your real credentials.
 | 
			
		||||
 | 
			
		||||
If you'd like to turn off mocking after turning it on, you can do it at any time and every subsequent connection will be a real connection.
 | 
			
		||||
 | 
			
		||||
    # Turn on mocking
 | 
			
		||||
    Fog.mock!
 | 
			
		||||
 | 
			
		||||
    # Create a mock connection to S3
 | 
			
		||||
    storage = Fog::Storage.new({
 | 
			
		||||
      :aws_access_key_id => "asdf",
 | 
			
		||||
      :aws_secret_access_key => "asdf",
 | 
			
		||||
      :provider => "AWS"
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
    # Turn off mocking
 | 
			
		||||
    Fog.unmock!
 | 
			
		||||
 | 
			
		||||
    # Create a real connection to S3
 | 
			
		||||
    storage = Fog::Storage.new({
 | 
			
		||||
      :aws_access_key_id => "asdf",
 | 
			
		||||
      :aws_secret_access_key => "asdf",
 | 
			
		||||
      :provider => "AWS"
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
Don't worry about your losing mock data, it stays around until you reset it or until your process exits.
 | 
			
		||||
 | 
			
		||||
    # Reset all mock data
 | 
			
		||||
    Fog::Mock.reset
 | 
			
		||||
 | 
			
		||||
Congratulations and welcome to the cloud!  Continue your journey at [fog.io](http://fog.io)
 | 
			
		||||
| 
						 | 
				
			
			@ -1,52 +0,0 @@
 | 
			
		|||
---
 | 
			
		||||
layout: default
 | 
			
		||||
title:  Press
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
Mentions and blog posts from elsewhere in reverse chronological order by day (and alphasorted for same days).
 | 
			
		||||
 | 
			
		||||
**September 13th, 2011**
 | 
			
		||||
 | 
			
		||||
* [Libvirt support for fog](http://jedi.be/blog/2011/09/13/libvirt-fog-provider/)
 | 
			
		||||
 | 
			
		||||
**August 1st, 2011**
 | 
			
		||||
 | 
			
		||||
* [Using EBS Snapshots with Fog](http://www.mediamolecule.com/lab/article/using_ebs_snapshots_with_fog/)
 | 
			
		||||
 | 
			
		||||
**June 21st, 2011**
 | 
			
		||||
 | 
			
		||||
* [Mocking fog When Using It With Carrierwave](http://www.engineyard.com/blog/2011/mocking-fog-when-using-it-with-carrierwave/)
 | 
			
		||||
 | 
			
		||||
**June 14th, 2011**
 | 
			
		||||
 | 
			
		||||
* [Backing Up Your Data With Fog](http://larrywright.me/blog/articles/221-backing-up-your-data-with-fog)
 | 
			
		||||
 | 
			
		||||
**April 7th, 2011**
 | 
			
		||||
 | 
			
		||||
* [Testing multipart Uploads to S3 with Threads](http://blog.vicecity.co.uk/post/4425574978/multipart-uploads-fog-threads-win)
 | 
			
		||||
 | 
			
		||||
**March 9th, 2011**
 | 
			
		||||
 | 
			
		||||
* [Offsite Backups with fog](http://www.engineyard.com/blog/2011/offsite-backups-with-fog/)
 | 
			
		||||
 | 
			
		||||
**March 2nd, 2011**
 | 
			
		||||
 | 
			
		||||
* [Better AWS Access Control with IAM and Fog](http://blog.zerosum.org/2011/03/02/better-aws-access-control-with-iam-and-fog.html)
 | 
			
		||||
* [Using Amazon's CloudFormation, cloud-init, chef and fog to automate infrastructure](http://allanfeid.com/content/using-amazons-cloudformation-cloud-init-chef-and-fog-automate-infrastructure)
 | 
			
		||||
 | 
			
		||||
**January 6th, 2011**
 | 
			
		||||
 | 
			
		||||
* [Happy New Year (and 0.4.0) from fog!](http://www.engineyard.com/blog/2011/happy-new-year-and-0-4-0-from-fog/)
 | 
			
		||||
 | 
			
		||||
**November 30th, 2010**
 | 
			
		||||
 | 
			
		||||
* [Getting Hired: fog Edition](http://www.engineyard.com/blog/2010/getting-hired-fog-edition/)
 | 
			
		||||
 | 
			
		||||
**October 13, 2010**
 | 
			
		||||
 | 
			
		||||
* [Engine Yard Announces Formal Support for ‘fog’ to Ensure Application Portability in the Cloud](http://www.engineyard.com/company/press/2010-10-13-engine-yard-announces-formal-support-for-%E2%80%98fog%E2%80%99-to-ensure-application-portability-in-the-cloud)
 | 
			
		||||
* [Wesley Beary and fog Promoted to the Engine Yard Open Source Program](http://www.engineyard.com/blog/2010/wesley-beary-and-fog-promoted-to-the-engine-yard-open-source-program/)
 | 
			
		||||
 | 
			
		||||
**September 28, 2010**
 | 
			
		||||
 | 
			
		||||
* [The Curious Tale of the Humble Micro](http://www.engineyard.com/blog/2010/the-curious-tale-of-the-humble-micro/)
 | 
			
		||||
| 
						 | 
				
			
			@ -1,78 +0,0 @@
 | 
			
		|||
---
 | 
			
		||||
layout: default
 | 
			
		||||
title:  Structure
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
fog is the Ruby cloud computing library, top to bottom:
 | 
			
		||||
 | 
			
		||||
* Collections provide a simplified interface, making clouds easier to work with and switch between.
 | 
			
		||||
* Requests allow power users to get the most out of the features of each individual cloud.
 | 
			
		||||
* Mocks make testing and integrating a breeze.
 | 
			
		||||
                                               
 | 
			
		||||
## Collections
 | 
			
		||||
 | 
			
		||||
A high level interface to each cloud is provided through collections, such as `images` and `servers`.
 | 
			
		||||
You can see a list of available collections by calling `collections` on the connection object. You can try it out using the `fog` command:
 | 
			
		||||
 | 
			
		||||
    >> AWS.collections
 | 
			
		||||
    [:addresses, :directories, ..., :volumes, :zones]
 | 
			
		||||
 | 
			
		||||
Some collections are available across multiple providers:
 | 
			
		||||
 | 
			
		||||
* compute providers have `flavors`, `images` and `servers`
 | 
			
		||||
* dns providers have `zones` and `records`
 | 
			
		||||
* storage providers have `directories` and `files`
 | 
			
		||||
 | 
			
		||||
Collections share basic CRUD type operations, such as:
 | 
			
		||||
* `all` - fetch every object of that type from the provider.
 | 
			
		||||
* `create` - initialize a new record locally and a remote resource with the provider.
 | 
			
		||||
* `get` - fetch a single object by it's identity from the provider.
 | 
			
		||||
* `new` - initialize a new record locally, but do not create a remote resource with the provider.
 | 
			
		||||
 | 
			
		||||
As an example, we'll try initializing and persisting a Rackspace Cloud server:
 | 
			
		||||
 | 
			
		||||
    require 'fog'
 | 
			
		||||
 | 
			
		||||
    compute = Fog::Compute.new({
 | 
			
		||||
      :provider           => 'Rackspace',
 | 
			
		||||
      :rackspace_api_key  => key,
 | 
			
		||||
      :rackspace_username => username
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
    # boot a gentoo server (flavor 1 = 256, image 3 = gentoo 2008.0)
 | 
			
		||||
    server = compute.servers.create(:flavor_id => 1, :image_id => 3, :name => 'my_server')
 | 
			
		||||
    server.wait_for { ready? } # give server time to boot
 | 
			
		||||
 | 
			
		||||
    # DO STUFF
 | 
			
		||||
 | 
			
		||||
    server.destroy # cleanup after yourself or regret it, trust me
 | 
			
		||||
 | 
			
		||||
## Models
 | 
			
		||||
 | 
			
		||||
Many of the collection methods return individual objects, which also provide common methods:
 | 
			
		||||
* `destroy` - will destroy the persisted object from the provider
 | 
			
		||||
* `save` - persist the object to the provider
 | 
			
		||||
* `wait_for` - takes a block and waits for either the block to return true for the object or for a timeout (defaults to 10 minutes)
 | 
			
		||||
 | 
			
		||||
## Requests
 | 
			
		||||
 | 
			
		||||
Requests allow you to dive deeper when the models just can't cut it.
 | 
			
		||||
You can see a list of available requests by calling #requests on the connection object.
 | 
			
		||||
 | 
			
		||||
For instance, ec2 provides methods related to reserved instances that don't have any models (yet). Here is how you can lookup your reserved instances:
 | 
			
		||||
 | 
			
		||||
    $ fog
 | 
			
		||||
    >> AWS[:ec2].describe_reserved_instances
 | 
			
		||||
    #<Excon::Response [...]>
 | 
			
		||||
 | 
			
		||||
It will return an [excon](http://github.com/geemus/excon) response, which has `body`, `headers` and `status`. Both return nice hashes.
 | 
			
		||||
 | 
			
		||||
## Mocks
 | 
			
		||||
 | 
			
		||||
As you might imagine, testing code using Fog can be slow and expensive, constantly turning on and and shutting down instances.
 | 
			
		||||
Mocking allows skipping this overhead by providing an in memory representation resources as you make requests.
 | 
			
		||||
Enabling mocking easy to use, before you run other commands, simply run:
 | 
			
		||||
 | 
			
		||||
    Fog.mock!
 | 
			
		||||
 | 
			
		||||
Then proceed as usual, if you run into unimplemented mocks fog will raise an error and as always contributions are welcome!
 | 
			
		||||
| 
						 | 
				
			
			@ -1,34 +0,0 @@
 | 
			
		|||
---
 | 
			
		||||
layout: default
 | 
			
		||||
title:  Users
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
Here lies a listing of projects and products that are using fog.
 | 
			
		||||
 | 
			
		||||
Please feel free to add your own, just please follow these rules for consistency and readability.
 | 
			
		||||
 | 
			
		||||
1. Listings should be in alphabetical order and should have a link and list of services used.
 | 
			
		||||
2. Projects that are open source should link to where the source code can be found.
 | 
			
		||||
3. Products that are not open source should link to where more information about the product can be found.
 | 
			
		||||
 | 
			
		||||
Thanks for following these rules to keep the quality high and and the content useful!
 | 
			
		||||
 | 
			
		||||
## Projects
 | 
			
		||||
 | 
			
		||||
* [carrierwave](http://github.com/jnicklas/carrierwave) = AWS => Storage
 | 
			
		||||
* [chef](http://github.com/opscode/chef) = AWS => Compute, Slicehost => Compute, Terremark => vCloud, Rackspace => Compute
 | 
			
		||||
* [deckard](http://github.com/joewilliams/deckard) = AWS => Compute
 | 
			
		||||
* [gaff](http://github.com/joewilliams/gaff) = AWS => Compute, Slicehost => Compute
 | 
			
		||||
* [gemcutter](http://github.com/rubygems/gemcutter) = AWS => Storage
 | 
			
		||||
* [plover](http://github.com/railsmachine/plover) = AWS => Compute
 | 
			
		||||
 | 
			
		||||
## Products
 | 
			
		||||
 | 
			
		||||
* [DevStructure](http://devstructure.com/) = AWS => Compute, Rackspace => Compute, Slicehost => Compute
 | 
			
		||||
* [Engine Yard AppCloud](http://www.engineyard.com/cloud) = AWS => \[Compute, Storage\]
 | 
			
		||||
* [iSwifter](http://iswifter.youwebinc.com/) = BlueBox => Compute
 | 
			
		||||
* [OpenFeint](http://openfeint.com) = BlueBox => Compute
 | 
			
		||||
* [PeopleAdmin](http://www.peopleadmin.com) = AWS => [Compute, Storage]
 | 
			
		||||
* [PHPFog](https://phpfog.com) = AWS => Compute
 | 
			
		||||
* [RowFeeder](https://rowfeeder.com) = Blue Box Group => Compute
 | 
			
		||||
* [Viximo](http://viximo.com) = AWS => Compute
 | 
			
		||||
| 
						 | 
				
			
			@ -1,148 +0,0 @@
 | 
			
		|||
---
 | 
			
		||||
layout: default
 | 
			
		||||
title:  CDN
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
Faster websites are better. <a href="http://www.websiteoptimization.com/speed/tweak/design-factors/">Better experience</a>, <a href="http://exp-platform.com/Documents/IEEEComputer2007OnlineExperiments.pdf">better sales</a>, <a href="http://www.stevesouders.com/blog/2009/07/27/wikia-fast-pages-retain-users/">you name it</a>. Unfortunately, making a website faster can be tough. Thankfully a content distribution network, or CDN, can give you great performance bang for your buck. A CDN helps speed things up by putting copies of your files closer to your users. It's like the difference between pizza delivery from across the street and pizza delivery from the next town over.
 | 
			
		||||
 | 
			
		||||
The ease and deliciousness are the good news, but until recently CDN's were only available in the big leagues via 'my business guys will talk to your business guys' deals.  Fortunately for us, Amazon recently updated <a href="http://aws.amazon.com/cloudfront/">CloudFront</a>, their CDN service, to allow us to get these benefits with just a credit card and an API call. So now we'll see how you can spend a few minutes to save your users countless hours of load time.
 | 
			
		||||
 | 
			
		||||
## Preliminaries
 | 
			
		||||
 | 
			
		||||
First, make sure you have fog installed:
 | 
			
		||||
 | 
			
		||||
    gem install fog
 | 
			
		||||
 | 
			
		||||
Now you'll need to <a href="https://aws-portal.amazon.com/gp/aws/developer/subscription/index.html?productCode=AmazonCloudFront">sign up for Cloudfront</a>. Gather up the credentials your new credentials to initialize a connection to the service:
 | 
			
		||||
 | 
			
		||||
    require 'fog'
 | 
			
		||||
 | 
			
		||||
    # create a connection to the service
 | 
			
		||||
    cdn = Fog::CDN.new({
 | 
			
		||||
      :provider               => 'AWS',
 | 
			
		||||
      :aws_access_key_id      => YOUR_AWS_ACCESS_KEY_ID,
 | 
			
		||||
      :aws_secret_access_key  => YOUR_AWS_SECRET_ACCESS_KEY
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
## Setting Up Your CDN
 | 
			
		||||
 | 
			
		||||
Now you'll need to create a 'distribution' which represents a mapping from the CDN to your domain. For the examples we'll pretend we are working on 'http://www.example.com', but you can just switch it to your actual domain. Some <a href="http://docs.amazonwebservices.com/AmazonCloudFront/latest/APIReference/CreateDistribution.html">other options</a> are available, but the only other one we need to fill in is OriginProtocolPolicy.  This sets what to do about http vs https. We will use 'match-viewer' which returns the same protocol as the request, but you can also choose 'http-only' which always returns http responses.
 | 
			
		||||
 | 
			
		||||
    data = cdn.post_distribution({
 | 
			
		||||
      'CustomOrigin' => {
 | 
			
		||||
        'DNSName'               => 'www.example.com',
 | 
			
		||||
        'OriginProtocolPolicy'  => 'match-viewer'
 | 
			
		||||
      }
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
    # parse the response for stuff you'll need later
 | 
			
		||||
    distribution_id   = data.body['Id']
 | 
			
		||||
    caller_reference  = data.body['DistributionConfig']['CallerReference']
 | 
			
		||||
    etag              = data.headers['ETag']
 | 
			
		||||
    cdn_domain_name   = data.body['DomainName']
 | 
			
		||||
 | 
			
		||||
    # wait for the updates to propogate
 | 
			
		||||
    Fog.wait_for {
 | 
			
		||||
      cdn.get_distribution(distribution_id).body['Status'] == 'Deployed'
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
Fog also supports models for the AWS CDN. The above code can also be written like this:
 | 
			
		||||
 | 
			
		||||
    distribution = cdn.distributions.create( :custom_origin => {
 | 
			
		||||
          'DNSName'               => 'www.example.com',
 | 
			
		||||
          'OriginProtocolPolicy'  => 'match-viewer'
 | 
			
		||||
        }, :enabled => true
 | 
			
		||||
    })
 | 
			
		||||
    
 | 
			
		||||
    distribution.wait_for { ready? }
 | 
			
		||||
 | 
			
		||||
Like other collections supported by Fog, it is also possible to browse the list of distributions:
 | 
			
		||||
 | 
			
		||||
    cdn.distributions.all
 | 
			
		||||
    
 | 
			
		||||
Or get access to a distinct distribution by its identity:
 | 
			
		||||
 | 
			
		||||
    cdn.distributions.get(distribution_id)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## Getting Served
 | 
			
		||||
 | 
			
		||||
With the domain name from the distribution in hand you should now be ready to serve content from the edge.  All you need to do is start replacing urls like `http://www.example.com/stylesheets/foo.css` with `#{cdn_domain_name}/stylesheets/foo.css`. Just because you can do something doesn't always mean you should though.  Dynamic pages are not really well suited to CDN storage, since CDN content will be the same for every user.  Fortunately some of your most used content is a great fit.  By just switching over your images, javascripts and stylesheets you can have an impact for each and every one of your users.
 | 
			
		||||
 | 
			
		||||
Congrats, your site is faster! By default the urls aren't very pretty, something like `http://d1xdx2sah5udd0.cloudfront.net/stylesheets/foo.css`.  Thankfully you can use CNAME config options to utilize something like `http://assets.example.com/stylesheets/foo.css`, if you are interested in learning more about this let me know in the comments.
 | 
			
		||||
 | 
			
		||||
## Invalidating the CDN caches
 | 
			
		||||
 | 
			
		||||
Sometimes, some part of the CDN cache needs to be invalidated because the origin changed and we need a faster propagation than waiting for the objects to expire by themselves. To do this, CloudFront supports creating <a href="http://docs.amazonwebservices.com/AmazonCloudFront/latest/APIReference/Actions_Invalidations.html">distributions invalidation</a>.
 | 
			
		||||
 | 
			
		||||
An invalidation can be created with the following code:
 | 
			
		||||
 | 
			
		||||
    # let's invalidate /test.html and /path/to/file.html
 | 
			
		||||
    data = cdn.post_invalidation(distribution_id, [ "/test.html", "/path/to/file.html" ])
 | 
			
		||||
    invalidation_id = data.body['Id']
 | 
			
		||||
 | 
			
		||||
    Fog.wait_for { cdn.get_invalidation(distribution_id, invalidation_id).body['Status'] == 'Completed' }
 | 
			
		||||
 | 
			
		||||
It is also possible to list past and current invalidation for a given distribution:
 | 
			
		||||
 | 
			
		||||
    cdn.get_invalidation_list(distribution_id)
 | 
			
		||||
 | 
			
		||||
The same can be written with Fog CDN model abstraction:
 | 
			
		||||
 | 
			
		||||
    distribution = cdn.distributions.get(distribution_id)
 | 
			
		||||
    
 | 
			
		||||
    invalidation = distribution.invalidations.create(:paths => [ "/test.html", "/path/to/file.html" ])
 | 
			
		||||
    invalidation.wait_for { ready? }
 | 
			
		||||
    
 | 
			
		||||
Listing invalidations is as simple as:
 | 
			
		||||
 | 
			
		||||
    distribution.invalidations.all
 | 
			
		||||
 | 
			
		||||
    # this returns only summarized invalidation
 | 
			
		||||
    # to get access to the invalidations path:
 | 
			
		||||
    distribution.invalidations.get(invalidation_id)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## Cleaning Up
 | 
			
		||||
 | 
			
		||||
But, just in case you need to update things I'll run through how you can make changes. In my case I just want to clean up after myself, so I'll use the distribution_id and ETag from before to disable the distribution. We need to use the ETag as well because it provides a way to refer to different versions of the same distribution and ensures we are updating the version that we think we are.
 | 
			
		||||
 | 
			
		||||
    data = cdn.put_distribution_config(
 | 
			
		||||
      distribution_id,
 | 
			
		||||
      etag,
 | 
			
		||||
      {
 | 
			
		||||
        'CustomOrigin'    => {
 | 
			
		||||
          'DNSName'               => 'www.example.com',
 | 
			
		||||
          'OriginProtocolPolicy'  => 'match-viewer'
 | 
			
		||||
        },
 | 
			
		||||
        'CallerReference' => caller_reference,
 | 
			
		||||
        'Enabled'         => 'false'
 | 
			
		||||
      }
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    # parse the updated etag
 | 
			
		||||
    etag = data.headers['ETag']
 | 
			
		||||
 | 
			
		||||
Now you just need to wait for the update to happen like before and once its disabled we can delete it:
 | 
			
		||||
 | 
			
		||||
    Fog.wait_for {
 | 
			
		||||
      cdn.get_distribution(distribution_id).body['Status'] == 'Deployed'
 | 
			
		||||
    }
 | 
			
		||||
    cdn.delete_distribution(distribution_id, etag)
 | 
			
		||||
 | 
			
		||||
This can also be written with CDN models as:
 | 
			
		||||
 | 
			
		||||
    distribution = cdn.distributions.get(distribution_id)
 | 
			
		||||
    
 | 
			
		||||
    # make sure the distribution is deployed otherwise it can't be disabled
 | 
			
		||||
    distribution.wait_for { ready? }
 | 
			
		||||
    
 | 
			
		||||
    distribution.disable
 | 
			
		||||
    
 | 
			
		||||
    # Disabling a distribution is a lengthy operation
 | 
			
		||||
    distribution.wait_for { ready? }
 | 
			
		||||
    
 | 
			
		||||
    # and finally let's get rid of it
 | 
			
		||||
    distribution.destroy
 | 
			
		||||
 | 
			
		||||
Thats it, now go forth and speed up some load times!
 | 
			
		||||
| 
						 | 
				
			
			@ -1,122 +0,0 @@
 | 
			
		|||
---
 | 
			
		||||
layout: default
 | 
			
		||||
title:  Compute
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
Compute is the lifeblood of the cloud, but with great power comes great complication. Compute opens up huge swaths of potential, but it varies greatly in both capabilities and usage from provider to provider. Thankfully fog helps to abstract these idiosyncrasies to provide a more seamless experience.
 | 
			
		||||
 | 
			
		||||
## Installing fog
 | 
			
		||||
 | 
			
		||||
fog is distributed as a RubyGem:
 | 
			
		||||
 | 
			
		||||
    gem install fog
 | 
			
		||||
 | 
			
		||||
Or for bundler users, you can add it in your Gemfile:
 | 
			
		||||
 | 
			
		||||
    gem "fog"
 | 
			
		||||
 | 
			
		||||
## Using Amazon EC2 and fog
 | 
			
		||||
 | 
			
		||||
Sign up for an account <a href="http://aws-portal.amazon.com/gp/aws/developer/subscription/index.html?productCode=AmazonEC2">here</a> and copy down your secret access key and access key id from <a href="http://aws-portal.amazon.com/gp/aws/developer/account/index.html?action=access-key">here</a>. We are about to get into the code samples, so be sure to fill in anything in ALL_CAPS with your own values!
 | 
			
		||||
 | 
			
		||||
First, create a connection with your new account:
 | 
			
		||||
 | 
			
		||||
    require 'rubygems'
 | 
			
		||||
    require 'fog'
 | 
			
		||||
 | 
			
		||||
    # create a connection
 | 
			
		||||
    connection = Fog::Compute.new({
 | 
			
		||||
      :provider                 => 'AWS',
 | 
			
		||||
      :aws_access_key_id        => YOUR_AWS_ACCESS_KEY_ID,
 | 
			
		||||
      :aws_secret_access_key    => YOUR_AWS_SECRET_ACCESS_KEY
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
With that in hand we are ready to start making EC2 calls!
 | 
			
		||||
 | 
			
		||||
## Servers the EC2 way
 | 
			
		||||
 | 
			
		||||
Creating a server on EC2 is very easy if you are willing to accept the defaults (the smallest server size, using Ubuntu 10.04 LTS). NOTE: the default EC2 image uses the 'ubuntu' username, rather than 'root' like other services.
 | 
			
		||||
 | 
			
		||||
    server = connection.servers.create
 | 
			
		||||
 | 
			
		||||
You can then list your servers to see that it now appears:
 | 
			
		||||
 | 
			
		||||
    connection.servers
 | 
			
		||||
 | 
			
		||||
Rather than worrying about the whole list, we can also just get the latest data for just our server:
 | 
			
		||||
 | 
			
		||||
    server.reload
 | 
			
		||||
 | 
			
		||||
That can get tedious quickly however, especially when servers can take several minutes to boot.  Fog has `wait_for` for cases like this and `ready?` for checking to see when a server has completed its start up.
 | 
			
		||||
 | 
			
		||||
    server.wait_for { ready? }
 | 
			
		||||
 | 
			
		||||
Once we are done with that we can shut it down.
 | 
			
		||||
 | 
			
		||||
    server.destroy
 | 
			
		||||
 | 
			
		||||
## Bootstrap: Servers the fog Way
 | 
			
		||||
 | 
			
		||||
Cycling servers is great, but in order to actually ssh in we need to setup ssh keys and open ports.  But rather than worrying about the nitty gritty, we will utilize `bootstrap`.  NOTE: normally we could leave out username and use the default (root), but the default Ubuntu from Canonical uses the ubuntu username instead.
 | 
			
		||||
 | 
			
		||||
    server = connection.servers.bootstrap(:private_key_path => '~/.ssh/id_rsa', :public_key_path => '~/.ssh/id_rsa.pub', :username => 'ubuntu')
 | 
			
		||||
 | 
			
		||||
Bootstrap will create the server, but it will also make sure that port 22 is open for traffic and has ssh keys setup. The ssh key pair you specified will be registered under the name "fog\_default" unless you've set `Fog.credential` to a custom string value. In order to hook everything up `bootstrap` will need the server to be running, so by the time it finishes it will be ready. You can then make commands to it directly:
 | 
			
		||||
 | 
			
		||||
    server.ssh('pwd')
 | 
			
		||||
    server.ssh(['pwd', 'whoami'])
 | 
			
		||||
 | 
			
		||||
These return an array of results, where each has stdout, stderr and status values so you can check out what your commands accomplished.  Now just shut it down to make sure you don't continue getting charged.
 | 
			
		||||
 | 
			
		||||
    server.destroy
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Managing multiple ssh key pairs on EC2
 | 
			
		||||
 | 
			
		||||
The key pair you've specified, will be registered as "fog\_default" after running `bootstrap` for the first time. If you want to use multiple key pairs with the same AWS credentials, you need to set `Fog.credential` to register your other key pairs under different names. Your additional key pair will then be registered as "fog\_#{Fog.credential}":
 | 
			
		||||
 | 
			
		||||
    Fog.credential = 'my_custom_key'
 | 
			
		||||
    connection.servers.bootstrap(:private_key_path => '~/.ssh/my_custom_key', :public_key_path => '~/.ssh/my_custom_key.pub')
 | 
			
		||||
 | 
			
		||||
If you've already registered a custom key pair e.g. using `connection.create_key_pair` or `connection.import_key_pair`, you can set your key paths using `Fog.credentials` and pass in the name of this key so `bootstrap` will use it instead of "fog\_default":
 | 
			
		||||
 | 
			
		||||
    Fog.credentials = Fog.credentials.merge({ :private_key_path => "~/.ssh/my_custom_key", :public_key_path => "~/.ssh/my_custom_key.pub" })
 | 
			
		||||
    connection.import_key_pair('my_custom_key', IO.read('~/.ssh/my_custom_key.pub')) if connection.key_pairs.get('my_custom_key').nil?
 | 
			
		||||
    server = connection.servers.bootstrap(:key_name => 'my_custom_key')
 | 
			
		||||
 | 
			
		||||
## Rackspace Cloud Servers
 | 
			
		||||
 | 
			
		||||
Rackspace has <a href="http://www.rackspacecloud.com/cloud_hosting_products/servers">Cloud Servers</a> and you can sign up <a href="https://www.rackspacecloud.com/signup">here</a> and get your credentials <a href="https://manage.rackspacecloud.com/APIAccess.do">here</a>.
 | 
			
		||||
 | 
			
		||||
    # create a connection
 | 
			
		||||
    connection = Fog::Compute.new({
 | 
			
		||||
      :provider           => 'Rackspace',
 | 
			
		||||
      :rackspace_username => RACKSPACE_USERNAME,
 | 
			
		||||
      :rackspace_api_key  => RACKSPACE_API_KEY
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
If you work with the European cloud from Rackspace you have to add the following:
 | 
			
		||||
 | 
			
		||||
    :rackspace_auth_url => "lon.auth.api.rackspacecloud.com"
 | 
			
		||||
 | 
			
		||||
We will skip over learning how to do this the 'Rackspace Way' and instead jump right to using bootstrap to get their smallest Ubuntu 10.04 LTS server.
 | 
			
		||||
 | 
			
		||||
    server = connection.servers.bootstrap
 | 
			
		||||
 | 
			
		||||
You can run all the same ssh commands and do what you need to, then once again shutdown to ensure you are not charged once you are done.
 | 
			
		||||
 | 
			
		||||
    server.destroy
 | 
			
		||||
 | 
			
		||||
## Mocking out Compute
 | 
			
		||||
 | 
			
		||||
You can also start any of these scripts with `Fog.mock!` or start the fog interactive tool from the command line with `FOG_MOCK=true fog` to run in mock mode. In this mode commands are run as local simulation, so no cloud resources are ever consumed and things operate much faster.
 | 
			
		||||
 | 
			
		||||
## Cleaning up
 | 
			
		||||
 | 
			
		||||
To cover your tracks its a good idea to check for running servers and shut them down, here is one way you might do that.
 | 
			
		||||
 | 
			
		||||
    connection.servers.select {|server| server.ready? && server.destroy}
 | 
			
		||||
 | 
			
		||||
## Summary
 | 
			
		||||
 | 
			
		||||
Compute can be tricky, but the abstractions in fog make it much easier to get started.  With your servers up and running you can then focus on the task at hand and get some work done.  Congratulations on adding a new tool to your arsenal and let us know what we can do better.
 | 
			
		||||
| 
						 | 
				
			
			@ -1,79 +0,0 @@
 | 
			
		|||
---
 | 
			
		||||
layout: default
 | 
			
		||||
title:  DNS
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
The power and flexibility of the cloud are amazing. But sometimes it can be a pain to chase your resources around and keep everything up to date. This is especially true of keeping track of addresses for DNS, but thankfully more and more API driven options are available, allowing you to automate your DNS to keep up with your hardware changes.
 | 
			
		||||
 | 
			
		||||
## Setup
 | 
			
		||||
 | 
			
		||||
First, make sure you have fog installed:
 | 
			
		||||
 | 
			
		||||
    gem install fog
 | 
			
		||||
 | 
			
		||||
For this first example we will use Zerigo (see below for how to use other providers). You can signup for Zerigo DNS <a href="https://www.zerigo.com/signup/dns">here</a>. Gather up your new credentials to initialize a connection to the service:
 | 
			
		||||
 | 
			
		||||
    require 'rubygems'
 | 
			
		||||
    require 'fog'
 | 
			
		||||
 | 
			
		||||
    # create a connection to the service
 | 
			
		||||
    dns = Fog::DNS.new({
 | 
			
		||||
      :provider     => 'Zerigo',
 | 
			
		||||
      :zerigo_email => ZERIGO_EMAIL,
 | 
			
		||||
      :zerigo_token => ZERIGO_TOKEN
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
## Getting in the Zone
 | 
			
		||||
 | 
			
		||||
The first thing you need to do to prepare for your DNS excursion is create a zone for your domain.  The zone will contain all of the more specific records that you will create later.  You will just need to specify the domain, which should be your url without the 'http' or 'www' parts, and an email address.  Then you can create the zone with your DNS connection:<!--more-->
 | 
			
		||||
 | 
			
		||||
    zone = @dns.zones.create(
 | 
			
		||||
      :domain => 'example.com',
 | 
			
		||||
      :email  => 'admin@example.com'
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
Now that you have a zone you will need to update your registrar to let them know what DNS servers are responsible for your domain.  You can ask the zone what values to use:
 | 
			
		||||
 | 
			
		||||
    zone.nameservers
 | 
			
		||||
 | 
			
		||||
## Spinning Records
 | 
			
		||||
 | 
			
		||||
With your new zone in hand you can add records as needed.  First and foremost you will probably want the 'www' version of your site to point to whatever your ip might be:
 | 
			
		||||
 | 
			
		||||
    record = @zone.records.create(
 | 
			
		||||
      :value   => '1.2.3.4',
 | 
			
		||||
      :name => 'example.com',
 | 
			
		||||
      :type => 'A'
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
Adding other records is similarly easy, for instance if we want 'www.example.com' to go to the same place, we can use a cname record:
 | 
			
		||||
 | 
			
		||||
    record = @zone.records.create(
 | 
			
		||||
      :value   => 'example.com',
 | 
			
		||||
      :name => 'www',
 | 
			
		||||
      :type => 'CNAME'
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
Or, similarly you might want to have your blog elsewhere:
 | 
			
		||||
 | 
			
		||||
    record = @zone.records.create(
 | 
			
		||||
      :value   => '4.3.2.1',
 | 
			
		||||
      :name => 'blog.example.com',
 | 
			
		||||
      :type => 'A'
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
You can add more specifics if you need to, but reasonable defaults make it just that easy.  You can also add any other kind of DNS record you might need for mail or other purposes, you can find a nice overview of record options and types <a href="http://en.wikipedia.org/wiki/Domain_Name_System#DNS_resource_records">on Wikipedia</a>.
 | 
			
		||||
 | 
			
		||||
## No Zerigo? No Problem
 | 
			
		||||
 | 
			
		||||
If you already have an account with another service you can just as easily use this same code with different credentials. fog currently supports <a href="http://aws.amazon.com/route53/">AWS Route 53</a>, <a href="http://bluebox.net">Blue Box</a>, <a href="http://dnsimple.com">DNSimple</a>, <a href="http://www.linode.com">Linode</a>, <a href="http://www.rackspace.com">Rackspace</a>, <a href="http://www.slicehost.com">Slicehost</a> and <a href="http://www.zerigo.com/managed-dns">Zerigo</a>; so you can have your pick.  As an example you can connect to AWS instead of Zerigo:
 | 
			
		||||
 | 
			
		||||
    dns = Fog::DNS.new({
 | 
			
		||||
      :provider               => 'AWS',
 | 
			
		||||
      :aws_access_key_id      => YOUR_AWS_ACCESS_KEY_ID,
 | 
			
		||||
      :aws_secret_access_key  => YOUR_AWS_SECRET_ACCESS_KEY
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
## Go Forth and Resolve
 | 
			
		||||
 | 
			
		||||
Using this makes it easier to give yourself shortcuts to your cloud servers and manage how clients and users access them as well. It is great to have this flexibility so that you can modify your cloud infrastructure as needed while keeping everything ship shape. It also provides a nice way to create custom subdomains for users and just generally round out your cloud solution.
 | 
			
		||||
| 
						 | 
				
			
			@ -1,93 +0,0 @@
 | 
			
		|||
---
 | 
			
		||||
layout: default
 | 
			
		||||
title:  The Ruby cloud services library
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
Whether you need compute, dns, storage, or a multitude of other services, fog provides an accessible entry point and facilitates cross service compatibility.
 | 
			
		||||
 | 
			
		||||
Just getting started working with cloud resources? You are not alone, and having so many complicated options makes it hard to know where to start. fog delivers the knowledge of cloud experts to you, helping you to bootstrap your cloud usage and guiding you as your own expertise develops.
 | 
			
		||||
 | 
			
		||||
By coding with fog from the start you avoid vendor lock-in and give yourself more flexibility to provide value. Whether you are writing a library, designing a software as a service product or just hacking on the weekend this flexibility is a huge boon.
 | 
			
		||||
 | 
			
		||||
With a rapidly expanding community and codebase the advantages of fog just keep coming. Join us and together we will realize the future of cloud computing.
 | 
			
		||||
 | 
			
		||||
## Getting Started
 | 
			
		||||
 | 
			
		||||
    sudo gem install fog
 | 
			
		||||
 | 
			
		||||
Now type 'fog' to try stuff, confident that fog will let you know what to do. Here is an example of wading through server creation for Amazon Elastic Compute Cloud:
 | 
			
		||||
 | 
			
		||||
    >> server = Compute[:aws].servers.create
 | 
			
		||||
    ArgumentError: image_id is required for this operation
 | 
			
		||||
 | 
			
		||||
    >> server = Compute[:aws].servers.create(:image_id => 'ami-5ee70037')
 | 
			
		||||
    <Fog::AWS::EC2::Server [...]>
 | 
			
		||||
 | 
			
		||||
    >> server.destroy # cleanup after yourself or regret it, trust me
 | 
			
		||||
    true
 | 
			
		||||
 | 
			
		||||
## Go forth and conquer
 | 
			
		||||
 | 
			
		||||
Play around and use the console to explore or check out the [getting started guide](/about/getting_started.html) for more details. Once you are reading to start scripting fog, here is a quick hint on how to make connections without the command line thing to help you.
 | 
			
		||||
 | 
			
		||||
    # create a compute connection
 | 
			
		||||
    compute = Fog::Compute.new({:provider => 'AWS', :aws_access_key_id => ACCESS_KEY_ID, :aws_secret_access_key => SECRET_ACCESS_KEY})
 | 
			
		||||
    # compute operations go here
 | 
			
		||||
 | 
			
		||||
    # create a storage connection
 | 
			
		||||
    storage = Fog::Storage.new({:provider => 'AWS', :aws_access_key_id => ACCESS_KEY_ID, :aws_secret_access_key => SECRET_ACCESS_KEY})
 | 
			
		||||
    # storage operations go here
 | 
			
		||||
 | 
			
		||||
geemus says: "That should give you everything you need to get started, but let me know if there is anything I can do to help!"
 | 
			
		||||
 | 
			
		||||
## Contributing
 | 
			
		||||
 | 
			
		||||
* Find something you would like to work on.
 | 
			
		||||
  * Look for anything you can help with in the [issue tracker](https://github.com/fog/fog/issues).
 | 
			
		||||
  * Look at the [code quality metrics](https://codeclimate.com/github/fog/fog) for anything you can help clean up.
 | 
			
		||||
  * Or anything else!
 | 
			
		||||
* Fork the project and do your work in a topic branch.
 | 
			
		||||
  * Make sure your changes will work on both Ruby 1.8.7 and Ruby 1.9.
 | 
			
		||||
* Add a config at `tests/.fog` for the component you want to test.
 | 
			
		||||
* Add shindo tests to prove your code works and run all the tests using `bundle exec rake`.
 | 
			
		||||
* Rebase your branch against `fog/fog` to make sure everything is up to date.
 | 
			
		||||
* Commit your changes and send a pull request.
 | 
			
		||||
 | 
			
		||||
## Resources
 | 
			
		||||
 | 
			
		||||
Enjoy, and let me know what I can do to continue improving fog!
 | 
			
		||||
 | 
			
		||||
* Work through the [fog tutorial](https://github.com/downloads/geemus/learn_fog/learn_fog.tar.gz)
 | 
			
		||||
* Read fog's API documentation [master branch](http://rubydoc.info/github/fog/fog) or [latest gem release](http://rubydoc.info/gems/fog)
 | 
			
		||||
* Stay up to date by following [@fog](http://twitter.com/fog) and/or [@geemus](http://twitter.com/geemus) on Twitter.
 | 
			
		||||
* Get and give help on the [#ruby-fog](irc://irc.freenode.net/ruby-fog) irc channel on Freenode
 | 
			
		||||
* Follow release notes and discussions on the [mailing list](http://groups.google.com/group/ruby-fog)
 | 
			
		||||
* Report bugs or find tasks to help with in the [issues](http://github.com/fog/fog/issues)
 | 
			
		||||
* Learn about [contributing](/about/contributing.html)
 | 
			
		||||
* See where fog is used and let the world know how you use it [in the wild](/about/users.html)
 | 
			
		||||
* Check out blog posts and other mentions in the [press](/about/press.html)
 | 
			
		||||
 | 
			
		||||
## Copyright
 | 
			
		||||
 | 
			
		||||
(The MIT License)
 | 
			
		||||
 | 
			
		||||
Copyright (c) 2012 [geemus (Wesley Beary)](http://github.com/geemus)
 | 
			
		||||
 | 
			
		||||
Permission is hereby granted, free of charge, to any person obtaining
 | 
			
		||||
a copy of this software and associated documentation files (the
 | 
			
		||||
"Software"), to deal in the Software without restriction, including
 | 
			
		||||
without limitation the rights to use, copy, modify, merge, publish,
 | 
			
		||||
distribute, sublicense, and/or sell copies of the Software, and to
 | 
			
		||||
permit persons to whom the Software is furnished to do so, subject to
 | 
			
		||||
the following conditions:
 | 
			
		||||
 | 
			
		||||
The above copyright notice and this permission notice shall be
 | 
			
		||||
included in all copies or substantial portions of the Software.
 | 
			
		||||
 | 
			
		||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 | 
			
		||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 | 
			
		||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 | 
			
		||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 | 
			
		||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 | 
			
		||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 | 
			
		||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 | 
			
		||||
| 
						 | 
				
			
			@ -1,25 +0,0 @@
 | 
			
		|||
<?xml version="1.0"?>
 | 
			
		||||
<!DOCTYPE cross-domain-policy SYSTEM "http://www.adobe.com/xml/dtds/cross-domain-policy.dtd">
 | 
			
		||||
<cross-domain-policy>
 | 
			
		||||
  
 | 
			
		||||
  
 | 
			
		||||
<!-- Read this: www.adobe.com/devnet/articles/crossdomain_policy_file_spec.html -->
 | 
			
		||||
 | 
			
		||||
<!-- Most restrictive policy: -->
 | 
			
		||||
	<site-control permitted-cross-domain-policies="none"/>
 | 
			
		||||
	
 | 
			
		||||
	
 | 
			
		||||
	
 | 
			
		||||
<!-- Least restrictive policy: -->
 | 
			
		||||
<!--
 | 
			
		||||
	<site-control permitted-cross-domain-policies="all"/>
 | 
			
		||||
	<allow-access-from domain="*" to-ports="*" secure="false"/>
 | 
			
		||||
	<allow-http-request-headers-from domain="*" headers="*" secure="false"/>
 | 
			
		||||
-->
 | 
			
		||||
<!--
 | 
			
		||||
  If you host a crossdomain.xml file with allow-access-from domain=“*” 	 	
 | 
			
		||||
  and don’t understand all of the points described here, you probably 	 	
 | 
			
		||||
  have a nasty security vulnerability. ~ simon willison
 | 
			
		||||
-->
 | 
			
		||||
 | 
			
		||||
</cross-domain-policy>
 | 
			
		||||
| 
						 | 
				
			
			@ -1,142 +0,0 @@
 | 
			
		|||
/* layout */
 | 
			
		||||
body {
 | 
			
		||||
  background-color: #EBF2F9;
 | 
			
		||||
  line-height: 1.5em;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#container {
 | 
			
		||||
  margin: auto;
 | 
			
		||||
  text-align: left;
 | 
			
		||||
  width: 800px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
header {
 | 
			
		||||
  background-color: #A0C0E1;
 | 
			
		||||
  border-color: #70A1D2;
 | 
			
		||||
  -moz-border-radius: 0 0 0.5em 0.5em;
 | 
			
		||||
  border-radius: 0 0 0.5em 0.5em;
 | 
			
		||||
  border-style: solid;
 | 
			
		||||
  border-width: 0 1px 1px 1px;
 | 
			
		||||
  color: #FFF;
 | 
			
		||||
  height: 154px;
 | 
			
		||||
  margin-bottom: 2em;
 | 
			
		||||
  position: relative;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
header a, header a:active, header a:visited {
 | 
			
		||||
  color: #FFF;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
header img {
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  left: 0;
 | 
			
		||||
  top: 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
header h1 {
 | 
			
		||||
  font-size: 2em;
 | 
			
		||||
  line-height: 154px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
header dl {
 | 
			
		||||
  background-color: #70A1D2;
 | 
			
		||||
  border-color: #70A1D2;
 | 
			
		||||
  -moz-border-radius: 0 0 0.5em 0.5em;
 | 
			
		||||
  border-radius: 0 0 0.5em 0.5em;
 | 
			
		||||
  height: 140px; /* 154 - padding-top */
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  padding: 14px 1.5em 0 1.5em;
 | 
			
		||||
  right: 0;
 | 
			
		||||
  top: 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
header dl dt {
 | 
			
		||||
  font-weight: bold;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
nav, #main {
 | 
			
		||||
  background-color: #FFF;
 | 
			
		||||
  -moz-border-radius: 0.5em;
 | 
			
		||||
  border-radius: 0.5em;
 | 
			
		||||
  color: #666;
 | 
			
		||||
  border: 1px solid #70A1D2;
 | 
			
		||||
  padding: 0 1em;
 | 
			
		||||
  margin-bottom: 2em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
nav {
 | 
			
		||||
  padding: 1em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
nav li {
 | 
			
		||||
  display: inline;
 | 
			
		||||
  padding-left: 2em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
nav li a {
 | 
			
		||||
  font-size: 1.5em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
footer {
 | 
			
		||||
  background-color: #A0C0E1;
 | 
			
		||||
  border-color: #70A1D2;
 | 
			
		||||
  -moz-border-radius: 0.5em 0.5em 0 0;
 | 
			
		||||
  border-radius: 0.5em 0.5em 0 0;
 | 
			
		||||
  border-style: solid;
 | 
			
		||||
  border-width: 1px 1px 0 1px;
 | 
			
		||||
  color: #FFF;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
footer img {
 | 
			
		||||
  padding: 5px;
 | 
			
		||||
  vertical-align: middle;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* misc */
 | 
			
		||||
 | 
			
		||||
h2 {
 | 
			
		||||
  border-bottom: 2px solid #A0C0E1;
 | 
			
		||||
  color: #70A1D2;
 | 
			
		||||
  font-size: 1.5em;
 | 
			
		||||
  margin-top: 1.33333333333333em;
 | 
			
		||||
  padding: 0 0.75em 0.75em 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
code, pre {
 | 
			
		||||
  background-color: #EBF2F9;
 | 
			
		||||
  border: 1px solid #70A1D2;
 | 
			
		||||
  color: #666;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
code {
 | 
			
		||||
  padding: 0 0.2em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
p, ul {
 | 
			
		||||
  margin-bottom: 1em;
 | 
			
		||||
  margin-top: 1em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pre {
 | 
			
		||||
  -moz-border-radius: 0.5em;
 | 
			
		||||
  border-radius: 0.5em;
 | 
			
		||||
  margin: 1em;
 | 
			
		||||
  white-space: pre;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pre code {
 | 
			
		||||
  border: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@media all and (orientation:portrait) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@media all and (orientation:landscape) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@media screen and (max-device-width: 480px) {
 | 
			
		||||
  /* html { -webkit-text-size-adjust:none; -ms-text-size-adjust:none; } */
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,8 +0,0 @@
 | 
			
		|||
* {
 | 
			
		||||
  float: none;       
 | 
			
		||||
  background: #fff;  
 | 
			
		||||
  color: #000;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
body { font-size: 80%; }
 | 
			
		||||
| 
						 | 
				
			
			@ -1,129 +0,0 @@
 | 
			
		|||
/*  HTML5 ✰ Boilerplate  */
 | 
			
		||||
 | 
			
		||||
html, body, div, span, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre,
 | 
			
		||||
abbr, address, cite, code, del, dfn, em, img, ins, kbd, q, samp,
 | 
			
		||||
small, strong, sub, sup, var, b, i, dl, dt, dd, ol, ul, li,
 | 
			
		||||
fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td,
 | 
			
		||||
article, aside, canvas, details, figcaption, figure,  footer, header, hgroup, 
 | 
			
		||||
menu, nav, section, summary, time, mark, audio, video {
 | 
			
		||||
  margin:0;
 | 
			
		||||
  padding:0;
 | 
			
		||||
  border:0;
 | 
			
		||||
  outline:0;
 | 
			
		||||
  font-size:100%;
 | 
			
		||||
  vertical-align:baseline;
 | 
			
		||||
  background:transparent;
 | 
			
		||||
}                  
 | 
			
		||||
article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section { 
 | 
			
		||||
    display:block;
 | 
			
		||||
}
 | 
			
		||||
nav ul { list-style:none; }
 | 
			
		||||
blockquote, q { quotes:none; }
 | 
			
		||||
blockquote:before, blockquote:after,
 | 
			
		||||
q:before, q:after { content:''; content:none; }
 | 
			
		||||
a { margin:0; padding:0; font-size:100%; vertical-align:baseline; background:transparent; }
 | 
			
		||||
ins { background-color:#ff9; color:#000; text-decoration:none; }
 | 
			
		||||
mark { background-color:#ff9; color:#000; font-style:italic; font-weight:bold; }
 | 
			
		||||
del { text-decoration: line-through; }
 | 
			
		||||
abbr[title], dfn[title] { border-bottom:1px dotted; cursor:help; }
 | 
			
		||||
table { border-collapse:collapse; border-spacing:0; }
 | 
			
		||||
hr { display:block; height:1px; border:0; border-top:1px solid #ccc; margin:1em 0; padding:0; }
 | 
			
		||||
input, select { vertical-align:middle; }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
body { font:13px/1.231 sans-serif; *font-size:small; } 
 | 
			
		||||
select, input, textarea, button { font:99% sans-serif; }
 | 
			
		||||
pre, code, kbd, samp { font-family: monospace, sans-serif; }
 | 
			
		||||
 | 
			
		||||
body, select, input, textarea {   color: #444; }
 | 
			
		||||
h1,h2,h3,h4,h5,h6 { font-weight: bold; }
 | 
			
		||||
html { overflow-y: scroll; }
 | 
			
		||||
 | 
			
		||||
a:hover, a:active { outline: none; }
 | 
			
		||||
a, a:active, a:visited { color: #607890; }
 | 
			
		||||
a:hover { color: #036; }
 | 
			
		||||
 | 
			
		||||
ul, ol { margin-left: 1.8em; }
 | 
			
		||||
ol { list-style-type: decimal; }
 | 
			
		||||
 | 
			
		||||
nav ul, nav li { margin: 0; } 
 | 
			
		||||
small { font-size: 85%; }
 | 
			
		||||
strong, th { font-weight: bold; }
 | 
			
		||||
td, td img { vertical-align: top; } 
 | 
			
		||||
sub { vertical-align: sub; font-size: smaller; }
 | 
			
		||||
sup { vertical-align: super; font-size: smaller; }
 | 
			
		||||
pre {  padding: 15px;  white-space: pre;  white-space: pre-wrap;  white-space: pre-line;  word-wrap: break-word; }
 | 
			
		||||
textarea { overflow: auto; } 
 | 
			
		||||
.ie6 legend, .ie7 legend { margin-left: -7px; } 
 | 
			
		||||
input[type="radio"] { vertical-align: text-bottom; }
 | 
			
		||||
input[type="checkbox"] { vertical-align: bottom; }
 | 
			
		||||
.ie7 input[type="checkbox"] { vertical-align: baseline; }
 | 
			
		||||
.ie6 input { vertical-align: text-bottom; }
 | 
			
		||||
label, input[type=button], input[type=submit], button { cursor: pointer; }
 | 
			
		||||
button, input, select, textarea { margin: 0; }
 | 
			
		||||
input:valid, textarea:valid   {  }
 | 
			
		||||
input:invalid, textarea:invalid { border-radius: 1px;  -moz-box-shadow: 0px 0px 5px red; -webkit-box-shadow: 0px 0px 5px red;  box-shadow: 0px 0px 5px red; }
 | 
			
		||||
.no-boxshadow input:invalid, 
 | 
			
		||||
.no-boxshadow textarea:invalid { background-color: #f0dddd; }
 | 
			
		||||
 | 
			
		||||
::-moz-selection{ background: #FF5E99; color:#fff; text-shadow: none; }
 | 
			
		||||
::selection { background:#FF5E99; color:#fff; text-shadow: none; } 
 | 
			
		||||
a:link { -webkit-tap-highlight-color: #FF5E99; } 
 | 
			
		||||
 | 
			
		||||
button {  width: auto; overflow: visible; }
 | 
			
		||||
.ie7 img { -ms-interpolation-mode: bicubic; }
 | 
			
		||||
 | 
			
		||||
.ir { display: block; text-indent: -999em; overflow: hidden; background-repeat: no-repeat; text-align: left; direction: ltr; }
 | 
			
		||||
.hidden { display: none; visibility: hidden; } 
 | 
			
		||||
.visuallyhidden { position: absolute !important; clip: rect(1px 1px 1px 1px);  clip: rect(1px, 1px, 1px, 1px); }
 | 
			
		||||
.invisible { visibility: hidden; }
 | 
			
		||||
.clearfix:before, .clearfix:after {  content: "\0020"; display: block; height: 0; visibility: hidden;	 } 
 | 
			
		||||
.clearfix:after { clear: both; }
 | 
			
		||||
.clearfix { zoom: 1; }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 /* Primary Styles
 | 
			
		||||
    Author: 
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@media all and (orientation:portrait) { 
 | 
			
		||||
  
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@media all and (orientation:landscape) { 
 | 
			
		||||
  
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@media screen and (max-device-width: 480px) {
 | 
			
		||||
  
 | 
			
		||||
  
 | 
			
		||||
  /* html { -webkit-text-size-adjust:none; -ms-text-size-adjust:none; } */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@media print {
 | 
			
		||||
  * { background: transparent !important; color: #444 !important; text-shadow: none !important; }
 | 
			
		||||
  a, a:visited { color: #444 !important; text-decoration: underline; }
 | 
			
		||||
  a:after { content: " (" attr(href) ")"; } 
 | 
			
		||||
  abbr:after { content: " (" attr(title) ")"; }
 | 
			
		||||
  .ir a:after { content: ""; }  
 | 
			
		||||
  pre, blockquote { border: 1px solid #999; page-break-inside: avoid; }
 | 
			
		||||
  thead { display: table-header-group; }  
 | 
			
		||||
  tr, img { page-break-inside: avoid; }
 | 
			
		||||
  @page { margin: 0.5cm; }
 | 
			
		||||
  p, h2, h3 { orphans: 3; widows: 3; }
 | 
			
		||||
  h2, h3{ page-break-after: avoid; }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										3
									
								
								docs/public/images/.gitignore
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								docs/public/images/.gitignore
									
										
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -1,3 +0,0 @@
 | 
			
		|||
*
 | 
			
		||||
!.gitignore
 | 
			
		||||
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							| 
		 Before Width: | Height: | Size: 1.9 KiB  | 
										
											Binary file not shown.
										
									
								
							| 
		 Before Width: | Height: | Size: 14 KiB  | 
| 
						 | 
				
			
			@ -1,289 +0,0 @@
 | 
			
		|||
/**
 | 
			
		||||
* DD_belatedPNG: Adds IE6 support: PNG images for CSS background-image and HTML <IMG/>.
 | 
			
		||||
* Author: Drew Diller
 | 
			
		||||
* Email: drew.diller@gmail.com
 | 
			
		||||
* URL: http://www.dillerdesign.com/experiment/DD_belatedPNG/
 | 
			
		||||
* Version: 0.0.8a
 | 
			
		||||
* Licensed under the MIT License: http://dillerdesign.com/experiment/DD_belatedPNG/#license
 | 
			
		||||
*
 | 
			
		||||
* Example usage:
 | 
			
		||||
* DD_belatedPNG.fix('.png_bg'); // argument is a CSS selector
 | 
			
		||||
* DD_belatedPNG.fixPng( someNode ); // argument is an HTMLDomElement
 | 
			
		||||
**/
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
PLEASE READ:
 | 
			
		||||
Absolutely everything in this script is SILLY.  I know this.  IE's rendering of certain pixels doesn't make sense, so neither does this code!
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
var DD_belatedPNG = {
 | 
			
		||||
	ns: 'DD_belatedPNG',
 | 
			
		||||
	imgSize: {},
 | 
			
		||||
	delay: 10,
 | 
			
		||||
	nodesFixed: 0,
 | 
			
		||||
	createVmlNameSpace: function () { /* enable VML */
 | 
			
		||||
		if (document.namespaces && !document.namespaces[this.ns]) {
 | 
			
		||||
			document.namespaces.add(this.ns, 'urn:schemas-microsoft-com:vml');
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	createVmlStyleSheet: function () { /* style VML, enable behaviors */
 | 
			
		||||
		/*
 | 
			
		||||
			Just in case lots of other developers have added
 | 
			
		||||
			lots of other stylesheets using document.createStyleSheet
 | 
			
		||||
			and hit the 31-limit mark, let's not use that method!
 | 
			
		||||
			further reading: http://msdn.microsoft.com/en-us/library/ms531194(VS.85).aspx
 | 
			
		||||
		*/
 | 
			
		||||
		var screenStyleSheet, printStyleSheet;
 | 
			
		||||
		screenStyleSheet = document.createElement('style');
 | 
			
		||||
		screenStyleSheet.setAttribute('media', 'screen');
 | 
			
		||||
		document.documentElement.firstChild.insertBefore(screenStyleSheet, document.documentElement.firstChild.firstChild);
 | 
			
		||||
		if (screenStyleSheet.styleSheet) {
 | 
			
		||||
			screenStyleSheet = screenStyleSheet.styleSheet;
 | 
			
		||||
			screenStyleSheet.addRule(this.ns + '\\:*', '{behavior:url(#default#VML)}');
 | 
			
		||||
			screenStyleSheet.addRule(this.ns + '\\:shape', 'position:absolute;');
 | 
			
		||||
			screenStyleSheet.addRule('img.' + this.ns + '_sizeFinder', 'behavior:none; border:none; position:absolute; z-index:-1; top:-10000px; visibility:hidden;'); /* large negative top value for avoiding vertical scrollbars for large images, suggested by James O'Brien, http://www.thanatopsic.org/hendrik/ */
 | 
			
		||||
			this.screenStyleSheet = screenStyleSheet;
 | 
			
		||||
			
 | 
			
		||||
			/* Add a print-media stylesheet, for preventing VML artifacts from showing up in print (including preview). */
 | 
			
		||||
			/* Thanks to Rémi Prévost for automating this! */
 | 
			
		||||
			printStyleSheet = document.createElement('style');
 | 
			
		||||
			printStyleSheet.setAttribute('media', 'print');
 | 
			
		||||
			document.documentElement.firstChild.insertBefore(printStyleSheet, document.documentElement.firstChild.firstChild);
 | 
			
		||||
			printStyleSheet = printStyleSheet.styleSheet;
 | 
			
		||||
			printStyleSheet.addRule(this.ns + '\\:*', '{display: none !important;}');
 | 
			
		||||
			printStyleSheet.addRule('img.' + this.ns + '_sizeFinder', '{display: none !important;}');
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	readPropertyChange: function () {
 | 
			
		||||
		var el, display, v;
 | 
			
		||||
		el = event.srcElement;
 | 
			
		||||
		if (!el.vmlInitiated) {
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
		if (event.propertyName.search('background') != -1 || event.propertyName.search('border') != -1) {
 | 
			
		||||
			DD_belatedPNG.applyVML(el);
 | 
			
		||||
		}
 | 
			
		||||
		if (event.propertyName == 'style.display') {
 | 
			
		||||
			display = (el.currentStyle.display == 'none') ? 'none' : 'block';
 | 
			
		||||
			for (v in el.vml) {
 | 
			
		||||
				if (el.vml.hasOwnProperty(v)) {
 | 
			
		||||
					el.vml[v].shape.style.display = display;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if (event.propertyName.search('filter') != -1) {
 | 
			
		||||
			DD_belatedPNG.vmlOpacity(el);
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	vmlOpacity: function (el) {
 | 
			
		||||
		if (el.currentStyle.filter.search('lpha') != -1) {
 | 
			
		||||
			var trans = el.currentStyle.filter;
 | 
			
		||||
			trans = parseInt(trans.substring(trans.lastIndexOf('=')+1, trans.lastIndexOf(')')), 10)/100;
 | 
			
		||||
			el.vml.color.shape.style.filter = el.currentStyle.filter; /* complete guesswork */
 | 
			
		||||
			el.vml.image.fill.opacity = trans; /* complete guesswork */
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	handlePseudoHover: function (el) {
 | 
			
		||||
		setTimeout(function () { /* wouldn't work as intended without setTimeout */
 | 
			
		||||
			DD_belatedPNG.applyVML(el);
 | 
			
		||||
		}, 1);
 | 
			
		||||
	},
 | 
			
		||||
	/**
 | 
			
		||||
	* This is the method to use in a document.
 | 
			
		||||
	* @param {String} selector - REQUIRED - a CSS selector, such as '#doc .container'
 | 
			
		||||
	**/
 | 
			
		||||
	fix: function (selector) {
 | 
			
		||||
		if (this.screenStyleSheet) {
 | 
			
		||||
			var selectors, i;
 | 
			
		||||
			selectors = selector.split(','); /* multiple selectors supported, no need for multiple calls to this anymore */
 | 
			
		||||
			for (i=0; i<selectors.length; i++) {
 | 
			
		||||
				this.screenStyleSheet.addRule(selectors[i], 'behavior:expression(DD_belatedPNG.fixPng(this))'); /* seems to execute the function without adding it to the stylesheet - interesting... */
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	applyVML: function (el) {
 | 
			
		||||
		el.runtimeStyle.cssText = '';
 | 
			
		||||
		this.vmlFill(el);
 | 
			
		||||
		this.vmlOffsets(el);
 | 
			
		||||
		this.vmlOpacity(el);
 | 
			
		||||
		if (el.isImg) {
 | 
			
		||||
			this.copyImageBorders(el);
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	attachHandlers: function (el) {
 | 
			
		||||
		var self, handlers, handler, moreForAs, a, h;
 | 
			
		||||
		self = this;
 | 
			
		||||
		handlers = {resize: 'vmlOffsets', move: 'vmlOffsets'};
 | 
			
		||||
		if (el.nodeName == 'A') {
 | 
			
		||||
			moreForAs = {mouseleave: 'handlePseudoHover', mouseenter: 'handlePseudoHover', focus: 'handlePseudoHover', blur: 'handlePseudoHover'};
 | 
			
		||||
			for (a in moreForAs) {			
 | 
			
		||||
				if (moreForAs.hasOwnProperty(a)) {
 | 
			
		||||
					handlers[a] = moreForAs[a];
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		for (h in handlers) {
 | 
			
		||||
			if (handlers.hasOwnProperty(h)) {
				handler = function () {
					self[handlers[h]](el);
				};
 | 
			
		||||
				el.attachEvent('on' + h, handler);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		el.attachEvent('onpropertychange', this.readPropertyChange);
 | 
			
		||||
	},
 | 
			
		||||
	giveLayout: function (el) {
 | 
			
		||||
		el.style.zoom = 1;
 | 
			
		||||
		if (el.currentStyle.position == 'static') {
 | 
			
		||||
			el.style.position = 'relative';
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	copyImageBorders: function (el) {
 | 
			
		||||
		var styles, s;
 | 
			
		||||
		styles = {'borderStyle':true, 'borderWidth':true, 'borderColor':true};
 | 
			
		||||
		for (s in styles) {
 | 
			
		||||
			if (styles.hasOwnProperty(s)) {
 | 
			
		||||
				el.vml.color.shape.style[s] = el.currentStyle[s];
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	vmlFill: function (el) {
 | 
			
		||||
		if (!el.currentStyle) {
 | 
			
		||||
			return;
 | 
			
		||||
		} else {
 | 
			
		||||
			var elStyle, noImg, lib, v, img, imgLoaded;
 | 
			
		||||
			elStyle = el.currentStyle;
 | 
			
		||||
		}
 | 
			
		||||
		for (v in el.vml) {
 | 
			
		||||
			if (el.vml.hasOwnProperty(v)) {
 | 
			
		||||
				el.vml[v].shape.style.zIndex = elStyle.zIndex;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		el.runtimeStyle.backgroundColor = '';
 | 
			
		||||
		el.runtimeStyle.backgroundImage = '';
 | 
			
		||||
		noImg = true;
 | 
			
		||||
		if (elStyle.backgroundImage != 'none' || el.isImg) {
 | 
			
		||||
			if (!el.isImg) {
 | 
			
		||||
				el.vmlBg = elStyle.backgroundImage;
 | 
			
		||||
				el.vmlBg = el.vmlBg.substr(5, el.vmlBg.lastIndexOf('")')-5);
 | 
			
		||||
			}
 | 
			
		||||
			else {
 | 
			
		||||
				el.vmlBg = el.src;
 | 
			
		||||
			}
 | 
			
		||||
			lib = this;
 | 
			
		||||
			if (!lib.imgSize[el.vmlBg]) { /* determine size of loaded image */
 | 
			
		||||
				img = document.createElement('img');
 | 
			
		||||
				lib.imgSize[el.vmlBg] = img;
 | 
			
		||||
				img.className = lib.ns + '_sizeFinder';
 | 
			
		||||
				img.runtimeStyle.cssText = 'behavior:none; position:absolute; left:-10000px; top:-10000px; border:none; margin:0; padding:0;'; /* make sure to set behavior to none to prevent accidental matching of the helper elements! */
				imgLoaded = function () {
					this.width = this.offsetWidth; /* weird cache-busting requirement! */
					this.height = this.offsetHeight;
					lib.vmlOffsets(el);
				};
 | 
			
		||||
				img.attachEvent('onload', imgLoaded);
 | 
			
		||||
				img.src = el.vmlBg;
 | 
			
		||||
				img.removeAttribute('width');
 | 
			
		||||
				img.removeAttribute('height');
 | 
			
		||||
				document.body.insertBefore(img, document.body.firstChild);
 | 
			
		||||
			}
 | 
			
		||||
			el.vml.image.fill.src = el.vmlBg;
 | 
			
		||||
			noImg = false;
 | 
			
		||||
		}
 | 
			
		||||
		el.vml.image.fill.on = !noImg;
 | 
			
		||||
		el.vml.image.fill.color = 'none';
 | 
			
		||||
		el.vml.color.shape.style.backgroundColor = elStyle.backgroundColor;
 | 
			
		||||
		el.runtimeStyle.backgroundImage = 'none';
 | 
			
		||||
		el.runtimeStyle.backgroundColor = 'transparent';
 | 
			
		||||
	},
 | 
			
		||||
	/* IE can't figure out what do when the offsetLeft and the clientLeft add up to 1, and the VML ends up getting fuzzy... so we have to push/enlarge things by 1 pixel and then clip off the excess */
 | 
			
		||||
	vmlOffsets: function (el) {
 | 
			
		||||
		var thisStyle, size, fudge, makeVisible, bg, bgR, dC, altC, b, c, v;
 | 
			
		||||
		thisStyle = el.currentStyle;
 | 
			
		||||
		size = {'W':el.clientWidth+1, 'H':el.clientHeight+1, 'w':this.imgSize[el.vmlBg].width, 'h':this.imgSize[el.vmlBg].height, 'L':el.offsetLeft, 'T':el.offsetTop, 'bLW':el.clientLeft, 'bTW':el.clientTop};
 | 
			
		||||
		fudge = (size.L + size.bLW == 1) ? 1 : 0;
 | 
			
		||||
		/* vml shape, left, top, width, height, origin */
 | 
			
		||||
		makeVisible = function (vml, l, t, w, h, o) {
 | 
			
		||||
			vml.coordsize = w+','+h;
 | 
			
		||||
			vml.coordorigin = o+','+o;
 | 
			
		||||
			vml.path = 'm0,0l'+w+',0l'+w+','+h+'l0,'+h+' xe';
 | 
			
		||||
			vml.style.width = w + 'px';
 | 
			
		||||
			vml.style.height = h + 'px';
 | 
			
		||||
			vml.style.left = l + 'px';
 | 
			
		||||
			vml.style.top = t + 'px';
 | 
			
		||||
		};
 | 
			
		||||
		makeVisible(el.vml.color.shape, (size.L + (el.isImg ? 0 : size.bLW)), (size.T + (el.isImg ? 0 : size.bTW)), (size.W-1), (size.H-1), 0);
 | 
			
		||||
		makeVisible(el.vml.image.shape, (size.L + size.bLW), (size.T + size.bTW), (size.W), (size.H), 1 );
 | 
			
		||||
		bg = {'X':0, 'Y':0};
 | 
			
		||||
		if (el.isImg) {
 | 
			
		||||
			bg.X = parseInt(thisStyle.paddingLeft, 10) + 1;
 | 
			
		||||
			bg.Y = parseInt(thisStyle.paddingTop, 10) + 1;
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
			for (b in bg) {
 | 
			
		||||
				if (bg.hasOwnProperty(b)) {
 | 
			
		||||
					this.figurePercentage(bg, size, b, thisStyle['backgroundPosition'+b]);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		el.vml.image.fill.position = (bg.X/size.W) + ',' + (bg.Y/size.H);
 | 
			
		||||
		bgR = thisStyle.backgroundRepeat;
 | 
			
		||||
		dC = {'T':1, 'R':size.W+fudge, 'B':size.H, 'L':1+fudge}; /* these are defaults for repeat of any kind */
 | 
			
		||||
		altC = { 'X': {'b1': 'L', 'b2': 'R', 'd': 'W'}, 'Y': {'b1': 'T', 'b2': 'B', 'd': 'H'} };
 | 
			
		||||
		if (bgR != 'repeat' || el.isImg) {
 | 
			
		||||
			c = {'T':(bg.Y), 'R':(bg.X+size.w), 'B':(bg.Y+size.h), 'L':(bg.X)}; /* these are defaults for no-repeat - clips down to the image location */
 | 
			
		||||
			if (bgR.search('repeat-') != -1) { /* now let's revert to dC for repeat-x or repeat-y */
 | 
			
		||||
				v = bgR.split('repeat-')[1].toUpperCase();
 | 
			
		||||
				c[altC[v].b1] = 1;
 | 
			
		||||
				c[altC[v].b2] = size[altC[v].d];
 | 
			
		||||
			}
 | 
			
		||||
			if (c.B > size.H) {
 | 
			
		||||
				c.B = size.H;
 | 
			
		||||
			}
 | 
			
		||||
			el.vml.image.shape.style.clip = 'rect('+c.T+'px '+(c.R+fudge)+'px '+c.B+'px '+(c.L+fudge)+'px)';
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
			el.vml.image.shape.style.clip = 'rect('+dC.T+'px '+dC.R+'px '+dC.B+'px '+dC.L+'px)';
 | 
			
		||||
		}
 | 
			
		||||
	},
	figurePercentage: function (bg, size, axis, position) {
		var horizontal, fraction;
		fraction = true;
		horizontal = (axis == 'X');
		switch(position) {
			case 'left':
			case 'top':
				bg[axis] = 0;
				break;
			case 'center':
				bg[axis] = 0.5;
				break;
			case 'right':
			case 'bottom':
				bg[axis] = 1;
				break;
			default:
				if (position.search('%') != -1) {
					bg[axis] = parseInt(position, 10) / 100;
				}
				else {
					fraction = false;
				}
		}
		bg[axis] = Math.ceil(  fraction ? ( (size[horizontal?'W': 'H'] * bg[axis]) - (size[horizontal?'w': 'h'] * bg[axis]) ) : parseInt(position, 10)  );
		if (bg[axis] % 2 === 0) {
			bg[axis]++;
		}
		return bg[axis];
	},
 | 
			
		||||
	fixPng: function (el) {
 | 
			
		||||
		el.style.behavior = 'none';
		var lib, els, nodeStr, v, e;
 | 
			
		||||
		if (el.nodeName == 'BODY' || el.nodeName == 'TD' || el.nodeName == 'TR') { /* elements not supported yet */
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
		el.isImg = false;
 | 
			
		||||
		if (el.nodeName == 'IMG') {
 | 
			
		||||
			if(el.src.toLowerCase().search(/\.png$/) != -1) {
 | 
			
		||||
				el.isImg = true;
 | 
			
		||||
				el.style.visibility = 'hidden';
 | 
			
		||||
			}
 | 
			
		||||
			else {
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		else if (el.currentStyle.backgroundImage.toLowerCase().search('.png') == -1) {
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
		lib = DD_belatedPNG;
 | 
			
		||||
		el.vml = {color: {}, image: {}};
 | 
			
		||||
		els = {shape: {}, fill: {}};
 | 
			
		||||
		for (v in el.vml) {
 | 
			
		||||
			if (el.vml.hasOwnProperty(v)) {
 | 
			
		||||
				for (e in els) {
 | 
			
		||||
					if (els.hasOwnProperty(e)) {
 | 
			
		||||
						nodeStr = lib.ns + ':' + e;
 | 
			
		||||
						el.vml[v][e] = document.createElement(nodeStr);
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				el.vml[v].shape.stroked = false;
 | 
			
		||||
				el.vml[v].shape.appendChild(el.vml[v].fill);
 | 
			
		||||
				el.parentNode.insertBefore(el.vml[v].shape, el);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		el.vml.image.shape.fillcolor = 'none'; /* Don't show blank white shapeangle when waiting for image to load. */
 | 
			
		||||
		el.vml.image.fill.type = 'tile'; /* Makes image show up. */
 | 
			
		||||
		el.vml.color.fill.on = false; /* Actually going to apply vml element's style.backgroundColor, so hide the whiteness. */
 | 
			
		||||
		lib.attachHandlers(el);
 | 
			
		||||
		lib.giveLayout(el);
 | 
			
		||||
		lib.giveLayout(el.offsetParent);
 | 
			
		||||
		el.vmlInitiated = true;
 | 
			
		||||
		lib.applyVML(el); /* Render! */
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
try {
 | 
			
		||||
	document.execCommand("BackgroundImageCache", false, true); /* TredoSoft Multiple IE doesn't like this, so try{} it */
 | 
			
		||||
} catch(r) {}
 | 
			
		||||
DD_belatedPNG.createVmlNameSpace();
 | 
			
		||||
DD_belatedPNG.createVmlStyleSheet();
 | 
			
		||||
							
								
								
									
										13
									
								
								docs/public/js/libs/dd_belatedpng.min.js
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										13
									
								
								docs/public/js/libs/dd_belatedpng.min.js
									
										
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										6240
									
								
								docs/public/js/libs/jquery-1.4.2.js
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										6240
									
								
								docs/public/js/libs/jquery-1.4.2.js
									
										
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										154
									
								
								docs/public/js/libs/jquery-1.4.2.min.js
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										154
									
								
								docs/public/js/libs/jquery-1.4.2.min.js
									
										
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -1,154 +0,0 @@
 | 
			
		|||
/*!
 | 
			
		||||
 * jQuery JavaScript Library v1.4.2
 | 
			
		||||
 * http://jquery.com/
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright 2010, John Resig
 | 
			
		||||
 * Dual licensed under the MIT or GPL Version 2 licenses.
 | 
			
		||||
 * http://jquery.org/license
 | 
			
		||||
 *
 | 
			
		||||
 * Includes Sizzle.js
 | 
			
		||||
 * http://sizzlejs.com/
 | 
			
		||||
 * Copyright 2010, The Dojo Foundation
 | 
			
		||||
 * Released under the MIT, BSD, and GPL Licenses.
 | 
			
		||||
 *
 | 
			
		||||
 * Date: Sat Feb 13 22:33:48 2010 -0500
 | 
			
		||||
 */
 | 
			
		||||
(function(A,w){function ma(){if(!c.isReady){try{s.documentElement.doScroll("left")}catch(a){setTimeout(ma,1);return}c.ready()}}function Qa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function X(a,b,d,f,e,j){var i=a.length;if(typeof b==="object"){for(var o in b)X(a,o,b[o],f,e,d);return a}if(d!==w){f=!j&&f&&c.isFunction(d);for(o=0;o<i;o++)e(a[o],b,f?d.call(a[o],o,e(a[o],b)):d,j);return a}return i?
 | 
			
		||||
e(a[0],b):w}function J(){return(new Date).getTime()}function Y(){return false}function Z(){return true}function na(a,b,d){d[0].type=a;return c.event.handle.apply(b,d)}function oa(a){var b,d=[],f=[],e=arguments,j,i,o,k,n,r;i=c.data(this,"events");if(!(a.liveFired===this||!i||!i.live||a.button&&a.type==="click")){a.liveFired=this;var u=i.live.slice(0);for(k=0;k<u.length;k++){i=u[k];i.origType.replace(O,"")===a.type?f.push(i.selector):u.splice(k--,1)}j=c(a.target).closest(f,a.currentTarget);n=0;for(r=
 | 
			
		||||
j.length;n<r;n++)for(k=0;k<u.length;k++){i=u[k];if(j[n].selector===i.selector){o=j[n].elem;f=null;if(i.preType==="mouseenter"||i.preType==="mouseleave")f=c(a.relatedTarget).closest(i.selector)[0];if(!f||f!==o)d.push({elem:o,handleObj:i})}}n=0;for(r=d.length;n<r;n++){j=d[n];a.currentTarget=j.elem;a.data=j.handleObj.data;a.handleObj=j.handleObj;if(j.handleObj.origHandler.apply(j.elem,e)===false){b=false;break}}return b}}function pa(a,b){return"live."+(a&&a!=="*"?a+".":"")+b.replace(/\./g,"`").replace(/ /g,
 | 
			
		||||
"&")}function qa(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function ra(a,b){var d=0;b.each(function(){if(this.nodeName===(a[d]&&a[d].nodeName)){var f=c.data(a[d++]),e=c.data(this,f);if(f=f&&f.events){delete e.handle;e.events={};for(var j in f)for(var i in f[j])c.event.add(this,j,f[j][i],f[j][i].data)}}})}function sa(a,b,d){var f,e,j;b=b&&b[0]?b[0].ownerDocument||b[0]:s;if(a.length===1&&typeof a[0]==="string"&&a[0].length<512&&b===s&&!ta.test(a[0])&&(c.support.checkClone||!ua.test(a[0]))){e=
 | 
			
		||||
true;if(j=c.fragments[a[0]])if(j!==1)f=j}if(!f){f=b.createDocumentFragment();c.clean(a,b,f,d)}if(e)c.fragments[a[0]]=j?f:1;return{fragment:f,cacheable:e}}function K(a,b){var d={};c.each(va.concat.apply([],va.slice(0,b)),function(){d[this]=a});return d}function wa(a){return"scrollTo"in a&&a.document?a:a.nodeType===9?a.defaultView||a.parentWindow:false}var c=function(a,b){return new c.fn.init(a,b)},Ra=A.jQuery,Sa=A.$,s=A.document,T,Ta=/^[^<]*(<[\w\W]+>)[^>]*$|^#([\w-]+)$/,Ua=/^.[^:#\[\.,]*$/,Va=/\S/,
 | 
			
		||||
Wa=/^(\s|\u00A0)+|(\s|\u00A0)+$/g,Xa=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,P=navigator.userAgent,xa=false,Q=[],L,$=Object.prototype.toString,aa=Object.prototype.hasOwnProperty,ba=Array.prototype.push,R=Array.prototype.slice,ya=Array.prototype.indexOf;c.fn=c.prototype={init:function(a,b){var d,f;if(!a)return this;if(a.nodeType){this.context=this[0]=a;this.length=1;return this}if(a==="body"&&!b){this.context=s;this[0]=s.body;this.selector="body";this.length=1;return this}if(typeof a==="string")if((d=Ta.exec(a))&&
 | 
			
		||||
(d[1]||!b))if(d[1]){f=b?b.ownerDocument||b:s;if(a=Xa.exec(a))if(c.isPlainObject(b)){a=[s.createElement(a[1])];c.fn.attr.call(a,b,true)}else a=[f.createElement(a[1])];else{a=sa([d[1]],[f]);a=(a.cacheable?a.fragment.cloneNode(true):a.fragment).childNodes}return c.merge(this,a)}else{if(b=s.getElementById(d[2])){if(b.id!==d[2])return T.find(a);this.length=1;this[0]=b}this.context=s;this.selector=a;return this}else if(!b&&/^\w+$/.test(a)){this.selector=a;this.context=s;a=s.getElementsByTagName(a);return c.merge(this,
 | 
			
		||||
a)}else return!b||b.jquery?(b||T).find(a):c(b).find(a);else if(c.isFunction(a))return T.ready(a);if(a.selector!==w){this.selector=a.selector;this.context=a.context}return c.makeArray(a,this)},selector:"",jquery:"1.4.2",length:0,size:function(){return this.length},toArray:function(){return R.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this.slice(a)[0]:this[a]},pushStack:function(a,b,d){var f=c();c.isArray(a)?ba.apply(f,a):c.merge(f,a);f.prevObject=this;f.context=this.context;if(b===
 | 
			
		||||
"find")f.selector=this.selector+(this.selector?" ":"")+d;else if(b)f.selector=this.selector+"."+b+"("+d+")";return f},each:function(a,b){return c.each(this,a,b)},ready:function(a){c.bindReady();if(c.isReady)a.call(s,c);else Q&&Q.push(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(R.apply(this,arguments),"slice",R.call(arguments).join(","))},map:function(a){return this.pushStack(c.map(this,
 | 
			
		||||
function(b,d){return a.call(b,d,b)}))},end:function(){return this.prevObject||c(null)},push:ba,sort:[].sort,splice:[].splice};c.fn.init.prototype=c.fn;c.extend=c.fn.extend=function(){var a=arguments[0]||{},b=1,d=arguments.length,f=false,e,j,i,o;if(typeof a==="boolean"){f=a;a=arguments[1]||{};b=2}if(typeof a!=="object"&&!c.isFunction(a))a={};if(d===b){a=this;--b}for(;b<d;b++)if((e=arguments[b])!=null)for(j in e){i=a[j];o=e[j];if(a!==o)if(f&&o&&(c.isPlainObject(o)||c.isArray(o))){i=i&&(c.isPlainObject(i)||
 | 
			
		||||
c.isArray(i))?i:c.isArray(o)?[]:{};a[j]=c.extend(f,i,o)}else if(o!==w)a[j]=o}return a};c.extend({noConflict:function(a){A.$=Sa;if(a)A.jQuery=Ra;return c},isReady:false,ready:function(){if(!c.isReady){if(!s.body)return setTimeout(c.ready,13);c.isReady=true;if(Q){for(var a,b=0;a=Q[b++];)a.call(s,c);Q=null}c.fn.triggerHandler&&c(s).triggerHandler("ready")}},bindReady:function(){if(!xa){xa=true;if(s.readyState==="complete")return c.ready();if(s.addEventListener){s.addEventListener("DOMContentLoaded",
 | 
			
		||||
L,false);A.addEventListener("load",c.ready,false)}else if(s.attachEvent){s.attachEvent("onreadystatechange",L);A.attachEvent("onload",c.ready);var a=false;try{a=A.frameElement==null}catch(b){}s.documentElement.doScroll&&a&&ma()}}},isFunction:function(a){return $.call(a)==="[object Function]"},isArray:function(a){return $.call(a)==="[object Array]"},isPlainObject:function(a){if(!a||$.call(a)!=="[object Object]"||a.nodeType||a.setInterval)return false;if(a.constructor&&!aa.call(a,"constructor")&&!aa.call(a.constructor.prototype,
 | 
			
		||||
"isPrototypeOf"))return false;var b;for(b in a);return b===w||aa.call(a,b)},isEmptyObject:function(a){for(var b in a)return false;return true},error:function(a){throw a;},parseJSON:function(a){if(typeof a!=="string"||!a)return null;a=c.trim(a);if(/^[\],:{}\s]*$/.test(a.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,"")))return A.JSON&&A.JSON.parse?A.JSON.parse(a):(new Function("return "+
 | 
			
		||||
a))();else c.error("Invalid JSON: "+a)},noop:function(){},globalEval:function(a){if(a&&Va.test(a)){var b=s.getElementsByTagName("head")[0]||s.documentElement,d=s.createElement("script");d.type="text/javascript";if(c.support.scriptEval)d.appendChild(s.createTextNode(a));else d.text=a;b.insertBefore(d,b.firstChild);b.removeChild(d)}},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,b,d){var f,e=0,j=a.length,i=j===w||c.isFunction(a);if(d)if(i)for(f in a){if(b.apply(a[f],
 | 
			
		||||
d)===false)break}else for(;e<j;){if(b.apply(a[e++],d)===false)break}else if(i)for(f in a){if(b.call(a[f],f,a[f])===false)break}else for(d=a[0];e<j&&b.call(d,e,d)!==false;d=a[++e]);return a},trim:function(a){return(a||"").replace(Wa,"")},makeArray:function(a,b){b=b||[];if(a!=null)a.length==null||typeof a==="string"||c.isFunction(a)||typeof a!=="function"&&a.setInterval?ba.call(b,a):c.merge(b,a);return b},inArray:function(a,b){if(b.indexOf)return b.indexOf(a);for(var d=0,f=b.length;d<f;d++)if(b[d]===
 | 
			
		||||
a)return d;return-1},merge:function(a,b){var d=a.length,f=0;if(typeof b.length==="number")for(var e=b.length;f<e;f++)a[d++]=b[f];else for(;b[f]!==w;)a[d++]=b[f++];a.length=d;return a},grep:function(a,b,d){for(var f=[],e=0,j=a.length;e<j;e++)!d!==!b(a[e],e)&&f.push(a[e]);return f},map:function(a,b,d){for(var f=[],e,j=0,i=a.length;j<i;j++){e=b(a[j],j,d);if(e!=null)f[f.length]=e}return f.concat.apply([],f)},guid:1,proxy:function(a,b,d){if(arguments.length===2)if(typeof b==="string"){d=a;a=d[b];b=w}else if(b&&
 | 
			
		||||
!c.isFunction(b)){d=b;b=w}if(!b&&a)b=function(){return a.apply(d||this,arguments)};if(a)b.guid=a.guid=a.guid||b.guid||c.guid++;return b},uaMatch:function(a){a=a.toLowerCase();a=/(webkit)[ \/]([\w.]+)/.exec(a)||/(opera)(?:.*version)?[ \/]([\w.]+)/.exec(a)||/(msie) ([\w.]+)/.exec(a)||!/compatible/.test(a)&&/(mozilla)(?:.*? rv:([\w.]+))?/.exec(a)||[];return{browser:a[1]||"",version:a[2]||"0"}},browser:{}});P=c.uaMatch(P);if(P.browser){c.browser[P.browser]=true;c.browser.version=P.version}if(c.browser.webkit)c.browser.safari=
 | 
			
		||||
true;if(ya)c.inArray=function(a,b){return ya.call(b,a)};T=c(s);if(s.addEventListener)L=function(){s.removeEventListener("DOMContentLoaded",L,false);c.ready()};else if(s.attachEvent)L=function(){if(s.readyState==="complete"){s.detachEvent("onreadystatechange",L);c.ready()}};(function(){c.support={};var a=s.documentElement,b=s.createElement("script"),d=s.createElement("div"),f="script"+J();d.style.display="none";d.innerHTML="   <link/><table></table><a href='/a' style='color:red;float:left;opacity:.55;'>a</a><input type='checkbox'/>";
 | 
			
		||||
var e=d.getElementsByTagName("*"),j=d.getElementsByTagName("a")[0];if(!(!e||!e.length||!j)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(j.getAttribute("style")),hrefNormalized:j.getAttribute("href")==="/a",opacity:/^0.55$/.test(j.style.opacity),cssFloat:!!j.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:s.createElement("select").appendChild(s.createElement("option")).selected,
 | 
			
		||||
parentNode:d.removeChild(d.appendChild(s.createElement("div"))).parentNode===null,deleteExpando:true,checkClone:false,scriptEval:false,noCloneEvent:true,boxModel:null};b.type="text/javascript";try{b.appendChild(s.createTextNode("window."+f+"=1;"))}catch(i){}a.insertBefore(b,a.firstChild);if(A[f]){c.support.scriptEval=true;delete A[f]}try{delete b.test}catch(o){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function k(){c.support.noCloneEvent=
 | 
			
		||||
false;d.detachEvent("onclick",k)});d.cloneNode(true).fireEvent("onclick")}d=s.createElement("div");d.innerHTML="<input type='radio' name='radiotest' checked='checked'/>";a=s.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var k=s.createElement("div");k.style.width=k.style.paddingLeft="1px";s.body.appendChild(k);c.boxModel=c.support.boxModel=k.offsetWidth===2;s.body.removeChild(k).style.display="none"});a=function(k){var n=
 | 
			
		||||
s.createElement("div");k="on"+k;var r=k in n;if(!r){n.setAttribute(k,"return;");r=typeof n[k]==="function"}return r};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=e=j=null}})();c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};var G="jQuery"+J(),Ya=0,za={};c.extend({cache:{},expando:G,noData:{embed:true,object:true,
 | 
			
		||||
applet:true},data:function(a,b,d){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var f=a[G],e=c.cache;if(!f&&typeof b==="string"&&d===w)return null;f||(f=++Ya);if(typeof b==="object"){a[G]=f;e[f]=c.extend(true,{},b)}else if(!e[f]){a[G]=f;e[f]={}}a=e[f];if(d!==w)a[b]=d;return typeof b==="string"?a[b]:a}},removeData:function(a,b){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var d=a[G],f=c.cache,e=f[d];if(b){if(e){delete e[b];c.isEmptyObject(e)&&c.removeData(a)}}else{if(c.support.deleteExpando)delete a[c.expando];
 | 
			
		||||
else a.removeAttribute&&a.removeAttribute(c.expando);delete f[d]}}}});c.fn.extend({data:function(a,b){if(typeof a==="undefined"&&this.length)return c.data(this[0]);else if(typeof a==="object")return this.each(function(){c.data(this,a)});var d=a.split(".");d[1]=d[1]?"."+d[1]:"";if(b===w){var f=this.triggerHandler("getData"+d[1]+"!",[d[0]]);if(f===w&&this.length)f=c.data(this[0],a);return f===w&&d[1]?this.data(d[0]):f}else return this.trigger("setData"+d[1]+"!",[d[0],b]).each(function(){c.data(this,
 | 
			
		||||
a,b)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var f=c.data(a,b);if(!d)return f||[];if(!f||c.isArray(d))f=c.data(a,b,c.makeArray(d));else f.push(d);return f}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),f=d.shift();if(f==="inprogress")f=d.shift();if(f){b==="fx"&&d.unshift("inprogress");f.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b===
 | 
			
		||||
w)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var Aa=/[\n\t]/g,ca=/\s+/,Za=/\r/g,$a=/href|src|style/,ab=/(button|input)/i,bb=/(button|input|object|select|textarea)/i,
 | 
			
		||||
cb=/^(a|area)$/i,Ba=/radio|checkbox/;c.fn.extend({attr:function(a,b){return X(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(n){var r=c(this);r.addClass(a.call(this,n,r.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ca),d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1)if(e.className){for(var j=" "+e.className+" ",
 | 
			
		||||
i=e.className,o=0,k=b.length;o<k;o++)if(j.indexOf(" "+b[o]+" ")<0)i+=" "+b[o];e.className=c.trim(i)}else e.className=a}return this},removeClass:function(a){if(c.isFunction(a))return this.each(function(k){var n=c(this);n.removeClass(a.call(this,k,n.attr("class")))});if(a&&typeof a==="string"||a===w)for(var b=(a||"").split(ca),d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1&&e.className)if(a){for(var j=(" "+e.className+" ").replace(Aa," "),i=0,o=b.length;i<o;i++)j=j.replace(" "+b[i]+" ",
 | 
			
		||||
" ");e.className=c.trim(j)}else e.className=""}return this},toggleClass:function(a,b){var d=typeof a,f=typeof b==="boolean";if(c.isFunction(a))return this.each(function(e){var j=c(this);j.toggleClass(a.call(this,e,j.attr("class"),b),b)});return this.each(function(){if(d==="string")for(var e,j=0,i=c(this),o=b,k=a.split(ca);e=k[j++];){o=f?o:!i.hasClass(e);i[o?"addClass":"removeClass"](e)}else if(d==="undefined"||d==="boolean"){this.className&&c.data(this,"__className__",this.className);this.className=
 | 
			
		||||
this.className||a===false?"":c.data(this,"__className__")||""}})},hasClass:function(a){a=" "+a+" ";for(var b=0,d=this.length;b<d;b++)if((" "+this[b].className+" ").replace(Aa," ").indexOf(a)>-1)return true;return false},val:function(a){if(a===w){var b=this[0];if(b){if(c.nodeName(b,"option"))return(b.attributes.value||{}).specified?b.value:b.text;if(c.nodeName(b,"select")){var d=b.selectedIndex,f=[],e=b.options;b=b.type==="select-one";if(d<0)return null;var j=b?d:0;for(d=b?d+1:e.length;j<d;j++){var i=
 | 
			
		||||
e[j];if(i.selected){a=c(i).val();if(b)return a;f.push(a)}}return f}if(Ba.test(b.type)&&!c.support.checkOn)return b.getAttribute("value")===null?"on":b.value;return(b.value||"").replace(Za,"")}return w}var o=c.isFunction(a);return this.each(function(k){var n=c(this),r=a;if(this.nodeType===1){if(o)r=a.call(this,k,n.val());if(typeof r==="number")r+="";if(c.isArray(r)&&Ba.test(this.type))this.checked=c.inArray(n.val(),r)>=0;else if(c.nodeName(this,"select")){var u=c.makeArray(r);c("option",this).each(function(){this.selected=
 | 
			
		||||
c.inArray(c(this).val(),u)>=0});if(!u.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(a,b,d,f){if(!a||a.nodeType===3||a.nodeType===8)return w;if(f&&b in c.attrFn)return c(a)[b](d);f=a.nodeType!==1||!c.isXMLDoc(a);var e=d!==w;b=f&&c.props[b]||b;if(a.nodeType===1){var j=$a.test(b);if(b in a&&f&&!j){if(e){b==="type"&&ab.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed");
 | 
			
		||||
a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&b.specified?b.value:bb.test(a.nodeName)||cb.test(a.nodeName)&&a.href?0:w;return a[b]}if(!c.support.style&&f&&b==="style"){if(e)a.style.cssText=""+d;return a.style.cssText}e&&a.setAttribute(b,""+d);a=!c.support.hrefNormalized&&f&&j?a.getAttribute(b,2):a.getAttribute(b);return a===null?w:a}return c.style(a,b,d)}});var O=/\.(.*)$/,db=function(a){return a.replace(/[^\w\s\.\|`]/g,
 | 
			
		||||
function(b){return"\\"+b})};c.event={add:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){if(a.setInterval&&a!==A&&!a.frameElement)a=A;var e,j;if(d.handler){e=d;d=e.handler}if(!d.guid)d.guid=c.guid++;if(j=c.data(a)){var i=j.events=j.events||{},o=j.handle;if(!o)j.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem,arguments):w};o.elem=a;b=b.split(" ");for(var k,n=0,r;k=b[n++];){j=e?c.extend({},e):{handler:d,data:f};if(k.indexOf(".")>-1){r=k.split(".");
 | 
			
		||||
k=r.shift();j.namespace=r.slice(0).sort().join(".")}else{r=[];j.namespace=""}j.type=k;j.guid=d.guid;var u=i[k],z=c.event.special[k]||{};if(!u){u=i[k]=[];if(!z.setup||z.setup.call(a,f,r,o)===false)if(a.addEventListener)a.addEventListener(k,o,false);else a.attachEvent&&a.attachEvent("on"+k,o)}if(z.add){z.add.call(a,j);if(!j.handler.guid)j.handler.guid=d.guid}u.push(j);c.event.global[k]=true}a=null}}},global:{},remove:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){var e,j=0,i,o,k,n,r,u,z=c.data(a),
 | 
			
		||||
C=z&&z.events;if(z&&C){if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(e in C)c.event.remove(a,e+b)}else{for(b=b.split(" ");e=b[j++];){n=e;i=e.indexOf(".")<0;o=[];if(!i){o=e.split(".");e=o.shift();k=new RegExp("(^|\\.)"+c.map(o.slice(0).sort(),db).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(r=C[e])if(d){n=c.event.special[e]||{};for(B=f||0;B<r.length;B++){u=r[B];if(d.guid===u.guid){if(i||k.test(u.namespace)){f==null&&r.splice(B--,1);n.remove&&n.remove.call(a,u)}if(f!=
 | 
			
		||||
null)break}}if(r.length===0||f!=null&&r.length===1){if(!n.teardown||n.teardown.call(a,o)===false)Ca(a,e,z.handle);delete C[e]}}else for(var B=0;B<r.length;B++){u=r[B];if(i||k.test(u.namespace)){c.event.remove(a,n,u.handler,B);r.splice(B--,1)}}}if(c.isEmptyObject(C)){if(b=z.handle)b.elem=null;delete z.events;delete z.handle;c.isEmptyObject(z)&&c.removeData(a)}}}}},trigger:function(a,b,d,f){var e=a.type||a;if(!f){a=typeof a==="object"?a[G]?a:c.extend(c.Event(e),a):c.Event(e);if(e.indexOf("!")>=0){a.type=
 | 
			
		||||
e=e.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[e]&&c.each(c.cache,function(){this.events&&this.events[e]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===8)return w;a.result=w;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(f=c.data(d,"handle"))&&f.apply(d,b);f=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+e]&&d["on"+e].apply(d,b)===false)a.result=false}catch(j){}if(!a.isPropagationStopped()&&
 | 
			
		||||
f)c.event.trigger(a,b,f,true);else if(!a.isDefaultPrevented()){f=a.target;var i,o=c.nodeName(f,"a")&&e==="click",k=c.event.special[e]||{};if((!k._default||k._default.call(d,a)===false)&&!o&&!(f&&f.nodeName&&c.noData[f.nodeName.toLowerCase()])){try{if(f[e]){if(i=f["on"+e])f["on"+e]=null;c.event.triggered=true;f[e]()}}catch(n){}if(i)f["on"+e]=i;c.event.triggered=false}}},handle:function(a){var b,d,f,e;a=arguments[0]=c.event.fix(a||A.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive;
 | 
			
		||||
if(!b){d=a.type.split(".");a.type=d.shift();f=new RegExp("(^|\\.)"+d.slice(0).sort().join("\\.(?:.*\\.)?")+"(\\.|$)")}e=c.data(this,"events");d=e[a.type];if(e&&d){d=d.slice(0);e=0;for(var j=d.length;e<j;e++){var i=d[e];if(b||f.test(i.namespace)){a.handler=i.handler;a.data=i.data;a.handleObj=i;i=i.handler.apply(this,arguments);if(i!==w){a.result=i;if(i===false){a.preventDefault();a.stopPropagation()}}if(a.isImmediatePropagationStopped())break}}}return a.result},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
 | 
			
		||||
fix:function(a){if(a[G])return a;var b=a;a=c.Event(b);for(var d=this.props.length,f;d;){f=this.props[--d];a[f]=b[f]}if(!a.target)a.target=a.srcElement||s;if(a.target.nodeType===3)a.target=a.target.parentNode;if(!a.relatedTarget&&a.fromElement)a.relatedTarget=a.fromElement===a.target?a.toElement:a.fromElement;if(a.pageX==null&&a.clientX!=null){b=s.documentElement;d=s.body;a.pageX=a.clientX+(b&&b.scrollLeft||d&&d.scrollLeft||0)-(b&&b.clientLeft||d&&d.clientLeft||0);a.pageY=a.clientY+(b&&b.scrollTop||
 | 
			
		||||
d&&d.scrollTop||0)-(b&&b.clientTop||d&&d.clientTop||0)}if(!a.which&&(a.charCode||a.charCode===0?a.charCode:a.keyCode))a.which=a.charCode||a.keyCode;if(!a.metaKey&&a.ctrlKey)a.metaKey=a.ctrlKey;if(!a.which&&a.button!==w)a.which=a.button&1?1:a.button&2?3:a.button&4?2:0;return a},guid:1E8,proxy:c.proxy,special:{ready:{setup:c.bindReady,teardown:c.noop},live:{add:function(a){c.event.add(this,a.origType,c.extend({},a,{handler:oa}))},remove:function(a){var b=true,d=a.origType.replace(O,"");c.each(c.data(this,
 | 
			
		||||
"events").live||[],function(){if(d===this.origType.replace(O,""))return b=false});b&&c.event.remove(this,a.origType,oa)}},beforeunload:{setup:function(a,b,d){if(this.setInterval)this.onbeforeunload=d;return false},teardown:function(a,b){if(this.onbeforeunload===b)this.onbeforeunload=null}}}};var Ca=s.removeEventListener?function(a,b,d){a.removeEventListener(b,d,false)}:function(a,b,d){a.detachEvent("on"+b,d)};c.Event=function(a){if(!this.preventDefault)return new c.Event(a);if(a&&a.type){this.originalEvent=
 | 
			
		||||
a;this.type=a.type}else this.type=a;this.timeStamp=J();this[G]=true};c.Event.prototype={preventDefault:function(){this.isDefaultPrevented=Z;var a=this.originalEvent;if(a){a.preventDefault&&a.preventDefault();a.returnValue=false}},stopPropagation:function(){this.isPropagationStopped=Z;var a=this.originalEvent;if(a){a.stopPropagation&&a.stopPropagation();a.cancelBubble=true}},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=Z;this.stopPropagation()},isDefaultPrevented:Y,isPropagationStopped:Y,
 | 
			
		||||
isImmediatePropagationStopped:Y};var Da=function(a){var b=a.relatedTarget;try{for(;b&&b!==this;)b=b.parentNode;if(b!==this){a.type=a.data;c.event.handle.apply(this,arguments)}}catch(d){}},Ea=function(a){a.type=a.data;c.event.handle.apply(this,arguments)};c.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){c.event.special[a]={setup:function(d){c.event.add(this,b,d&&d.selector?Ea:Da,a)},teardown:function(d){c.event.remove(this,b,d&&d.selector?Ea:Da)}}});if(!c.support.submitBubbles)c.event.special.submit=
 | 
			
		||||
{setup:function(){if(this.nodeName.toLowerCase()!=="form"){c.event.add(this,"click.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="submit"||d==="image")&&c(b).closest("form").length)return na("submit",this,arguments)});c.event.add(this,"keypress.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="text"||d==="password")&&c(b).closest("form").length&&a.keyCode===13)return na("submit",this,arguments)})}else return false},teardown:function(){c.event.remove(this,".specialSubmit")}};
 | 
			
		||||
if(!c.support.changeBubbles){var da=/textarea|input|select/i,ea,Fa=function(a){var b=a.type,d=a.value;if(b==="radio"||b==="checkbox")d=a.checked;else if(b==="select-multiple")d=a.selectedIndex>-1?c.map(a.options,function(f){return f.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},fa=function(a,b){var d=a.target,f,e;if(!(!da.test(d.nodeName)||d.readOnly)){f=c.data(d,"_change_data");e=Fa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data",
 | 
			
		||||
e);if(!(f===w||e===f))if(f!=null||e){a.type="change";return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:fa,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return fa.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return fa.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a,
 | 
			
		||||
"_change_data",Fa(a))}},setup:function(){if(this.type==="file")return false;for(var a in ea)c.event.add(this,a+".specialChange",ea[a]);return da.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return da.test(this.nodeName)}};ea=c.event.special.change.filters}s.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(f){f=c.event.fix(f);f.type=b;return c.event.handle.call(this,f)}c.event.special[b]={setup:function(){this.addEventListener(a,
 | 
			
		||||
d,true)},teardown:function(){this.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,f,e){if(typeof d==="object"){for(var j in d)this[b](j,f,d[j],e);return this}if(c.isFunction(f)){e=f;f=w}var i=b==="one"?c.proxy(e,function(k){c(this).unbind(k,i);return e.apply(this,arguments)}):e;if(d==="unload"&&b!=="one")this.one(d,f,e);else{j=0;for(var o=this.length;j<o;j++)c.event.add(this[j],d,i,f)}return this}});c.fn.extend({unbind:function(a,b){if(typeof a==="object"&&
 | 
			
		||||
!a.preventDefault)for(var d in a)this.unbind(d,a[d]);else{d=0;for(var f=this.length;d<f;d++)c.event.remove(this[d],a,b)}return this},delegate:function(a,b,d,f){return this.live(b,d,f,a)},undelegate:function(a,b,d){return arguments.length===0?this.unbind("live"):this.die(b,null,d,a)},trigger:function(a,b){return this.each(function(){c.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0]){a=c.Event(a);a.preventDefault();a.stopPropagation();c.event.trigger(a,b,this[0]);return a.result}},
 | 
			
		||||
toggle:function(a){for(var b=arguments,d=1;d<b.length;)c.proxy(a,b[d++]);return this.click(c.proxy(a,function(f){var e=(c.data(this,"lastToggle"+a.guid)||0)%d;c.data(this,"lastToggle"+a.guid,e+1);f.preventDefault();return b[e].apply(this,arguments)||false}))},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}});var Ga={focus:"focusin",blur:"focusout",mouseenter:"mouseover",mouseleave:"mouseout"};c.each(["live","die"],function(a,b){c.fn[b]=function(d,f,e,j){var i,o=0,k,n,r=j||this.selector,
 | 
			
		||||
u=j?this:c(this.context);if(c.isFunction(f)){e=f;f=w}for(d=(d||"").split(" ");(i=d[o++])!=null;){j=O.exec(i);k="";if(j){k=j[0];i=i.replace(O,"")}if(i==="hover")d.push("mouseenter"+k,"mouseleave"+k);else{n=i;if(i==="focus"||i==="blur"){d.push(Ga[i]+k);i+=k}else i=(Ga[i]||i)+k;b==="live"?u.each(function(){c.event.add(this,pa(i,r),{data:f,selector:r,handler:e,origType:i,origHandler:e,preType:n})}):u.unbind(pa(i,r),e)}}return this}});c.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error".split(" "),
 | 
			
		||||
function(a,b){c.fn[b]=function(d){return d?this.bind(b,d):this.trigger(b)};if(c.attrFn)c.attrFn[b]=true});A.attachEvent&&!A.addEventListener&&A.attachEvent("onunload",function(){for(var a in c.cache)if(c.cache[a].handle)try{c.event.remove(c.cache[a].handle.elem)}catch(b){}});(function(){function a(g){for(var h="",l,m=0;g[m];m++){l=g[m];if(l.nodeType===3||l.nodeType===4)h+=l.nodeValue;else if(l.nodeType!==8)h+=a(l.childNodes)}return h}function b(g,h,l,m,q,p){q=0;for(var v=m.length;q<v;q++){var t=m[q];
 | 
			
		||||
if(t){t=t[g];for(var y=false;t;){if(t.sizcache===l){y=m[t.sizset];break}if(t.nodeType===1&&!p){t.sizcache=l;t.sizset=q}if(t.nodeName.toLowerCase()===h){y=t;break}t=t[g]}m[q]=y}}}function d(g,h,l,m,q,p){q=0;for(var v=m.length;q<v;q++){var t=m[q];if(t){t=t[g];for(var y=false;t;){if(t.sizcache===l){y=m[t.sizset];break}if(t.nodeType===1){if(!p){t.sizcache=l;t.sizset=q}if(typeof h!=="string"){if(t===h){y=true;break}}else if(k.filter(h,[t]).length>0){y=t;break}}t=t[g]}m[q]=y}}}var f=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
 | 
			
		||||
e=0,j=Object.prototype.toString,i=false,o=true;[0,0].sort(function(){o=false;return 0});var k=function(g,h,l,m){l=l||[];var q=h=h||s;if(h.nodeType!==1&&h.nodeType!==9)return[];if(!g||typeof g!=="string")return l;for(var p=[],v,t,y,S,H=true,M=x(h),I=g;(f.exec(""),v=f.exec(I))!==null;){I=v[3];p.push(v[1]);if(v[2]){S=v[3];break}}if(p.length>1&&r.exec(g))if(p.length===2&&n.relative[p[0]])t=ga(p[0]+p[1],h);else for(t=n.relative[p[0]]?[h]:k(p.shift(),h);p.length;){g=p.shift();if(n.relative[g])g+=p.shift();
 | 
			
		||||
t=ga(g,t)}else{if(!m&&p.length>1&&h.nodeType===9&&!M&&n.match.ID.test(p[0])&&!n.match.ID.test(p[p.length-1])){v=k.find(p.shift(),h,M);h=v.expr?k.filter(v.expr,v.set)[0]:v.set[0]}if(h){v=m?{expr:p.pop(),set:z(m)}:k.find(p.pop(),p.length===1&&(p[0]==="~"||p[0]==="+")&&h.parentNode?h.parentNode:h,M);t=v.expr?k.filter(v.expr,v.set):v.set;if(p.length>0)y=z(t);else H=false;for(;p.length;){var D=p.pop();v=D;if(n.relative[D])v=p.pop();else D="";if(v==null)v=h;n.relative[D](y,v,M)}}else y=[]}y||(y=t);y||k.error(D||
 | 
			
		||||
g);if(j.call(y)==="[object Array]")if(H)if(h&&h.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&E(h,y[g])))l.push(t[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&l.push(t[g]);else l.push.apply(l,y);else z(y,l);if(S){k(S,q,l,m);k.uniqueSort(l)}return l};k.uniqueSort=function(g){if(B){i=o;g.sort(B);if(i)for(var h=1;h<g.length;h++)g[h]===g[h-1]&&g.splice(h--,1)}return g};k.matches=function(g,h){return k(g,null,null,h)};k.find=function(g,h,l){var m,q;if(!g)return[];
 | 
			
		||||
for(var p=0,v=n.order.length;p<v;p++){var t=n.order[p];if(q=n.leftMatch[t].exec(g)){var y=q[1];q.splice(1,1);if(y.substr(y.length-1)!=="\\"){q[1]=(q[1]||"").replace(/\\/g,"");m=n.find[t](q,h,l);if(m!=null){g=g.replace(n.match[t],"");break}}}}m||(m=h.getElementsByTagName("*"));return{set:m,expr:g}};k.filter=function(g,h,l,m){for(var q=g,p=[],v=h,t,y,S=h&&h[0]&&x(h[0]);g&&h.length;){for(var H in n.filter)if((t=n.leftMatch[H].exec(g))!=null&&t[2]){var M=n.filter[H],I,D;D=t[1];y=false;t.splice(1,1);if(D.substr(D.length-
 | 
			
		||||
1)!=="\\"){if(v===p)p=[];if(n.preFilter[H])if(t=n.preFilter[H](t,v,l,p,m,S)){if(t===true)continue}else y=I=true;if(t)for(var U=0;(D=v[U])!=null;U++)if(D){I=M(D,t,U,v);var Ha=m^!!I;if(l&&I!=null)if(Ha)y=true;else v[U]=false;else if(Ha){p.push(D);y=true}}if(I!==w){l||(v=p);g=g.replace(n.match[H],"");if(!y)return[];break}}}if(g===q)if(y==null)k.error(g);else break;q=g}return v};k.error=function(g){throw"Syntax error, unrecognized expression: "+g;};var n=k.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF-]|\\.)+)/,
 | 
			
		||||
CLASS:/\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(g){return g.getAttribute("href")}},
 | 
			
		||||
relative:{"+":function(g,h){var l=typeof h==="string",m=l&&!/\W/.test(h);l=l&&!m;if(m)h=h.toLowerCase();m=0;for(var q=g.length,p;m<q;m++)if(p=g[m]){for(;(p=p.previousSibling)&&p.nodeType!==1;);g[m]=l||p&&p.nodeName.toLowerCase()===h?p||false:p===h}l&&k.filter(h,g,true)},">":function(g,h){var l=typeof h==="string";if(l&&!/\W/.test(h)){h=h.toLowerCase();for(var m=0,q=g.length;m<q;m++){var p=g[m];if(p){l=p.parentNode;g[m]=l.nodeName.toLowerCase()===h?l:false}}}else{m=0;for(q=g.length;m<q;m++)if(p=g[m])g[m]=
 | 
			
		||||
l?p.parentNode:p.parentNode===h;l&&k.filter(h,g,true)}},"":function(g,h,l){var m=e++,q=d;if(typeof h==="string"&&!/\W/.test(h)){var p=h=h.toLowerCase();q=b}q("parentNode",h,m,g,p,l)},"~":function(g,h,l){var m=e++,q=d;if(typeof h==="string"&&!/\W/.test(h)){var p=h=h.toLowerCase();q=b}q("previousSibling",h,m,g,p,l)}},find:{ID:function(g,h,l){if(typeof h.getElementById!=="undefined"&&!l)return(g=h.getElementById(g[1]))?[g]:[]},NAME:function(g,h){if(typeof h.getElementsByName!=="undefined"){var l=[];
 | 
			
		||||
h=h.getElementsByName(g[1]);for(var m=0,q=h.length;m<q;m++)h[m].getAttribute("name")===g[1]&&l.push(h[m]);return l.length===0?null:l}},TAG:function(g,h){return h.getElementsByTagName(g[1])}},preFilter:{CLASS:function(g,h,l,m,q,p){g=" "+g[1].replace(/\\/g,"")+" ";if(p)return g;p=0;for(var v;(v=h[p])!=null;p++)if(v)if(q^(v.className&&(" "+v.className+" ").replace(/[\t\n]/g," ").indexOf(g)>=0))l||m.push(v);else if(l)h[p]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()},
 | 
			
		||||
CHILD:function(g){if(g[1]==="nth"){var h=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=h[1]+(h[2]||1)-0;g[3]=h[3]-0}g[0]=e++;return g},ATTR:function(g,h,l,m,q,p){h=g[1].replace(/\\/g,"");if(!p&&n.attrMap[h])g[1]=n.attrMap[h];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,h,l,m,q){if(g[1]==="not")if((f.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,h);else{g=k.filter(g[3],h,l,true^q);l||m.push.apply(m,
 | 
			
		||||
g);return false}else if(n.match.POS.test(g[0])||n.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,h,l){return!!k(l[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)},
 | 
			
		||||
text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}},
 | 
			
		||||
setFilters:{first:function(g,h){return h===0},last:function(g,h,l,m){return h===m.length-1},even:function(g,h){return h%2===0},odd:function(g,h){return h%2===1},lt:function(g,h,l){return h<l[3]-0},gt:function(g,h,l){return h>l[3]-0},nth:function(g,h,l){return l[3]-0===h},eq:function(g,h,l){return l[3]-0===h}},filter:{PSEUDO:function(g,h,l,m){var q=h[1],p=n.filters[q];if(p)return p(g,l,h,m);else if(q==="contains")return(g.textContent||g.innerText||a([g])||"").indexOf(h[3])>=0;else if(q==="not"){h=
 | 
			
		||||
h[3];l=0;for(m=h.length;l<m;l++)if(h[l]===g)return false;return true}else k.error("Syntax error, unrecognized expression: "+q)},CHILD:function(g,h){var l=h[1],m=g;switch(l){case "only":case "first":for(;m=m.previousSibling;)if(m.nodeType===1)return false;if(l==="first")return true;m=g;case "last":for(;m=m.nextSibling;)if(m.nodeType===1)return false;return true;case "nth":l=h[2];var q=h[3];if(l===1&&q===0)return true;h=h[0];var p=g.parentNode;if(p&&(p.sizcache!==h||!g.nodeIndex)){var v=0;for(m=p.firstChild;m;m=
 | 
			
		||||
m.nextSibling)if(m.nodeType===1)m.nodeIndex=++v;p.sizcache=h}g=g.nodeIndex-q;return l===0?g===0:g%l===0&&g/l>=0}},ID:function(g,h){return g.nodeType===1&&g.getAttribute("id")===h},TAG:function(g,h){return h==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===h},CLASS:function(g,h){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(h)>-1},ATTR:function(g,h){var l=h[1];g=n.attrHandle[l]?n.attrHandle[l](g):g[l]!=null?g[l]:g.getAttribute(l);l=g+"";var m=h[2];h=h[4];return g==null?m==="!=":m===
 | 
			
		||||
"="?l===h:m==="*="?l.indexOf(h)>=0:m==="~="?(" "+l+" ").indexOf(h)>=0:!h?l&&g!==false:m==="!="?l!==h:m==="^="?l.indexOf(h)===0:m==="$="?l.substr(l.length-h.length)===h:m==="|="?l===h||l.substr(0,h.length+1)===h+"-":false},POS:function(g,h,l,m){var q=n.setFilters[h[2]];if(q)return q(g,l,h,m)}}},r=n.match.POS;for(var u in n.match){n.match[u]=new RegExp(n.match[u].source+/(?![^\[]*\])(?![^\(]*\))/.source);n.leftMatch[u]=new RegExp(/(^(?:.|\r|\n)*?)/.source+n.match[u].source.replace(/\\(\d+)/g,function(g,
 | 
			
		||||
h){return"\\"+(h-0+1)}))}var z=function(g,h){g=Array.prototype.slice.call(g,0);if(h){h.push.apply(h,g);return h}return g};try{Array.prototype.slice.call(s.documentElement.childNodes,0)}catch(C){z=function(g,h){h=h||[];if(j.call(g)==="[object Array]")Array.prototype.push.apply(h,g);else if(typeof g.length==="number")for(var l=0,m=g.length;l<m;l++)h.push(g[l]);else for(l=0;g[l];l++)h.push(g[l]);return h}}var B;if(s.documentElement.compareDocumentPosition)B=function(g,h){if(!g.compareDocumentPosition||
 | 
			
		||||
!h.compareDocumentPosition){if(g==h)i=true;return g.compareDocumentPosition?-1:1}g=g.compareDocumentPosition(h)&4?-1:g===h?0:1;if(g===0)i=true;return g};else if("sourceIndex"in s.documentElement)B=function(g,h){if(!g.sourceIndex||!h.sourceIndex){if(g==h)i=true;return g.sourceIndex?-1:1}g=g.sourceIndex-h.sourceIndex;if(g===0)i=true;return g};else if(s.createRange)B=function(g,h){if(!g.ownerDocument||!h.ownerDocument){if(g==h)i=true;return g.ownerDocument?-1:1}var l=g.ownerDocument.createRange(),m=
 | 
			
		||||
h.ownerDocument.createRange();l.setStart(g,0);l.setEnd(g,0);m.setStart(h,0);m.setEnd(h,0);g=l.compareBoundaryPoints(Range.START_TO_END,m);if(g===0)i=true;return g};(function(){var g=s.createElement("div"),h="script"+(new Date).getTime();g.innerHTML="<a name='"+h+"'/>";var l=s.documentElement;l.insertBefore(g,l.firstChild);if(s.getElementById(h)){n.find.ID=function(m,q,p){if(typeof q.getElementById!=="undefined"&&!p)return(q=q.getElementById(m[1]))?q.id===m[1]||typeof q.getAttributeNode!=="undefined"&&
 | 
			
		||||
q.getAttributeNode("id").nodeValue===m[1]?[q]:w:[]};n.filter.ID=function(m,q){var p=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&p&&p.nodeValue===q}}l.removeChild(g);l=g=null})();(function(){var g=s.createElement("div");g.appendChild(s.createComment(""));if(g.getElementsByTagName("*").length>0)n.find.TAG=function(h,l){l=l.getElementsByTagName(h[1]);if(h[1]==="*"){h=[];for(var m=0;l[m];m++)l[m].nodeType===1&&h.push(l[m]);l=h}return l};g.innerHTML="<a href='#'></a>";
 | 
			
		||||
if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")n.attrHandle.href=function(h){return h.getAttribute("href",2)};g=null})();s.querySelectorAll&&function(){var g=k,h=s.createElement("div");h.innerHTML="<p class='TEST'></p>";if(!(h.querySelectorAll&&h.querySelectorAll(".TEST").length===0)){k=function(m,q,p,v){q=q||s;if(!v&&q.nodeType===9&&!x(q))try{return z(q.querySelectorAll(m),p)}catch(t){}return g(m,q,p,v)};for(var l in g)k[l]=g[l];h=null}}();
 | 
			
		||||
(function(){var g=s.createElement("div");g.innerHTML="<div class='test e'></div><div class='test'></div>";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){n.order.splice(1,0,"CLASS");n.find.CLASS=function(h,l,m){if(typeof l.getElementsByClassName!=="undefined"&&!m)return l.getElementsByClassName(h[1])};g=null}}})();var E=s.compareDocumentPosition?function(g,h){return!!(g.compareDocumentPosition(h)&16)}:
 | 
			
		||||
function(g,h){return g!==h&&(g.contains?g.contains(h):true)},x=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false},ga=function(g,h){var l=[],m="",q;for(h=h.nodeType?[h]:h;q=n.match.PSEUDO.exec(g);){m+=q[0];g=g.replace(n.match.PSEUDO,"")}g=n.relative[g]?g+"*":g;q=0;for(var p=h.length;q<p;q++)k(g,h[q],l);return k.filter(m,l)};c.find=k;c.expr=k.selectors;c.expr[":"]=c.expr.filters;c.unique=k.uniqueSort;c.text=a;c.isXMLDoc=x;c.contains=E})();var eb=/Until$/,fb=/^(?:parents|prevUntil|prevAll)/,
 | 
			
		||||
gb=/,/;R=Array.prototype.slice;var Ia=function(a,b,d){if(c.isFunction(b))return c.grep(a,function(e,j){return!!b.call(e,j,e)===d});else if(b.nodeType)return c.grep(a,function(e){return e===b===d});else if(typeof b==="string"){var f=c.grep(a,function(e){return e.nodeType===1});if(Ua.test(b))return c.filter(b,f,!d);else b=c.filter(b,f)}return c.grep(a,function(e){return c.inArray(e,b)>=0===d})};c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,f=0,e=this.length;f<e;f++){d=b.length;
 | 
			
		||||
c.find(a,this[f],b);if(f>0)for(var j=d;j<b.length;j++)for(var i=0;i<d;i++)if(b[i]===b[j]){b.splice(j--,1);break}}return b},has:function(a){var b=c(a);return this.filter(function(){for(var d=0,f=b.length;d<f;d++)if(c.contains(this,b[d]))return true})},not:function(a){return this.pushStack(Ia(this,a,false),"not",a)},filter:function(a){return this.pushStack(Ia(this,a,true),"filter",a)},is:function(a){return!!a&&c.filter(a,this).length>0},closest:function(a,b){if(c.isArray(a)){var d=[],f=this[0],e,j=
 | 
			
		||||
{},i;if(f&&a.length){e=0;for(var o=a.length;e<o;e++){i=a[e];j[i]||(j[i]=c.expr.match.POS.test(i)?c(i,b||this.context):i)}for(;f&&f.ownerDocument&&f!==b;){for(i in j){e=j[i];if(e.jquery?e.index(f)>-1:c(f).is(e)){d.push({selector:i,elem:f});delete j[i]}}f=f.parentNode}}return d}var k=c.expr.match.POS.test(a)?c(a,b||this.context):null;return this.map(function(n,r){for(;r&&r.ownerDocument&&r!==b;){if(k?k.index(r)>-1:c(r).is(a))return r;r=r.parentNode}return null})},index:function(a){if(!a||typeof a===
 | 
			
		||||
"string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){a=typeof a==="string"?c(a,b||this.context):c.makeArray(a);b=c.merge(this.get(),a);return this.pushStack(qa(a[0])||qa(b[0])?b:c.unique(b))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode",
 | 
			
		||||
d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")?
 | 
			
		||||
a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,b){c.fn[a]=function(d,f){var e=c.map(this,b,d);eb.test(a)||(f=d);if(f&&typeof f==="string")e=c.filter(f,e);e=this.length>1?c.unique(e):e;if((this.length>1||gb.test(f))&&fb.test(a))e=e.reverse();return this.pushStack(e,a,R.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return c.find.matches(a,b)},dir:function(a,b,d){var f=[];for(a=a[b];a&&a.nodeType!==9&&(d===w||a.nodeType!==1||!c(a).is(d));){a.nodeType===
 | 
			
		||||
1&&f.push(a);a=a[b]}return f},nth:function(a,b,d){b=b||1;for(var f=0;a;a=a[d])if(a.nodeType===1&&++f===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var Ja=/ jQuery\d+="(?:\d+|null)"/g,V=/^\s+/,Ka=/(<([\w:]+)[^>]*?)\/>/g,hb=/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,La=/<([\w:]+)/,ib=/<tbody/i,jb=/<|&#?\w+;/,ta=/<script|<object|<embed|<option|<style/i,ua=/checked\s*(?:[^=]|=\s*.checked.)/i,Ma=function(a,b,d){return hb.test(d)?
 | 
			
		||||
a:b+"></"+d+">"},F={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]};F.optgroup=F.option;F.tbody=F.tfoot=F.colgroup=F.caption=F.thead;F.th=F.td;if(!c.support.htmlSerialize)F._default=[1,"div<div>","</div>"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d=
 | 
			
		||||
c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==w)return this.empty().append((this[0]&&this[0].ownerDocument||s).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this},
 | 
			
		||||
wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})},
 | 
			
		||||
prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,
 | 
			
		||||
this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,f;(f=this[d])!=null;d++)if(!a||c.filter(a,[f]).length){if(!b&&f.nodeType===1){c.cleanData(f.getElementsByTagName("*"));c.cleanData([f])}f.parentNode&&f.parentNode.removeChild(f)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild);
 | 
			
		||||
return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,f=this.ownerDocument;if(!d){d=f.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(Ja,"").replace(/=([^="'>\s]+\/)>/g,'="$1">').replace(V,"")],f)[0]}else return this.cloneNode(true)});if(a===true){ra(this,b);ra(this.find("*"),b.find("*"))}return b},html:function(a){if(a===w)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Ja,
 | 
			
		||||
""):null;else if(typeof a==="string"&&!ta.test(a)&&(c.support.leadingWhitespace||!V.test(a))&&!F[(La.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Ka,Ma);try{for(var b=0,d=this.length;b<d;b++)if(this[b].nodeType===1){c.cleanData(this[b].getElementsByTagName("*"));this[b].innerHTML=a}}catch(f){this.empty().append(a)}}else c.isFunction(a)?this.each(function(e){var j=c(this),i=j.html();j.empty().append(function(){return a.call(this,e,i)})}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&&
 | 
			
		||||
this[0].parentNode){if(c.isFunction(a))return this.each(function(b){var d=c(this),f=d.html();d.replaceWith(a.call(this,b,f))});if(typeof a!=="string")a=c(a).detach();return this.each(function(){var b=this.nextSibling,d=this.parentNode;c(this).remove();b?c(b).before(a):c(d).append(a)})}else return this.pushStack(c(c.isFunction(a)?a():a),"replaceWith",a)},detach:function(a){return this.remove(a,true)},domManip:function(a,b,d){function f(u){return c.nodeName(u,"table")?u.getElementsByTagName("tbody")[0]||
 | 
			
		||||
u.appendChild(u.ownerDocument.createElement("tbody")):u}var e,j,i=a[0],o=[],k;if(!c.support.checkClone&&arguments.length===3&&typeof i==="string"&&ua.test(i))return this.each(function(){c(this).domManip(a,b,d,true)});if(c.isFunction(i))return this.each(function(u){var z=c(this);a[0]=i.call(this,u,b?z.html():w);z.domManip(a,b,d)});if(this[0]){e=i&&i.parentNode;e=c.support.parentNode&&e&&e.nodeType===11&&e.childNodes.length===this.length?{fragment:e}:sa(a,this,o);k=e.fragment;if(j=k.childNodes.length===
 | 
			
		||||
1?(k=k.firstChild):k.firstChild){b=b&&c.nodeName(j,"tr");for(var n=0,r=this.length;n<r;n++)d.call(b?f(this[n],j):this[n],n>0||e.cacheable||this.length>1?k.cloneNode(true):k)}o.length&&c.each(o,Qa)}return this}});c.fragments={};c.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var f=[];d=c(d);var e=this.length===1&&this[0].parentNode;if(e&&e.nodeType===11&&e.childNodes.length===1&&d.length===1){d[b](this[0]);
 | 
			
		||||
return this}else{e=0;for(var j=d.length;e<j;e++){var i=(e>0?this.clone(true):this).get();c.fn[b].apply(c(d[e]),i);f=f.concat(i)}return this.pushStack(f,a,d.selector)}}});c.extend({clean:function(a,b,d,f){b=b||s;if(typeof b.createElement==="undefined")b=b.ownerDocument||b[0]&&b[0].ownerDocument||s;for(var e=[],j=0,i;(i=a[j])!=null;j++){if(typeof i==="number")i+="";if(i){if(typeof i==="string"&&!jb.test(i))i=b.createTextNode(i);else if(typeof i==="string"){i=i.replace(Ka,Ma);var o=(La.exec(i)||["",
 | 
			
		||||
""])[1].toLowerCase(),k=F[o]||F._default,n=k[0],r=b.createElement("div");for(r.innerHTML=k[1]+i+k[2];n--;)r=r.lastChild;if(!c.support.tbody){n=ib.test(i);o=o==="table"&&!n?r.firstChild&&r.firstChild.childNodes:k[1]==="<table>"&&!n?r.childNodes:[];for(k=o.length-1;k>=0;--k)c.nodeName(o[k],"tbody")&&!o[k].childNodes.length&&o[k].parentNode.removeChild(o[k])}!c.support.leadingWhitespace&&V.test(i)&&r.insertBefore(b.createTextNode(V.exec(i)[0]),r.firstChild);i=r.childNodes}if(i.nodeType)e.push(i);else e=
 | 
			
		||||
c.merge(e,i)}}if(d)for(j=0;e[j];j++)if(f&&c.nodeName(e[j],"script")&&(!e[j].type||e[j].type.toLowerCase()==="text/javascript"))f.push(e[j].parentNode?e[j].parentNode.removeChild(e[j]):e[j]);else{e[j].nodeType===1&&e.splice.apply(e,[j+1,0].concat(c.makeArray(e[j].getElementsByTagName("script"))));d.appendChild(e[j])}return e},cleanData:function(a){for(var b,d,f=c.cache,e=c.event.special,j=c.support.deleteExpando,i=0,o;(o=a[i])!=null;i++)if(d=o[c.expando]){b=f[d];if(b.events)for(var k in b.events)e[k]?
 | 
			
		||||
c.event.remove(o,k):Ca(o,k,b.handle);if(j)delete o[c.expando];else o.removeAttribute&&o.removeAttribute(c.expando);delete f[d]}}});var kb=/z-?index|font-?weight|opacity|zoom|line-?height/i,Na=/alpha\([^)]*\)/,Oa=/opacity=([^)]*)/,ha=/float/i,ia=/-([a-z])/ig,lb=/([A-Z])/g,mb=/^-?\d+(?:px)?$/i,nb=/^-?\d/,ob={position:"absolute",visibility:"hidden",display:"block"},pb=["Left","Right"],qb=["Top","Bottom"],rb=s.defaultView&&s.defaultView.getComputedStyle,Pa=c.support.cssFloat?"cssFloat":"styleFloat",ja=
 | 
			
		||||
function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){return X(this,a,b,true,function(d,f,e){if(e===w)return c.curCSS(d,f);if(typeof e==="number"&&!kb.test(f))e+="px";c.style(d,f,e)})};c.extend({style:function(a,b,d){if(!a||a.nodeType===3||a.nodeType===8)return w;if((b==="width"||b==="height")&&parseFloat(d)<0)d=w;var f=a.style||a,e=d!==w;if(!c.support.opacity&&b==="opacity"){if(e){f.zoom=1;b=parseInt(d,10)+""==="NaN"?"":"alpha(opacity="+d*100+")";a=f.filter||c.curCSS(a,"filter")||"";f.filter=
 | 
			
		||||
Na.test(a)?a.replace(Na,b):b}return f.filter&&f.filter.indexOf("opacity=")>=0?parseFloat(Oa.exec(f.filter)[1])/100+"":""}if(ha.test(b))b=Pa;b=b.replace(ia,ja);if(e)f[b]=d;return f[b]},css:function(a,b,d,f){if(b==="width"||b==="height"){var e,j=b==="width"?pb:qb;function i(){e=b==="width"?a.offsetWidth:a.offsetHeight;f!=="border"&&c.each(j,function(){f||(e-=parseFloat(c.curCSS(a,"padding"+this,true))||0);if(f==="margin")e+=parseFloat(c.curCSS(a,"margin"+this,true))||0;else e-=parseFloat(c.curCSS(a,
 | 
			
		||||
"border"+this+"Width",true))||0})}a.offsetWidth!==0?i():c.swap(a,ob,i);return Math.max(0,Math.round(e))}return c.curCSS(a,b,d)},curCSS:function(a,b,d){var f,e=a.style;if(!c.support.opacity&&b==="opacity"&&a.currentStyle){f=Oa.test(a.currentStyle.filter||"")?parseFloat(RegExp.$1)/100+"":"";return f===""?"1":f}if(ha.test(b))b=Pa;if(!d&&e&&e[b])f=e[b];else if(rb){if(ha.test(b))b="float";b=b.replace(lb,"-$1").toLowerCase();e=a.ownerDocument.defaultView;if(!e)return null;if(a=e.getComputedStyle(a,null))f=
 | 
			
		||||
a.getPropertyValue(b);if(b==="opacity"&&f==="")f="1"}else if(a.currentStyle){d=b.replace(ia,ja);f=a.currentStyle[b]||a.currentStyle[d];if(!mb.test(f)&&nb.test(f)){b=e.left;var j=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;e.left=d==="fontSize"?"1em":f||0;f=e.pixelLeft+"px";e.left=b;a.runtimeStyle.left=j}}return f},swap:function(a,b,d){var f={};for(var e in b){f[e]=a.style[e];a.style[e]=b[e]}d.call(a);for(e in b)a.style[e]=f[e]}});if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b=
 | 
			
		||||
a.offsetWidth,d=a.offsetHeight,f=a.nodeName.toLowerCase()==="tr";return b===0&&d===0&&!f?true:b>0&&d>0&&!f?false:c.curCSS(a,"display")==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var sb=J(),tb=/<script(.|\s)*?\/script>/gi,ub=/select|textarea/i,vb=/color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week/i,N=/=\?(&|$)/,ka=/\?/,wb=/(\?|&)_=.*?(&|$)/,xb=/^(\w+:)?\/\/([^\/?#]+)/,yb=/%20/g,zb=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!==
 | 
			
		||||
"string")return zb.call(this,a);else if(!this.length)return this;var f=a.indexOf(" ");if(f>=0){var e=a.slice(f,a.length);a=a.slice(0,f)}f="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b==="object"){b=c.param(b,c.ajaxSettings.traditional);f="POST"}var j=this;c.ajax({url:a,type:f,dataType:"html",data:b,complete:function(i,o){if(o==="success"||o==="notmodified")j.html(e?c("<div />").append(i.responseText.replace(tb,"")).find(e):i.responseText);d&&j.each(d,[i.responseText,o,i])}});return this},
 | 
			
		||||
serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||ub.test(this.nodeName)||vb.test(this.type))}).map(function(a,b){a=c(this).val();return a==null?null:c.isArray(a)?c.map(a,function(d){return{name:b.name,value:d}}):{name:b.name,value:a}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),
 | 
			
		||||
function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:f})},getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:f})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href,
 | 
			
		||||
global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:A.XMLHttpRequest&&(A.location.protocol!=="file:"||!A.ActiveXObject)?function(){return new A.XMLHttpRequest}:function(){try{return new A.ActiveXObject("Microsoft.XMLHTTP")}catch(a){}},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},etag:{},ajax:function(a){function b(){e.success&&
 | 
			
		||||
e.success.call(k,o,i,x);e.global&&f("ajaxSuccess",[x,e])}function d(){e.complete&&e.complete.call(k,x,i);e.global&&f("ajaxComplete",[x,e]);e.global&&!--c.active&&c.event.trigger("ajaxStop")}function f(q,p){(e.context?c(e.context):c.event).trigger(q,p)}var e=c.extend(true,{},c.ajaxSettings,a),j,i,o,k=a&&a.context||e,n=e.type.toUpperCase();if(e.data&&e.processData&&typeof e.data!=="string")e.data=c.param(e.data,e.traditional);if(e.dataType==="jsonp"){if(n==="GET")N.test(e.url)||(e.url+=(ka.test(e.url)?
 | 
			
		||||
"&":"?")+(e.jsonp||"callback")+"=?");else if(!e.data||!N.test(e.data))e.data=(e.data?e.data+"&":"")+(e.jsonp||"callback")+"=?";e.dataType="json"}if(e.dataType==="json"&&(e.data&&N.test(e.data)||N.test(e.url))){j=e.jsonpCallback||"jsonp"+sb++;if(e.data)e.data=(e.data+"").replace(N,"="+j+"$1");e.url=e.url.replace(N,"="+j+"$1");e.dataType="script";A[j]=A[j]||function(q){o=q;b();d();A[j]=w;try{delete A[j]}catch(p){}z&&z.removeChild(C)}}if(e.dataType==="script"&&e.cache===null)e.cache=false;if(e.cache===
 | 
			
		||||
false&&n==="GET"){var r=J(),u=e.url.replace(wb,"$1_="+r+"$2");e.url=u+(u===e.url?(ka.test(e.url)?"&":"?")+"_="+r:"")}if(e.data&&n==="GET")e.url+=(ka.test(e.url)?"&":"?")+e.data;e.global&&!c.active++&&c.event.trigger("ajaxStart");r=(r=xb.exec(e.url))&&(r[1]&&r[1]!==location.protocol||r[2]!==location.host);if(e.dataType==="script"&&n==="GET"&&r){var z=s.getElementsByTagName("head")[0]||s.documentElement,C=s.createElement("script");C.src=e.url;if(e.scriptCharset)C.charset=e.scriptCharset;if(!j){var B=
 | 
			
		||||
false;C.onload=C.onreadystatechange=function(){if(!B&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){B=true;b();d();C.onload=C.onreadystatechange=null;z&&C.parentNode&&z.removeChild(C)}}}z.insertBefore(C,z.firstChild);return w}var E=false,x=e.xhr();if(x){e.username?x.open(n,e.url,e.async,e.username,e.password):x.open(n,e.url,e.async);try{if(e.data||a&&a.contentType)x.setRequestHeader("Content-Type",e.contentType);if(e.ifModified){c.lastModified[e.url]&&x.setRequestHeader("If-Modified-Since",
 | 
			
		||||
c.lastModified[e.url]);c.etag[e.url]&&x.setRequestHeader("If-None-Match",c.etag[e.url])}r||x.setRequestHeader("X-Requested-With","XMLHttpRequest");x.setRequestHeader("Accept",e.dataType&&e.accepts[e.dataType]?e.accepts[e.dataType]+", */*":e.accepts._default)}catch(ga){}if(e.beforeSend&&e.beforeSend.call(k,x,e)===false){e.global&&!--c.active&&c.event.trigger("ajaxStop");x.abort();return false}e.global&&f("ajaxSend",[x,e]);var g=x.onreadystatechange=function(q){if(!x||x.readyState===0||q==="abort"){E||
 | 
			
		||||
d();E=true;if(x)x.onreadystatechange=c.noop}else if(!E&&x&&(x.readyState===4||q==="timeout")){E=true;x.onreadystatechange=c.noop;i=q==="timeout"?"timeout":!c.httpSuccess(x)?"error":e.ifModified&&c.httpNotModified(x,e.url)?"notmodified":"success";var p;if(i==="success")try{o=c.httpData(x,e.dataType,e)}catch(v){i="parsererror";p=v}if(i==="success"||i==="notmodified")j||b();else c.handleError(e,x,i,p);d();q==="timeout"&&x.abort();if(e.async)x=null}};try{var h=x.abort;x.abort=function(){x&&h.call(x);
 | 
			
		||||
g("abort")}}catch(l){}e.async&&e.timeout>0&&setTimeout(function(){x&&!E&&g("timeout")},e.timeout);try{x.send(n==="POST"||n==="PUT"||n==="DELETE"?e.data:null)}catch(m){c.handleError(e,x,null,m);d()}e.async||g();return x}},handleError:function(a,b,d,f){if(a.error)a.error.call(a.context||a,b,d,f);if(a.global)(a.context?c(a.context):c.event).trigger("ajaxError",[b,a,f])},active:0,httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status===
 | 
			
		||||
1223||a.status===0}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),f=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(f)c.etag[b]=f;return a.status===304||a.status===0},httpData:function(a,b,d){var f=a.getResponseHeader("content-type")||"",e=b==="xml"||!b&&f.indexOf("xml")>=0;a=e?a.responseXML:a.responseText;e&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b===
 | 
			
		||||
"json"||!b&&f.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&f.indexOf("javascript")>=0)c.globalEval(a);return a},param:function(a,b){function d(i,o){if(c.isArray(o))c.each(o,function(k,n){b||/\[\]$/.test(i)?f(i,n):d(i+"["+(typeof n==="object"||c.isArray(n)?k:"")+"]",n)});else!b&&o!=null&&typeof o==="object"?c.each(o,function(k,n){d(i+"["+k+"]",n)}):f(i,o)}function f(i,o){o=c.isFunction(o)?o():o;e[e.length]=encodeURIComponent(i)+"="+encodeURIComponent(o)}var e=[];if(b===w)b=c.ajaxSettings.traditional;
 | 
			
		||||
if(c.isArray(a)||a.jquery)c.each(a,function(){f(this.name,this.value)});else for(var j in a)d(j,a[j]);return e.join("&").replace(yb,"+")}});var la={},Ab=/toggle|show|hide/,Bb=/^([+-]=)?([\d+-.]+)(.*)$/,W,va=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b){if(a||a===0)return this.animate(K("show",3),a,b);else{a=0;for(b=this.length;a<b;a++){var d=c.data(this[a],"olddisplay");
 | 
			
		||||
this[a].style.display=d||"";if(c.css(this[a],"display")==="none"){d=this[a].nodeName;var f;if(la[d])f=la[d];else{var e=c("<"+d+" />").appendTo("body");f=e.css("display");if(f==="none")f="block";e.remove();la[d]=f}c.data(this[a],"olddisplay",f)}}a=0;for(b=this.length;a<b;a++)this[a].style.display=c.data(this[a],"olddisplay")||"";return this}},hide:function(a,b){if(a||a===0)return this.animate(K("hide",3),a,b);else{a=0;for(b=this.length;a<b;a++){var d=c.data(this[a],"olddisplay");!d&&d!=="none"&&c.data(this[a],
 | 
			
		||||
"olddisplay",c.css(this[a],"display"))}a=0;for(b=this.length;a<b;a++)this[a].style.display="none";return this}},_toggle:c.fn.toggle,toggle:function(a,b){var d=typeof a==="boolean";if(c.isFunction(a)&&c.isFunction(b))this._toggle.apply(this,arguments);else a==null||d?this.each(function(){var f=d?a:c(this).is(":hidden");c(this)[f?"show":"hide"]()}):this.animate(K("toggle",3),a,b);return this},fadeTo:function(a,b,d){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,d)},
 | 
			
		||||
animate:function(a,b,d,f){var e=c.speed(b,d,f);if(c.isEmptyObject(a))return this.each(e.complete);return this[e.queue===false?"each":"queue"](function(){var j=c.extend({},e),i,o=this.nodeType===1&&c(this).is(":hidden"),k=this;for(i in a){var n=i.replace(ia,ja);if(i!==n){a[n]=a[i];delete a[i];i=n}if(a[i]==="hide"&&o||a[i]==="show"&&!o)return j.complete.call(this);if((i==="height"||i==="width")&&this.style){j.display=c.css(this,"display");j.overflow=this.style.overflow}if(c.isArray(a[i])){(j.specialEasing=
 | 
			
		||||
j.specialEasing||{})[i]=a[i][1];a[i]=a[i][0]}}if(j.overflow!=null)this.style.overflow="hidden";j.curAnim=c.extend({},a);c.each(a,function(r,u){var z=new c.fx(k,j,r);if(Ab.test(u))z[u==="toggle"?o?"show":"hide":u](a);else{var C=Bb.exec(u),B=z.cur(true)||0;if(C){u=parseFloat(C[2]);var E=C[3]||"px";if(E!=="px"){k.style[r]=(u||1)+E;B=(u||1)/z.cur(true)*B;k.style[r]=B+E}if(C[1])u=(C[1]==="-="?-1:1)*u+B;z.custom(B,u,E)}else z.custom(B,u,"")}});return true})},stop:function(a,b){var d=c.timers;a&&this.queue([]);
 | 
			
		||||
this.each(function(){for(var f=d.length-1;f>=0;f--)if(d[f].elem===this){b&&d[f](true);d.splice(f,1)}});b||this.dequeue();return this}});c.each({slideDown:K("show",1),slideUp:K("hide",1),slideToggle:K("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(a,b){c.fn[a]=function(d,f){return this.animate(b,d,f)}});c.extend({speed:function(a,b,d){var f=a&&typeof a==="object"?a:{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};f.duration=c.fx.off?0:typeof f.duration===
 | 
			
		||||
"number"?f.duration:c.fx.speeds[f.duration]||c.fx.speeds._default;f.old=f.complete;f.complete=function(){f.queue!==false&&c(this).dequeue();c.isFunction(f.old)&&f.old.call(this)};return f},easing:{linear:function(a,b,d,f){return d+f*a},swing:function(a,b,d,f){return(-Math.cos(a*Math.PI)/2+0.5)*f+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]||
 | 
			
		||||
c.fx.step._default)(this);if((this.prop==="height"||this.prop==="width")&&this.elem.style)this.elem.style.display="block"},cur:function(a){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];return(a=parseFloat(c.css(this.elem,this.prop,a)))&&a>-10000?a:parseFloat(c.curCSS(this.elem,this.prop))||0},custom:function(a,b,d){function f(j){return e.step(j)}this.startTime=J();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start;
 | 
			
		||||
this.pos=this.state=0;var e=this;f.elem=this.elem;if(f()&&c.timers.push(f)&&!W)W=setInterval(c.fx.tick,13)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(a){var b=J(),d=true;if(a||b>=this.options.duration+this.startTime){this.now=
 | 
			
		||||
this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var f in this.options.curAnim)if(this.options.curAnim[f]!==true)d=false;if(d){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;a=c.data(this.elem,"olddisplay");this.elem.style.display=a?a:this.options.display;if(c.css(this.elem,"display")==="none")this.elem.style.display="block"}this.options.hide&&c(this.elem).hide();if(this.options.hide||this.options.show)for(var e in this.options.curAnim)c.style(this.elem,
 | 
			
		||||
e,this.options.orig[e]);this.options.complete.call(this.elem)}return false}else{e=b-this.startTime;this.state=e/this.options.duration;a=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||a](this.state,e,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=c.timers,b=0;b<a.length;b++)a[b]()||a.splice(b--,1);a.length||
 | 
			
		||||
c.fx.stop()},stop:function(){clearInterval(W);W=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){c.style(a.elem,"opacity",a.now)},_default:function(a){if(a.elem.style&&a.elem.style[a.prop]!=null)a.elem.style[a.prop]=(a.prop==="width"||a.prop==="height"?Math.max(0,a.now):a.now)+a.unit;else a.elem[a.prop]=a.now}}});if(c.expr&&c.expr.filters)c.expr.filters.animated=function(a){return c.grep(c.timers,function(b){return a===b.elem}).length};c.fn.offset="getBoundingClientRect"in s.documentElement?
 | 
			
		||||
function(a){var b=this[0];if(a)return this.each(function(e){c.offset.setOffset(this,a,e)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);var d=b.getBoundingClientRect(),f=b.ownerDocument;b=f.body;f=f.documentElement;return{top:d.top+(self.pageYOffset||c.support.boxModel&&f.scrollTop||b.scrollTop)-(f.clientTop||b.clientTop||0),left:d.left+(self.pageXOffset||c.support.boxModel&&f.scrollLeft||b.scrollLeft)-(f.clientLeft||b.clientLeft||0)}}:function(a){var b=
 | 
			
		||||
this[0];if(a)return this.each(function(r){c.offset.setOffset(this,a,r)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);c.offset.initialize();var d=b.offsetParent,f=b,e=b.ownerDocument,j,i=e.documentElement,o=e.body;f=(e=e.defaultView)?e.getComputedStyle(b,null):b.currentStyle;for(var k=b.offsetTop,n=b.offsetLeft;(b=b.parentNode)&&b!==o&&b!==i;){if(c.offset.supportsFixedPosition&&f.position==="fixed")break;j=e?e.getComputedStyle(b,null):b.currentStyle;
 | 
			
		||||
k-=b.scrollTop;n-=b.scrollLeft;if(b===d){k+=b.offsetTop;n+=b.offsetLeft;if(c.offset.doesNotAddBorder&&!(c.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(b.nodeName))){k+=parseFloat(j.borderTopWidth)||0;n+=parseFloat(j.borderLeftWidth)||0}f=d;d=b.offsetParent}if(c.offset.subtractsBorderForOverflowNotVisible&&j.overflow!=="visible"){k+=parseFloat(j.borderTopWidth)||0;n+=parseFloat(j.borderLeftWidth)||0}f=j}if(f.position==="relative"||f.position==="static"){k+=o.offsetTop;n+=o.offsetLeft}if(c.offset.supportsFixedPosition&&
 | 
			
		||||
f.position==="fixed"){k+=Math.max(i.scrollTop,o.scrollTop);n+=Math.max(i.scrollLeft,o.scrollLeft)}return{top:k,left:n}};c.offset={initialize:function(){var a=s.body,b=s.createElement("div"),d,f,e,j=parseFloat(c.curCSS(a,"marginTop",true))||0;c.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"});b.innerHTML="<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";
 | 
			
		||||
a.insertBefore(b,a.firstChild);d=b.firstChild;f=d.firstChild;e=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=f.offsetTop!==5;this.doesAddBorderForTableAndCells=e.offsetTop===5;f.style.position="fixed";f.style.top="20px";this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15;f.style.position=f.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==j;a.removeChild(b);
 | 
			
		||||
c.offset.initialize=c.noop},bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.curCSS(a,"marginTop",true))||0;d+=parseFloat(c.curCSS(a,"marginLeft",true))||0}return{top:b,left:d}},setOffset:function(a,b,d){if(/static/.test(c.curCSS(a,"position")))a.style.position="relative";var f=c(a),e=f.offset(),j=parseInt(c.curCSS(a,"top",true),10)||0,i=parseInt(c.curCSS(a,"left",true),10)||0;if(c.isFunction(b))b=b.call(a,
 | 
			
		||||
d,e);d={top:b.top-e.top+j,left:b.left-e.left+i};"using"in b?b.using.call(a,d):f.css(d)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),f=/^body|html$/i.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.curCSS(a,"marginTop",true))||0;d.left-=parseFloat(c.curCSS(a,"marginLeft",true))||0;f.top+=parseFloat(c.curCSS(b[0],"borderTopWidth",true))||0;f.left+=parseFloat(c.curCSS(b[0],"borderLeftWidth",true))||0;return{top:d.top-
 | 
			
		||||
f.top,left:d.left-f.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||s.body;a&&!/^body|html$/i.test(a.nodeName)&&c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(f){var e=this[0],j;if(!e)return null;if(f!==w)return this.each(function(){if(j=wa(this))j.scrollTo(!a?f:c(j).scrollLeft(),a?f:c(j).scrollTop());else this[d]=f});else return(j=wa(e))?"pageXOffset"in j?j[a?"pageYOffset":
 | 
			
		||||
"pageXOffset"]:c.support.boxModel&&j.document.documentElement[d]||j.document.body[d]:e[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();c.fn["inner"+b]=function(){return this[0]?c.css(this[0],d,false,"padding"):null};c.fn["outer"+b]=function(f){return this[0]?c.css(this[0],d,false,f?"margin":"border"):null};c.fn[d]=function(f){var e=this[0];if(!e)return f==null?null:this;if(c.isFunction(f))return this.each(function(j){var i=c(this);i[d](f.call(this,j,i[d]()))});return"scrollTo"in
 | 
			
		||||
e&&e.document?e.document.compatMode==="CSS1Compat"&&e.document.documentElement["client"+b]||e.document.body["client"+b]:e.nodeType===9?Math.max(e.documentElement["client"+b],e.body["scroll"+b],e.documentElement["scroll"+b],e.body["offset"+b],e.documentElement["offset"+b]):f===w?c.css(e,d):this.css(d,typeof f==="string"?f:f+"px")}});A.jQuery=A.$=c})(window);
 | 
			
		||||
							
								
								
									
										892
									
								
								docs/public/js/libs/modernizr-1.6.js
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										892
									
								
								docs/public/js/libs/modernizr-1.6.js
									
										
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -1,892 +0,0 @@
 | 
			
		|||
/*!
 | 
			
		||||
 * Modernizr v1.6
 | 
			
		||||
 * http://www.modernizr.com
 | 
			
		||||
 *
 | 
			
		||||
 * Developed by: 
 | 
			
		||||
 * - Faruk Ates  http://farukat.es/
 | 
			
		||||
 * - Paul Irish  http://paulirish.com/
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (c) 2009-2010
 | 
			
		||||
 * Dual-licensed under the BSD or MIT licenses.
 | 
			
		||||
 * http://www.modernizr.com/license/
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
/*
 | 
			
		||||
 * Modernizr is a script that detects native CSS3 and HTML5 features
 | 
			
		||||
 * available in the current UA and provides an object containing all
 | 
			
		||||
 * features with a true/false value, depending on whether the UA has
 | 
			
		||||
 * native support for it or not.
 | 
			
		||||
 * 
 | 
			
		||||
 * Modernizr will also add classes to the <html> element of the page,
 | 
			
		||||
 * one for each feature it detects. If the UA supports it, a class
 | 
			
		||||
 * like "cssgradients" will be added. If not, the class name will be
 | 
			
		||||
 * "no-cssgradients". This allows for simple if-conditionals in your
 | 
			
		||||
 * CSS, giving you fine control over the look & feel of your website.
 | 
			
		||||
 * 
 | 
			
		||||
 * @author        Faruk Ates
 | 
			
		||||
 * @author        Paul Irish
 | 
			
		||||
 * @copyright     (c) 2009-2010 Faruk Ates.
 | 
			
		||||
 * @contributor   Ben Alman
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
window.Modernizr = (function(window,doc,undefined){
 | 
			
		||||
    
 | 
			
		||||
    var version = '1.6',
 | 
			
		||||
    
 | 
			
		||||
    ret = {},
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * !! DEPRECATED !!
 | 
			
		||||
     * 
 | 
			
		||||
     * enableHTML5 is a private property for advanced use only. If enabled,
 | 
			
		||||
     * it will make Modernizr.init() run through a brief while() loop in
 | 
			
		||||
     * which it will create all HTML5 elements in the DOM to allow for
 | 
			
		||||
     * styling them in Internet Explorer, which does not recognize any
 | 
			
		||||
     * non-HTML4 elements unless created in the DOM this way.
 | 
			
		||||
     * 
 | 
			
		||||
     * enableHTML5 is ON by default.
 | 
			
		||||
     * 
 | 
			
		||||
     * The enableHTML5 toggle option is DEPRECATED as per 1.6, and will be
 | 
			
		||||
     * replaced in 2.0 in lieu of the modular, configurable nature of 2.0.
 | 
			
		||||
     */
 | 
			
		||||
    enableHTML5 = true,
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    docElement = doc.documentElement,
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Create our "modernizr" element that we do most feature tests on.
 | 
			
		||||
     */
 | 
			
		||||
    mod = 'modernizr',
 | 
			
		||||
    m = doc.createElement( mod ),
 | 
			
		||||
    m_style = m.style,
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Create the input element for various Web Forms feature tests.
 | 
			
		||||
     */
 | 
			
		||||
    f = doc.createElement( 'input' ),
 | 
			
		||||
    
 | 
			
		||||
    smile = ':)',
 | 
			
		||||
    
 | 
			
		||||
    tostring = Object.prototype.toString,
 | 
			
		||||
    
 | 
			
		||||
    // List of property values to set for css tests. See ticket #21
 | 
			
		||||
    prefixes = ' -webkit- -moz- -o- -ms- -khtml- '.split(' '),
 | 
			
		||||
 | 
			
		||||
    // Following spec is to expose vendor-specific style properties as:
 | 
			
		||||
    //   elem.style.WebkitBorderRadius
 | 
			
		||||
    // and the following would be incorrect:
 | 
			
		||||
    //   elem.style.webkitBorderRadius
 | 
			
		||||
    
 | 
			
		||||
    // Webkit ghosts their properties in lowercase but Opera & Moz do not.
 | 
			
		||||
    // Microsoft foregoes prefixes entirely <= IE8, but appears to 
 | 
			
		||||
    //   use a lowercase `ms` instead of the correct `Ms` in IE9
 | 
			
		||||
    
 | 
			
		||||
    // More here: http://github.com/Modernizr/Modernizr/issues/issue/21
 | 
			
		||||
    domPrefixes = 'Webkit Moz O ms Khtml'.split(' '),
 | 
			
		||||
 | 
			
		||||
    ns = {'svg': 'http://www.w3.org/2000/svg'},
 | 
			
		||||
 | 
			
		||||
    tests = {},
 | 
			
		||||
    inputs = {},
 | 
			
		||||
    attrs = {},
 | 
			
		||||
    
 | 
			
		||||
    classes = [],
 | 
			
		||||
    
 | 
			
		||||
    featurename, // used in testing loop
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    // todo: consider using http://javascript.nwbox.com/CSSSupport/css-support.js instead
 | 
			
		||||
    testMediaQuery = function(mq){
 | 
			
		||||
 | 
			
		||||
      var st = document.createElement('style'),
 | 
			
		||||
          div = doc.createElement('div'),
 | 
			
		||||
          ret;
 | 
			
		||||
 | 
			
		||||
      st.textContent = mq + '{#modernizr{height:3px}}';
 | 
			
		||||
      (doc.head || doc.getElementsByTagName('head')[0]).appendChild(st);
 | 
			
		||||
      div.id = 'modernizr';
 | 
			
		||||
      docElement.appendChild(div);
 | 
			
		||||
 | 
			
		||||
      ret = div.offsetHeight === 3;
 | 
			
		||||
 | 
			
		||||
      st.parentNode.removeChild(st);
 | 
			
		||||
      div.parentNode.removeChild(div);
 | 
			
		||||
 | 
			
		||||
      return !!ret;
 | 
			
		||||
 | 
			
		||||
    },
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
      * isEventSupported determines if a given element supports the given event
 | 
			
		||||
      * function from http://yura.thinkweb2.com/isEventSupported/
 | 
			
		||||
      */
 | 
			
		||||
    isEventSupported = (function(){
 | 
			
		||||
 | 
			
		||||
      var TAGNAMES = {
 | 
			
		||||
        'select':'input','change':'input',
 | 
			
		||||
        'submit':'form','reset':'form',
 | 
			
		||||
        'error':'img','load':'img','abort':'img'
 | 
			
		||||
      };
 | 
			
		||||
 | 
			
		||||
      function isEventSupported(eventName, element) {
 | 
			
		||||
 | 
			
		||||
        element = element || document.createElement(TAGNAMES[eventName] || 'div');
 | 
			
		||||
        eventName = 'on' + eventName;
 | 
			
		||||
 | 
			
		||||
        // When using `setAttribute`, IE skips "unload", WebKit skips "unload" and "resize", whereas `in` "catches" those
 | 
			
		||||
        var isSupported = (eventName in element);
 | 
			
		||||
 | 
			
		||||
        if (!isSupported) {
 | 
			
		||||
          // If it has no `setAttribute` (i.e. doesn't implement Node interface), try generic element
 | 
			
		||||
          if (!element.setAttribute) {
 | 
			
		||||
            element = document.createElement('div');
 | 
			
		||||
          }
 | 
			
		||||
          if (element.setAttribute && element.removeAttribute) {
 | 
			
		||||
            element.setAttribute(eventName, '');
 | 
			
		||||
            isSupported = typeof element[eventName] == 'function';
 | 
			
		||||
 | 
			
		||||
            // If property was created, "remove it" (by setting value to `undefined`)
 | 
			
		||||
            if (typeof element[eventName] != 'undefined') {
 | 
			
		||||
              element[eventName] = undefined;
 | 
			
		||||
            }
 | 
			
		||||
            element.removeAttribute(eventName);
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        element = null;
 | 
			
		||||
        return isSupported;
 | 
			
		||||
      }
 | 
			
		||||
      return isEventSupported;
 | 
			
		||||
    })();
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    // hasOwnProperty shim by kangax needed for Safari 2.0 support
 | 
			
		||||
    var _hasOwnProperty = ({}).hasOwnProperty, hasOwnProperty;
 | 
			
		||||
    if (typeof _hasOwnProperty !== 'undefined' && typeof _hasOwnProperty.call !== 'undefined') {
 | 
			
		||||
      hasOwnProperty = function (object, property) {
 | 
			
		||||
        return _hasOwnProperty.call(object, property);
 | 
			
		||||
      };
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
      hasOwnProperty = function (object, property) { /* yes, this can give false positives/negatives, but most of the time we don't care about those */
 | 
			
		||||
        return ((property in object) && typeof object.constructor.prototype[property] === 'undefined');
 | 
			
		||||
      };
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * set_css applies given styles to the Modernizr DOM node.
 | 
			
		||||
     */
 | 
			
		||||
    function set_css( str ) {
 | 
			
		||||
        m_style.cssText = str;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * set_css_all extrapolates all vendor-specific css strings.
 | 
			
		||||
     */
 | 
			
		||||
    function set_css_all( str1, str2 ) {
 | 
			
		||||
        return set_css(prefixes.join(str1 + ';') + ( str2 || '' ));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * contains returns a boolean for if substr is found within str.
 | 
			
		||||
     */
 | 
			
		||||
    function contains( str, substr ) {
 | 
			
		||||
        return (''+str).indexOf( substr ) !== -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * test_props is a generic CSS / DOM property test; if a browser supports
 | 
			
		||||
     *   a certain property, it won't return undefined for it.
 | 
			
		||||
     *   A supported CSS property returns empty string when its not yet set.
 | 
			
		||||
     */
 | 
			
		||||
    function test_props( props, callback ) {
 | 
			
		||||
        for ( var i in props ) {
 | 
			
		||||
            if ( m_style[ props[i] ] !== undefined && ( !callback || callback( props[i], m ) ) ) {
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * test_props_all tests a list of DOM properties we want to check against.
 | 
			
		||||
     *   We specify literally ALL possible (known and/or likely) properties on 
 | 
			
		||||
     *   the element including the non-vendor prefixed one, for forward-
 | 
			
		||||
     *   compatibility.
 | 
			
		||||
     */
 | 
			
		||||
    function test_props_all( prop, callback ) {
 | 
			
		||||
      
 | 
			
		||||
        var uc_prop = prop.charAt(0).toUpperCase() + prop.substr(1),
 | 
			
		||||
            props   = (prop + ' ' + domPrefixes.join(uc_prop + ' ') + uc_prop).split(' ');
 | 
			
		||||
 | 
			
		||||
        return !!test_props( props, callback );
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Tests
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    tests['flexbox'] = function() {
 | 
			
		||||
        /**
 | 
			
		||||
         * set_prefixed_value_css sets the property of a specified element
 | 
			
		||||
         * adding vendor prefixes to the VALUE of the property.
 | 
			
		||||
         * @param {Element} element
 | 
			
		||||
         * @param {string} property The property name. This will not be prefixed.
 | 
			
		||||
         * @param {string} value The value of the property. This WILL be prefixed.
 | 
			
		||||
         * @param {string=} extra Additional CSS to append unmodified to the end of
 | 
			
		||||
         * the CSS string.
 | 
			
		||||
         */
 | 
			
		||||
        function set_prefixed_value_css(element, property, value, extra) {
 | 
			
		||||
            property += ':';
 | 
			
		||||
            element.style.cssText = (property + prefixes.join(value + ';' + property)).slice(0, -property.length) + (extra || '');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * set_prefixed_property_css sets the property of a specified element
 | 
			
		||||
         * adding vendor prefixes to the NAME of the property.
 | 
			
		||||
         * @param {Element} element
 | 
			
		||||
         * @param {string} property The property name. This WILL be prefixed.
 | 
			
		||||
         * @param {string} value The value of the property. This will not be prefixed.
 | 
			
		||||
         * @param {string=} extra Additional CSS to append unmodified to the end of
 | 
			
		||||
         * the CSS string.
 | 
			
		||||
         */
 | 
			
		||||
        function set_prefixed_property_css(element, property, value, extra) {
 | 
			
		||||
            element.style.cssText = prefixes.join(property + ':' + value + ';') + (extra || '');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var c = doc.createElement('div'),
 | 
			
		||||
            elem = doc.createElement('div');
 | 
			
		||||
 | 
			
		||||
        set_prefixed_value_css(c, 'display', 'box', 'width:42px;padding:0;');
 | 
			
		||||
        set_prefixed_property_css(elem, 'box-flex', '1', 'width:10px;');
 | 
			
		||||
 | 
			
		||||
        c.appendChild(elem);
 | 
			
		||||
        docElement.appendChild(c);
 | 
			
		||||
 | 
			
		||||
        var ret = elem.offsetWidth === 42;
 | 
			
		||||
 | 
			
		||||
        c.removeChild(elem);
 | 
			
		||||
        docElement.removeChild(c);
 | 
			
		||||
 | 
			
		||||
        return ret;
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
    // On the S60 and BB Storm, getContext exists, but always returns undefined
 | 
			
		||||
    // http://github.com/Modernizr/Modernizr/issues/issue/97/ 
 | 
			
		||||
    
 | 
			
		||||
    tests['canvas'] = function() {
 | 
			
		||||
        var elem = doc.createElement( 'canvas' );
 | 
			
		||||
        return !!(elem.getContext && elem.getContext('2d'));
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
    tests['canvastext'] = function() {
 | 
			
		||||
        return !!(ret['canvas'] && typeof doc.createElement( 'canvas' ).getContext('2d').fillText == 'function');
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    tests['webgl'] = function(){
 | 
			
		||||
 | 
			
		||||
        var elem = doc.createElement( 'canvas' ); 
 | 
			
		||||
        
 | 
			
		||||
        try {
 | 
			
		||||
            if (elem.getContext('webgl')){ return true; }
 | 
			
		||||
        } catch(e){	}
 | 
			
		||||
        
 | 
			
		||||
        try {
 | 
			
		||||
            if (elem.getContext('experimental-webgl')){ return true; }
 | 
			
		||||
        } catch(e){	}
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * The Modernizr.touch test only indicates if the browser supports
 | 
			
		||||
     *    touch events, which does not necessarily reflect a touchscreen
 | 
			
		||||
     *    device, as evidenced by tablets running Windows 7 or, alas,
 | 
			
		||||
     *    the Palm Pre / WebOS (touch) phones.
 | 
			
		||||
     *    
 | 
			
		||||
     * Additionally, Chrome (desktop) used to lie about its support on this,
 | 
			
		||||
     *    but that has since been rectified: http://crbug.com/36415
 | 
			
		||||
     *    
 | 
			
		||||
     * We also test for Firefox 4 Multitouch Support.
 | 
			
		||||
     *
 | 
			
		||||
     * For more info, see: http://modernizr.github.com/Modernizr/touch.html
 | 
			
		||||
     */
 | 
			
		||||
     
 | 
			
		||||
    tests['touch'] = function() {
 | 
			
		||||
 | 
			
		||||
        return ('ontouchstart' in window) || testMediaQuery('@media ('+prefixes.join('touch-enabled),(')+'modernizr)');
 | 
			
		||||
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * geolocation tests for the new Geolocation API specification.
 | 
			
		||||
     *   This test is a standards compliant-only test; for more complete
 | 
			
		||||
     *   testing, including a Google Gears fallback, please see:
 | 
			
		||||
     *   http://code.google.com/p/geo-location-javascript/
 | 
			
		||||
     * or view a fallback solution using google's geo API:
 | 
			
		||||
     *   http://gist.github.com/366184
 | 
			
		||||
     */
 | 
			
		||||
    tests['geolocation'] = function() {
 | 
			
		||||
        return !!navigator.geolocation;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // Per 1.6: 
 | 
			
		||||
    // This used to be Modernizr.crosswindowmessaging but the longer
 | 
			
		||||
    // name has been deprecated in favor of a shorter and property-matching one.
 | 
			
		||||
    // The old API is still available in 1.6, but as of 2.0 will throw a warning,
 | 
			
		||||
    // and in the first release thereafter disappear entirely.
 | 
			
		||||
    tests['postmessage'] = function() {
 | 
			
		||||
      return !!window.postMessage;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // Web SQL database detection is tricky:
 | 
			
		||||
 | 
			
		||||
    // In chrome incognito mode, openDatabase is truthy, but using it will 
 | 
			
		||||
    //   throw an exception: http://crbug.com/42380
 | 
			
		||||
    // We can create a dummy database, but there is no way to delete it afterwards. 
 | 
			
		||||
    
 | 
			
		||||
    // Meanwhile, Safari users can get prompted on any database creation.
 | 
			
		||||
    //   If they do, any page with Modernizr will give them a prompt:
 | 
			
		||||
    //   http://github.com/Modernizr/Modernizr/issues/closed#issue/113
 | 
			
		||||
    
 | 
			
		||||
    // We have chosen to allow the Chrome incognito false positive, so that Modernizr
 | 
			
		||||
    //   doesn't litter the web with these test databases. As a developer, you'll have
 | 
			
		||||
    //   to account for this gotcha yourself.
 | 
			
		||||
    tests['websqldatabase'] = function() {
 | 
			
		||||
      var result = !!window.openDatabase;
 | 
			
		||||
      /*
 | 
			
		||||
      if (result){
 | 
			
		||||
        try {
 | 
			
		||||
          result = !!openDatabase( mod + "testdb", "1.0", mod + "testdb", 2e4);
 | 
			
		||||
        } catch(e) {
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      */
 | 
			
		||||
      return result;
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
    // Vendors have inconsistent prefixing with the experimental Indexed DB:
 | 
			
		||||
    // - Firefox is shipping indexedDB in FF4 as moz_indexedDB
 | 
			
		||||
    // - Webkit's implementation is accessible through webkitIndexedDB
 | 
			
		||||
    // We test both styles.
 | 
			
		||||
    tests['indexedDB'] = function(){
 | 
			
		||||
      for (var i = -1, len = domPrefixes.length; ++i < len; ){ 
 | 
			
		||||
        var prefix = domPrefixes[i].toLowerCase();
 | 
			
		||||
        if (window[prefix + '_indexedDB'] || window[prefix + 'IndexedDB']){
 | 
			
		||||
          return true;
 | 
			
		||||
        } 
 | 
			
		||||
      }
 | 
			
		||||
      return false;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // documentMode logic from YUI to filter out IE8 Compat Mode
 | 
			
		||||
    //   which false positives.
 | 
			
		||||
    tests['hashchange'] = function() {
 | 
			
		||||
      return isEventSupported('hashchange', window) && ( document.documentMode === undefined || document.documentMode > 7 );
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // Per 1.6: 
 | 
			
		||||
    // This used to be Modernizr.historymanagement but the longer
 | 
			
		||||
    // name has been deprecated in favor of a shorter and property-matching one.
 | 
			
		||||
    // The old API is still available in 1.6, but as of 2.0 will throw a warning,
 | 
			
		||||
    // and in the first release thereafter disappear entirely.
 | 
			
		||||
    tests['history'] = function() {
 | 
			
		||||
      return !!(window.history && history.pushState);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    tests['draganddrop'] = function() {
 | 
			
		||||
        return  isEventSupported('drag') && 
 | 
			
		||||
                isEventSupported('dragstart') && 
 | 
			
		||||
                isEventSupported('dragenter') &&
 | 
			
		||||
                isEventSupported('dragover') &&
 | 
			
		||||
                isEventSupported('dragleave') &&
 | 
			
		||||
                isEventSupported('dragend') &&
 | 
			
		||||
                isEventSupported('drop');
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
    tests['websockets'] = function(){
 | 
			
		||||
        return ('WebSocket' in window);
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    // http://css-tricks.com/rgba-browser-support/
 | 
			
		||||
    tests['rgba'] = function() {
 | 
			
		||||
        // Set an rgba() color and check the returned value
 | 
			
		||||
        
 | 
			
		||||
        set_css(  'background-color:rgba(150,255,150,.5)' );
 | 
			
		||||
        
 | 
			
		||||
        return contains( m_style.backgroundColor, 'rgba' );
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
    tests['hsla'] = function() {
 | 
			
		||||
        // Same as rgba(), in fact, browsers re-map hsla() to rgba() internally,
 | 
			
		||||
        //   except IE9 who retains it as hsla
 | 
			
		||||
        
 | 
			
		||||
        set_css('background-color:hsla(120,40%,100%,.5)' );
 | 
			
		||||
        
 | 
			
		||||
        return contains( m_style.backgroundColor, 'rgba' ) || contains( m_style.backgroundColor, 'hsla' );
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
    tests['multiplebgs'] = function() {
 | 
			
		||||
        // Setting multiple images AND a color on the background shorthand property
 | 
			
		||||
        //  and then querying the style.background property value for the number of
 | 
			
		||||
        //  occurrences of "url(" is a reliable method for detecting ACTUAL support for this!
 | 
			
		||||
        
 | 
			
		||||
        set_css( 'background:url(//:),url(//:),red url(//:)' );
 | 
			
		||||
        
 | 
			
		||||
        // If the UA supports multiple backgrounds, there should be three occurrences
 | 
			
		||||
        //   of the string "url(" in the return value for elem_style.background
 | 
			
		||||
 | 
			
		||||
        return new RegExp("(url\\s*\\(.*?){3}").test(m_style.background);
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    // In testing support for a given CSS property, it's legit to test:
 | 
			
		||||
    //    elem.style[styleName] !== undefined
 | 
			
		||||
    // If the property is supported it will return an empty string,
 | 
			
		||||
    // if unsupported it will return undefined.
 | 
			
		||||
    // We'll take advantage of this quick test and skip setting a style 
 | 
			
		||||
    // on our modernizr element, but instead just testing undefined vs
 | 
			
		||||
    // empty string.
 | 
			
		||||
    // The legacy set_css_all calls will remain in the source 
 | 
			
		||||
    // (however, commented) for clarity, yet functionally they are 
 | 
			
		||||
    // no longer needed.
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    tests['backgroundsize'] = function() {
 | 
			
		||||
        return test_props_all( 'backgroundSize' );
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
    tests['borderimage'] = function() {
 | 
			
		||||
        //  set_css_all( 'border-image:url(m.png) 1 1 stretch' );
 | 
			
		||||
        return test_props_all( 'borderImage' );
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    // Super comprehensive table about all the unique implementations of 
 | 
			
		||||
    // border-radius: http://muddledramblings.com/table-of-css3-border-radius-compliance
 | 
			
		||||
    
 | 
			
		||||
    tests['borderradius'] = function() {
 | 
			
		||||
        //  set_css_all( 'border-radius:10px' );
 | 
			
		||||
        return test_props_all( 'borderRadius', '', function( prop ) {
 | 
			
		||||
            return contains( prop, 'orderRadius' );
 | 
			
		||||
        });
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    tests['boxshadow'] = function() {
 | 
			
		||||
        //  set_css_all( 'box-shadow:#000 1px 1px 3px' );
 | 
			
		||||
        return test_props_all( 'boxShadow' );
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
    // Note: FF3.0 will false positive on this test 
 | 
			
		||||
    tests['textshadow'] = function(){
 | 
			
		||||
        return doc.createElement('div').style.textShadow === '';
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    tests['opacity'] = function() {
 | 
			
		||||
        // Browsers that actually have CSS Opacity implemented have done so
 | 
			
		||||
        //  according to spec, which means their return values are within the
 | 
			
		||||
        //  range of [0.0,1.0] - including the leading zero.
 | 
			
		||||
        
 | 
			
		||||
        set_css_all( 'opacity:.5' );
 | 
			
		||||
        
 | 
			
		||||
        return contains( m_style.opacity, '0.5' );
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    tests['cssanimations'] = function() {
 | 
			
		||||
        //  set_css_all( 'animation:"animate" 2s ease 2', 'position:relative' );
 | 
			
		||||
        return test_props_all( 'animationName' );
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    tests['csscolumns'] = function() {
 | 
			
		||||
        //  set_css_all( 'column-count:3' );
 | 
			
		||||
        return test_props_all( 'columnCount' );
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    tests['cssgradients'] = function() {
 | 
			
		||||
        /**
 | 
			
		||||
         * For CSS Gradients syntax, please see:
 | 
			
		||||
         * http://webkit.org/blog/175/introducing-css-gradients/
 | 
			
		||||
         * https://developer.mozilla.org/en/CSS/-moz-linear-gradient
 | 
			
		||||
         * https://developer.mozilla.org/en/CSS/-moz-radial-gradient
 | 
			
		||||
         * http://dev.w3.org/csswg/css3-images/#gradients-
 | 
			
		||||
         */
 | 
			
		||||
        
 | 
			
		||||
        var str1 = 'background-image:',
 | 
			
		||||
            str2 = 'gradient(linear,left top,right bottom,from(#9f9),to(white));',
 | 
			
		||||
            str3 = 'linear-gradient(left top,#9f9, white);';
 | 
			
		||||
        
 | 
			
		||||
        set_css(
 | 
			
		||||
            (str1 + prefixes.join(str2 + str1) + prefixes.join(str3 + str1)).slice(0,-str1.length)
 | 
			
		||||
        );
 | 
			
		||||
        
 | 
			
		||||
        return contains( m_style.backgroundImage, 'gradient' );
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    tests['cssreflections'] = function() {
 | 
			
		||||
        //  set_css_all( 'box-reflect:right 1px' );
 | 
			
		||||
        return test_props_all( 'boxReflect' );
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    tests['csstransforms'] = function() {
 | 
			
		||||
        //  set_css_all( 'transform:rotate(3deg)' );
 | 
			
		||||
        return !!test_props([ 'transformProperty', 'WebkitTransform', 'MozTransform', 'OTransform', 'msTransform' ]);
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    tests['csstransforms3d'] = function() {
 | 
			
		||||
        //  set_css_all( 'perspective:500' );
 | 
			
		||||
        
 | 
			
		||||
        var ret = !!test_props([ 'perspectiveProperty', 'WebkitPerspective', 'MozPerspective', 'OPerspective', 'msPerspective' ]);
 | 
			
		||||
        
 | 
			
		||||
        // Webkit’s 3D transforms are passed off to the browser's own graphics renderer.
 | 
			
		||||
        //   It works fine in Safari on Leopard and Snow Leopard, but not in Chrome (yet?).
 | 
			
		||||
        //   As a result, Webkit typically recognizes the syntax but will sometimes throw a false
 | 
			
		||||
        //   positive, thus we must do a more thorough check:
 | 
			
		||||
        if (ret){
 | 
			
		||||
          
 | 
			
		||||
          // Webkit allows this media query to succeed only if the feature is enabled.    
 | 
			
		||||
          // "@media (transform-3d),(-o-transform-3d),(-moz-transform-3d),(-ms-transform-3d),(-webkit-transform-3d),(modernizr){ ... }"      
 | 
			
		||||
          ret = testMediaQuery('@media ('+prefixes.join('transform-3d),(')+'modernizr)');
 | 
			
		||||
        }
 | 
			
		||||
        return ret;
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    tests['csstransitions'] = function() {
 | 
			
		||||
        //  set_css_all( 'transition:all .5s linear' );
 | 
			
		||||
        return test_props_all( 'transitionProperty' );
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    // @font-face detection routine by Diego Perini
 | 
			
		||||
    // http://javascript.nwbox.com/CSSSupport/
 | 
			
		||||
    tests['fontface'] = function(){
 | 
			
		||||
 | 
			
		||||
        var 
 | 
			
		||||
        sheet,
 | 
			
		||||
        head = doc.head || doc.getElementsByTagName('head')[0] || docElement,
 | 
			
		||||
        style = doc.createElement("style"),
 | 
			
		||||
        impl = doc.implementation || { hasFeature: function() { return false; } };
 | 
			
		||||
        
 | 
			
		||||
        style.type = 'text/css';
 | 
			
		||||
        head.insertBefore(style, head.firstChild);
 | 
			
		||||
        sheet = style.sheet || style.styleSheet;
 | 
			
		||||
 | 
			
		||||
        // removing it crashes IE browsers
 | 
			
		||||
        //head.removeChild(style);
 | 
			
		||||
 | 
			
		||||
        var supportAtRule = impl.hasFeature('CSS2', '') ?
 | 
			
		||||
                function(rule) {
 | 
			
		||||
                    if (!(sheet && rule)) return false;
 | 
			
		||||
                    var result = false;
 | 
			
		||||
                    try {
 | 
			
		||||
                        sheet.insertRule(rule, 0);
 | 
			
		||||
                        result = !(/unknown/i).test(sheet.cssRules[0].cssText);
 | 
			
		||||
                        sheet.deleteRule(sheet.cssRules.length - 1);
 | 
			
		||||
                    } catch(e) { }
 | 
			
		||||
                    return result;
 | 
			
		||||
                } :
 | 
			
		||||
                function(rule) {
 | 
			
		||||
                    if (!(sheet && rule)) return false;
 | 
			
		||||
                    sheet.cssText = rule;
 | 
			
		||||
                    
 | 
			
		||||
                    return sheet.cssText.length !== 0 && !(/unknown/i).test(sheet.cssText) &&
 | 
			
		||||
                      sheet.cssText
 | 
			
		||||
                            .replace(/\r+|\n+/g, '')
 | 
			
		||||
                            .indexOf(rule.split(' ')[0]) === 0;
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // DEPRECATED - allow for a callback
 | 
			
		||||
        ret._fontfaceready = function(fn){
 | 
			
		||||
          fn(ret.fontface);
 | 
			
		||||
        };
 | 
			
		||||
        
 | 
			
		||||
        return supportAtRule('@font-face { font-family: "font"; src: "font.ttf"; }');
 | 
			
		||||
        
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    // These tests evaluate support of the video/audio elements, as well as
 | 
			
		||||
    // testing what types of content they support.
 | 
			
		||||
    //
 | 
			
		||||
    // We're using the Boolean constructor here, so that we can extend the value
 | 
			
		||||
    // e.g.  Modernizr.video     // true
 | 
			
		||||
    //       Modernizr.video.ogg // 'probably'
 | 
			
		||||
    //
 | 
			
		||||
    // Codec values from : http://github.com/NielsLeenheer/html5test/blob/9106a8/index.html#L845
 | 
			
		||||
    //                     thx to NielsLeenheer and zcorpan
 | 
			
		||||
    
 | 
			
		||||
    // Note: in FF 3.5.1 and 3.5.0, "no" was a return value instead of empty string.
 | 
			
		||||
    //   Modernizr does not normalize for that.
 | 
			
		||||
    
 | 
			
		||||
    tests['video'] = function() {
 | 
			
		||||
        var elem = doc.createElement('video'),
 | 
			
		||||
            bool = !!elem.canPlayType;
 | 
			
		||||
        
 | 
			
		||||
        if (bool){  
 | 
			
		||||
            bool      = new Boolean(bool);  
 | 
			
		||||
            bool.ogg  = elem.canPlayType('video/ogg; codecs="theora"');
 | 
			
		||||
            
 | 
			
		||||
            // Workaround required for IE9, which doesn't report video support without audio codec specified.
 | 
			
		||||
            //   bug 599718 @ msft connect
 | 
			
		||||
            var h264 = 'video/mp4; codecs="avc1.42E01E';
 | 
			
		||||
            bool.h264 = elem.canPlayType(h264 + '"') || elem.canPlayType(h264 + ', mp4a.40.2"');
 | 
			
		||||
            
 | 
			
		||||
            bool.webm = elem.canPlayType('video/webm; codecs="vp8, vorbis"');
 | 
			
		||||
        }
 | 
			
		||||
        return bool;
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
    tests['audio'] = function() {
 | 
			
		||||
        var elem = doc.createElement('audio'),
 | 
			
		||||
            bool = !!elem.canPlayType;
 | 
			
		||||
        
 | 
			
		||||
        if (bool){  
 | 
			
		||||
            bool      = new Boolean(bool);  
 | 
			
		||||
            bool.ogg  = elem.canPlayType('audio/ogg; codecs="vorbis"');
 | 
			
		||||
            bool.mp3  = elem.canPlayType('audio/mpeg;');
 | 
			
		||||
            
 | 
			
		||||
            // Mimetypes accepted: 
 | 
			
		||||
            //   https://developer.mozilla.org/En/Media_formats_supported_by_the_audio_and_video_elements
 | 
			
		||||
            //   http://bit.ly/iphoneoscodecs
 | 
			
		||||
            bool.wav  = elem.canPlayType('audio/wav; codecs="1"');
 | 
			
		||||
            bool.m4a  = elem.canPlayType('audio/x-m4a;') || elem.canPlayType('audio/aac;');
 | 
			
		||||
        }
 | 
			
		||||
        return bool;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    // Both localStorage and sessionStorage are
 | 
			
		||||
    //   tested via the `in` operator because otherwise Firefox will
 | 
			
		||||
    //   throw an error: https://bugzilla.mozilla.org/show_bug.cgi?id=365772
 | 
			
		||||
    //   if cookies are disabled
 | 
			
		||||
    
 | 
			
		||||
    // They require try/catch because of possible firefox configuration:
 | 
			
		||||
    //   http://github.com/Modernizr/Modernizr/issues#issue/92
 | 
			
		||||
    
 | 
			
		||||
    // FWIW miller device resolves to [object Storage] in all supporting browsers
 | 
			
		||||
    //   except for IE who does [object Object]
 | 
			
		||||
    
 | 
			
		||||
    // IE8 Compat mode supports these features completely:
 | 
			
		||||
    //   http://www.quirksmode.org/dom/html5.html
 | 
			
		||||
    
 | 
			
		||||
    tests['localstorage'] = function() {
 | 
			
		||||
        try {
 | 
			
		||||
          return ('localStorage' in window) && window.localStorage !== null;
 | 
			
		||||
        } catch(e) {
 | 
			
		||||
          return false;
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    tests['sessionstorage'] = function() {
 | 
			
		||||
        try {
 | 
			
		||||
            return ('sessionStorage' in window) && window.sessionStorage !== null;
 | 
			
		||||
        } catch(e){
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    tests['webWorkers'] = function () {
 | 
			
		||||
        return !!window.Worker;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    tests['applicationcache'] =  function() {
 | 
			
		||||
        return !!window.applicationCache;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
    // Thanks to Erik Dahlstrom
 | 
			
		||||
    tests['svg'] = function(){
 | 
			
		||||
        return !!doc.createElementNS && !!doc.createElementNS(ns.svg, "svg").createSVGRect;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    tests['inlinesvg'] = function() {
 | 
			
		||||
      var div = document.createElement('div');
 | 
			
		||||
      div.innerHTML = '<svg/>';
 | 
			
		||||
      return (div.firstChild && div.firstChild.namespaceURI) == ns.svg;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // Thanks to F1lt3r and lucideer
 | 
			
		||||
    // http://github.com/Modernizr/Modernizr/issues#issue/35
 | 
			
		||||
    tests['smil'] = function(){
 | 
			
		||||
        return !!doc.createElementNS && /SVG/.test(tostring.call(doc.createElementNS(ns.svg,'animate')));
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    tests['svgclippaths'] = function(){
 | 
			
		||||
        // Possibly returns a false positive in Safari 3.2?
 | 
			
		||||
        return !!doc.createElementNS && /SVG/.test(tostring.call(doc.createElementNS(ns.svg,'clipPath')));
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    // input features and input types go directly onto the ret object, bypassing the tests loop.
 | 
			
		||||
    // Hold this guy to execute in a moment.
 | 
			
		||||
    function webforms(){
 | 
			
		||||
    
 | 
			
		||||
        // Run through HTML5's new input attributes to see if the UA understands any.
 | 
			
		||||
        // We're using f which is the <input> element created early on
 | 
			
		||||
        // Mike Taylr has created a comprehensive resource for testing these attributes
 | 
			
		||||
        //   when applied to all input types: 
 | 
			
		||||
        //   http://miketaylr.com/code/input-type-attr.html
 | 
			
		||||
        // spec: http://www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#input-type-attr-summary
 | 
			
		||||
        ret['input'] = (function(props) {
 | 
			
		||||
            for (var i = 0,len=props.length;i<len;i++) {
 | 
			
		||||
                attrs[ props[i] ] = !!(props[i] in f);
 | 
			
		||||
            }
 | 
			
		||||
            return attrs;
 | 
			
		||||
        })('autocomplete autofocus list placeholder max min multiple pattern required step'.split(' '));
 | 
			
		||||
 | 
			
		||||
        // Run through HTML5's new input types to see if the UA understands any.
 | 
			
		||||
        //   This is put behind the tests runloop because it doesn't return a
 | 
			
		||||
        //   true/false like all the other tests; instead, it returns an object
 | 
			
		||||
        //   containing each input type with its corresponding true/false value 
 | 
			
		||||
        
 | 
			
		||||
        // Big thanks to @miketaylr for the html5 forms expertise. http://miketaylr.com/
 | 
			
		||||
        ret['inputtypes'] = (function(props) {
 | 
			
		||||
            for (var i = 0, bool, len=props.length ; i < len ; i++) {
 | 
			
		||||
              
 | 
			
		||||
                f.setAttribute('type', props[i]);
 | 
			
		||||
                bool = f.type !== 'text';
 | 
			
		||||
                
 | 
			
		||||
                // Chrome likes to falsely purport support, so we feed it a textual value;
 | 
			
		||||
                // if that doesnt succeed then we know there's a custom UI
 | 
			
		||||
                if (bool){  
 | 
			
		||||
 | 
			
		||||
                    f.value = smile;
 | 
			
		||||
     
 | 
			
		||||
                    if (/^range$/.test(f.type) && f.style.WebkitAppearance !== undefined){
 | 
			
		||||
                      
 | 
			
		||||
                      docElement.appendChild(f);
 | 
			
		||||
                      var defaultView = doc.defaultView;
 | 
			
		||||
                      
 | 
			
		||||
                      // Safari 2-4 allows the smiley as a value, despite making a slider
 | 
			
		||||
                      bool =  defaultView.getComputedStyle && 
 | 
			
		||||
                              defaultView.getComputedStyle(f, null).WebkitAppearance !== 'textfield' && 
 | 
			
		||||
                      
 | 
			
		||||
                              // Mobile android web browser has false positive, so must
 | 
			
		||||
                              // check the height to see if the widget is actually there.
 | 
			
		||||
                              (f.offsetHeight !== 0);
 | 
			
		||||
                              
 | 
			
		||||
                      docElement.removeChild(f);
 | 
			
		||||
                              
 | 
			
		||||
                    } else if (/^(search|tel)$/.test(f.type)){
 | 
			
		||||
                      // Spec doesnt define any special parsing or detectable UI 
 | 
			
		||||
                      //   behaviors so we pass these through as true
 | 
			
		||||
                      
 | 
			
		||||
                      // Interestingly, opera fails the earlier test, so it doesn't
 | 
			
		||||
                      //  even make it here.
 | 
			
		||||
                      
 | 
			
		||||
                    } else if (/^(url|email)$/.test(f.type)) {
 | 
			
		||||
 | 
			
		||||
                      // Real url and email support comes with prebaked validation.
 | 
			
		||||
                      bool = f.checkValidity && f.checkValidity() === false;
 | 
			
		||||
                      
 | 
			
		||||
                    } else {
 | 
			
		||||
                      // If the upgraded input compontent rejects the :) text, we got a winner
 | 
			
		||||
                      bool = f.value != smile;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                inputs[ props[i] ] = !!bool;
 | 
			
		||||
            }
 | 
			
		||||
            return inputs;
 | 
			
		||||
        })('search tel url email datetime date month week time datetime-local number range color'.split(' '));
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    // End of test definitions
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    // Run through all tests and detect their support in the current UA.
 | 
			
		||||
    // todo: hypothetically we could be doing an array of tests and use a basic loop here.
 | 
			
		||||
    for ( var feature in tests ) {
 | 
			
		||||
        if ( hasOwnProperty( tests, feature ) ) {
 | 
			
		||||
            // run the test, throw the return value into the Modernizr,
 | 
			
		||||
            //   then based on that boolean, define an appropriate className
 | 
			
		||||
            //   and push it into an array of classes we'll join later.
 | 
			
		||||
            featurename  = feature.toLowerCase();
 | 
			
		||||
            ret[ featurename ] = tests[ feature ]();
 | 
			
		||||
 | 
			
		||||
            classes.push( ( ret[ featurename ] ? '' : 'no-' ) + featurename );
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // input tests need to run.
 | 
			
		||||
    if (!ret.input) webforms();
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
   
 | 
			
		||||
    // Per 1.6: deprecated API is still accesible for now:
 | 
			
		||||
    ret.crosswindowmessaging = ret.postmessage;
 | 
			
		||||
    ret.historymanagement = ret.history;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Addtest allows the user to define their own feature tests
 | 
			
		||||
     * the result will be added onto the Modernizr object,
 | 
			
		||||
     * as well as an appropriate className set on the html element
 | 
			
		||||
     * 
 | 
			
		||||
     * @param feature - String naming the feature
 | 
			
		||||
     * @param test - Function returning true if feature is supported, false if not
 | 
			
		||||
     */
 | 
			
		||||
    ret.addTest = function (feature, test) {
 | 
			
		||||
      feature = feature.toLowerCase();
 | 
			
		||||
      
 | 
			
		||||
      if (ret[ feature ]) {
 | 
			
		||||
        return; // quit if you're trying to overwrite an existing test
 | 
			
		||||
      } 
 | 
			
		||||
      test = !!(test());
 | 
			
		||||
      docElement.className += ' ' + (test ? '' : 'no-') + feature; 
 | 
			
		||||
      ret[ feature ] = test;
 | 
			
		||||
      return ret; // allow chaining.
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Reset m.style.cssText to nothing to reduce memory footprint.
 | 
			
		||||
     */
 | 
			
		||||
    set_css( '' );
 | 
			
		||||
    m = f = null;
 | 
			
		||||
 | 
			
		||||
    // Enable HTML 5 elements for styling in IE. 
 | 
			
		||||
    // fyi: jscript version does not reflect trident version
 | 
			
		||||
    //      therefore ie9 in ie7 mode will still have a jScript v.9
 | 
			
		||||
    if ( enableHTML5 && window.attachEvent && (function(){ var elem = doc.createElement("div");
 | 
			
		||||
                                      elem.innerHTML = "<elem></elem>";
 | 
			
		||||
                                      return elem.childNodes.length !== 1; })()) {
 | 
			
		||||
        // iepp v1.6 by @jon_neal : code.google.com/p/ie-print-protector
 | 
			
		||||
        (function(f,l){var j="abbr|article|aside|audio|canvas|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",n=j.split("|"),k=n.length,g=new RegExp("<(/*)("+j+")","gi"),h=new RegExp("\\b("+j+")\\b(?!.*[;}])","gi"),m=l.createDocumentFragment(),d=l.documentElement,i=d.firstChild,b=l.createElement("style"),e=l.createElement("body");b.media="all";function c(p){var o=-1;while(++o<k){p.createElement(n[o])}}c(l);c(m);function a(t,s){var r=t.length,q=-1,o,p=[];while(++q<r){o=t[q];s=o.media||s;p.push(a(o.imports,s));p.push(o.cssText)}return p.join("")}f.attachEvent("onbeforeprint",function(){var r=-1;while(++r<k){var o=l.getElementsByTagName(n[r]),q=o.length,p=-1;while(++p<q){if(o[p].className.indexOf("iepp_")<0){o[p].className+=" iepp_"+n[r]}}}i.insertBefore(b,i.firstChild);b.styleSheet.cssText=a(l.styleSheets,"all").replace(h,".iepp_$1");m.appendChild(l.body);d.appendChild(e);e.innerHTML=m.firstChild.innerHTML.replace(g,"<$1bdo")});f.attachEvent("onafterprint",function(){e.innerHTML="";d.removeChild(e);i.removeChild(b);d.appendChild(m.firstChild)})})(this,document);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Assign private properties to the return object with prefix
 | 
			
		||||
    ret._enableHTML5     = enableHTML5;
 | 
			
		||||
    ret._version         = version;
 | 
			
		||||
 | 
			
		||||
    // Remove "no-js" class from <html> element, if it exists:
 | 
			
		||||
    docElement.className=docElement.className.replace(/\bno-js\b/,'') + ' js';
 | 
			
		||||
 | 
			
		||||
    // Add the new classes to the <html> element.
 | 
			
		||||
    docElement.className += ' ' + classes.join( ' ' );
 | 
			
		||||
    
 | 
			
		||||
    return ret;
 | 
			
		||||
 | 
			
		||||
})(this,this.document);
 | 
			
		||||
							
								
								
									
										30
									
								
								docs/public/js/libs/modernizr-1.6.min.js
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										30
									
								
								docs/public/js/libs/modernizr-1.6.min.js
									
										
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -1,30 +0,0 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Modernizr v1.6
 | 
			
		||||
 * http://www.modernizr.com
 | 
			
		||||
 *
 | 
			
		||||
 * Developed by: 
 | 
			
		||||
 * - Faruk Ates  http://farukat.es/
 | 
			
		||||
 * - Paul Irish  http://paulirish.com/
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (c) 2009-2010
 | 
			
		||||
 * Dual-licensed under the BSD or MIT licenses.
 | 
			
		||||
 * http://www.modernizr.com/license/
 | 
			
		||||
 */
 | 
			
		||||
window.Modernizr=function(i,e,u){function s(a,b){return(""+a).indexOf(b)!==-1}function D(a,b){for(var c in a)if(j[a[c]]!==u&&(!b||b(a[c],E)))return true}function n(a,b){var c=a.charAt(0).toUpperCase()+a.substr(1);c=(a+" "+F.join(c+" ")+c).split(" ");return!!D(c,b)}function S(){f.input=function(a){for(var b=0,c=a.length;b<c;b++)L[a[b]]=!!(a[b]in h);return L}("autocomplete autofocus list placeholder max min multiple pattern required step".split(" "));f.inputtypes=function(a){for(var b=0,c,k=a.length;b<
 | 
			
		||||
k;b++){h.setAttribute("type",a[b]);if(c=h.type!=="text"){h.value=M;if(/^range$/.test(h.type)&&h.style.WebkitAppearance!==u){l.appendChild(h);c=e.defaultView;c=c.getComputedStyle&&c.getComputedStyle(h,null).WebkitAppearance!=="textfield"&&h.offsetHeight!==0;l.removeChild(h)}else/^(search|tel)$/.test(h.type)||(c=/^(url|email)$/.test(h.type)?h.checkValidity&&h.checkValidity()===false:h.value!=M)}N[a[b]]=!!c}return N}("search tel url email datetime date month week time datetime-local number range color".split(" "))}
 | 
			
		||||
var f={},l=e.documentElement,E=e.createElement("modernizr"),j=E.style,h=e.createElement("input"),M=":)",O=Object.prototype.toString,q=" -webkit- -moz- -o- -ms- -khtml- ".split(" "),F="Webkit Moz O ms Khtml".split(" "),v={svg:"http://www.w3.org/2000/svg"},d={},N={},L={},P=[],w,Q=function(a){var b=document.createElement("style"),c=e.createElement("div");b.textContent=a+"{#modernizr{height:3px}}";(e.head||e.getElementsByTagName("head")[0]).appendChild(b);c.id="modernizr";l.appendChild(c);a=c.offsetHeight===
 | 
			
		||||
3;b.parentNode.removeChild(b);c.parentNode.removeChild(c);return!!a},o=function(){var a={select:"input",change:"input",submit:"form",reset:"form",error:"img",load:"img",abort:"img"};return function(b,c){c=c||document.createElement(a[b]||"div");b="on"+b;var k=b in c;if(!k){c.setAttribute||(c=document.createElement("div"));if(c.setAttribute&&c.removeAttribute){c.setAttribute(b,"");k=typeof c[b]=="function";if(typeof c[b]!="undefined")c[b]=u;c.removeAttribute(b)}}return k}}(),G={}.hasOwnProperty,R;R=
 | 
			
		||||
typeof G!=="undefined"&&typeof G.call!=="undefined"?function(a,b){return G.call(a,b)}:function(a,b){return b in a&&typeof a.constructor.prototype[b]==="undefined"};d.flexbox=function(){var a=e.createElement("div"),b=e.createElement("div");(function(k,g,r,x){g+=":";k.style.cssText=(g+q.join(r+";"+g)).slice(0,-g.length)+(x||"")})(a,"display","box","width:42px;padding:0;");b.style.cssText=q.join("box-flex:1;")+"width:10px;";a.appendChild(b);l.appendChild(a);var c=b.offsetWidth===42;a.removeChild(b);
 | 
			
		||||
l.removeChild(a);return c};d.canvas=function(){var a=e.createElement("canvas");return!!(a.getContext&&a.getContext("2d"))};d.canvastext=function(){return!!(f.canvas&&typeof e.createElement("canvas").getContext("2d").fillText=="function")};d.webgl=function(){var a=e.createElement("canvas");try{if(a.getContext("webgl"))return true}catch(b){}try{if(a.getContext("experimental-webgl"))return true}catch(c){}return false};d.touch=function(){return"ontouchstart"in i||Q("@media ("+q.join("touch-enabled),(")+
 | 
			
		||||
"modernizr)")};d.geolocation=function(){return!!navigator.geolocation};d.postmessage=function(){return!!i.postMessage};d.websqldatabase=function(){return!!i.openDatabase};d.indexedDB=function(){for(var a=-1,b=F.length;++a<b;){var c=F[a].toLowerCase();if(i[c+"_indexedDB"]||i[c+"IndexedDB"])return true}return false};d.hashchange=function(){return o("hashchange",i)&&(document.documentMode===u||document.documentMode>7)};d.history=function(){return!!(i.history&&history.pushState)};d.draganddrop=function(){return o("drag")&&
 | 
			
		||||
o("dragstart")&&o("dragenter")&&o("dragover")&&o("dragleave")&&o("dragend")&&o("drop")};d.websockets=function(){return"WebSocket"in i};d.rgba=function(){j.cssText="background-color:rgba(150,255,150,.5)";return s(j.backgroundColor,"rgba")};d.hsla=function(){j.cssText="background-color:hsla(120,40%,100%,.5)";return s(j.backgroundColor,"rgba")||s(j.backgroundColor,"hsla")};d.multiplebgs=function(){j.cssText="background:url(//:),url(//:),red url(//:)";return/(url\s*\(.*?){3}/.test(j.background)};d.backgroundsize=
 | 
			
		||||
function(){return n("backgroundSize")};d.borderimage=function(){return n("borderImage")};d.borderradius=function(){return n("borderRadius","",function(a){return s(a,"orderRadius")})};d.boxshadow=function(){return n("boxShadow")};d.textshadow=function(){return e.createElement("div").style.textShadow===""};d.opacity=function(){var a=q.join("opacity:.5;")+"";j.cssText=a;return s(j.opacity,"0.5")};d.cssanimations=function(){return n("animationName")};d.csscolumns=function(){return n("columnCount")};d.cssgradients=
 | 
			
		||||
function(){var a=("background-image:"+q.join("gradient(linear,left top,right bottom,from(#9f9),to(white));background-image:")+q.join("linear-gradient(left top,#9f9, white);background-image:")).slice(0,-17);j.cssText=a;return s(j.backgroundImage,"gradient")};d.cssreflections=function(){return n("boxReflect")};d.csstransforms=function(){return!!D(["transformProperty","WebkitTransform","MozTransform","OTransform","msTransform"])};d.csstransforms3d=function(){var a=!!D(["perspectiveProperty","WebkitPerspective",
 | 
			
		||||
"MozPerspective","OPerspective","msPerspective"]);if(a)a=Q("@media ("+q.join("transform-3d),(")+"modernizr)");return a};d.csstransitions=function(){return n("transitionProperty")};d.fontface=function(){var a,b=e.head||e.getElementsByTagName("head")[0]||l,c=e.createElement("style"),k=e.implementation||{hasFeature:function(){return false}};c.type="text/css";b.insertBefore(c,b.firstChild);a=c.sheet||c.styleSheet;b=k.hasFeature("CSS2","")?function(g){if(!(a&&g))return false;var r=false;try{a.insertRule(g,
 | 
			
		||||
0);r=!/unknown/i.test(a.cssRules[0].cssText);a.deleteRule(a.cssRules.length-1)}catch(x){}return r}:function(g){if(!(a&&g))return false;a.cssText=g;return a.cssText.length!==0&&!/unknown/i.test(a.cssText)&&a.cssText.replace(/\r+|\n+/g,"").indexOf(g.split(" ")[0])===0};f._fontfaceready=function(g){g(f.fontface)};return b('@font-face { font-family: "font"; src: "font.ttf"; }')};d.video=function(){var a=e.createElement("video"),b=!!a.canPlayType;if(b){b=new Boolean(b);b.ogg=a.canPlayType('video/ogg; codecs="theora"');
 | 
			
		||||
b.h264=a.canPlayType('video/mp4; codecs="avc1.42E01E"')||a.canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"');b.webm=a.canPlayType('video/webm; codecs="vp8, vorbis"')}return b};d.audio=function(){var a=e.createElement("audio"),b=!!a.canPlayType;if(b){b=new Boolean(b);b.ogg=a.canPlayType('audio/ogg; codecs="vorbis"');b.mp3=a.canPlayType("audio/mpeg;");b.wav=a.canPlayType('audio/wav; codecs="1"');b.m4a=a.canPlayType("audio/x-m4a;")||a.canPlayType("audio/aac;")}return b};d.localstorage=function(){try{return"localStorage"in
 | 
			
		||||
i&&i.localStorage!==null}catch(a){return false}};d.sessionstorage=function(){try{return"sessionStorage"in i&&i.sessionStorage!==null}catch(a){return false}};d.webWorkers=function(){return!!i.Worker};d.applicationcache=function(){return!!i.applicationCache};d.svg=function(){return!!e.createElementNS&&!!e.createElementNS(v.svg,"svg").createSVGRect};d.inlinesvg=function(){var a=document.createElement("div");a.innerHTML="<svg/>";return(a.firstChild&&a.firstChild.namespaceURI)==v.svg};d.smil=function(){return!!e.createElementNS&&
 | 
			
		||||
/SVG/.test(O.call(e.createElementNS(v.svg,"animate")))};d.svgclippaths=function(){return!!e.createElementNS&&/SVG/.test(O.call(e.createElementNS(v.svg,"clipPath")))};for(var H in d)if(R(d,H)){w=H.toLowerCase();f[w]=d[H]();P.push((f[w]?"":"no-")+w)}f.input||S();f.crosswindowmessaging=f.postmessage;f.historymanagement=f.history;f.addTest=function(a,b){a=a.toLowerCase();if(!f[a]){b=!!b();l.className+=" "+(b?"":"no-")+a;f[a]=b;return f}};j.cssText="";E=h=null;i.attachEvent&&function(){var a=e.createElement("div");
 | 
			
		||||
a.innerHTML="<elem></elem>";return a.childNodes.length!==1}()&&function(a,b){function c(p){for(var m=-1;++m<r;)p.createElement(g[m])}function k(p,m){for(var I=p.length,t=-1,y,J=[];++t<I;){y=p[t];m=y.media||m;J.push(k(y.imports,m));J.push(y.cssText)}return J.join("")}var g="abbr|article|aside|audio|canvas|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video".split("|"),r=g.length,x=RegExp("<(/*)(abbr|article|aside|audio|canvas|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video)",
 | 
			
		||||
"gi"),T=RegExp("\\b(abbr|article|aside|audio|canvas|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video)\\b(?!.*[;}])","gi"),z=b.createDocumentFragment(),A=b.documentElement,K=A.firstChild,B=b.createElement("style"),C=b.createElement("body");B.media="all";c(b);c(z);a.attachEvent("onbeforeprint",function(){for(var p=-1;++p<r;)for(var m=b.getElementsByTagName(g[p]),I=m.length,t=-1;++t<I;)if(m[t].className.indexOf("iepp_")<0)m[t].className+=" iepp_"+
 | 
			
		||||
g[p];K.insertBefore(B,K.firstChild);B.styleSheet.cssText=k(b.styleSheets,"all").replace(T,".iepp_$1");z.appendChild(b.body);A.appendChild(C);C.innerHTML=z.firstChild.innerHTML.replace(x,"<$1bdo")});a.attachEvent("onafterprint",function(){C.innerHTML="";A.removeChild(C);K.removeChild(B);A.appendChild(z.firstChild)})}(this,document);f._enableHTML5=true;f._version="1.6";l.className=l.className.replace(/\bno-js\b/,"")+" js";l.className+=" "+P.join(" ");return f}(this,this.document);
 | 
			
		||||
							
								
								
									
										3
									
								
								docs/public/js/mylibs/.gitignore
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								docs/public/js/mylibs/.gitignore
									
										
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -1,3 +0,0 @@
 | 
			
		|||
*
 | 
			
		||||
!.gitignore
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1,34 +0,0 @@
 | 
			
		|||
 | 
			
		||||
(function($){
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
})(this.jQuery);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
window.log = function(){
 | 
			
		||||
  log.history = log.history || [];   
 | 
			
		||||
  log.history.push(arguments);
 | 
			
		||||
  if(this.console){
 | 
			
		||||
    console.log( Array.prototype.slice.call(arguments) );
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
(function(doc){
 | 
			
		||||
  var write = doc.write;
 | 
			
		||||
  doc.write = function(q){ 
 | 
			
		||||
    log('document.write(): ',arguments); 
 | 
			
		||||
    if (/docwriteregexwhitelist/.test(q)) write.apply(doc,arguments);  
 | 
			
		||||
  };
 | 
			
		||||
})(document);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1,59 +0,0 @@
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
// call PROFILE.show() to show the profileViewer
 | 
			
		||||
 | 
			
		||||
var PROFILE = {
 | 
			
		||||
 | 
			
		||||
  init : function(bool) {
 | 
			
		||||
  
 | 
			
		||||
  	// define what objects, constructors and functions you want to profile
 | 
			
		||||
  	// documentation here: http://developer.yahoo.com/yui/profiler/
 | 
			
		||||
  	
 | 
			
		||||
  	YAHOO.tool.Profiler.registerObject("jQuery", jQuery, true);
 | 
			
		||||
  	
 | 
			
		||||
  	// the following would profile all methods within constructor's prototype
 | 
			
		||||
    // YAHOO.tool.Profiler.registerConstructor("Person");
 | 
			
		||||
  	
 | 
			
		||||
    // the following would profile the global function sayHi
 | 
			
		||||
    // YAHOO.tool.Profiler.registerFunction("sayHi", window); 
 | 
			
		||||
    
 | 
			
		||||
    // if true is passed into init(), F9 will bring up the profiler
 | 
			
		||||
    if (bool){
 | 
			
		||||
      $(document).keyup(function(e){
 | 
			
		||||
        if (e.keyCode === 120){ 
 | 
			
		||||
          PROFILE.show(); 
 | 
			
		||||
          $(document).unbind('keyup',arguments.callee); 
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  
 | 
			
		||||
  //When the showProfile button is clicked, use YUI Loader to get all required
 | 
			
		||||
  //dependencies and then show the profile:
 | 
			
		||||
  show : function() {
 | 
			
		||||
  
 | 
			
		||||
          
 | 
			
		||||
          
 | 
			
		||||
          var s = document.createElement('link');
 | 
			
		||||
          s.setAttribute('rel','stylesheet');      
 | 
			
		||||
          s.setAttribute('type','text/css');
 | 
			
		||||
          s.setAttribute('href','js/profiling/yahoo-profiling.css');
 | 
			
		||||
          document.body.appendChild(s);
 | 
			
		||||
          
 | 
			
		||||
	        YAHOO.util.Dom.addClass(document.body, 'yui-skin-sam');
 | 
			
		||||
 | 
			
		||||
      		//instantiate ProfilerViewer with desired options:
 | 
			
		||||
      		var pv = new YAHOO.widget.ProfilerViewer("", {
 | 
			
		||||
      			visible: true, //expand the viewer mmediately after instantiation
 | 
			
		||||
      			showChart: true,
 | 
			
		||||
      		  //	base:"../../build/",
 | 
			
		||||
      		  swfUrl: "js/profiling/charts.swf"
 | 
			
		||||
      		});
 | 
			
		||||
  	
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// check some global debug variable to see if we should be profiling..
 | 
			
		||||
if (true) { PROFILE.init(true) }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1,7 +0,0 @@
 | 
			
		|||
/*
 | 
			
		||||
Copyright (c) 2009, Yahoo! Inc. All rights reserved.
 | 
			
		||||
Code licensed under the BSD License:
 | 
			
		||||
http://developer.yahoo.net/yui/license.txt
 | 
			
		||||
version: 2.7.0
 | 
			
		||||
*/
 | 
			
		||||
.yui-skin-sam .yui-pv{background-color:#4a4a4a;font:arial;position:relative;width:99%;z-index:1000;margin-bottom:1em;overflow:hidden;}.yui-skin-sam .yui-pv .hd{background:url(http://yui.yahooapis.com/2.7.0/build/profilerviewer/assets/skins/sam/header_background.png) repeat-x;min-height:30px;overflow:hidden;zoom:1;padding:2px 0;}.yui-skin-sam .yui-pv .hd h4{padding:8px 10px;margin:0;font:bold 14px arial;color:#fff;}.yui-skin-sam .yui-pv .hd a{background:#3f6bc3;font:bold 11px arial;color:#fff;padding:4px;margin:3px 10px 0 0;border:1px solid #3f567d;cursor:pointer;display:block;float:right;}.yui-skin-sam .yui-pv .hd span{display:none;}.yui-skin-sam .yui-pv .hd span.yui-pv-busy{height:18px;width:18px;background:url(http://yui.yahooapis.com/2.7.0/build/profilerviewer/assets/skins/sam/wait.gif) no-repeat;overflow:hidden;display:block;float:right;margin:4px 10px 0 0;}.yui-skin-sam .yui-pv .hd:after,.yui-pv .bd:after,.yui-skin-sam .yui-pv-chartlegend dl:after{content:'.';visibility:hidden;clear:left;height:0;display:block;}.yui-skin-sam .yui-pv .bd{position:relative;zoom:1;overflow-x:auto;overflow-y:hidden;}.yui-skin-sam .yui-pv .yui-pv-table{padding:0 10px;margin:5px 0 10px 0;}.yui-skin-sam .yui-pv .yui-pv-table .yui-dt-bd td{color:#eeee5c;font:12px arial;}.yui-skin-sam .yui-pv .yui-pv-table tr.yui-dt-odd{background:#929292;}.yui-skin-sam .yui-pv .yui-pv-table tr.yui-dt-even{background:#58637a;}.yui-skin-sam .yui-pv .yui-pv-table tr.yui-dt-even td.yui-dt-asc,.yui-skin-sam .yui-pv .yui-pv-table tr.yui-dt-even td.yui-dt-desc{background:#384970;}.yui-skin-sam .yui-pv .yui-pv-table tr.yui-dt-odd td.yui-dt-asc,.yui-skin-sam .yui-pv .yui-pv-table tr.yui-dt-odd td.yui-dt-desc{background:#6F6E6E;}.yui-skin-sam .yui-pv .yui-pv-table .yui-dt-hd th{background-image:none;background:#2E2D2D;}.yui-skin-sam .yui-pv th.yui-dt-asc .yui-dt-liner{background:transparent url(http://yui.yahooapis.com/2.7.0/build/profilerviewer/assets/skins/sam/asc.gif) no-repeat scroll right center;}.yui-skin-sam .yui-pv th.yui-dt-desc .yui-dt-liner{background:transparent url(http://yui.yahooapis.com/2.7.0/build/profilerviewer/assets/skins/sam/desc.gif) no-repeat scroll right center;}.yui-skin-sam .yui-pv .yui-pv-table .yui-dt-hd th a{color:#fff;font:bold 12px arial;}.yui-skin-sam .yui-pv .yui-pv-table .yui-dt-hd th.yui-dt-asc,.yui-skin-sam .yui-pv .yui-pv-table .yui-dt-hd th.yui-dt-desc{background:#333;}.yui-skin-sam .yui-pv-chartcontainer{padding:0 10px;}.yui-skin-sam .yui-pv-chart{height:250px;clear:right;margin:5px 0 0 0;color:#fff;}.yui-skin-sam .yui-pv-chartlegend div{float:right;margin:0 0 0 10px;_width:250px;}.yui-skin-sam .yui-pv-chartlegend dl{border:1px solid #999;padding:.2em 0 .2em .5em;zoom:1;margin:5px 0;}.yui-skin-sam .yui-pv-chartlegend dt{float:left;display:block;height:.7em;width:.7em;padding:0;}.yui-skin-sam .yui-pv-chartlegend dd{float:left;display:block;color:#fff;margin:0 1em 0 .5em;padding:0;font:11px arial;}.yui-skin-sam .yui-pv-minimized{height:35px;}.yui-skin-sam .yui-pv-minimized .bd{top:-3000px;}.yui-skin-sam .yui-pv-minimized .hd a.yui-pv-refresh{display:none;}
 | 
			
		||||
							
								
								
									
										1028
									
								
								docs/public/js/profiling/yahoo-profiling.js
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										1028
									
								
								docs/public/js/profiling/yahoo-profiling.js
									
										
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										39
									
								
								docs/public/js/profiling/yahoo-profiling.min.js
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										39
									
								
								docs/public/js/profiling/yahoo-profiling.min.js
									
										
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| 
						 | 
				
			
			@ -1,26 +0,0 @@
 | 
			
		|||
/* Author: 
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1,5 +0,0 @@
 | 
			
		|||
# www.robotstxt.org/
 | 
			
		||||
# www.google.com/support/webmasters/bin/answer.py?hl=en&answer=156449
 | 
			
		||||
 | 
			
		||||
User-agent: *
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1,206 +0,0 @@
 | 
			
		|||
---
 | 
			
		||||
layout: default
 | 
			
		||||
title:  Storage
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
Having Ruby experience makes you hirable; but how can you stand out? You need to demonstrate your abilities. What better way than using Ruby and "the cloud" to store and serve your resume!
 | 
			
		||||
 | 
			
		||||
In this blog post you will learn to use <a href="http://github.com/fog/fog">fog</a> - the cloud computing library - to upload your resume to Amazon's <a href="http://aws.amazon.com/s3/">Simple Storage Service</a> (S3), Rackspace's <a href="http://www.rackspacecloud.com/cloud_hosting_products/files">CloudFiles</a> or Google's <a href="http://code.google.com/apis/storage/">Cloud Storage</a>.
 | 
			
		||||
 | 
			
		||||
Here's my out of date resume stored on <a href="http://geemus.s3.amazonaws.com/resume.html">S3</a>, <a href="http://c0023559.cdn2.cloudfiles.rackspacecloud.com/resume.html">CloudFiles</a> and <a href="https://geemus.storage.googleapis.com/resume.html">Google Storage</a>; programmatically stored in the cloud using this tutorial. NOTE: my boss would like me to add that I'm not currently looking for a new gig ;)
 | 
			
		||||
 | 
			
		||||
Check out those cloud-specific URLs! You could put all three in your job application, add the Ruby source for how you did it, and have your choice of Ruby jobs for being so awesome!
 | 
			
		||||
 | 
			
		||||
How? The all-clouds-in-one library of choice is <a href="https://github.com/fog/fog">fog</a>.
 | 
			
		||||
 | 
			
		||||
## Installing fog
 | 
			
		||||
 | 
			
		||||
fog is distributed as a RubyGem:
 | 
			
		||||
 | 
			
		||||
    gem install fog
 | 
			
		||||
 | 
			
		||||
Or add it in your application's Gemfile:
 | 
			
		||||
 | 
			
		||||
    gem "fog"
 | 
			
		||||
 | 
			
		||||
## Using Amazon S3 and fog
 | 
			
		||||
 | 
			
		||||
Sign up for an account <a href="http://aws-portal.amazon.com/gp/aws/developer/subscription/index.html?productCode=AmazonS3">here</a> and copy down your secret access key and access key id from <a href="http://aws-portal.amazon.com/gp/aws/developer/account/index.html?action=access-key">here</a>. We are about to get into the code samples, so be sure to fill in anything in ALL_CAPS with your own values!
 | 
			
		||||
 | 
			
		||||
First, create a connection with your new account:
 | 
			
		||||
 | 
			
		||||
    require 'rubygems'
 | 
			
		||||
    require 'fog'
 | 
			
		||||
 | 
			
		||||
    # create a connection
 | 
			
		||||
    connection = Fog::Storage.new({
 | 
			
		||||
      :provider                 => 'AWS',
 | 
			
		||||
      :aws_access_key_id        => YOUR_AWS_ACCESS_KEY_ID,
 | 
			
		||||
      :aws_secret_access_key    => YOUR_AWS_SECRET_ACCESS_KEY
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
    # First, a place to contain the glorious details
 | 
			
		||||
    directory = connection.directories.create(
 | 
			
		||||
      :key    => "fog-demo-#{Time.now.to_i}", # globally unique name
 | 
			
		||||
      :public => true
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    # list directories
 | 
			
		||||
    p connection.directories
 | 
			
		||||
 | 
			
		||||
    # upload that resume
 | 
			
		||||
    file = directory.files.create(
 | 
			
		||||
      :key    => 'resume.html',
 | 
			
		||||
      :body   => File.open("/path/to/my/resume.html"),
 | 
			
		||||
      :public => true
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
If you are anything like me, you will continually tweak your resume. Pushing updates is easy:
 | 
			
		||||
 | 
			
		||||
    file.body = File.open("/path/to/my/resume.html")
 | 
			
		||||
    file.save
 | 
			
		||||
 | 
			
		||||
As you can see, cloud storage files in fog are a lot like an ActiveRecord model. Attributes that can be changed and a `#save` method that creates or updates the stored file in the cloud.
 | 
			
		||||
 | 
			
		||||
But if it took you longer to realize the mistake you might not still have file around, but you've got options.
 | 
			
		||||
 | 
			
		||||
directory = connection.directories.get("proclamations1234567890")
 | 
			
		||||
 | 
			
		||||
    # get the resume file
 | 
			
		||||
    file = directory.files.get('resume.html')
 | 
			
		||||
    file.body = File.open("/path/to/my/resume.html")
 | 
			
		||||
    file.save
 | 
			
		||||
 | 
			
		||||
    # also, create(attributes) is just new(attributes).save, so you can also do:
 | 
			
		||||
    file = directory.files.new({
 | 
			
		||||
      :key    => 'resume.html',
 | 
			
		||||
      :body   => 'improvements',
 | 
			
		||||
      :public => true
 | 
			
		||||
    })
 | 
			
		||||
    file.save
 | 
			
		||||
 | 
			
		||||
## Backing up your files
 | 
			
		||||
 | 
			
		||||
Now you've got a bunch of files in S3: your resume, some code samples,
 | 
			
		||||
and maybe some pictures of your cat doing funny stuff. Since this is
 | 
			
		||||
all of vital importance, you need to back it up.
 | 
			
		||||
 | 
			
		||||
    # copy each file to local disk
 | 
			
		||||
    directory.files.each do |s3_file|
 | 
			
		||||
      File.open(s3_file.key, 'w') do |local_file|
 | 
			
		||||
        local_file.write(s3_file.body)
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
One caveat: it's way more efficient to do this:
 | 
			
		||||
 | 
			
		||||
    # do two things per file
 | 
			
		||||
    directory.files.each do |file|
 | 
			
		||||
      do_one_thing(file)
 | 
			
		||||
      do_another_thing(file)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
than it is to do this:
 | 
			
		||||
 | 
			
		||||
    # do two things per file
 | 
			
		||||
    directory.files.each do |file|
 | 
			
		||||
      do_one_thing(file)
 | 
			
		||||
    end.each do |file|
 | 
			
		||||
      do_another_thing(file)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
The reason is that the list of files might be large. Really
 | 
			
		||||
large. Eat-all-your-RAM-and-ask-for-more large. Therefore, every time
 | 
			
		||||
you say `files.each`, fog makes a fresh set of API calls to Amazon to
 | 
			
		||||
list the available files (Amazon's API returns a page at a time, so
 | 
			
		||||
fog works a page at a time in order to keep its memory requirements sane).
 | 
			
		||||
 | 
			
		||||
## Sending it out
 | 
			
		||||
 | 
			
		||||
Alright, so you (eventually) become satisfied enough to send it off, what is the URL endpoint to your resume?
 | 
			
		||||
 | 
			
		||||
    puts file.public_url
 | 
			
		||||
 | 
			
		||||
Pop that link in an email and you should be ready to cruise job ads and send your resume far and wide (Engine Yard is <a href="http://www.engineyard.com/company/careers/wanted-head-in-the-clouds-engineer">hiring</a>, so check us out!). Now you are set, unless you are interviewing for Google, or Rackspace... Both of these companies have their own cloud storage services, so using Amazon S3 might not be the foot in the door you hoped for.
 | 
			
		||||
 | 
			
		||||
More clouds? How much extra stuff will you have to do for these services!?! Hardly anything needs to change, you just have to pass slightly different credentials in, but I'm getting ahead of myself.
 | 
			
		||||
 | 
			
		||||
Check out the Amazon S3 Storage page for further details, <a href="/storage/aws.html">AWS Storage</a>.
 | 
			
		||||
 | 
			
		||||
## Google Cloud Storage
 | 
			
		||||
 | 
			
		||||
Sign up <a href="http://gs-signup-redirect.appspot.com/">here</a> and get your credentials <a href="https://storage.cloud.google.com/m">here</a> under the section "Interoperable Access".
 | 
			
		||||
 | 
			
		||||
    connection = Fog::Storage.new({
 | 
			
		||||
      :provider                         => 'Google',
 | 
			
		||||
      :google_storage_access_key_id     => YOUR_SECRET_ACCESS_KEY_ID,
 | 
			
		||||
      :google_storage_secret_access_key => YOUR_SECRET_ACCESS_KEY
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
## Rackspace CloudFiles
 | 
			
		||||
 | 
			
		||||
Rackspace has <a href="http://www.rackspacecloud.com/cloud_hosting_products/files">Cloud Files</a> and you can sign up <a href="https://www.rackspacecloud.com/signup">here</a> and get your credentials <a href="https://manage.rackspacecloud.com/APIAccess.do">here</a>.
 | 
			
		||||
 | 
			
		||||
    connection = Fog::Storage.new({
 | 
			
		||||
      :provider           => 'Rackspace',
 | 
			
		||||
      :rackspace_username => RACKSPACE_USERNAME,
 | 
			
		||||
      :rackspace_api_key  => RACKSPACE_API_KEY
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
If you work with the European cloud from Rackspace you have to add the following:
 | 
			
		||||
 | 
			
		||||
    :rackspace_auth_url => "lon.auth.api.rackspacecloud.com"
 | 
			
		||||
 | 
			
		||||
Then create, save, destroy as per fog-for-AWS. The `:public => true` option when creating directories (see above) is important for Rackspace; your folder and files won't be shared to Rackspace's CDN and hence your users without it.  Similarly the `:public => true` on files is important for AWS and Google or they will be private.
 | 
			
		||||
 | 
			
		||||
## Local Storage
 | 
			
		||||
 | 
			
		||||
While you are working out the kinks you might not want to do everything live though, ditto for while you are running tests, so you have a couple options to try before you buy.  First, you can use a local provider to store things in a directory on your machine.
 | 
			
		||||
 | 
			
		||||
    connection = Fog::Storage.new({
 | 
			
		||||
      :provider   => 'Local',
 | 
			
		||||
      :local_root => '~/fog'
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
## Mocking out Cloud Storage
 | 
			
		||||
 | 
			
		||||
Of course when you are testing or developing you can always just use the mocks (at least for AWS and Google, Rackspace still needs mocks implemented if you are looking for somewhere to contribute).  They emulate the behavior of the external systems without actually using them.  It is as simple as:
 | 
			
		||||
 | 
			
		||||
    Fog.mock!
 | 
			
		||||
    connection = Fog::Storage.new(config_hash)
 | 
			
		||||
 | 
			
		||||
## Cleaning up
 | 
			
		||||
 | 
			
		||||
Fog takes care of the rest so you can focus on your cover letter. And with the awesome cover letter and cloud delivered resume you are probably a shoe-in. So all that is left is to cleanup that leftover job hunt residue.
 | 
			
		||||
 | 
			
		||||
    file.destroy
 | 
			
		||||
    directory.destroy
 | 
			
		||||
 | 
			
		||||
## Checking if a file already exists
 | 
			
		||||
 | 
			
		||||
Sometimes you might want to find out some information about a file without retrieving the whole file. You can do that using 'head'.
 | 
			
		||||
 | 
			
		||||
    #returns nil if the file doesn't exist
 | 
			
		||||
    unless directory.files.head('resume.html')
 | 
			
		||||
       #do something, like creating the file
 | 
			
		||||
    end
 | 
			
		||||
    
 | 
			
		||||
    #returns a hash with the following data:
 | 
			
		||||
    # 'key' - Key for the object
 | 
			
		||||
    # 'Content-Length' - Size of object contents
 | 
			
		||||
    # 'Content-Type' - MIME type of object
 | 
			
		||||
    # 'ETag' - Etag of object
 | 
			
		||||
    # 'Last-Modified' - Last modified timestamp for object
 | 
			
		||||
    puts directory.files.head('resume.html')
 | 
			
		||||
 | 
			
		||||
## Summary
 | 
			
		||||
 | 
			
		||||
All done. Try out all the different options and let me know if you have any bugs or issues.  I also wrote up a more <a href="https://gist.github.com/710869">consolidated example as a script</a> that you can use for reference.
 | 
			
		||||
 | 
			
		||||
Bonus, note the `Fog.mock!` command. In your tests you can easily mock out calls to cloud providers.
 | 
			
		||||
 | 
			
		||||
Please let me know in the comments if you got a new Ruby job because you hosted your CV on 3 different Cloud Stores without getting your hands dirty.
 | 
			
		||||
 | 
			
		||||
Have questions or comments?  Hop into <a href="irc://irc.freenode.net/">#ruby-fog</a> on freenode, ping <a href="http://twitter.com/fog">@fog</a> or <a href="http://twitter.com/geemus">@geemus</a>.
 | 
			
		||||
 | 
			
		||||
And please always remember that I accept high fives and contributions!
 | 
			
		||||
| 
						 | 
				
			
			@ -1,155 +0,0 @@
 | 
			
		|||
require "rake"
 | 
			
		||||
require "rake/tasklib"
 | 
			
		||||
 | 
			
		||||
module Fog
 | 
			
		||||
  module Rake
 | 
			
		||||
    class DocumentationTask < ::Rake::TaskLib
 | 
			
		||||
      def initialize
 | 
			
		||||
        task :docs do
 | 
			
		||||
          Rake::Task[:supported_services_docs].invoke
 | 
			
		||||
          Rake::Task[:upload_fog_io].invoke
 | 
			
		||||
          Rake::Task[:upload_yardoc].invoke
 | 
			
		||||
 | 
			
		||||
          # connect to storage provider
 | 
			
		||||
          Fog.credential = :geemus
 | 
			
		||||
          storage = Fog::Storage.new(:provider => 'AWS')
 | 
			
		||||
          directory = storage.directories.new(:key => 'fog.io')
 | 
			
		||||
          # write base index with redirect to new version
 | 
			
		||||
          directory.files.create(
 | 
			
		||||
            :body         => redirecter('latest'),
 | 
			
		||||
            :content_type => 'text/html',
 | 
			
		||||
            :key          => 'index.html',
 | 
			
		||||
            :public       => true
 | 
			
		||||
          )
 | 
			
		||||
 | 
			
		||||
          Formatador.display_line
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        task :supported_services_docs do
 | 
			
		||||
          support, shared = {}, []
 | 
			
		||||
          for key, values in Fog.services
 | 
			
		||||
            unless values.length == 1
 | 
			
		||||
              shared |= [key]
 | 
			
		||||
              values.each do |value|
 | 
			
		||||
                support[value] ||= {}
 | 
			
		||||
                support[value][key] = '+'
 | 
			
		||||
              end
 | 
			
		||||
            else
 | 
			
		||||
              value = values.first
 | 
			
		||||
              support[value] ||= {}
 | 
			
		||||
              support[value][:other] ||= []
 | 
			
		||||
              support[value][:other] << key
 | 
			
		||||
            end
 | 
			
		||||
          end
 | 
			
		||||
          shared.sort! {|x,y| x.to_s <=> y.to_s}
 | 
			
		||||
          columns = [:provider] + shared + [:other]
 | 
			
		||||
          data = []
 | 
			
		||||
          for key in support.keys.sort {|x,y| x.to_s <=> y.to_s}
 | 
			
		||||
            data << { :provider => key }.merge!(support[key])
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
          table = ''
 | 
			
		||||
          table << "<table border='1'>\n"
 | 
			
		||||
 | 
			
		||||
          table << "  <tr>"
 | 
			
		||||
          for column in columns
 | 
			
		||||
            table << "<th>#{column}</th>"
 | 
			
		||||
          end
 | 
			
		||||
          table << "</tr>\n"
 | 
			
		||||
 | 
			
		||||
          for datum in data
 | 
			
		||||
            table << "  <tr>"
 | 
			
		||||
            for column in columns
 | 
			
		||||
              if value = datum[column]
 | 
			
		||||
                case value
 | 
			
		||||
                when Array
 | 
			
		||||
                  table << "<td>#{value.join(', ')}</td>"
 | 
			
		||||
                when '+'
 | 
			
		||||
                  table << "<td style='text-align: center;'>#{value}</td>"
 | 
			
		||||
                else
 | 
			
		||||
                  table << "<th>#{value}</th>"
 | 
			
		||||
                end
 | 
			
		||||
              else
 | 
			
		||||
                table << "<td></td>"
 | 
			
		||||
              end
 | 
			
		||||
            end
 | 
			
		||||
            table << "</tr>\n"
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
          table << "</table>\n"
 | 
			
		||||
 | 
			
		||||
          File.open('docs/about/supported_services.markdown', 'w') do |file|
 | 
			
		||||
            file.puts <<-METADATA
 | 
			
		||||
---
 | 
			
		||||
layout: default
 | 
			
		||||
title:  Supported Services
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
            METADATA
 | 
			
		||||
            file.puts(table)
 | 
			
		||||
          end
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        desc "Builds the fog.io site content locally"
 | 
			
		||||
        task :build_fog_io do
 | 
			
		||||
          sh "jekyll docs docs/_site"
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        task :upload_fog_io => :build_fog_io do
 | 
			
		||||
          # connect to storage provider
 | 
			
		||||
          Fog.credential = :geemus
 | 
			
		||||
          storage = Fog::Storage.new(:provider => 'AWS')
 | 
			
		||||
          directory = storage.directories.new(:key => 'fog.io')
 | 
			
		||||
 | 
			
		||||
          # write web page files to versioned 'folder'
 | 
			
		||||
          for file_path in Dir.glob('docs/_site/**/*')
 | 
			
		||||
            next if File.directory?(file_path)
 | 
			
		||||
            file_name = file_path.gsub('docs/_site/', '')
 | 
			
		||||
            key = '' << version << '/' << file_name
 | 
			
		||||
            Formatador.redisplay(' ' * 128)
 | 
			
		||||
            Formatador.redisplay("Uploading [bold]#{key}[/]")
 | 
			
		||||
            if File.extname(file_name) == '.html'
 | 
			
		||||
              # rewrite links with version
 | 
			
		||||
              body = File.read(file_path)
 | 
			
		||||
              body.gsub!(/vX.Y.Z/, 'v' << version)
 | 
			
		||||
              body.gsub!(/='\//, %{='/} << version << '/')
 | 
			
		||||
              body.gsub!(/="\//, %{="/} << version << '/')
 | 
			
		||||
              content_type = 'text/html'
 | 
			
		||||
              directory.files.create(
 | 
			
		||||
                :body         => redirecter(key),
 | 
			
		||||
                :content_type => 'text/html',
 | 
			
		||||
                :key          => 'latest/' << file_name,
 | 
			
		||||
                :public       => true
 | 
			
		||||
              )
 | 
			
		||||
            else
 | 
			
		||||
              body = File.open(file_path)
 | 
			
		||||
              content_type = nil # leave it up to mime-types
 | 
			
		||||
            end
 | 
			
		||||
            directory.files.create(
 | 
			
		||||
              :body         => body,
 | 
			
		||||
              :content_type => content_type,
 | 
			
		||||
              :key          => key,
 | 
			
		||||
              :public       => true
 | 
			
		||||
            )
 | 
			
		||||
          end
 | 
			
		||||
          Formatador.redisplay(' ' * 128)
 | 
			
		||||
          Formatador.redisplay("Uploaded docs/_site\n")
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        def redirecter(path)
 | 
			
		||||
          redirecter = <<-HTML
 | 
			
		||||
<!doctype html>
 | 
			
		||||
<head>
 | 
			
		||||
<title>fog</title>
 | 
			
		||||
<meta http-equiv="REFRESH" content="0;url=http://fog.io/#{path}">
 | 
			
		||||
</head>
 | 
			
		||||
<body>
 | 
			
		||||
  <a href="http://fog.io/#{path}">redirecting to lastest (#{path})</a>
 | 
			
		||||
</body>
 | 
			
		||||
</html>
 | 
			
		||||
          HTML
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue