<commit_before>import Debug from 'debug';
import intree from './intree';
import taskcluster from 'taskcluster-client';
import slugid from 'slugid';
import yaml from 'js-yaml';
import _ from 'lodash';

let debug = Debug('taskcluster-github');
let worker = module.exports = {};

const INSPECTOR_URL = 'https://tools.taskcluster.net/task-graph-inspector/#';

/**
 * If a .taskcluster.yml exists, attempt to turn it into a taskcluster
 * graph config, and submit it to the scheduler.
 **/
worker.webHookHandler = async function(message, context) {
  // We must attempt to convert the sanitized fields back to normal here.
  // Further discussion of how to deal with this cleanly is in
  // https://github.com/taskcluster/taskcluster-github/issues/52
  organization = organization.replace(/%/g, '.');
  repository = repository.replace(/%/g, '.');

  debug('handling webhook: ', message);
  let repoconf = undefined;

  // Try to fetch a .taskcluster.yml file for every request
  try {
    repoconf = new Buffer(await context.github.repos.getContent({
      user: organization,
      repo: repository,
      path: '.taskcluster.yml',
      ref: message.payload.details['event.head.sha'],
    }), 'base64').toString();
  } catch (e) {
    if (e.code === 404) {
      debug(`${organization}/${repository} has no '.taskcluster.yml'. Skipping.`);
      return;
    }
    if (_.endsWith(e.message, '\n\n') && e.message.length > 10000) {
      // We kept getting full html 500/400 pages from github in the logs.
      // I consider this to be a hard-to-fix bug in octokat, so let's make
      // the logs usable for now and try to fix this later. It's a relatively
      // rare occurence.
      debug('Detected an extremeley long error. Truncating!');
      e.message = _.join(_.take(e.message, 100).concat('...'), '');
      e.stack = e.stack.split('\n\n')[1] || e.stack;
    }
    throw e;
  }

  // Check if this is meant to be built by tc-github at all.
  // This is a bit of a hack, but is needed for bug 1274077 for now
  let c = yaml.safeLoad(repoconf);
  c.tasks = (c.tasks || []).filter((task) => _.has(task, 'extra.github'));
  if (c.tasks.length === 0) {
    debug('Skipping tasks because no task with "extra.github" exists!');
    debug(`Repository: ${organization}/${repository}`);
    return;
  }

  // Decide if a user has permissions to run tasks.
  let login = message.payload.details['event.head.user.login'];
  let isCollaborator = false;

  if (login === organization) {
    isCollaborator = true;
  }

  if (!isCollaborator) {
    // If the user is in the org, we consider them
    // qualified to trigger any job in that org.
    try {
      github.orgs.checkMembership({
        org: organization,
        user: login,
      });
      isCollaborator = true;
    } catch (e) {
      if (e.code == 404) {
        // Only a 404 error means the user isn't a member
        // anything else should just throw like normal
      } else {
        throw e;
      }
    }
  }

  if (!isCollaborator) {
    // GithubAPI's collaborator check returns an error if a user isn't
    // listed as a collaborator.
    try {
      await context.github.repos.checkCollaborator({
        user: organization,
        repo: repository,
        collabuser: login,
      });
      // No error, the user is a collaborator
      isCollaborator = true;
    } catch (e) {
      if (e.code == 404) {
        // Only a 404 error means the user isn't a collaborator
        // anything else should just throw like normal
      } else {
        throw e;
      }
    }
  }

  // If all of the collaborator checks fail, we should post to the commit
  // and ignore the request
  if (!isCollaborator) {
    let msg = `@${login} does not have permission to trigger tasks.`;
    debug(`${login} does not have permissions for ${organization}/${repository}. Skipping.`);
    await context.github.repos.createCommitComment({
      user: organization,
      repo: repository,
      sha: message.payload.details['event.head.sha'],
      body: 'TaskCluster: ' + msg,
    });
  }

  // Now we can try processing the config and kicking off a task.
  try {
    let graphConfig = intree({
      config: repoconf,
      payload: message.payload,
      validator: context.validator,
      schema: 'http://schemas.taskcluster.net/github/v1/taskcluster-github-config.json#',
    });
    if (graphConfig.tasks.length) {
      let graph = await context.scheduler.createTaskGraph(slugid.nice(), graphConfig);
      // On pushes, leave a comment on the commit
      if (message.payload.details['event.type'] == 'push') {
        await context.github.repos.createCommitComment({
          user: organization,
          repo: repository,
          sha: message.payload.details['event.head.sha'],
          body: 'TaskCluster: ' + INSPECTOR_URL + graph.status.taskGraphId + '/',
        });
      }
    } else {
      debug('intree config compiled with zero tasks. Skipping');
    }
  } catch (e) {
    let errorMessage = e.message;
    let errorBody = e.errors || e.body.error;
    // Let's prettify any objects
    if (typeof errorBody == 'object') {
      errorBody = JSON.stringify(errorBody, null, 4);
    }
    // Warn the user know that there was a problem processing their
    // config file with a comment.
    await context.github.repos.createCommitComment({
      user: organization,
      repo: repository,
      sha: message.payload.details['event.head.sha'],
      body: 'Submitting the task to TaskCluster failed. ' + errorMessage
      + 'Details:\n\n```js\n' +  errorBody + '\n```',
    });
    throw e;
  }
};

/**
 * Post updates to GitHub, when the status of a task changes.
 * TaskCluster States: http://docs.taskcluster.net/queue/exchanges/
 * GitHub Statuses: https://developer.github.com/v3/repos/statuses/
 **/
worker.graphStateChangeHandler = async function(message, context) {
  let statusMapping = {
    running:  'pending',
    blocked:  'failure',
    finished: 'success',
  };
  debug('handling state change for message: ', message);
  let route = message.routes[0].split('.');
  try {
    await context.github.repos.createStatus({
      user: route[0],
      repo: route[1],
      sha: route[2],
      state:        StatusMapping[message.payload.status.state],
      target_url:   INSPECTOR_URL + message.payload.status.taskGraphId + '/',
      description:  'TaskGraph: ' + message.payload.status.state,
      context:      'Taskcluster',
    });
  } catch (e) {
    debug(`Failed to update status: ${route[0]}/${route[1]}@${route[2]}`);
    throw e;
  }
};

<commit_msg>Fix sed-based bug<commit_after>import Debug from 'debug';
import intree from './intree';
import taskcluster from 'taskcluster-client';
import slugid from 'slugid';
import yaml from 'js-yaml';
import _ from 'lodash';

let debug = Debug('taskcluster-github');
let worker = module.exports = {};

const INSPECTOR_URL = 'https://tools.taskcluster.net/task-graph-inspector/#';

/**
 * If a .taskcluster.yml exists, attempt to turn it into a taskcluster
 * graph config, and submit it to the scheduler.
 **/
worker.webHookHandler = async function(message, context) {
  // We must attempt to convert the sanitized fields back to normal here.
  // Further discussion of how to deal with this cleanly is in
  // https://github.com/taskcluster/taskcluster-github/issues/52
  organization = message.payload.organization.replace(/%/g, '.');
  repository = message.payload.repository.replace(/%/g, '.');

  debug('handling webhook: ', message);
  let repoconf = undefined;

  // Try to fetch a .taskcluster.yml file for every request
  try {
    repoconf = new Buffer(await context.github.repos.getContent({
      user: organization,
      repo: repository,
      path: '.taskcluster.yml',
      ref: message.payload.details['event.head.sha'],
    }), 'base64').toString();
  } catch (e) {
    if (e.code === 404) {
      debug(`${organization}/${repository} has no '.taskcluster.yml'. Skipping.`);
      return;
    }
    if (_.endsWith(e.message, '\n\n') && e.message.length > 10000) {
      // We kept getting full html 500/400 pages from github in the logs.
      // I consider this to be a hard-to-fix bug in octokat, so let's make
      // the logs usable for now and try to fix this later. It's a relatively
      // rare occurence.
      debug('Detected an extremeley long error. Truncating!');
      e.message = _.join(_.take(e.message, 100).concat('...'), '');
      e.stack = e.stack.split('\n\n')[1] || e.stack;
    }
    throw e;
  }

  // Check if this is meant to be built by tc-github at all.
  // This is a bit of a hack, but is needed for bug 1274077 for now
  let c = yaml.safeLoad(repoconf);
  c.tasks = (c.tasks || []).filter((task) => _.has(task, 'extra.github'));
  if (c.tasks.length === 0) {
    debug('Skipping tasks because no task with "extra.github" exists!');
    debug(`Repository: ${organization}/${repository}`);
    return;
  }

  // Decide if a user has permissions to run tasks.
  let login = message.payload.details['event.head.user.login'];
  let isCollaborator = false;

  if (login === organization) {
    isCollaborator = true;
  }

  if (!isCollaborator) {
    // If the user is in the org, we consider them
    // qualified to trigger any job in that org.
    try {
      github.orgs.checkMembership({
        org: organization,
        user: login,
      });
      isCollaborator = true;
    } catch (e) {
      if (e.code == 404) {
        // Only a 404 error means the user isn't a member
        // anything else should just throw like normal
      } else {
        throw e;
      }
    }
  }

  if (!isCollaborator) {
    // GithubAPI's collaborator check returns an error if a user isn't
    // listed as a collaborator.
    try {
      await context.github.repos.checkCollaborator({
        user: organization,
        repo: repository,
        collabuser: login,
      });
      // No error, the user is a collaborator
      isCollaborator = true;
    } catch (e) {
      if (e.code == 404) {
        // Only a 404 error means the user isn't a collaborator
        // anything else should just throw like normal
      } else {
        throw e;
      }
    }
  }

  // If all of the collaborator checks fail, we should post to the commit
  // and ignore the request
  if (!isCollaborator) {
    let msg = `@${login} does not have permission to trigger tasks.`;
    debug(`${login} does not have permissions for ${organization}/${repository}. Skipping.`);
    await context.github.repos.createCommitComment({
      user: organization,
      repo: repository,
      sha: message.payload.details['event.head.sha'],
      body: 'TaskCluster: ' + msg,
    });
  }

  // Now we can try processing the config and kicking off a task.
  try {
    let graphConfig = intree({
      config: repoconf,
      payload: message.payload,
      validator: context.validator,
      schema: 'http://schemas.taskcluster.net/github/v1/taskcluster-github-config.json#',
    });
    if (graphConfig.tasks.length) {
      let graph = await context.scheduler.createTaskGraph(slugid.nice(), graphConfig);
      // On pushes, leave a comment on the commit
      if (message.payload.details['event.type'] == 'push') {
        await context.github.repos.createCommitComment({
          user: organization,
          repo: repository,
          sha: message.payload.details['event.head.sha'],
          body: 'TaskCluster: ' + INSPECTOR_URL + graph.status.taskGraphId + '/',
        });
      }
    } else {
      debug('intree config compiled with zero tasks. Skipping');
    }
  } catch (e) {
    let errorMessage = e.message;
    let errorBody = e.errors || e.body.error;
    // Let's prettify any objects
    if (typeof errorBody == 'object') {
      errorBody = JSON.stringify(errorBody, null, 4);
    }
    // Warn the user know that there was a problem processing their
    // config file with a comment.
    await context.github.repos.createCommitComment({
      user: organization,
      repo: repository,
      sha: message.payload.details['event.head.sha'],
      body: 'Submitting the task to TaskCluster failed. ' + errorMessage
      + 'Details:\n\n```js\n' +  errorBody + '\n```',
    });
    throw e;
  }
};

/**
 * Post updates to GitHub, when the status of a task changes.
 * TaskCluster States: http://docs.taskcluster.net/queue/exchanges/
 * GitHub Statuses: https://developer.github.com/v3/repos/statuses/
 **/
worker.graphStateChangeHandler = async function(message, context) {
  let statusMapping = {
    running:  'pending',
    blocked:  'failure',
    finished: 'success',
  };
  debug('handling state change for message: ', message);
  let route = message.routes[0].split('.');
  try {
    await context.github.repos.createStatus({
      user: route[0],
      repo: route[1],
      sha: route[2],
      state:        StatusMapping[message.payload.status.state],
      target_url:   INSPECTOR_URL + message.payload.status.taskGraphId + '/',
      description:  'TaskGraph: ' + message.payload.status.state,
      context:      'Taskcluster',
    });
  } catch (e) {
    debug(`Failed to update status: ${route[0]}/${route[1]}@${route[2]}`);
    throw e;
  }
};

<|endoftext|>


<commit_before>/**
 * Copyright (c) 2014 and beyond Dwayne Charrington
 * Email: dwaynecharrington (at) gmail (dot) com
 * Twitter: abolitionof_
 * Licensed under MIT
 * @author Dwayne Charrington
 * @version 1.0
 */

(function($, window, document, History, undefined) {

    // Events trigger

    // While loading: wpAjax.loading: (event, url)
    // If failed: wpAjax.failed: (event, url)
    // Content loaded: wpAjax.loaded: (event, data, url)
    // Content loaded and populated: wpAjax.complete: (event, contentEl)

    /*
        Example:

        //To configure wpAjax:
        wpAjax.configure({
            content: "#content" // Element with our content which will be AJAX''d out
        });

        // Call this from within a click event
        wpAjax.trigger("http://www.someurl.com");

        // Request is currently happening (with current URL and new URL)
        $(document).on("wpAjax.loading", function(event) {
            // Methods are;
            // event.previousUrl
            // event.previousSlug
            // event.previousID
            // event.url
            // event.slug
            // event.ID
        });

        // All data has loaded
        $(document).on("wpAjax.loaded", function(event) {
            // Methods are;
            // event.previousUrl
            // event.previousSlug
            // event.previousID
            // event.content
            // event.url
            // event.slug
            // event.ID
        });

        $(document).on("wpAjax.failed", function(event) {
            // Methods are;
            // event.url
        });

        // All data has been populated the content element returned
        $(document).on("wpAjax.complete", function(event) {
            // Methods are;
            // event.contentEl
            // event.url
            // event.slug
            // event.ID
        });
    */

    var currentRequest = null,
         previousUrl = "",
         previousSlug = "",
         previousID = 0,
         requestCount = 0;

    // Main WP Ajax object
    var wpAjax = {};

    // Options
    var settings = {
            content: '#content',      // This is our container
            cacheRequests: true,  // Use HTML5 localStorage to cache pages?
            cacheExpiry: 1,          // Time in hours cached items should be cached for
            waitForImages: true,   // Wait for images to load before loading a page?
            debug: false,              // Debug mode shows console messages if true
            testMode: false           // Modifies certain methods so we can test them
        },
        o = settings;

    // These two elements never disappear and are always consistent
    var $body    = $("body");
    var $wpvars = $("wpvars");
    var $content = $(o.content);

    // Statechange when the URL changes, we roll
    $(window).off("statechange").on("statechange", function() {
        var State = History.getState();

        log("Event.statechange: HTML5 History statechange event trigger with URL: "+State.url);

        if (previousUrl !== State.url) {
            log("Event.statechange: Calling the wpAjax.loadPage function with State.url as its parameter");
            wpAjax.loadPage(State.url);
        } else {
            log("Event.statechange: User is already on the requested page to load. No request will be made.");
        }
    });

    // Allows us to configure wpAjax
    wpAjax.configure = function(options) {
        log("configure: Setting options for Wpajax");
        $.extend(settings, options);
        return this;
    };

    // Return the configuration object
    wpAjax.getConfiguration = function() {
        return settings;
    };

    // Helper function for checking the current URL
    wpAjax.getCurrentUrl = function() {
        log("getCurrentUrl: Getting the current browser address URL");
        return window.location.href;
    };

    // Get all vars supplied via the URL
    wpAjax.getPluginUrlVars = function() {
        var classes    = $body.attr("class");
        var returnObj = {};

        if (classes) {
            var classesArr = classes.split(" ");

            for (var i = 0, len = classesArr.length; i < len; ++i) {
                var pointer = classesArr[i];
            }
        }
    };

    // Trigger a page load
    wpAjax.trigger = function(url) {
        log("trigger: Calling History.pushState which will trigger a statechange");

        // Store current URL as the previous URL
        previousUrl = wpAjax.getCurrentUrl();

        wpAjax.getTitle(url, function(title) {
            History.pushState({}, title, url);
        });
    };

    // Have we reached our page limit
    wpAjax.pageLimitReached = function() {
        return (wpvars.max == wpvars.paged);
    }

    // What is the current page we are on
    wpAjax.getCurrentPageNumber = function() {
        return wpvars.paged;
    }

    // Get the maximum number of pages in our results
    wpAjax.getMaxPages = function() {
        return wpvars.max;
    }

    // Load page function
    wpAjax.loadPage = function(url) {

        log("loadPage: No other request is taking place, we are good to go");

        if (!o.testMode) {
            // Apply a loading class to the body
            $body.addClass("loading-page");

            var loadingEvent = jQuery.Event("wpAjax.loading", {
                previousUrl: previousUrl,
                previousSlug: previousSlug,
                previousID: previousID,
                url: url
            });

            // Trigger loading event
            $(document).trigger(loadingEvent);

            // Before content is loaded in, fade out the old content
            wpAjax.fadeOutContent(function() {

               // Perform our AJAX request
                wpAjax.doRequest(url, function(data) {
                    wpAjax.processRequest(data, url);
                }, function() {

                    if (!o.testMode) {
                        wpAjax.fadeInContent();

                        log("loadPage: Called doRequest and the request failed. Throwing a failed event on document");

                        var failedEvent = jQuery.Event("wpAjax.failed", {
                            url: url
                        });

                        // Trigger failed event
                        $(document).trigger(failedEvent);
                    }
                });

            });

            log("loadPage: Loading class applied to body, loading event fired and content element faded out");
        }

    };

    // Fade out the content area
    wpAjax.fadeOutContent = function(callback) {
        log("fadeOutContent: Animating content element out");

        if (arguments.length == 0) callback = function() {};

        $content.animate({opacity:0}, 800, callback);
    };

    // Fade in the content area
    wpAjax.fadeInContent = function(callback) {
        log("fadeInContent: Animating content element in");

        if (arguments.length == 0) callback = function() {};

        $content.animate({opacity:1}, 800, callback);
    };

    // Performs an AJAX request to get the page title
    // Also has the advantage of pre-fetching the page
    // for us as well.
    wpAjax.getTitle = function(url, callback) {
        var title = "";

        log("getTitle: Calling wpAjax.doRequest now to get the title");

        wpAjax.doRequest(url, function(data) {
            title = $(data).filter("title").text();
            log("getTitle: doRequest AJAX call successful. Title returned: "+title+" ");

            if ($.isFunction(callback)) {
                callback(title);
            }
        }, function() {
            if ($.isFunction(callback)) {
                callback(title);
            }
        });
    };

    // Handles performing the page load request
    // Leaves checking for other requests and validity to other functions
    wpAjax.doRequest = function(url, success, error) {

        log("doRequest: About to perform an AJAX call");

        // Do the fetching and stuff...
        currentRequest = $.ajax({
            url: url,
            localCache: o.cacheRequests,
            cacheTTL: o.cacheExpiry,
            type: 'GET',
            dataType: 'html',
            requestCount: ++requestCount,
            beforeSend: function() {
                // Check if we have a promise and cancel any current requests
                if (currentRequest !== null) {
                    currentRequest.abort();
                }
            },
            success: function(response, textStatus, jqXHR) {
                log("doRequest: AJAX success callback");
                if (requestCount !== this.requestCount) return;
                success(response, textStatus, jqXHR);
            },
            error: function(jqXHR, textStatus, errorThrown) {
                log("doRequest: AJAX error callback");
                if ($.isFunction(error)) {
                    error(jqXHR, textStatus, errorThrown);
                }
            }
        });

    };

    // Once our AJAX request is done, this function is called
    // Which allows us to process the response
    wpAjax.processRequest = function(data, url) {
        var _html = $(data);

        if (!o.testMode) {
            var _content = _html.find(o.content).html();
            var _wpvars = _html.find("#wpvars").html();
        } else {
            var _content = _html.find("body").html();
        }

        log("processRequest: Processing the data returned by a successful AJAX call");

        // Do we have content?
        if (_content && _content.length) {

            if (!o.testMode) {
                // Get latest version of WP Vars object
                $("#wpvars").remove();

                var s = document.createElement("script");
                s.id = "wpvars";
                s.type = "text/javascript";
                s.text = _wpvars;
                $("body").append(s);
            }

            var loadedEvent = jQuery.Event("wpAjax.loaded", {
                content: data,
                url: url
            });

             // AJAX load finished fire a loaded event with the data
             $(document).trigger(loadedEvent);

            log("processRequest: Content found from the AJAX request, determining what to do with it");

            // We want to wait for images to load before proceeding
            if (o.waitForImages) {

                log("processRequest Wait for images option is enabled, finding images");

                // We have images to preload
                if ($(_content).find("img").length) {

                    log("processRequest: We found images. Waiting for all images in the returned data to preload");

                    // Populate the content element
                    wpAjax.populateContent(_content, function(contentEl) {

                        log("processRequest: Populated the content element with content, about to preload iamges");

                        // Wait for any newly populated images to load
                        contentEl.waitForImages(function() {

                            log("processRequest: All images in AJAX loaded content have preloaded");

                            // Replace body classes with those of the loaded body classes
                            $body.attr("class",_html.filter("body").attr("class"));

                            var completeEvent = jQuery.Event("wpAjax.complete", {
                                contentEl: contentEl
                            });

                            // All content has been populated, assume we've succeeded
                            $(document).trigger(completeEvent);

                        });

                    });

                } else {
                    // Populate the content element
                    wpAjax.populateContent(_content, function(contentEl) {

                        log("processRequest: Requested AJAX content has been added to the content element and classes changed");

                        // Replace body classes with those of the loaded body classes
                        $body.attr("class", _html.filter("body").attr("class"));

                            var completeEvent = jQuery.Event("wpAjax.complete", {
                                contentEl: contentEl
                            });

                            // All content has been populated, assume we've succeeded
                            $(document).trigger(completeEvent);

                    });
                }

            } else {
                // Populate the content element
                wpAjax.populateContent(_content, function(contentEl) {

                    log("processRequest: Requested AJAX content has been added to the content element and classes changed");

                    // Replace body classes with those of the loaded body classes
                    $body.attr("class",data.filter("body").attr("class"));

                            var completeEvent = jQuery.Event("wpAjax.complete", {
                                contentEl: contentEl
                            });

                            // All content has been populated, assume we've succeeded
                            $(document).trigger(completeEvent);
                });
            }

            // Fade in the content DIV now we've done what we've wanted with it
            wpAjax.fadeInContent();

        } else {
            log("processRequest: Returned AJAX content is empty. Could be a problem server-side.");
        }
    };

    // Populates the appropriate content DIV with our
    // load content from the AJAX request (if successful)
    wpAjax.populateContent = function(content, callback) {
        log("populateContent: About to populate the content element with returned HTML");

        if (!o.testMode) {
            // Populate the content element
            $content.html(content);
        }

        // If we have a callback function
        if ($.isFunction(callback)) {
            log("populateContent: We've added in the content, calling the callback function with the element as an argument");
            callback($content);
        }
    };

    // Console log wrapper checks if debugging is on
    function log(msg) {
        if (o.debug) {
            console.log(msg);
        }
    }

    // Expose our method to the world
    window.wpAjax = wpAjax;

})(jQuery, window, window.document, window.History);

// Regex selector for jQuery: http://james.padolsey.com/javascript/regex-selector-for-jquery/
(function($, undefined) {

    jQuery.expr[':'].regex = function(elem, index, match) {
        var matchParams = match[3].split(','),
            validLabels = /^(data|css):/,
            attr = {
                method: matchParams[0].match(validLabels) ?
                            matchParams[0].split(':')[0] : 'attr',
                property: matchParams.shift().replace(validLabels,'')
            },
            regexFlags = 'ig',
            regex = new RegExp(matchParams.join('').replace(/^\s+|\s+$/g,''), regexFlags);
        return regex.test(jQuery(elem)[attr.method](attr.property));
    };

})(jQuery);

(function($, undefined) {

    // github.com/paulirish/jquery-ajax-localstorage-cache
    // dependent on Modernizr's localStorage test
    $.ajaxPrefilter( function( options, originalOptions, jqXHR ) {

      // Modernizr.localstorage, version 3 12/12/13
      function hasLocalStorage() {
        var mod = 'modernizr';
        try {
          localStorage.setItem(mod, mod);
          localStorage.removeItem(mod);
          return true;
        } catch(e) {
          return false;
        }
      }

      // Cache it ?
      if ( !hasLocalStorage() || !options.localCache ) return;

      var hourstl = options.cacheTTL || 5;

      var cacheKey = options.cacheKey ||
                     options.url.replace( /jQuery.*/,'' ) + options.type + (options.data || '');

      // isCacheValid is a function to validate cache
      if ( options.isCacheValid &&  ! options.isCacheValid() ){
        localStorage.removeItem( cacheKey );
      }
      // if there's a TTL that's expired, flush this item
      var ttl = localStorage.getItem(cacheKey + 'cachettl');
      if ( ttl && ttl < +new Date() ){
        localStorage.removeItem( cacheKey );
        localStorage.removeItem( cacheKey  + 'cachettl' );
        ttl = 'expired';
      }

      var value = localStorage.getItem( cacheKey );
      if ( value ){
        //In the cache? So get it, apply success callback & abort the XHR request
        // parse back to JSON if we can.
        if ( options.dataType.indexOf( 'json' ) === 0 ) value = JSON.parse( value );
        options.success( value );
        // Abort is broken on JQ 1.5 :(
        jqXHR.abort();
      } else {

        //If it not in the cache, we change the success callback, just put data on localstorage and after that apply the initial callback
        if ( options.success ) {
          options.realsuccess = options.success;
        }
        options.success = function( data ) {
          var strdata = data;
          if ( this.dataType.indexOf( 'json' ) === 0 ) strdata = JSON.stringify( data );

          // Save the data to localStorage catching exceptions (possibly QUOTA_EXCEEDED_ERR)
          try {
            localStorage.setItem( cacheKey, strdata );
          } catch (e) {
            // Remove any incomplete data that may have been saved before the exception was caught
            localStorage.removeItem( cacheKey );
            localStorage.removeItem( cacheKey + 'cachettl' );
            if ( options.cacheError ) options.cacheError( e, cacheKey, strdata );
          }

          if ( options.realsuccess ) options.realsuccess( data );
        };

        // store timestamp
        if ( ! ttl || ttl === 'expired' ) {
          localStorage.setItem( cacheKey  + 'cachettl', +new Date() + 1000 * 60 * 60 * hourstl );
        }

      }
    });

});
<commit_msg>Add previous details to loaded event.<commit_after>/**
 * Copyright (c) 2014 and beyond Dwayne Charrington
 * Email: dwaynecharrington (at) gmail (dot) com
 * Twitter: abolitionof_
 * Licensed under MIT
 * @author Dwayne Charrington
 * @version 1.0
 */

(function($, window, document, History, undefined) {

    // Events trigger

    // While loading: wpAjax.loading: (event, url)
    // If failed: wpAjax.failed: (event, url)
    // Content loaded: wpAjax.loaded: (event, data, url)
    // Content loaded and populated: wpAjax.complete: (event, contentEl)

    /*
        Example:

        //To configure wpAjax:
        wpAjax.configure({
            content: "#content" // Element with our content which will be AJAX''d out
        });

        // Call this from within a click event
        wpAjax.trigger("http://www.someurl.com");

        // Request is currently happening (with current URL and new URL)
        $(document).on("wpAjax.loading", function(event) {
            // Methods are;
            // event.previousUrl
            // event.previousSlug
            // event.previousID
            // event.url
            // event.slug
            // event.ID
        });

        // All data has loaded
        $(document).on("wpAjax.loaded", function(event) {
            // Methods are;
            // event.previousUrl
            // event.previousSlug
            // event.previousID
            // event.content
            // event.url
            // event.slug
            // event.ID
        });

        $(document).on("wpAjax.failed", function(event) {
            // Methods are;
            // event.url
        });

        // All data has been populated the content element returned
        $(document).on("wpAjax.complete", function(event) {
            // Methods are;
            // event.contentEl
            // event.url
            // event.slug
            // event.ID
        });
    */

    var currentRequest = null,
         previousUrl = "",
         previousSlug = "",
         previousID = 0,
         requestCount = 0;

    // Main WP Ajax object
    var wpAjax = {};

    // Options
    var settings = {
            content: '#content',      // This is our container
            cacheRequests: true,  // Use HTML5 localStorage to cache pages?
            cacheExpiry: 1,          // Time in hours cached items should be cached for
            waitForImages: true,   // Wait for images to load before loading a page?
            debug: false,              // Debug mode shows console messages if true
            testMode: false           // Modifies certain methods so we can test them
        },
        o = settings;

    // These two elements never disappear and are always consistent
    var $body    = $("body");
    var $wpvars = $("wpvars");
    var $content = $(o.content);

    // Statechange when the URL changes, we roll
    $(window).off("statechange").on("statechange", function() {
        var State = History.getState();

        log("Event.statechange: HTML5 History statechange event trigger with URL: "+State.url);

        if (previousUrl !== State.url) {
            log("Event.statechange: Calling the wpAjax.loadPage function with State.url as its parameter");
            wpAjax.loadPage(State.url);
        } else {
            log("Event.statechange: User is already on the requested page to load. No request will be made.");
        }
    });

    // Allows us to configure wpAjax
    wpAjax.configure = function(options) {
        log("configure: Setting options for Wpajax");
        $.extend(settings, options);
        return this;
    };

    // Return the configuration object
    wpAjax.getConfiguration = function() {
        return settings;
    };

    // Helper function for checking the current URL
    wpAjax.getCurrentUrl = function() {
        log("getCurrentUrl: Getting the current browser address URL");
        return window.location.href;
    };

    // Get all vars supplied via the URL
    wpAjax.getPluginUrlVars = function() {
        var classes    = $body.attr("class");
        var returnObj = {};

        if (classes) {
            var classesArr = classes.split(" ");

            for (var i = 0, len = classesArr.length; i < len; ++i) {
                var pointer = classesArr[i];
            }
        }
    };

    // Trigger a page load
    wpAjax.trigger = function(url) {
        log("trigger: Calling History.pushState which will trigger a statechange");

        // Store current URL as the previous URL
        previousUrl = wpAjax.getCurrentUrl();

        wpAjax.getTitle(url, function(title) {
            History.pushState({}, title, url);
        });
    };

    // Have we reached our page limit
    wpAjax.pageLimitReached = function() {
        return (wpvars.max == wpvars.paged);
    }

    // What is the current page we are on
    wpAjax.getCurrentPageNumber = function() {
        return wpvars.paged;
    }

    // Get the maximum number of pages in our results
    wpAjax.getMaxPages = function() {
        return wpvars.max;
    }

    // Load page function
    wpAjax.loadPage = function(url) {

        log("loadPage: No other request is taking place, we are good to go");

        if (!o.testMode) {
            // Apply a loading class to the body
            $body.addClass("loading-page");

            var loadingEvent = jQuery.Event("wpAjax.loading", {
                previousUrl: previousUrl,
                previousSlug: previousSlug,
                previousID: previousID,
                url: url
            });

            // Trigger loading event
            $(document).trigger(loadingEvent);

            // Before content is loaded in, fade out the old content
            wpAjax.fadeOutContent(function() {

               // Perform our AJAX request
                wpAjax.doRequest(url, function(data) {
                    wpAjax.processRequest(data, url);
                }, function() {

                    if (!o.testMode) {
                        wpAjax.fadeInContent();

                        log("loadPage: Called doRequest and the request failed. Throwing a failed event on document");

                        var failedEvent = jQuery.Event("wpAjax.failed", {
                            url: url
                        });

                        // Trigger failed event
                        $(document).trigger(failedEvent);
                    }
                });

            });

            log("loadPage: Loading class applied to body, loading event fired and content element faded out");
        }

    };

    // Fade out the content area
    wpAjax.fadeOutContent = function(callback) {
        log("fadeOutContent: Animating content element out");

        if (arguments.length == 0) callback = function() {};

        $content.animate({opacity:0}, 800, callback);
    };

    // Fade in the content area
    wpAjax.fadeInContent = function(callback) {
        log("fadeInContent: Animating content element in");

        if (arguments.length == 0) callback = function() {};

        $content.animate({opacity:1}, 800, callback);
    };

    // Performs an AJAX request to get the page title
    // Also has the advantage of pre-fetching the page
    // for us as well.
    wpAjax.getTitle = function(url, callback) {
        var title = "";

        log("getTitle: Calling wpAjax.doRequest now to get the title");

        wpAjax.doRequest(url, function(data) {
            title = $(data).filter("title").text();
            log("getTitle: doRequest AJAX call successful. Title returned: "+title+" ");

            if ($.isFunction(callback)) {
                callback(title);
            }
        }, function() {
            if ($.isFunction(callback)) {
                callback(title);
            }
        });
    };

    // Handles performing the page load request
    // Leaves checking for other requests and validity to other functions
    wpAjax.doRequest = function(url, success, error) {

        log("doRequest: About to perform an AJAX call");

        // Do the fetching and stuff...
        currentRequest = $.ajax({
            url: url,
            localCache: o.cacheRequests,
            cacheTTL: o.cacheExpiry,
            type: 'GET',
            dataType: 'html',
            requestCount: ++requestCount,
            beforeSend: function() {
                // Check if we have a promise and cancel any current requests
                if (currentRequest !== null) {
                    currentRequest.abort();
                }
            },
            success: function(response, textStatus, jqXHR) {
                log("doRequest: AJAX success callback");
                if (requestCount !== this.requestCount) return;
                success(response, textStatus, jqXHR);
            },
            error: function(jqXHR, textStatus, errorThrown) {
                log("doRequest: AJAX error callback");
                if ($.isFunction(error)) {
                    error(jqXHR, textStatus, errorThrown);
                }
            }
        });

    };

    // Once our AJAX request is done, this function is called
    // Which allows us to process the response
    wpAjax.processRequest = function(data, url) {
        var _html = $(data);

        if (!o.testMode) {
            var _content = _html.find(o.content).html();
            var _wpvars = _html.find("#wpvars").html();
        } else {
            var _content = _html.find("body").html();
        }

        log("processRequest: Processing the data returned by a successful AJAX call");

        // Do we have content?
        if (_content && _content.length) {

            if (!o.testMode) {
                // Get latest version of WP Vars object
                $("#wpvars").remove();

                var s = document.createElement("script");
                s.id = "wpvars";
                s.type = "text/javascript";
                s.text = _wpvars;
                $("body").append(s);
            }

            var loadedEvent = jQuery.Event("wpAjax.loaded", {
                previousUrl: previousUrl,
                previousSlug: previousSlug,
                previousID: previousID,
                content: data,
                url: url
            });

             // AJAX load finished fire a loaded event with the data
             $(document).trigger(loadedEvent);

            log("processRequest: Content found from the AJAX request, determining what to do with it");

            // We want to wait for images to load before proceeding
            if (o.waitForImages) {

                log("processRequest Wait for images option is enabled, finding images");

                // We have images to preload
                if ($(_content).find("img").length) {

                    log("processRequest: We found images. Waiting for all images in the returned data to preload");

                    // Populate the content element
                    wpAjax.populateContent(_content, function(contentEl) {

                        log("processRequest: Populated the content element with content, about to preload iamges");

                        // Wait for any newly populated images to load
                        contentEl.waitForImages(function() {

                            log("processRequest: All images in AJAX loaded content have preloaded");

                            // Replace body classes with those of the loaded body classes
                            $body.attr("class",_html.filter("body").attr("class"));

                            var completeEvent = jQuery.Event("wpAjax.complete", {
                                contentEl: contentEl
                            });

                            // All content has been populated, assume we've succeeded
                            $(document).trigger(completeEvent);

                        });

                    });

                } else {
                    // Populate the content element
                    wpAjax.populateContent(_content, function(contentEl) {

                        log("processRequest: Requested AJAX content has been added to the content element and classes changed");

                        // Replace body classes with those of the loaded body classes
                        $body.attr("class", _html.filter("body").attr("class"));

                            var completeEvent = jQuery.Event("wpAjax.complete", {
                                contentEl: contentEl
                            });

                            // All content has been populated, assume we've succeeded
                            $(document).trigger(completeEvent);

                    });
                }

            } else {
                // Populate the content element
                wpAjax.populateContent(_content, function(contentEl) {

                    log("processRequest: Requested AJAX content has been added to the content element and classes changed");

                    // Replace body classes with those of the loaded body classes
                    $body.attr("class",data.filter("body").attr("class"));

                            var completeEvent = jQuery.Event("wpAjax.complete", {
                                contentEl: contentEl
                            });

                            // All content has been populated, assume we've succeeded
                            $(document).trigger(completeEvent);
                });
            }

            // Fade in the content DIV now we've done what we've wanted with it
            wpAjax.fadeInContent();

        } else {
            log("processRequest: Returned AJAX content is empty. Could be a problem server-side.");
        }
    };

    // Populates the appropriate content DIV with our
    // load content from the AJAX request (if successful)
    wpAjax.populateContent = function(content, callback) {
        log("populateContent: About to populate the content element with returned HTML");

        if (!o.testMode) {
            // Populate the content element
            $content.html(content);
        }

        // If we have a callback function
        if ($.isFunction(callback)) {
            log("populateContent: We've added in the content, calling the callback function with the element as an argument");
            callback($content);
        }
    };

    // Console log wrapper checks if debugging is on
    function log(msg) {
        if (o.debug) {
            console.log(msg);
        }
    }

    // Expose our method to the world
    window.wpAjax = wpAjax;

})(jQuery, window, window.document, window.History);

// Regex selector for jQuery: http://james.padolsey.com/javascript/regex-selector-for-jquery/
(function($, undefined) {

    jQuery.expr[':'].regex = function(elem, index, match) {
        var matchParams = match[3].split(','),
            validLabels = /^(data|css):/,
            attr = {
                method: matchParams[0].match(validLabels) ?
                            matchParams[0].split(':')[0] : 'attr',
                property: matchParams.shift().replace(validLabels,'')
            },
            regexFlags = 'ig',
            regex = new RegExp(matchParams.join('').replace(/^\s+|\s+$/g,''), regexFlags);
        return regex.test(jQuery(elem)[attr.method](attr.property));
    };

})(jQuery);

(function($, undefined) {

    // github.com/paulirish/jquery-ajax-localstorage-cache
    // dependent on Modernizr's localStorage test
    $.ajaxPrefilter( function( options, originalOptions, jqXHR ) {

      // Modernizr.localstorage, version 3 12/12/13
      function hasLocalStorage() {
        var mod = 'modernizr';
        try {
          localStorage.setItem(mod, mod);
          localStorage.removeItem(mod);
          return true;
        } catch(e) {
          return false;
        }
      }

      // Cache it ?
      if ( !hasLocalStorage() || !options.localCache ) return;

      var hourstl = options.cacheTTL || 5;

      var cacheKey = options.cacheKey ||
                     options.url.replace( /jQuery.*/,'' ) + options.type + (options.data || '');

      // isCacheValid is a function to validate cache
      if ( options.isCacheValid &&  ! options.isCacheValid() ){
        localStorage.removeItem( cacheKey );
      }
      // if there's a TTL that's expired, flush this item
      var ttl = localStorage.getItem(cacheKey + 'cachettl');
      if ( ttl && ttl < +new Date() ){
        localStorage.removeItem( cacheKey );
        localStorage.removeItem( cacheKey  + 'cachettl' );
        ttl = 'expired';
      }

      var value = localStorage.getItem( cacheKey );
      if ( value ){
        //In the cache? So get it, apply success callback & abort the XHR request
        // parse back to JSON if we can.
        if ( options.dataType.indexOf( 'json' ) === 0 ) value = JSON.parse( value );
        options.success( value );
        // Abort is broken on JQ 1.5 :(
        jqXHR.abort();
      } else {

        //If it not in the cache, we change the success callback, just put data on localstorage and after that apply the initial callback
        if ( options.success ) {
          options.realsuccess = options.success;
        }
        options.success = function( data ) {
          var strdata = data;
          if ( this.dataType.indexOf( 'json' ) === 0 ) strdata = JSON.stringify( data );

          // Save the data to localStorage catching exceptions (possibly QUOTA_EXCEEDED_ERR)
          try {
            localStorage.setItem( cacheKey, strdata );
          } catch (e) {
            // Remove any incomplete data that may have been saved before the exception was caught
            localStorage.removeItem( cacheKey );
            localStorage.removeItem( cacheKey + 'cachettl' );
            if ( options.cacheError ) options.cacheError( e, cacheKey, strdata );
          }

          if ( options.realsuccess ) options.realsuccess( data );
        };

        // store timestamp
        if ( ! ttl || ttl === 'expired' ) {
          localStorage.setItem( cacheKey  + 'cachettl', +new Date() + 1000 * 60 * 60 * hourstl );
        }

      }
    });

});
<|endoftext|>


<commit_before>$(document).ready(function() {
  var player = $("video.html5-main-video")[0];

  if (!player) {
    return;
  }

  function makeDistortionCurve(amount) {
    var k = typeof amount === 'number' ? amount : 50,
      samples = 44100,
      curve = new Float32Array(samples),
      deg = Math.PI / 180,
      i = 0,
      x;
    for ( ; i < samples; ++i ) {
      x = i * 2 / samples - 1;
      curve[i] = ( 3 + k ) * x * 20 * deg / ( Math.PI + k * Math.abs(x) );
    }
    return curve;
  }

  var context = new AudioContext();
  var source = context.createMediaElementSource(player);
  source.connect(context.destination);

  // Set up the different audio nodes we will use for the app
  var analyser = context.createAnalyser();
  var distortion = context.createWaveShaper();
  var gainNode = context.createGain();
  var biquadFilter = context.createBiquadFilter();
  var convolver = context.createConvolver();
  var oscillator = context.createOscillator();
  var compressor = context.createDynamicsCompressor();

  $.get(chrome.extension.getURL("templates/body.html"), function(data) {
    $('#watch-header').after(data);
  });

  $('body').on('change', "#ym-presets", function() {
    var preset = $(this).val();
    console.log(preset);
    presets(preset);
  });

  function presets(preset) {
    source.disconnect();

    switch (preset) {
      case 'normal':
        source.connect(context.destination);
        break;
      case 'underwater':

      case 'lowpass':

      case 'compressor'
        // Connect the source node to the destination
        source.connect(compressor);
        compressor.threshold.value = -50;
        compressor.knee.value = 40;
        compressor.ratio.value = 12;
        compressor.reduction.value = -20;
        compressor.attack.value = 0;
        compressor.release.value = 0.25;
      break;

      case 'hallway':

        source.connect(biquadFilter);
        biquadFilter.connect(gainNode);

        // Connect to output
        gainNode.connect(context.destination);

        biquadFilter.type = "highpass";

        biquadFilter.frequency.value = 1000;
        biquadFilter.gain.value = 688;
        break;
    }
  }
});<commit_msg>Connect the compressor to the output<commit_after>$(document).ready(function() {
  var player = $("video.html5-main-video")[0];

  if (!player) {
    return;
  }

  function makeDistortionCurve(amount) {
    var k = typeof amount === 'number' ? amount : 50,
      samples = 44100,
      curve = new Float32Array(samples),
      deg = Math.PI / 180,
      i = 0,
      x;
    for ( ; i < samples; ++i ) {
      x = i * 2 / samples - 1;
      curve[i] = ( 3 + k ) * x * 20 * deg / ( Math.PI + k * Math.abs(x) );
    }
    return curve;
  }

  var context = new AudioContext();
  var source = context.createMediaElementSource(player);
  source.connect(context.destination);

  // Set up the different audio nodes we will use for the app
  var analyser = context.createAnalyser();
  var distortion = context.createWaveShaper();
  var gainNode = context.createGain();
  var biquadFilter = context.createBiquadFilter();
  var convolver = context.createConvolver();
  var oscillator = context.createOscillator();
  var compressor = context.createDynamicsCompressor();

  $.get(chrome.extension.getURL("templates/body.html"), function(data) {
    $('#watch-header').after(data);
  });

  $('body').on('change', "#ym-presets", function() {
    var preset = $(this).val();
    console.log(preset);
    presets(preset);
  });

  function presets(preset) {
    source.disconnect();

    switch (preset) {
      case 'normal':
        source.connect(context.destination);
        break;
      case 'underwater':
      break;
      case 'lowpass':
      break;
      case 'compressor':
        // Connect the source node to the destination
        source.connect(compressor);
        compressor.threshold.value = -50;
        compressor.knee.value = 40;
        compressor.ratio.value = 12;
        compressor.reduction.value = -20;
        compressor.attack.value = 0;
        compressor.release.value = 0.25;
        // Connect to output
        gainNode.connect(context.destination);
      break;

      case 'hallway':

        source.connect(biquadFilter);
        biquadFilter.connect(gainNode);
        biquadFilter.type = "highpass";
        biquadFilter.frequency.value = 1000;
        biquadFilter.gain.value = 688;

        // Connect to output
        gainNode.connect(context.destination);

        break;
    }
  }
});<|endoftext|>


<commit_before>var w = 960,
pw = 14,
z = ~~((w - pw * 2) / 53),
ph = z >> 1,
h = z * 7;

var mindate="1720";
var maxdate="1729";
try {
    var queryString=decodeURIComponent(window.location.search.substring(1));

    if (queryString.length){

        var query=JSON.parse(queryString);
        mindate=""+query.start;
        maxdate=""+query.finish;

    }
}catch(e){
    if (console&&console.log)
        console.log(e+" for "+queryString);
}
var vis = d3.select("#chart")
    .selectAll("svg")
    .data(d3.range(parseInt(mindate.substr(0,4)), 1+parseInt(maxdate.substr(0,4))))
    .enter().append("svg:svg")
    .attr("width", w)
    .attr("height", h + ph * 2)
    .attr("class", "RdGy")
    .append("svg:g")
    .attr("transform", "translate(" + pw + "," + ph + ")");

vis.append("svg:text")
    .attr("transform", "translate(-6," + h / 2 + ")rotate(-90)")
    .attr("text-anchor", "middle")
    .text(function(d) { return d; });

vis.selectAll("rect.day")
    .data(calendar.dates)
    .enter().append("svg:rect")
    .attr("x", function(d) { return d.week * z; })
    .attr("y", function(d) { return d.day * z; })
    .attr("class", "day")
    .attr("fill", "#fff")
    .attr("width", z)
    .attr("height", z);

vis.selectAll("path.month")
    .data(calendar.months)
    .enter().append("svg:path")
    .attr("class", "month")
    .attr("d", function(d) {
              return "M" + (d.firstWeek + 1) * z + "," + d.firstDay * z
                  + "H" + d.firstWeek * z
                  + "V" + 7 * z
                  + "H" + d.lastWeek * z
                  + "V" + (d.lastDay + 1) * z
                  + "H" + (d.lastWeek + 1) * z
                  + "V" + 0
                  + "H" + (d.firstWeek + 1) * z
                  + "Z";
          });
function requestDateChange(mindate,maxdate){

    var xhr=new XMLHttpRequest();
    xhr.onreadystatechange = function() {
        if (xhr.readyState==4&&(xhr.status==200||xhr.status==0)) {
            var data=JSON.parse(xhr.responseText);
            /*
            var color = d3.scale.quantize()
                .domain([-.05, .05])
                .range(d3.range(9));
            */
            vis.selectAll("rect.day")
                .attr("class", function(d) { return "day q" + (data[d.Date]+5) + "-9";})
                .append("svg:title")
                .text(function(d) { return d.Date + ": " + data[d.Date]; });
        }
    };
    var requestObject={msg:"daterange",start:mindate,finish:maxdate};

    xhr.open("GET","query?q="+encodeURIComponent(JSON.stringify(requestObject)));
    return xhr.send();
}
requestDateChange(mindate,maxdate);
<commit_msg>Fixed the algorithm to recognize letters sent from january to september as well as the rest. Visually inspected correct values for some values such as 1789-8-12<commit_after>var w = 960,
pw = 14,
z = ~~((w - pw * 2) / 53),
ph = z >> 1,
h = z * 7;

var mindate="1720";
var maxdate="1729";
try {
    var queryString=decodeURIComponent(window.location.search.substring(1));

    if (queryString.length){

        var query=JSON.parse(queryString);
        mindate=""+query.start;
        maxdate=""+query.finish;

    }
}catch(e){
    if (console&&console.log)
        console.log(e+" for "+queryString);
}
var vis = d3.select("#chart")
    .selectAll("svg")
    .data(d3.range(parseInt(mindate.substr(0,4)), 1+parseInt(maxdate.substr(0,4))))
    .enter().append("svg:svg")
    .attr("width", w)
    .attr("height", h + ph * 2)
    .attr("class", "RdGy")
    .append("svg:g")
    .attr("transform", "translate(" + pw + "," + ph + ")");

vis.append("svg:text")
    .attr("transform", "translate(-6," + h / 2 + ")rotate(-90)")
    .attr("text-anchor", "middle")
    .text(function(d) { return d; });

vis.selectAll("rect.day")
    .data(calendar.dates)
    .enter().append("svg:rect")
    .attr("x", function(d) { return d.week * z; })
    .attr("y", function(d) { return d.day * z; })
    .attr("class", "day")
    .attr("fill", "#fff")
    .attr("width", z)
    .attr("height", z);

vis.selectAll("path.month")
    .data(calendar.months)
    .enter().append("svg:path")
    .attr("class", "month")
    .attr("d", function(d) {
              return "M" + (d.firstWeek + 1) * z + "," + d.firstDay * z
                  + "H" + d.firstWeek * z
                  + "V" + 7 * z
                  + "H" + d.lastWeek * z
                  + "V" + (d.lastDay + 1) * z
                  + "H" + (d.lastWeek + 1) * z
                  + "V" + 0
                  + "H" + (d.firstWeek + 1) * z
                  + "Z";
          });
function sumDate(data,str){
    var year=str.substr(0,4);
    var day=str.substr(str.length-2);
    if (day[0]=="-") {
        day=day.substr(1);
    }
    var month = str.substr(5,2);
    if (month[1]=="-"){
        month=month.substr(0,1);
    }
    monthInt=""+parseInt(month[0]=="0"?month.substr(1):month);
    dayInt=""+parseInt(day[0]=="0"?day.substr(1):day);
    //console.log(str+" == Y"+year+"M"+monthInt+"D"+dayInt;
    var full=str;//year+"-"+month+"-"+day;
    var part=year+"-"+monthInt+"-"+dayInt;
    var retval=0;
    if (full in data) {
        retval+=data[full];
    }
    if (part!=full&&part in data) {
        retval+=data[part];
    }
    return retval;
}
function requestDateChange(mindate,maxdate){

    var xhr=new XMLHttpRequest();
    xhr.onreadystatechange = function() {
        if (xhr.readyState==4&&(xhr.status==200||xhr.status==0)) {
            var data=JSON.parse(xhr.responseText);
            console.log("AHOY: "+data["1789-8-12"]);
            /*
            var color = d3.scale.quantize()
                .domain([-.05, .05])
                .range(d3.range(9));
            */
            vis.selectAll("rect.day")
                .attr("class", function(d) {return "day q" + (sumDate(data,d.Date)+5) + "-9";})
                .append("svg:title")
                .text(function(d) { return d.Date + ": " + (sumDate(data,d.Date)); });
        }
    };
    var requestObject={msg:"daterange",start:mindate,finish:maxdate};

    xhr.open("GET","query?q="+encodeURIComponent(JSON.stringify(requestObject)));
    return xhr.send();
}
requestDateChange(mindate,maxdate);
<|endoftext|>


<commit_before>// Copyright (c) 2012-2015, Matt Godbolt
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

var currentCompiler = null;
var allCompilers = [];

function getSource() {
    var source = $('.source').val();
    if (source == "browser") {
        if (window.localStorage.files === undefined) window.localStorage.files = "{}";
        return {
            list: function (callback) {
                var files = JSON.parse(window.localStorage.files);
                callback($.map(files, function (val, key) {
                    return val;
                }));
            },
            load: function (name, callback) {
                var files = JSON.parse(window.localStorage.files);
                callback(files[name]);
            },
            save: function (obj, callback) {
                var files = JSON.parse(window.localStorage.files);
                files[obj.name] = obj;
                window.localStorage.files = JSON.stringify(files);
                callback(true);
            }
        };
    } else {
        var base = "/source/" + source;
        return {
            list: function (callback) {
                $.getJSON(base + "/list", callback);
            },
            load: function (name, callback) {
                $.getJSON(base + "/load/" + name, callback);
            },
            save: function (obj, callback) {
                alert("Coming soon...");
            }
        };
    }
}

var currentFileList = {};
function updateFileList() {
    getSource().list(function (results) {
        currentFileList = {};
        $('.filename option').remove();
        $.each(results, function (index, arg) {
            currentFileList[arg.name] = arg;
            $('.filename').append($('<option value="' + arg.urlpart + '">' + arg.name + '</option>'));
            if (window.localStorage.filename == arg.urlpart) $('.filename').val(arg.urlpart);
        });
    });
}

function onSourceChange() {
    updateFileList();
    window.localStorage.source = $('.source').val();
}

function loadFile() {
    var name = $('.filename').val();
    window.localStorage.filename = name;
    getSource().load(name, function (results) {
        if (results.file) {
            currentCompiler.setSource(results.file);
        } else {
            // TODO: error?
            console.log(results);
        }
    });
}

function saveFile() {
    saveAs($('.files .filename').val());
}

function saveAs(filename) {
    var prevFilename = window.localStorage.filename || "";
    if (filename != prevFilename && currentFileList[filename]) {
        // TODO!
        alert("Coming soon - overwriting files");
        return;
    }
    var obj = {urlpart: filename, name: filename, file: currentCompiler.getSource()};
    getSource().save(obj, function (ok) {
        if (ok) {
            window.localStorage.filename = filename;
            updateFileList();
        }
    });
}

function saveFileAs() {
    $('#saveDialog').modal();
    $('#saveDialog .save-filename').val($('.files .filename').val());
    $('#saveDialog .save-filename').focus();
    function onSave() {
        $('#saveDialog').modal('hide');
        saveAs($('#saveDialog .save-filename').val());
    }

    $('#saveDialog .save').click(onSave);
    $('#saveDialog .save-filename').keyup(function (event) {
        if (event.keyCode == 13) onSave();
    });
}

function makePermalink() {
    $('#permalink').val('');

    shortenURL(window.location.href.split('#')[0] + '#' + serialiseState(),
        function (shorturl) {
            $('#permalink').val(shorturl);
        });
}

function hidePermalink() {
    if ($('.files .permalink').hasClass('active')) {  // do nothing if already hidden.
        togglePermalink();
    }
}

function togglePermalink() {
    if (!$('.files .permalink').hasClass('active')) {
        $('.files .permalink').addClass('active');
        $('.files .permalink-collapse').collapse('show');
        makePermalink();
    } else {
        $('.files .permalink-collapse').collapse('hide');
        $('.files .permalink').removeClass('active');
    }
}

function serialiseState() {
    return encodeURIComponent(JSON.stringify(getState(true)));
}

function getState(compress) {
    return {
        version: 3,
        filterAsm: getAsmFilters(),
        compilers: $.map(allCompilers, function (compiler) {
            return compiler.serialiseState(compress);
        })
    };
}

function toGist(state) {
    files = {};
    function nameFor(compiler) {
        var addNum = 0;
        var name, add;
        for (; ;) {
            add = addNum ? addNum.toString() : "";
            name = compiler + add + '.' + OPTIONS.sourceExtension;
            if (files[name] === undefined) return name;
            addNum++;
        }
    };
    state.compilers.forEach(function (s) {
        var name = nameFor(s.compiler);
        files[name] = {
            content: s.source,
            language: OPTIONS.language
        };
        s.source = name;
    });
    files['state.json'] = {content: JSON.stringify(state)};
    return JSON.stringify({
        description: "Compiler Explorer automatically generated files",
        'public': false,
        files: files
    });
}

function isGithubLimitError(request) {
    var remaining = parseInt(request.getResponseHeader('X-RateLimit-Remaining'));
    var reset = parseInt(request.getResponseHeader('X-RateLimit-Reset'));
    var limit = parseInt(request.getResponseHeader('X-RateLimit-Limit'));
    if (remaining !== 0) return null;
    var left = (new Date(reset * 1000) - Date.now()) / 1000;
    return "Rate limit of " + limit + " exceeded: " + Math.round(left / 60) + " mins til reset";
}

function makeGist(onDone, onFail) {
    var req = $.ajax('https://api.github.com/gists', {
        type: 'POST',
        //accepts: 'application/vnd.github.v3+json',
        dataType: 'json',
        contentType: 'application/json',
        data: toGist(getState())
    });
    req.done(function (msg) {
        onDone(msg);
    });
    req.fail(function (jqXHR, textStatus) {
        var rateLimited = isGithubLimitError(jqXHR);
        if (rateLimited)
            onFail(rateLimited);
        else
            onFail(textStatus + " (" + jqXHR.statusText + ")");
    });
}

function fromGist(msg) {
    var state = JSON.parse(msg.files['state.json'].content);
    state.compilers.forEach(function (s) {
        s.source = msg.files[s.source].content;
    });
    return state;
}
function loadGist(gist) {
    var req = $.ajax('https://api.github.com/gists/' + gist);
    req.done(function (msg) {
        loadState(fromGist(msg));
    });
    req.fail(function (jqXHR, textStatus) {
        var err = isGithubLimitError(jqXHR);
        if (!err) {
            err = textStatus + " (" + jqXHR.statusText + ")";
        }
        alert("Unable to load gist: " + err);
    });
}

function deserialiseState(state) {
    if (state.substr(0, 2) == "g=") {
        loadGist(state.substr(2));
        return;
    }
    try {
        state = $.parseJSON(decodeURIComponent(state));
    } catch (ignored) {
        return false;
    }
    return loadState(state);
}

function loadState(state) {
    if (!state || state['version'] === undefined) return false;
    switch (state.version) {
        case 1:
            state.filterAsm = {};
        /* falls through */
        case 2:
            state.compilers = [state];
        /* falls through */
        case 3:
            break;
        default:
            return false;
    }
    setFilterUi(state.filterAsm);
    for (var i = 0; i < Math.min(allCompilers.length, state.compilers.length); i++) {
        allCompilers[i].setFilters(state.filterAsm);
        allCompilers[i].deserialiseState(state.compilers[i]);
    }
    return true;
}

function initialise(options) {
    var defaultFilters = JSON.stringify(getAsmFilters());
    var actualFilters = $.parseJSON(window.localStorage.filter || defaultFilters);
    setFilterUi(actualFilters);

    $(".compiler_options").val(options.compileoptions);
    $(".language-name").text(options.language);

    var compiler = new Compiler($('body'), actualFilters, "a", function () {
        hidePermalink();
    }, options.language);
    allCompilers.push(compiler);
    currentCompiler = compiler;

    $('form').submit(function () {
        return false;
    });
    $('.files .source').change(onSourceChange);
    compiler.setCompilers(options.compilers, options.defaultCompiler);
    function setSources(sources, defaultSource) {
        $('.source option').remove();
        $.each(sources, function (index, arg) {
            $('.files .source').append($('<option value="' + arg.urlpart + '">' + arg.name + '</option>'));
            if (defaultSource == arg.urlpart) {
                $('.files .source').val(arg.urlpart);
            }
        });
        onSourceChange();
    }

    setSources(options.sources, window.localStorage.source || options.defaultSource);
    $('.files .load').click(function () {
        loadFile();
        return false;
    });
    $('.files .save').click(function () {
        saveFile();
        return false;
    });
    $('.files .saveas').click(function () {
        saveFileAs();
        return false;
    });
    $('.files .permalink').click(function (e) {
        togglePermalink(e);
        return false;
    });

    $('.filter button.btn').click(function (e) {
        $(e.target).toggleClass('active');
        var filters = getAsmFilters();
        window.localStorage.filter = JSON.stringify(filters);
        currentCompiler.setFilters(filters);
    });

    function loadFromHash() {
        deserialiseState(window.location.hash.substr(1));
    }

    $(window).bind('hashchange', function () {
        loadFromHash();
    });
    loadFromHash();

    function resizeEditors() {
        var codeMirrors = $('.CodeMirror');
        var top = codeMirrors.position().top;
        var windowHeight = $(window).height();
        var compOutputSize = Math.max(100, windowHeight * 0.05);
        $('.output').height(compOutputSize);
        var resultHeight = $('.result').height();
        var height = windowHeight - top - resultHeight - 40;
        currentCompiler.setEditorHeight(height);
    }

    $(window).on("resize", resizeEditors);
    resizeEditors();
}

function getAsmFilters() {
    var asmFilters = {};
    $('.filter button.btn.active').each(function () {
        asmFilters[$(this).val()] = true;
    });
    return asmFilters;
}

function setFilterUi(asmFilters) {
    $('.filter button.btn').each(function () {
        $(this).toggleClass('active', !!asmFilters[$(this).val()]);
    });
}

$(function () {
    initialise(OPTIONS);
});
<commit_msg>Attempt to send accepts header on gist requests<commit_after>// Copyright (c) 2012-2015, Matt Godbolt
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

var currentCompiler = null;
var allCompilers = [];

function getSource() {
    var source = $('.source').val();
    if (source == "browser") {
        if (window.localStorage.files === undefined) window.localStorage.files = "{}";
        return {
            list: function (callback) {
                var files = JSON.parse(window.localStorage.files);
                callback($.map(files, function (val, key) {
                    return val;
                }));
            },
            load: function (name, callback) {
                var files = JSON.parse(window.localStorage.files);
                callback(files[name]);
            },
            save: function (obj, callback) {
                var files = JSON.parse(window.localStorage.files);
                files[obj.name] = obj;
                window.localStorage.files = JSON.stringify(files);
                callback(true);
            }
        };
    } else {
        var base = "/source/" + source;
        return {
            list: function (callback) {
                $.getJSON(base + "/list", callback);
            },
            load: function (name, callback) {
                $.getJSON(base + "/load/" + name, callback);
            },
            save: function (obj, callback) {
                alert("Coming soon...");
            }
        };
    }
}

var currentFileList = {};
function updateFileList() {
    getSource().list(function (results) {
        currentFileList = {};
        $('.filename option').remove();
        $.each(results, function (index, arg) {
            currentFileList[arg.name] = arg;
            $('.filename').append($('<option value="' + arg.urlpart + '">' + arg.name + '</option>'));
            if (window.localStorage.filename == arg.urlpart) $('.filename').val(arg.urlpart);
        });
    });
}

function onSourceChange() {
    updateFileList();
    window.localStorage.source = $('.source').val();
}

function loadFile() {
    var name = $('.filename').val();
    window.localStorage.filename = name;
    getSource().load(name, function (results) {
        if (results.file) {
            currentCompiler.setSource(results.file);
        } else {
            // TODO: error?
            console.log(results);
        }
    });
}

function saveFile() {
    saveAs($('.files .filename').val());
}

function saveAs(filename) {
    var prevFilename = window.localStorage.filename || "";
    if (filename != prevFilename && currentFileList[filename]) {
        // TODO!
        alert("Coming soon - overwriting files");
        return;
    }
    var obj = {urlpart: filename, name: filename, file: currentCompiler.getSource()};
    getSource().save(obj, function (ok) {
        if (ok) {
            window.localStorage.filename = filename;
            updateFileList();
        }
    });
}

function saveFileAs() {
    $('#saveDialog').modal();
    $('#saveDialog .save-filename').val($('.files .filename').val());
    $('#saveDialog .save-filename').focus();
    function onSave() {
        $('#saveDialog').modal('hide');
        saveAs($('#saveDialog .save-filename').val());
    }

    $('#saveDialog .save').click(onSave);
    $('#saveDialog .save-filename').keyup(function (event) {
        if (event.keyCode == 13) onSave();
    });
}

function makePermalink() {
    $('#permalink').val('');

    shortenURL(window.location.href.split('#')[0] + '#' + serialiseState(),
        function (shorturl) {
            $('#permalink').val(shorturl);
        });
}

function hidePermalink() {
    if ($('.files .permalink').hasClass('active')) {  // do nothing if already hidden.
        togglePermalink();
    }
}

function togglePermalink() {
    if (!$('.files .permalink').hasClass('active')) {
        $('.files .permalink').addClass('active');
        $('.files .permalink-collapse').collapse('show');
        makePermalink();
    } else {
        $('.files .permalink-collapse').collapse('hide');
        $('.files .permalink').removeClass('active');
    }
}

function serialiseState() {
    return encodeURIComponent(JSON.stringify(getState(true)));
}

function getState(compress) {
    return {
        version: 3,
        filterAsm: getAsmFilters(),
        compilers: $.map(allCompilers, function (compiler) {
            return compiler.serialiseState(compress);
        })
    };
}

function toGist(state) {
    files = {};
    function nameFor(compiler) {
        var addNum = 0;
        var name, add;
        for (; ;) {
            add = addNum ? addNum.toString() : "";
            name = compiler + add + '.' + OPTIONS.sourceExtension;
            if (files[name] === undefined) return name;
            addNum++;
        }
    };
    state.compilers.forEach(function (s) {
        var name = nameFor(s.compiler);
        files[name] = {
            content: s.source,
            language: OPTIONS.language
        };
        s.source = name;
    });
    files['state.json'] = {content: JSON.stringify(state)};
    return JSON.stringify({
        description: "Compiler Explorer automatically generated files",
        'public': false,
        files: files
    });
}

function isGithubLimitError(request) {
    var remaining = parseInt(request.getResponseHeader('X-RateLimit-Remaining'));
    var reset = parseInt(request.getResponseHeader('X-RateLimit-Reset'));
    var limit = parseInt(request.getResponseHeader('X-RateLimit-Limit'));
    if (remaining !== 0) return null;
    var left = (new Date(reset * 1000) - Date.now()) / 1000;
    return "Rate limit of " + limit + " exceeded: " + Math.round(left / 60) + " mins til reset";
}

function makeGist(onDone, onFail) {
    var req = $.ajax('https://api.github.com/gists', {
        type: 'POST',
        accepts: 'application/vnd.github.v3+json',
        dataType: 'json',
        contentType: 'application/json',
        data: toGist(getState())
    });
    req.done(function (msg) {
        onDone(msg);
    });
    req.fail(function (jqXHR, textStatus) {
        var rateLimited = isGithubLimitError(jqXHR);
        if (rateLimited)
            onFail(rateLimited);
        else
            onFail(textStatus + " (" + jqXHR.statusText + ")");
    });
}

function fromGist(msg) {
    var state = JSON.parse(msg.files['state.json'].content);
    state.compilers.forEach(function (s) {
        s.source = msg.files[s.source].content;
    });
    return state;
}
function loadGist(gist) {
    var req = $.ajax('https://api.github.com/gists/' + gist);
    req.done(function (msg) {
        loadState(fromGist(msg));
    });
    req.fail(function (jqXHR, textStatus) {
        var err = isGithubLimitError(jqXHR);
        if (!err) {
            err = textStatus + " (" + jqXHR.statusText + ")";
        }
        alert("Unable to load gist: " + err);
    });
}

function deserialiseState(state) {
    if (state.substr(0, 2) == "g=") {
        loadGist(state.substr(2));
        return;
    }
    try {
        state = $.parseJSON(decodeURIComponent(state));
    } catch (ignored) {
        return false;
    }
    return loadState(state);
}

function loadState(state) {
    if (!state || state['version'] === undefined) return false;
    switch (state.version) {
        case 1:
            state.filterAsm = {};
        /* falls through */
        case 2:
            state.compilers = [state];
        /* falls through */
        case 3:
            break;
        default:
            return false;
    }
    setFilterUi(state.filterAsm);
    for (var i = 0; i < Math.min(allCompilers.length, state.compilers.length); i++) {
        allCompilers[i].setFilters(state.filterAsm);
        allCompilers[i].deserialiseState(state.compilers[i]);
    }
    return true;
}

function initialise(options) {
    var defaultFilters = JSON.stringify(getAsmFilters());
    var actualFilters = $.parseJSON(window.localStorage.filter || defaultFilters);
    setFilterUi(actualFilters);

    $(".compiler_options").val(options.compileoptions);
    $(".language-name").text(options.language);

    var compiler = new Compiler($('body'), actualFilters, "a", function () {
        hidePermalink();
    }, options.language);
    allCompilers.push(compiler);
    currentCompiler = compiler;

    $('form').submit(function () {
        return false;
    });
    $('.files .source').change(onSourceChange);
    compiler.setCompilers(options.compilers, options.defaultCompiler);
    function setSources(sources, defaultSource) {
        $('.source option').remove();
        $.each(sources, function (index, arg) {
            $('.files .source').append($('<option value="' + arg.urlpart + '">' + arg.name + '</option>'));
            if (defaultSource == arg.urlpart) {
                $('.files .source').val(arg.urlpart);
            }
        });
        onSourceChange();
    }

    setSources(options.sources, window.localStorage.source || options.defaultSource);
    $('.files .load').click(function () {
        loadFile();
        return false;
    });
    $('.files .save').click(function () {
        saveFile();
        return false;
    });
    $('.files .saveas').click(function () {
        saveFileAs();
        return false;
    });
    $('.files .permalink').click(function (e) {
        togglePermalink(e);
        return false;
    });

    $('.filter button.btn').click(function (e) {
        $(e.target).toggleClass('active');
        var filters = getAsmFilters();
        window.localStorage.filter = JSON.stringify(filters);
        currentCompiler.setFilters(filters);
    });

    function loadFromHash() {
        deserialiseState(window.location.hash.substr(1));
    }

    $(window).bind('hashchange', function () {
        loadFromHash();
    });
    loadFromHash();

    function resizeEditors() {
        var codeMirrors = $('.CodeMirror');
        var top = codeMirrors.position().top;
        var windowHeight = $(window).height();
        var compOutputSize = Math.max(100, windowHeight * 0.05);
        $('.output').height(compOutputSize);
        var resultHeight = $('.result').height();
        var height = windowHeight - top - resultHeight - 40;
        currentCompiler.setEditorHeight(height);
    }

    $(window).on("resize", resizeEditors);
    resizeEditors();
}

function getAsmFilters() {
    var asmFilters = {};
    $('.filter button.btn.active').each(function () {
        asmFilters[$(this).val()] = true;
    });
    return asmFilters;
}

function setFilterUi(asmFilters) {
    $('.filter button.btn').each(function () {
        $(this).toggleClass('active', !!asmFilters[$(this).val()]);
    });
}

$(function () {
    initialise(OPTIONS);
});
<|endoftext|>