<commit_before>/**
 * User sign-in/sign-on for Webmaker.org apps
 */
(function setupUIHandler( window, document, $ ) {

  // make sure jQuery is available to us
  if( !$ ) {
    var jq = document.createElement( "script" );
    jq.src = "{{ hostname }}/js/ext/jquery-1.9.1.min.js";
    jq.onload = function() {
      // retry, this time in the knowledge that we have jQuery
      setupUIHandler( window, document, window.jQuery );
    };
    document.head.appendChild( jq );
    return;
  }

  // SSO UI handling object
  var ui =  {
    displayLogin: function( userData ) {
      var placeHolder = $( "#identity" ),
          userElement = $( "div.user-name" );
      if ( userData ) {
        placeHolder.html( '' + userData.name + "" );
        placeHolder.before( "" );
      } else {
        userElement.html( "" );
      }
    },
    showNewMakerForm: function( loggedInUser, formAnchor, callback ) {
      /**
       * load in HTML include containing the HTML form
       * display form
       * munge values into form
       * attach submit handlers to the form
       * AJAX post to createMaker API
       * remove form and listeners once everything is sorted
       */

      var $formContainer,
          $formFrag;

      if ( !errMsg ) {
        $( ".row.error-message" ).html( "" );
      }

      $formContainer = $( ".webmaker-create-user", formAnchor );
      $formContainer.text("");

      $.get( "{{ hostname }}/ajax/forms/new_user.html", function( html ) {
        $formContainer = $( html ).appendTo( $( "#webmaker-nav" ) );
        $formContainer.slideDown();
        $formFrag = $( "#sso_create", formAnchor );
        $mailSignUp = $( "#bsd" );
        $formFrag.submit(function( data ) {
          if( $mailSignUp.is( ":checked" ) ) {
            $.ajax({
              type: "POST",
              url: "https://sendto.mozilla.org/page/s/webmaker",
              data: {
                email: $( "#username" ).val(),
                "custom-1216": 1
              },
              success: function( resp ) {
                return true;
              },
              error: function( resp ) {
                return false;
              }
            });
          }

          $.ajax({
            type: "POST",
            url: "{{ hostname }}/user",
            headers: {
              "X-CSRF-Token": csrfMeta.content
            },
            dataType: "json",
            data: {
              "email": loggedInUser,
              "username": $( "#username" ).val()
            },
            success: function(resp) {
              ui.existingMaker({
                name: resp.user.username,
                hash: resp.user.emailHash
              });
              $formContainer.slideUp();
              callback( null, loggedInUser, resp.user.username );
            },
            error: function( resp ) {
              callback( JSON.parse( resp.responseText ).error, $( "#username" ).val() );
              return false;
            }
          });
          return false;
        });
      });
    },
    existingMaker: function( userData ) {
      /**
       * API call to the getUserData API
       * display logged in user data in the UI (where to be defined)
       */
      ui.displayLogin( userData );
    },
    loggedOut: function() {
      /**
       * remove logged in user data from the UI
       * remove any listeners we have attached
       */
      ui.displayLogin();
      $( ".webmaker-create-user" ).slideUp();
    }
  };

  // Set up the 'my makes' functionality.
  var makes = $( "#webmaker-nav .my-projects-container" ),
      makeButton = $( "#webmaker-nav .makes button" ).click(function() {
        makes.toggleClass( "open" );
      });

  // Window level control over updating the iframe when a consumer
  // app knows that the publications have changed and need to be
  // refreshed:
  window.userBar = window.userBar || {
    updateMakes: function() {
      var iframe = $( "iframe",makes )[0];
      iframe.src = iframe.src;
    }
  };

  // User-defined login/logout handling
  var noop = function(){};
  navigator.idSSO.app = navigator.idSSO.app || {};
  navigator.idSSO.app.onlogin = navigator.idSSO.app.onlogin || noop;
  navigator.idSSO.app.onlogout = navigator.idSSO.app.onlogout || noop;

  // Which button do we show?
  var emailMeta = document.querySelector( "meta[name='persona-email']" ),
      cookieEmail = emailMeta.content ? emailMeta.content : "",
      loggedIn = !!cookieEmail,
      csrfMeta = document.querySelector( "meta[name='X-CSRF-Token']" ),
      errMsg;

  // Start listening for Persona events
  navigator.idSSO.watch({
    // Note: 'loggedInUser:cookieEmail' yet, see https://bugzilla.mozilla.org/show_bug.cgi?id=872710
    onlogin: function( assertion ) {
      $.ajax({
        type: "POST",
        url: "/persona/verify",
        headers: {
          "X-CSRF-Token": csrfMeta.content
        },
        data: { assertion: assertion },
        success: function( res, status, xhr ) {
          // login succeeded, show this user as logged in
          // and call the on-page onlogin handler.
          ui.existingMaker({
            name: res.user.username,
            hash: res.user.emailHash
          });
          $( "#webmaker-nav iframe.include-frame" ).addClass( "loggedin" );
          $( "body" ).addClass( "loggedin" );
          navigator.idSSO.app.onlogin( res.email, res.user.username, res.user );
        },
        error: function( xhr, status, err ) {
          var error = JSON.parse( xhr.responseText );

          function onNewMakerSubmitted ( err, loggedInUser, displayName ) {
            // hook-out to the owning page, so that it can perform a
            // webmaker-loginAPI lookup, allowing it to bind the user's
            // email and webmaker ID in its req.session.[...]
            if ( err ) {
              errMsg = err;
              // Username existed
              if ( err.code === 11000 ) {
                $( ".row.error-message" ).html( "Another user has already claimed " + loggedInUser + "!" );
                ui.showNewMakerForm( error.email, $( "#webmaker-nav" ), onNewMakerSubmitted );
                return;
              }
              return navigator.idSSO.logout();
            }
            $.ajax({
              type: "POST",
              url: "/persona/verify",
              headers: {
                "X-CSRF-Token": csrfMeta.content
              },
              data: { assertion: assertion },
              success: function( res, status, xhr ) {
                // login succeeded, show this user as logged in
                // and call the on-page onlogin handler.
                errMsg = null;
                $( "#webmaker-nav iframe.include-frame" ).addClass( "loggedin" );
                $( "body" ).addClass( "loggedin" );
                navigator.idSSO.app.onlogin( loggedInUser, displayName, res.user );
              },
              error: function( xhr, status, err ) {
                errMsg = err;
                navigator.idSSO.logout();
              }
            });
          }

          if( xhr.status === 404 && error.status === "failure" ) {
            ui.showNewMakerForm( error.email, $( "#webmaker-nav" ), onNewMakerSubmitted );
          } else {
            errMsg = err;
            navigator.idSSO.logout();
          }
        }
      });
    },
    onlogout: function() {
      ui.loggedOut();
      makes.removeClass( "open" );
      $('body').removeClass( "loggedin" );
      $( "#webmaker-nav iframe.include-frame" ).removeClass( "loggedin" );
      // make sure the page does whatever it needs to,
      navigator.idSSO.app.onlogout( errMsg );
      errMsg = null;
      // and make sure the app knows we're logged out.
      $.ajax({
        type: "POST",
        url: "/persona/logout",
        headers: {
          "X-CSRF-Token": csrfMeta.content
        },
        async: true
      });
    }
  });

}( window, document, window.jQuery ) );
<commit_msg>code comments<commit_after>/**
 * User sign-in/sign-on for Webmaker.org apps
 */
(function setupUIHandler( window, document, $ ) {

  // make sure jQuery is available to us
  if( !$ ) {
    var jq = document.createElement( "script" );
    jq.src = "{{ hostname }}/js/ext/jquery-1.9.1.min.js";
    jq.onload = function() {
      // retry, this time in the knowledge that we have jQuery
      setupUIHandler( window, document, window.jQuery );
    };
    document.head.appendChild( jq );
    return;
  }

  // SSO UI handling object
  var ui =  {
    displayLogin: function( userData ) {
      var placeHolder = $( "#identity" ),
          userElement = $( "div.user-name" );
      if ( userData ) {
        placeHolder.html( '' + userData.name + "" );
        placeHolder.before( "" );
      } else {
        userElement.html( "" );
      }
    },
    showNewMakerForm: function( loggedInUser, formAnchor, callback ) {
      /**
       * load in HTML include containing the HTML form
       * display form
       * munge values into form
       * attach submit handlers to the form
       * AJAX post to createMaker API
       * remove form and listeners once everything is sorted
       */

      var $formContainer,
          $formFrag;

      if ( !errMsg ) {
        $( ".row.error-message" ).html( "" );
      }

      $formContainer = $( ".webmaker-create-user", formAnchor );
      $formContainer.text("");

      // Get the new user form from webmaker.org so that a persona-authenticated
      // user can sign up for a webmaker account before being let into the site.
      $.get( "{{ hostname }}/ajax/forms/new_user.html", function( html ) {
        $formContainer = $( html ).appendTo( $( "#webmaker-nav" ) );
        $formContainer.slideDown();
        $formFrag = $( "#sso_create", formAnchor );
        $mailSignUp = $( "#bsd" );

        // form submission requires some validation before being allowed
        $formFrag.submit(function( data ) {
          if( $mailSignUp.is( ":checked" ) ) {
            $.ajax({
              type: "POST",
              url: "https://sendto.mozilla.org/page/s/webmaker",
              data: {
                email: $( "#username" ).val(),
                "custom-1216": 1
              },
              success: function( resp ) {
                return true;
              },
              error: function( resp ) {
                return false;
              }
            });
          }

          // All the data is good - inform the login service (Through
          // the /user route that loginapi sets up) to creat this user,
          // and update the on-page UI after creation with this user's
          // information.
          $.ajax({
            type: "POST",
            url: "{{ hostname }}/user",
            headers: {
              "X-CSRF-Token": csrfMeta.content
            },
            dataType: "json",
            data: {
              "email": loggedInUser,
              "username": $( "#username" ).val()
            },
            success: function(resp) {
              ui.existingMaker({
                name: resp.user.username,
                hash: resp.user.emailHash
              });
              $formContainer.slideUp();
              callback( null, loggedInUser, resp.user.username );
            },
            error: function( resp ) {
              callback( JSON.parse( resp.responseText ).error, $( "#username" ).val() );
              return false;
            }
          });
          return false;
        });
      });
    },
    existingMaker: function( userData ) {
      /**
       * API call to the getUserData API
       * display logged in user data in the UI (where to be defined)
       */
      ui.displayLogin( userData );
    },
    loggedOut: function() {
      /**
       * remove logged in user data from the UI
       * remove any listeners we have attached
       */
      ui.displayLogin();
      $( ".webmaker-create-user" ).slideUp();
    }
  };

  // Set up the 'my makes' functionality.
  var makes = $( "#webmaker-nav .my-projects-container" ),
      makeButton = $( "#webmaker-nav .makes button" ).click(function() {
        makes.toggleClass( "open" );
      });

  // Window level control over updating the iframe when a consumer
  // app knows that the publications have changed and need to be
  // refreshed:
  window.userBar = window.userBar || {
    updateMakes: function() {
      var iframe = $( "iframe",makes )[0];
      iframe.src = iframe.src;
    }
  };

  // User-defined login/logout handling
  var noop = function(){};
  navigator.idSSO.app = navigator.idSSO.app || {};
  navigator.idSSO.app.onlogin = navigator.idSSO.app.onlogin || noop;
  navigator.idSSO.app.onlogout = navigator.idSSO.app.onlogout || noop;

  // Which button do we show?
  var emailMeta = document.querySelector( "meta[name='persona-email']" ),
      cookieEmail = emailMeta.content ? emailMeta.content : "",
      loggedIn = !!cookieEmail,
      csrfMeta = document.querySelector( "meta[name='X-CSRF-Token']" ),
      errMsg;

  // Start listening for Persona events
  navigator.idSSO.watch({
    // Note: 'loggedInUser:cookieEmail' yet, see https://bugzilla.mozilla.org/show_bug.cgi?id=872710
    onlogin: function( assertion ) {
      $.ajax({
        type: "POST",
        url: "/persona/verify",
        headers: {
          "X-CSRF-Token": csrfMeta.content
        },
        data: { assertion: assertion },
        success: function( res, status, xhr ) {
          // login succeeded, show this user as logged in
          // and call the on-page onlogin handler.
          ui.existingMaker({
            name: res.user.username,
            hash: res.user.emailHash
          });
          $( "#webmaker-nav iframe.include-frame" ).addClass( "loggedin" );
          $( "body" ).addClass( "loggedin" );
          navigator.idSSO.app.onlogin( res.email, res.user.username, res.user );
        },
        error: function( xhr, status, err ) {
          var error = JSON.parse( xhr.responseText );

          function onNewMakerSubmitted ( err, loggedInUser, displayName ) {
            // hook-out to the owning page, so that it can perform a
            // webmaker-loginAPI lookup, allowing it to bind the user's
            // email and webmaker ID in its req.session.[...]
            if ( err ) {
              errMsg = err;
              // Username existed
              if ( err.code === 11000 ) {
                $( ".row.error-message" ).html( "Another user has already claimed " + loggedInUser + "!" );
                ui.showNewMakerForm( error.email, $( "#webmaker-nav" ), onNewMakerSubmitted );
                return;
              }
              return navigator.idSSO.logout();
            }
            $.ajax({
              type: "POST",
              url: "/persona/verify",
              headers: {
                "X-CSRF-Token": csrfMeta.content
              },
              data: { assertion: assertion },
              success: function( res, status, xhr ) {
                // login succeeded, show this user as logged in
                // and call the on-page onlogin handler.
                errMsg = null;
                $( "#webmaker-nav iframe.include-frame" ).addClass( "loggedin" );
                $( "body" ).addClass( "loggedin" );
                navigator.idSSO.app.onlogin( loggedInUser, displayName, res.user );
              },
              error: function( xhr, status, err ) {
                errMsg = err;
                navigator.idSSO.logout();
              }
            });
          }

          if( xhr.status === 404 && error.status === "failure" ) {
            ui.showNewMakerForm( error.email, $( "#webmaker-nav" ), onNewMakerSubmitted );
          } else {
            errMsg = err;
            navigator.idSSO.logout();
          }
        }
      });
    },
    onlogout: function() {
      ui.loggedOut();
      makes.removeClass( "open" );
      $('body').removeClass( "loggedin" );
      $( "#webmaker-nav iframe.include-frame" ).removeClass( "loggedin" );
      // make sure the page does whatever it needs to,
      navigator.idSSO.app.onlogout( errMsg );
      errMsg = null;
      // and make sure the app knows we're logged out.
      $.ajax({
        type: "POST",
        url: "/persona/logout",
        headers: {
          "X-CSRF-Token": csrfMeta.content
        },
        async: true
      });
    }
  });

}( window, document, window.jQuery ) );
<|endoftext|>


<commit_before>var fs = require('fs'),
    nodePath = require('path'),

    _ = require('lodash'),
    mkdirp = require('mkdirp'),

    // @todo: ES6: Change the sequence below to use object destructuring when Node v4 support is dropped
    joinPath = nodePath.join,
    parsePath = nodePath.parse,
    resolvePath = nodePath.resolve,

    /**
     * The root path specifier
     *
     * @const
     * @private
     * @type {string}
     */
    E = '',

    /**
     * Default timestamp separator.
     *
     * @const
     * @private
     * @type {string}
     */
    TS_SEP = '-',

    /**
     * Generate a timestamp from date
     *
     * @param {Date=} date - The timestmap used to mark the exported file.
     * @param {String=} separator - The optional string with which to separate different sections of the timestamp,
     * defaults to TS_SEP
     * @returns {String} - yyyy-mm-dd-HH-MM-SS-MS-0
     */
    timestamp = function (date, separator) {
        // use the iso string to ensure left padding and other stuff is taken care of
        return (date || new Date()).toISOString().replace(/[^\d]+/g, _.isString(separator) ? separator : TS_SEP);
    };

/**
 * Module whose job is to export a file which is in an export format.
 *
 * @param {Object} options - The set of file export options.
 * @param {String} options.path - The path to the exported file.
 * @param {String|Object} options.content - The JSON / stringified content that is to be written to the file.
 * @param {Function} done - The callback whose invocation marks the end of the file export routine.
 * @returns {*}
 */
module.exports = function (options, done) {
    // parse the path if one is available as string
    var path = _.isString(options.path) && parsePath(resolvePath(options.path)),
        content = _.isPlainObject(options.content) ? JSON.stringify(options.content, 0, 2) : (options.content || E);

    // if a path was not provided by user, we need to prepare the default path. but create the default path only if one
    // is provided.
    if (!path && _.isString(options.default)) {
        path = parsePath(options.default);
        // delete the path and directory if one is detected when parsing defaults
        path.root = E;
        path.dir = 'newman';

        // append timestamp
        path.name = `${path.name}-${timestamp()}0`; // @todo make -0 become incremental if file name exists
        path.base = path.name + path.ext;
    }
    // final check that path is valid
    if (!(path && path.base)) {
        return;
    }

    // now sore the unparsed result back for quick re-use during writing and a single place for unparsing
    path.unparsed = joinPath(path.dir, path.base);

    // in case the path has a directory, ensure that the directory is available
    if (path.dir) {
        mkdirp(path.dir, function (err) {
            if (err) {
                return done(_.set(err, 'help',
                    `error creating path for file "${path.unparsed}" for ${options.name || 'unknown-source'}`));
            }

            fs.stat(path.unparsed, function (error, stat) {
                var target;

                // handle cases where the specified export path is a pre-existing directory
                if (stat && stat.isDirectory()) {
                    target = parsePath(options.default);

                    // append timestamp
                    // @todo make -0 become incremental if file name exists
                    target.name += '-' + timestamp() + '0';
                    target.base = target.name + target.ext;

                    path.unparsed = joinPath(path.unparsed, target.base);
                }

                fs.writeFile(path.unparsed, content, function (err) {
                    done(_.set(err, 'help',
                        `error writing file "${path.unparsed}" for ${options.name || 'unknown-source'}`), path);
                });
            });
        });
    }
    else {
        fs.writeFile(path.unparsed, content, function (err) {
            done(_.set(err, 'help',
                `error writing file "${path.unparsed}" for ${options.name || 'unknown-source'}`), path);
        });
    }
};
<commit_msg>Cleaned up export file code :art:<commit_after>var fs = require('fs'),
    nodePath = require('path'),

    _ = require('lodash'),
    async = require('async'),
    mkdirp = require('mkdirp'),

    // @todo: ES6: Change the sequence below to use object destructuring when Node v4 support is dropped
    joinPath = nodePath.join,
    parsePath = nodePath.parse,
    resolvePath = nodePath.resolve,

    /**
     * The root path specifier
     *
     * @const
     * @private
     * @type {string}
     */
    E = '',

    /**
     * Default timestamp separator.
     *
     * @const
     * @private
     * @type {string}
     */
    TS_SEP = '-',

    /**
     * Writes the specified content to a file at the provided path.
     *
     * @param {Object} path - A set of path details for file writing.
     * @param {String|Buffer} content - The content to be written to the file.
     * @param {Object} options - A set of options for the current file write.
     * @param {Function} cb - The callback invoked when the file writing operation has completed, with/without errors.
     */
    writeFile = function (path, content, options, cb) {
        fs.writeFile(path.unparsed, content, function (err) {
            cb(_.set(err, 'help',
                `error writing file "${path.unparsed}" for ${options.name || 'unknown-source'}`), path);
        });
    },

    /**
     * Generate a timestamp from date
     *
     * @param {Date=} date - The timestmap used to mark the exported file.
     * @param {String=} separator - The optional string with which to separate different sections of the timestamp,
     * defaults to TS_SEP
     * @returns {String} - yyyy-mm-dd-HH-MM-SS-MS-0
     */
    timestamp = function (date, separator) {
        // use the iso string to ensure left padding and other stuff is taken care of
        return (date || new Date()).toISOString().replace(/[^\d]+/g, _.isString(separator) ? separator : TS_SEP);
    };

/**
 * Module whose job is to export a file which is in an export format.
 *
 * @param {Object} options - The set of file export options.
 * @param {String} options.path - The path to the exported file.
 * @param {String|Object} options.content - The JSON / stringified content that is to be written to the file.
 * @param {Function} done - The callback whose invocation marks the end of the file export routine.
 * @returns {*}
 */
module.exports = function (options, done) {
    // parse the path if one is available as string
    var path = _.isString(options.path) && parsePath(resolvePath(options.path)),
        content = _.isPlainObject(options.content) ? JSON.stringify(options.content, 0, 2) : (options.content || E);

    // if a path was not provided by user, we need to prepare the default path. but create the default path only if one
    // is provided.
    if (!path && _.isString(options.default)) {
        path = parsePath(options.default);
        // delete the path and directory if one is detected when parsing defaults
        path.root = E;
        path.dir = 'newman';

        // append timestamp
        path.name = `${path.name}-${timestamp()}0`; // @todo make -0 become incremental if file name exists
        path.base = path.name + path.ext;
    }
    // final check that path is valid
    if (!(path && path.base)) {
        return;
    }

    // now sore the unparsed result back for quick re-use during writing and a single place for unparsing
    path.unparsed = joinPath(path.dir, path.base);

    // in case the path has a directory, ensure that the directory is available
    if (path.dir) {
        async.waterfall([
            function (next) {
                mkdirp(path.dir, function (err) {
                    if (err) {
                        return next(_.set(err, 'help',
                            `error creating path for file "${path.unparsed}" for ${options.name || 'unknown-source'}`));
                    }

                    return next();
                });
            },
            function (next) {
                fs.stat(path.unparsed, function (err, stat) { // eslint-disable-line handle-callback-err
                    next(null, stat);
                });
            },
            function (stat, next) {
                var target;

                // handle cases where the specified export path is a pre-existing directory
                if (stat && stat.isDirectory()) {
                    target = parsePath(options.default);

                    // append timestamp
                    // @todo make -0 become incremental if file name exists
                    target.name += '-' + timestamp() + '0';
                    target.base = target.name + target.ext;

                    path.unparsed = joinPath(path.unparsed, target.base);
                }

                next(null, path);
            },
            function (path, next) {
                writeFile(path, content, options, next);
            }
        ], done);
    }
    else {
        writeFile(path, content, options, done);
    }
};
<|endoftext|>


<commit_before>Projects = {
  organizationsWithProjects: function() {
    var projects = [];
    for(var i in my_projects) {
      if(!isNaN(i) && my_projects[i]) {
        var p = my_projects[i];
        p.id = parseInt(i);
        p.my_role = Projects.roles[p.role];
        p.admin = p.role == 3;
        projects.push(p);
      }
    }
    return my_external_organizations.collect(function(org) {
      org.projects = projects.
        select(function(p) {
          return p.organization_id == org.id; }).
        sortBy(function(p) {
          return p.name.toLowerCase(); });
      org.active_projects = org.projects.
        reject(function(p) {
          return p.archived; });
      org.archived_projects = org.projects.
        select(function(p) {
          return p.archived; });
      org.has_archived_projects =
        (org.archived_projects.length > 0) ?
        { count: org.archived_projects.length,
          name: org.name,
          projects: org.archived_projects } :
        false;
      return org;
    }).compact();
  },
  showAllProjects: function() {
    var html = Mustache.to_html(Templates.projects.index, {
      organizations: Projects.organizationsWithProjects()
    });
    Pane.replace(html);
  },
  roles: [
    I18n.translations.roles.observer,
    I18n.translations.roles.commenter,
    I18n.translations.roles.participant,
    I18n.translations.roles.admin
  ],
  fastCommentForm: function() {
    if (!$('project_id')) {
      return;
    }
    var projects_in_orgs = {};
    (new Hash(my_projects)).each(function(p) {
      var org_id = p[1].organization_id;
      if (projects_in_orgs[org_id]) {
        projects_in_orgs[org_id].push([p[0], p[1].name]);
      }
      else {
        projects_in_orgs[org_id] = [[p[0], p[1].name]];
      }
    });
    var groups = [];
    my_organizations.each(function(o) {
      var group = new Element('optgroup', { label: o.name });
      projects_in_orgs[o.id].sortBy(function(p) {return p[1]}).collect(function(p) {return p[0]}).each(function(p) {
        if (!my_projects[p].archived) {
          var project = new Element('option', { value: p }).insert(my_projects[p].name);
          group.insert(project);
        }
      });
      groups.push(group);
      $('project_id').insert(group);
    });

  }
}

document.on('click', 'a.show_archived', function(e,el) {
  e.stop()
  el.hide()
  el.up().next('.archived_projects').appear({duration: 0.2})
})

document.on('click', 'a.delete_project', function(e, el){
	e.preventDefault()
	Prototype.Facebox.open($('delete_project_html').innerHTML, 'html delete_project_box', {
		buttons: [
			{className: 'close', href:'#close', description: I18n.translations.common.cancel},
			{className: 'confirm', href:el.readAttribute('href'), description: I18n.translations.projects.fields.delete_this_project,
			 extra:"data-method='delete'"}
		]
	})
})

document.on("dom:loaded", function () {
  Projects.fastCommentForm();
})

<commit_msg>Showing external projects in quick comment box<commit_after>Projects = {
  organizationsWithProjects: function() {
    var projects = [];
    for(var i in my_projects) {
      if(!isNaN(i) && my_projects[i]) {
        var p = my_projects[i];
        p.id = parseInt(i);
        p.my_role = Projects.roles[p.role];
        p.admin = p.role == 3;
        projects.push(p);
      }
    }
    return my_external_organizations.collect(function(org) {
      org.projects = projects.
        select(function(p) {
          return p.organization_id == org.id; }).
        sortBy(function(p) {
          return p.name.toLowerCase(); });
      org.active_projects = org.projects.
        reject(function(p) {
          return p.archived; });
      org.archived_projects = org.projects.
        select(function(p) {
          return p.archived; });
      org.has_archived_projects =
        (org.archived_projects.length > 0) ?
        { count: org.archived_projects.length,
          name: org.name,
          projects: org.archived_projects } :
        false;
      return org;
    }).compact();
  },
  showAllProjects: function() {
    var html = Mustache.to_html(Templates.projects.index, {
      organizations: Projects.organizationsWithProjects()
    });
    Pane.replace(html);
  },
  roles: [
    I18n.translations.roles.observer,
    I18n.translations.roles.commenter,
    I18n.translations.roles.participant,
    I18n.translations.roles.admin
  ],
  fastCommentForm: function() {
    if (!$('project_id')) {
      return;
    }
    var projects_in_orgs = {};
    (new Hash(my_projects)).each(function(p) {
      var org_id = p[1].organization_id;
      if (projects_in_orgs[org_id]) {
        projects_in_orgs[org_id].push([p[0], p[1].name]);
      }
      else {
        projects_in_orgs[org_id] = [[p[0], p[1].name]];
      }
    });
    var groups = [];
    my_external_organizations.each(function(o) {
      var group = new Element('optgroup', { label: o.name });
      projects_in_orgs[o.id].sortBy(function(p) {return p[1]}).collect(function(p) {return p[0]}).each(function(p) {
        if (!my_projects[p].archived && (my_projects[p].role > 0)) {
          var project = new Element('option', { value: p }).insert(my_projects[p].name);
          group.insert(project);
        }
      });
      groups.push(group);
      $('project_id').insert(group);
    });

  }
}

document.on('click', 'a.show_archived', function(e,el) {
  e.stop()
  el.hide()
  el.up().next('.archived_projects').appear({duration: 0.2})
})

document.on('click', 'a.delete_project', function(e, el){
	e.preventDefault()
	Prototype.Facebox.open($('delete_project_html').innerHTML, 'html delete_project_box', {
		buttons: [
			{className: 'close', href:'#close', description: I18n.translations.common.cancel},
			{className: 'confirm', href:el.readAttribute('href'), description: I18n.translations.projects.fields.delete_this_project,
			 extra:"data-method='delete'"}
		]
	})
})

document.on("dom:loaded", function () {
  Projects.fastCommentForm();
})

<|endoftext|>


<commit_before>const assert = require('assert');

const errors = require('../errors');
const routeGET = require('./routes/routeGET');
const routePUT = require('./routes/routePUT');
const routeDELETE = require('./routes/routeDELETE');
const routeHEAD = require('./routes/routeHEAD');
const routePOST = require('./routes/routePOST');
const routeOPTIONS = require('./routes/routeOPTIONS');
const routesUtils = require('./routesUtils');
const routeWebsite = require('./routes/routeWebsite');

const routeMap = {
    GET: routeGET,
    PUT: routePUT,
    POST: routePOST,
    DELETE: routeDELETE,
    HEAD: routeHEAD,
    OPTIONS: routeOPTIONS,
};

function isValidReqUids(reqUids) {
    // baseline check, to avoid the risk of running into issues if
    // users craft a large x-scal-request-uids header
    return reqUids.length < 128;
}

function checkUnsupportedRoutes(reqMethod) {
    const method = routeMap[reqMethod];
    if (!method) {
        return { error: errors.MethodNotAllowed };
    }
    return { method };
}

function checkBucketAndKey(bucketName, objectKey, method, reqQuery,
    blacklistedPrefixes, log) {
    // if empty name and request not a List Buckets
    if (!bucketName && !(method === 'GET' && !objectKey)) {
        log.debug('empty bucket name', { method: 'routes' });
        return (method !== 'OPTIONS') ?
            errors.MethodNotAllowed : errors.AccessForbidden
            .customizeDescription('CORSResponse: Bucket not found');
    }
    if (bucketName !== undefined && routesUtils.isValidBucketName(bucketName,
        blacklistedPrefixes.bucket) === false) {
        log.debug('invalid bucket name', { bucketName });
        return errors.InvalidBucketName;
    }
    if (objectKey !== undefined) {
        const result = routesUtils.isValidObjectKey(objectKey,
            blacklistedPrefixes.object);
        if (!result.isValid) {
            log.debug('invalid object key', { objectKey });
            return errors.InvalidArgument.customizeDescription('Object key ' +
            `must not start with "${result.invalidPrefix}".`);
        }
    }
    if ((reqQuery.partNumber || reqQuery.uploadId)
        && objectKey === undefined) {
        return errors.InvalidRequest
            .customizeDescription('A key must be specified');
    }
    return undefined;
}

function checkTypes(req, res, params, logger) {
    assert.strictEqual(typeof req, 'object',
        'bad routes param: req must be an object');
    assert.strictEqual(typeof res, 'object',
        'bad routes param: res must be an object');
    assert.strictEqual(typeof logger, 'object',
        'bad routes param: logger must be an object');
    assert.strictEqual(typeof params.api, 'object',
        'bad routes param: api must be an object');
    assert.strictEqual(typeof params.api.callApiMethod, 'function',
        'bad routes param: api.callApiMethod must be a defined function');
    assert.strictEqual(typeof params.internalHandlers, 'object',
        'bad routes param: internalHandlers must be an object');
    if (params.statsClient) {
        assert.strictEqual(typeof params.statsClient, 'object',
        'bad routes param: statsClient must be an object');
    }
    assert(Array.isArray(params.allEndpoints),
        'bad routes param: allEndpoints must be an array');
    assert(params.allEndpoints.length > 0,
        'bad routes param: allEndpoints must have at least one endpoint');
    params.allEndpoints.forEach(endpoint => {
        assert.strictEqual(typeof endpoint, 'string',
        'bad routes param: each item in allEndpoints must be a string');
    });
    assert(Array.isArray(params.websiteEndpoints),
        'bad routes param: allEndpoints must be an array');
    params.websiteEndpoints.forEach(endpoint => {
        assert.strictEqual(typeof endpoint, 'string',
        'bad routes param: each item in websiteEndpoints must be a string');
    });
    assert.strictEqual(typeof params.blacklistedPrefixes, 'object',
        'bad routes param: blacklistedPrefixes must be an object');
    assert(Array.isArray(params.blacklistedPrefixes.bucket),
        'bad routes param: blacklistedPrefixes.bucket must be an array');
    params.blacklistedPrefixes.bucket.forEach(pre => {
        assert.strictEqual(typeof pre, 'string',
        'bad routes param: each blacklisted bucket prefix must be a string');
    });
    assert(Array.isArray(params.blacklistedPrefixes.object),
        'bad routes param: blacklistedPrefixes.object must be an array');
    params.blacklistedPrefixes.object.forEach(pre => {
        assert.strictEqual(typeof pre, 'string',
        'bad routes param: each blacklisted object prefix must be a string');
    });
    assert.strictEqual(typeof params.dataRetrievalFn, 'function',
        'bad routes param: dataRetrievalFn must be a defined function');
}

/** routes - route request to appropriate method
 * @param {Http.Request} req - http request object
 * @param {Http.ServerResponse} res - http response sent to the client
 * @param {object} params - additional routing parameters
 * @param {object} params.api - all api methods and method to call an api method
 *  i.e. api.callApiMethod(methodName, request, response, log, callback)
 * @param {function} params.internalHandlers - internal handlers API object
 *  for queries beginning with '/_/'
 * @param {StatsClient} [params.statsClient] - client to report stats to Redis
 * @param {string[]} params.allEndpoints - all accepted REST endpoints
 * @param {string[]} params.websiteEndpoints - all accepted website endpoints
 * @param {object} params.blacklistedPrefixes - blacklisted prefixes
 * @param {string[]} params.blacklistedPrefixes.bucket - bucket prefixes
 * @param {string[]} params.blacklistedPrefixes.object - object prefixes
 * @param {object} params.unsupportedQueries - object containing true/false
 *  values for whether queries are supported
 * @param {function} params.dataRetrievalFn - function to retrieve data
 * @param {RequestLogger} logger - werelogs logger instance
 * @returns {undefined}
 */
function routes(req, res, params, logger) {
    checkTypes(req, res, params, logger);

    const {
        api,
        internalHandlers,
        statsClient,
        allEndpoints,
        websiteEndpoints,
        blacklistedPrefixes,
        dataRetrievalFn,
    } = params;

    const clientInfo = {
        clientIP: req.socket.remoteAddress,
        clientPort: req.socket.remotePort,
        httpMethod: req.method,
        httpURL: req.url,
        endpoint: req.endpoint,
    };

    let reqUids = req.headers['x-scal-request-uids'];
    if (reqUids !== undefined && !isValidReqUids(reqUids)) {
        // simply ignore invalid id (any user can provide an
        // invalid request ID through a crafted header)
        reqUids = undefined;
    }
    const log = (reqUids !== undefined ?
                 logger.newRequestLoggerFromSerializedUids(reqUids) :
                 logger.newRequestLogger());

    if (!req.url.startsWith('/_/healthcheck')) {
        log.info('received request', clientInfo);
    }

    log.end().addDefaultFields(clientInfo);

    if (req.url.startsWith('/_/')) {
        let internalServiceName = req.url.slice(3);
        const serviceDelim = internalServiceName.indexOf('/');
        if (serviceDelim !== -1) {
            internalServiceName = internalServiceName.slice(0, serviceDelim);
        }
        if (internalHandlers[internalServiceName] === undefined) {
            return routesUtils.responseXMLBody(
                errors.InvalidURI, undefined, res, log);
        }
        return internalHandlers[internalServiceName](
            clientInfo.clientIP, req, res, log, statsClient);
    }

    if (statsClient) {
        // report new request for stats
        statsClient.reportNewRequest('s3');
    }

    try {
        const validHosts = allEndpoints.concat(websiteEndpoints);
        routesUtils.normalizeRequest(req, validHosts);
    } catch (err) {
        log.debug('could not normalize request', { error: err.stack });
        return routesUtils.responseXMLBody(
            errors.InvalidURI.customizeDescription('Could not parse the ' +
                'specified URI. Check your restEndpoints configuration.'),
                undefined, res, log);
    }

    log.addDefaultFields({
        bucketName: req.bucketName,
        objectKey: req.objectKey,
        bytesReceived: req.parsedContentLength || 0,
        bodyLength: parseInt(req.headers['content-length'], 10) || 0,
    });

    const { error, method } = checkUnsupportedRoutes(req.method, req.query);

    if (error) {
        log.trace('error validating route or uri params', { error });
        return routesUtils.responseXMLBody(error, null, res, log);
    }

    const bucketOrKeyError = checkBucketAndKey(req.bucketName, req.objectKey,
        req.method, req.query, blacklistedPrefixes, log);

    if (bucketOrKeyError) {
        log.trace('error with bucket or key value',
        { error: bucketOrKeyError });
        return routesUtils.responseXMLBody(bucketOrKeyError, null, res, log);
    }

    // bucket website request
    if (websiteEndpoints && websiteEndpoints.indexOf(req.parsedHost) > -1) {
        return routeWebsite(req, res, api, log, statsClient, dataRetrievalFn);
    }

    return method(req, res, api, log, statsClient, dataRetrievalFn);
}

module.exports = routes;
<commit_msg>bugfix: S3C-2172 change error message for compatibility<commit_after>const assert = require('assert');

const errors = require('../errors');
const routeGET = require('./routes/routeGET');
const routePUT = require('./routes/routePUT');
const routeDELETE = require('./routes/routeDELETE');
const routeHEAD = require('./routes/routeHEAD');
const routePOST = require('./routes/routePOST');
const routeOPTIONS = require('./routes/routeOPTIONS');
const routesUtils = require('./routesUtils');
const routeWebsite = require('./routes/routeWebsite');

const routeMap = {
    GET: routeGET,
    PUT: routePUT,
    POST: routePOST,
    DELETE: routeDELETE,
    HEAD: routeHEAD,
    OPTIONS: routeOPTIONS,
};

function isValidReqUids(reqUids) {
    // baseline check, to avoid the risk of running into issues if
    // users craft a large x-scal-request-uids header
    return reqUids.length < 128;
}

function checkUnsupportedRoutes(reqMethod) {
    const method = routeMap[reqMethod];
    if (!method) {
        return { error: errors.MethodNotAllowed };
    }
    return { method };
}

function checkBucketAndKey(bucketName, objectKey, method, reqQuery,
    blacklistedPrefixes, log) {
    // if empty name and request not a List Buckets
    if (!bucketName && !(method === 'GET' && !objectKey)) {
        log.debug('empty bucket name', { method: 'routes' });
        return (method !== 'OPTIONS') ?
            errors.MethodNotAllowed : errors.AccessForbidden
            .customizeDescription('CORSResponse: Bucket not found');
    }
    if (bucketName !== undefined && routesUtils.isValidBucketName(bucketName,
        blacklistedPrefixes.bucket) === false) {
        log.debug('invalid bucket name', { bucketName });
        if (method === 'DELETE') {
            return errors.NoSuchBucket;
        }
        return errors.InvalidBucketName;
    }
    if (objectKey !== undefined) {
        const result = routesUtils.isValidObjectKey(objectKey,
            blacklistedPrefixes.object);
        if (!result.isValid) {
            log.debug('invalid object key', { objectKey });
            return errors.InvalidArgument.customizeDescription('Object key ' +
            `must not start with "${result.invalidPrefix}".`);
        }
    }
    if ((reqQuery.partNumber || reqQuery.uploadId)
        && objectKey === undefined) {
        return errors.InvalidRequest
            .customizeDescription('A key must be specified');
    }
    return undefined;
}

function checkTypes(req, res, params, logger) {
    assert.strictEqual(typeof req, 'object',
        'bad routes param: req must be an object');
    assert.strictEqual(typeof res, 'object',
        'bad routes param: res must be an object');
    assert.strictEqual(typeof logger, 'object',
        'bad routes param: logger must be an object');
    assert.strictEqual(typeof params.api, 'object',
        'bad routes param: api must be an object');
    assert.strictEqual(typeof params.api.callApiMethod, 'function',
        'bad routes param: api.callApiMethod must be a defined function');
    assert.strictEqual(typeof params.internalHandlers, 'object',
        'bad routes param: internalHandlers must be an object');
    if (params.statsClient) {
        assert.strictEqual(typeof params.statsClient, 'object',
        'bad routes param: statsClient must be an object');
    }
    assert(Array.isArray(params.allEndpoints),
        'bad routes param: allEndpoints must be an array');
    assert(params.allEndpoints.length > 0,
        'bad routes param: allEndpoints must have at least one endpoint');
    params.allEndpoints.forEach(endpoint => {
        assert.strictEqual(typeof endpoint, 'string',
        'bad routes param: each item in allEndpoints must be a string');
    });
    assert(Array.isArray(params.websiteEndpoints),
        'bad routes param: allEndpoints must be an array');
    params.websiteEndpoints.forEach(endpoint => {
        assert.strictEqual(typeof endpoint, 'string',
        'bad routes param: each item in websiteEndpoints must be a string');
    });
    assert.strictEqual(typeof params.blacklistedPrefixes, 'object',
        'bad routes param: blacklistedPrefixes must be an object');
    assert(Array.isArray(params.blacklistedPrefixes.bucket),
        'bad routes param: blacklistedPrefixes.bucket must be an array');
    params.blacklistedPrefixes.bucket.forEach(pre => {
        assert.strictEqual(typeof pre, 'string',
        'bad routes param: each blacklisted bucket prefix must be a string');
    });
    assert(Array.isArray(params.blacklistedPrefixes.object),
        'bad routes param: blacklistedPrefixes.object must be an array');
    params.blacklistedPrefixes.object.forEach(pre => {
        assert.strictEqual(typeof pre, 'string',
        'bad routes param: each blacklisted object prefix must be a string');
    });
    assert.strictEqual(typeof params.dataRetrievalFn, 'function',
        'bad routes param: dataRetrievalFn must be a defined function');
}

/** routes - route request to appropriate method
 * @param {Http.Request} req - http request object
 * @param {Http.ServerResponse} res - http response sent to the client
 * @param {object} params - additional routing parameters
 * @param {object} params.api - all api methods and method to call an api method
 *  i.e. api.callApiMethod(methodName, request, response, log, callback)
 * @param {function} params.internalHandlers - internal handlers API object
 *  for queries beginning with '/_/'
 * @param {StatsClient} [params.statsClient] - client to report stats to Redis
 * @param {string[]} params.allEndpoints - all accepted REST endpoints
 * @param {string[]} params.websiteEndpoints - all accepted website endpoints
 * @param {object} params.blacklistedPrefixes - blacklisted prefixes
 * @param {string[]} params.blacklistedPrefixes.bucket - bucket prefixes
 * @param {string[]} params.blacklistedPrefixes.object - object prefixes
 * @param {object} params.unsupportedQueries - object containing true/false
 *  values for whether queries are supported
 * @param {function} params.dataRetrievalFn - function to retrieve data
 * @param {RequestLogger} logger - werelogs logger instance
 * @returns {undefined}
 */
function routes(req, res, params, logger) {
    checkTypes(req, res, params, logger);

    const {
        api,
        internalHandlers,
        statsClient,
        allEndpoints,
        websiteEndpoints,
        blacklistedPrefixes,
        dataRetrievalFn,
    } = params;

    const clientInfo = {
        clientIP: req.socket.remoteAddress,
        clientPort: req.socket.remotePort,
        httpMethod: req.method,
        httpURL: req.url,
        endpoint: req.endpoint,
    };

    let reqUids = req.headers['x-scal-request-uids'];
    if (reqUids !== undefined && !isValidReqUids(reqUids)) {
        // simply ignore invalid id (any user can provide an
        // invalid request ID through a crafted header)
        reqUids = undefined;
    }
    const log = (reqUids !== undefined ?
                 logger.newRequestLoggerFromSerializedUids(reqUids) :
                 logger.newRequestLogger());

    if (!req.url.startsWith('/_/healthcheck')) {
        log.info('received request', clientInfo);
    }

    log.end().addDefaultFields(clientInfo);

    if (req.url.startsWith('/_/')) {
        let internalServiceName = req.url.slice(3);
        const serviceDelim = internalServiceName.indexOf('/');
        if (serviceDelim !== -1) {
            internalServiceName = internalServiceName.slice(0, serviceDelim);
        }
        if (internalHandlers[internalServiceName] === undefined) {
            return routesUtils.responseXMLBody(
                errors.InvalidURI, undefined, res, log);
        }
        return internalHandlers[internalServiceName](
            clientInfo.clientIP, req, res, log, statsClient);
    }

    if (statsClient) {
        // report new request for stats
        statsClient.reportNewRequest('s3');
    }

    try {
        const validHosts = allEndpoints.concat(websiteEndpoints);
        routesUtils.normalizeRequest(req, validHosts);
    } catch (err) {
        log.debug('could not normalize request', { error: err.stack });
        return routesUtils.responseXMLBody(
            errors.InvalidURI.customizeDescription('Could not parse the ' +
                'specified URI. Check your restEndpoints configuration.'),
                undefined, res, log);
    }

    log.addDefaultFields({
        bucketName: req.bucketName,
        objectKey: req.objectKey,
        bytesReceived: req.parsedContentLength || 0,
        bodyLength: parseInt(req.headers['content-length'], 10) || 0,
    });

    const { error, method } = checkUnsupportedRoutes(req.method, req.query);

    if (error) {
        log.trace('error validating route or uri params', { error });
        return routesUtils.responseXMLBody(error, null, res, log);
    }

    const bucketOrKeyError = checkBucketAndKey(req.bucketName, req.objectKey,
        req.method, req.query, blacklistedPrefixes, log);

    if (bucketOrKeyError) {
        log.trace('error with bucket or key value',
        { error: bucketOrKeyError });
        return routesUtils.responseXMLBody(bucketOrKeyError, null, res, log);
    }

    // bucket website request
    if (websiteEndpoints && websiteEndpoints.indexOf(req.parsedHost) > -1) {
        return routeWebsite(req, res, api, log, statsClient, dataRetrievalFn);
    }

    return method(req, res, api, log, statsClient, dataRetrievalFn);
}

module.exports = routes;
<|endoftext|>


<commit_before>define(["mathjax"], function() {

	// Allow labels and numbers to be reset:
	// https://groups.google.com/forum/#!msg/mathjax-users/kzOOFw1qtxw/YdAEPJfCEXUJ

	MathJax.resetLabels = function() {
		//var AMS = MathJax.Extension["TeX/AMSmath"];
		//AMS.startNumber = 0;
		//AMS.labels = {};
	}

	// Allow inline maths with single $s
	MathJax.Hub.Config({

		config: ["TeX-AMS_HTML.js"],

		tex2jax: {
		inlineMath: [ ['$','$'], ["\\(","\\)"] ],
		displayMath: [ ['$$','$$'], ["\\[","\\]"] ],
		processEscapes: true,
		preview: ["---"],
		},
		TeX: {
			Macros: {
				// See http://docs.mathjax.org/en/latest/tex.html#defining-tex-macros
				"quantity": ["{#1}\\,{\\rm{#2}}",2],
				"valuedef": ["{#1}={\\quantity{#2}{#3}}",3],
				"vtr": ["{\\underline{\\boldsymbol{#1}}}",1],
				"d": "\\operatorname{d}",
				"vari": ["#1",1],
				"s": ["_{\\sf{#1}}", 1],
				"half": ["\\frac{1}{2}",0],
				"third": ["\\frac{1}{3}",0],
				"quarter": ["\\frac{1}{4}",0],
				"eighth": ["\\frac{1}{8}",0],
				"e": ["\\textrm{e}",0],
				"units": ["\\rm{#1}",1],
				"standardstate": ["\\mathbin{\u29B5}",0],
			},
			extensions: ["mhchem.js"],

		},
	});

	// Fix font issues in Chrome 32
	// https://groups.google.com/forum/#!msg/mathjax-users/S5x-RQDPJrI/p4nmRXJvoskJ

	MathJax.Hub.Config({
		extensions: ["MatchWebFonts.js"]
	});

	if (MathJax.Hub.Browser.isChrome /*&& MathJax.Hub.Browser.version.substr(0,3) === "32."*/) {
		MathJax.Hub.Register.StartupHook(
			"HTML-CSS Jax Config",
			function () {MathJax.OutputJax["HTML-CSS"].FontFaceBug = true}
		);
	}

	MathJax.Hub.Configured();

});

// Here is a very useful page:

// http://meta.math.stackexchange.com/questions/5020/mathjax-basic-tutorial-and-quick-reference
<commit_msg>Add support for boolean logic symbols<commit_after>define(["mathjax"], function() {

	// Allow labels and numbers to be reset:
	// https://groups.google.com/forum/#!msg/mathjax-users/kzOOFw1qtxw/YdAEPJfCEXUJ

	MathJax.resetLabels = function() {
		//var AMS = MathJax.Extension["TeX/AMSmath"];
		//AMS.startNumber = 0;
		//AMS.labels = {};
	}

	// Allow inline maths with single $s
	MathJax.Hub.Config({

		config: ["TeX-AMS_HTML.js"],

		tex2jax: {
		inlineMath: [ ['$','$'], ["\\(","\\)"] ],
		displayMath: [ ['$$','$$'], ["\\[","\\]"] ],
		processEscapes: true,
		preview: ["---"],
		},
		TeX: {
			Macros: {
				// See http://docs.mathjax.org/en/latest/tex.html#defining-tex-macros
				"quantity": ["{#1}\\,{\\rm{#2}}",2],
				"valuedef": ["{#1}={\\quantity{#2}{#3}}",3],
				"vtr": ["{\\underline{\\boldsymbol{#1}}}",1],
				"d": "\\operatorname{d}",
				"vari": ["#1",1],
				"s": ["_{\\sf{#1}}", 1],
				"half": ["\\frac{1}{2}",0],
				"third": ["\\frac{1}{3}",0],
				"quarter": ["\\frac{1}{4}",0],
				"eighth": ["\\frac{1}{8}",0],
				"e": ["\\textrm{e}",0],
				"units": ["\\rm{#1}",1],
				"standardstate": ["\\mathbin{\u29B5}",0],
				"and": ["{#1} \\wedge {#2}", 2],
				"or": ["{#1} \\lor {#2}", 2],
				"not": ["\\lnot{#1}", 1],
			},
			extensions: ["mhchem.js"],

		},
	});

	// Fix font issues in Chrome 32
	// https://groups.google.com/forum/#!msg/mathjax-users/S5x-RQDPJrI/p4nmRXJvoskJ

	MathJax.Hub.Config({
		extensions: ["MatchWebFonts.js"]
	});

	if (MathJax.Hub.Browser.isChrome /*&& MathJax.Hub.Browser.version.substr(0,3) === "32."*/) {
		MathJax.Hub.Register.StartupHook(
			"HTML-CSS Jax Config",
			function () {MathJax.OutputJax["HTML-CSS"].FontFaceBug = true}
		);
	}

	MathJax.Hub.Configured();

});

// Here is a very useful page:

// http://meta.math.stackexchange.com/questions/5020/mathjax-basic-tutorial-and-quick-reference
<|endoftext|>


<commit_before>/*

            _/    _/_/    _/_/_/_/_/                              _/
               _/    _/      _/      _/_/    _/    _/    _/_/_/  _/_/_/
          _/  _/  _/_/      _/    _/    _/  _/    _/  _/        _/    _/
         _/  _/    _/      _/    _/    _/  _/    _/  _/        _/    _/
        _/    _/_/  _/    _/      _/_/      _/_/_/    _/_/_/  _/    _/
       _/
    _/

    Created by David Kaneda <http://www.davidkaneda.com>
    Maintained by Jonathan Stark <http://jonathanstark.com/>
    Sponsored by Sencha Labs <http://www.sencha.com/>

    Documentation and issue tracking on GitHub <http://wiki.github.com/senchalabs/jQTouch/>

    (c) 2009-2011 by jQTouch project members.
    See LICENSE.txt for license.

    $Revision: $
    $Date: $
    $LastChangedBy: $

*/

(function($) {
    var SUPPORT_TOUCH = (!!window.Touch);
    var START_EVENT = SUPPORT_TOUCH? 'touchstart' : 'mousedown';
    var MOVE_EVENT = SUPPORT_TOUCH? 'touchmove' : 'mousemove';
    var END_EVENT = SUPPORT_TOUCH? 'touchend' : 'mouseup';
    var CANCEL_EVENT = SUPPORT_TOUCH? 'touchcancel' : 'mouseout'; // mouseout on document
    var lastTime = 0;
    var tapReady = true;
    var jQTSettings = {
          useFastTouch: true, // experimental
          debug: true,
          moveThreshold: 10,
          hoverDelay: 50,
          pressDelay: 1000
    };

    function _debug(message) {
        var now = new Date().getTime();
        var delta = now - lastTime;
        lastTime = now;
        if (jQTSettings.debug) {
            if (message) {
                _log(delta + ': ' + message);
            } else {
                _log(delta + ': ' + 'Called ' + arguments.callee.caller.name);
            }
        }
    }

    function _log(message) {
        if (window.console !== undefined) {
            console.log(message);
        }
    }

    function touchStartHandler(e) {
        _debug();

        if (!tapReady) {
            _debug('TouchStart handler aborted because tap is not ready');
            e.preventDefault();
            return false;
        }

        var $el = $(e.target);

        // Error check
        if (!$el.length) {
            _debug('Could not find target of touchstart event.');
            return;
        }

        var startTime = (new Date).getTime(),
            hoverTimeout = null,
            pressTimeout = null,
            touch,
            startX,
            startY,
            deltaX = 0,
            deltaY = 0,
            deltaT = 0;

        touch = SUPPORT_TOUCH? event.changedTouches[0]: event;
        startX = touch.pageX;
        startY = touch.pageY;

        // Prep the element
        bindEvents($el);

        hoverTimeout = setTimeout(function() {
            $el.makeActive();
        }, jQTSettings.hoverDelay);

        pressTimeout = setTimeout(function() {
            unbindEvents($el);
            $el.unselect();
            clearTimeout(hoverTimeout);
            $el.trigger('press');
        }, jQTSettings.pressDelay);

        // Private touch functions
        function touchCancelHandler(e) {
            _debug();
            clearTimeout(hoverTimeout);
            $el.unselect();
            unbindEvents($el);
        }

        function touchEndHandler(e) {
            _debug();
            // updateChanges();
            unbindEvents($el);
            clearTimeout(hoverTimeout);
            clearTimeout(pressTimeout);
            if (Math.abs(deltaX) < jQTSettings.moveThreshold && Math.abs(deltaY) < jQTSettings.moveThreshold && deltaT < jQTSettings.pressDelay) {
                // e.preventDefault();
                // e.stopImmediatePropagation();
                if (SUPPORT_TOUCH && jQTSettings.useFastTouch) {
                    $el.trigger('tap', e);
                }
            } else {
                $el.unselect();
            }
        }

        function touchMoveHandler(e) {
            // _debug();
            updateChanges();
            var absX = Math.abs(deltaX);
            var absY = Math.abs(deltaY);
            var direction;
            if (absX > absY && (absX > 35) && deltaT < 1000) {
                if (deltaX < 0) {
                    direction = 'left';
                } else {
                    direction = 'right';
                }
                unbindEvents($el);
                $el.trigger('swipe', {direction:direction, deltaX:deltaX, deltaY: deltaY});
            }
            $el.unselect();
            clearTimeout(hoverTimeout);
            if (absX > jQTSettings.moveThreshold || absY > jQTSettings.moveThreshold) {
                clearTimeout(pressTimeout);
            }
        }

        function touchCancelHandler(e) {
            if ($el) $el.removeClass('active');
            unbindEvents();
        };

        function updateChanges() {
            // _debug();
            var firstFinger = SUPPORT_TOUCH? event.changedTouches[0]: event;
            deltaX = firstFinger.pageX - startX;
            deltaY = firstFinger.pageY - startY;
            deltaT = (new Date).getTime() - startTime;
            // _debug('deltaX:'+deltaX+';deltaY:'+deltaY+';');
        }

        function bindEvents($el) {
            $el.bind(MOVE_EVENT, touchMoveHandler).bind(END_EVENT, touchEndHandler);
            if (SUPPORT_TOUCH) {
                $el.bind(CANCEL_EVENT, touchCancelHandler);
            } else {
                $(document).bind('mouseout', touchCancelHandler);
            }
        }

        function unbindEvents($el) {
            if (!$el) {
                return;
            }

            $el.unbind(MOVE_EVENT, touchMoveHandler).unbind(END_EVENT, touchEndHandler);
            if (SUPPORT_TOUCH) {
                $el.unbind(CANCEL_EVENT, touchCancelHandler);
            } else {
                $(document).unbind('mouseout', touchCancelHandler);
            }
        }
    } // End touch handler

    $.jQTouch = function(options) {

        // take in options
        for (i in options) jQTSettings[i] = options[i];

        $(document).bind('ready', function() {
            $('#jqt').bind(START_EVENT, touchStartHandler);
        });

        $.fn.press = function(fn) {
            if ($.isFunction(fn)) {
                return $(this).live('press', fn);
            } else {
                return $(this).trigger('press');
            }
        };
        $.fn.swipe = function(fn) {
            if ($.isFunction(fn)) {
                return $(this).live('swipe', fn);
            } else {
                return $(this).trigger('swipe');
            }
        };
        $.fn.tap = function(fn) {
            if ($.isFunction(fn)) {
                return $(this).live('tap', fn);
            } else {
                return $(this).trigger('tap');
            }
        };

        options.framework = $;

        options.serialize = function($form) {
            return $form.serialize();
        };

        var core = jQTouchCore(options);

        return core;
    };

    // Extensions directly manipulate the jQTouch object, before it's initialized.
    $.jQTouch.addExtension = function(extension) {
        jQTouchCore.prototype.extensions.push(extension);
    };

})(jQuery);
<commit_msg>Fixes to jQuery bridge<commit_after>/*

            _/    _/_/    _/_/_/_/_/                              _/
               _/    _/      _/      _/_/    _/    _/    _/_/_/  _/_/_/
          _/  _/  _/_/      _/    _/    _/  _/    _/  _/        _/    _/
         _/  _/    _/      _/    _/    _/  _/    _/  _/        _/    _/
        _/    _/_/  _/    _/      _/_/      _/_/_/    _/_/_/  _/    _/
       _/
    _/

    Created by David Kaneda <http://www.davidkaneda.com>
    Maintained by Jonathan Stark <http://jonathanstark.com/>
    Sponsored by Sencha Labs <http://www.sencha.com/>

    Documentation and issue tracking on GitHub <http://wiki.github.com/senchalabs/jQTouch/>

    (c) 2009-2011 by jQTouch project members.
    See LICENSE.txt for license.

*/

(function($) {
    var SUPPORT_TOUCH = (!!window.Touch);
    var START_EVENT = SUPPORT_TOUCH? 'touchstart' : 'mousedown';
    var MOVE_EVENT = SUPPORT_TOUCH? 'touchmove' : 'mousemove';
    var END_EVENT = SUPPORT_TOUCH? 'touchend' : 'mouseup';
    var CANCEL_EVENT = SUPPORT_TOUCH? 'touchcancel' : 'mouseout'; // mouseout on document
    var lastTime = 0;
    var tapReady = true;
    var jQTSettings = {
          useFastTouch: true, // experimental
          debug: true,
          moveThreshold: 10,
          hoverDelay: 50,
          pressDelay: 1000
    };

    function _debug(message) {
        var now = new Date().getTime();
        var delta = now - lastTime;
        lastTime = now;
        if (jQTSettings.debug) {
            if (message) {
                _log(delta + ': ' + message);
            } else {
                _log(delta + ': ' + 'Called ' + arguments.callee.caller.name);
            }
        }
    }

    function _log(message) {
        if (window.console !== undefined) {
            console.log(message);
        }
    }

    function touchStartHandler(e) {
        _debug();

        if (!tapReady) {
            _debug('TouchStart handler aborted because tap is not ready');
            e.preventDefault();
            return false;
        }

        var $el = $(e.target);

        // Error check
        if (!$el.length) {
            _debug('Could not find target of touchstart event.');
            return;
        }

        var startTime = new Date().getTime(),
            hoverTimeout = null,
            pressTimeout = null,
            touch,
            startX,
            startY,
            deltaX = 0,
            deltaY = 0,
            deltaT = 0;

        touch = SUPPORT_TOUCH? event.changedTouches[0]: event;
        startX = touch.pageX;
        startY = touch.pageY;

        // Prep the element
        bindEvents($el);

        hoverTimeout = setTimeout(function() {
            $el.makeActive();
        }, jQTSettings.hoverDelay);

        pressTimeout = setTimeout(function() {
            unbindEvents($el);
            $el.unselect();
            clearTimeout(hoverTimeout);
            $el.trigger('press');
        }, jQTSettings.pressDelay);

        // Private touch functions
        function touchCancelHandler(e) {
            _debug();
            clearTimeout(hoverTimeout);
            $el.unselect();
            unbindEvents($el);
        }

        function touchEndHandler(e) {
            _debug();
            // updateChanges();
            unbindEvents($el);
            clearTimeout(hoverTimeout);
            clearTimeout(pressTimeout);
            if (Math.abs(deltaX) < jQTSettings.moveThreshold && Math.abs(deltaY) < jQTSettings.moveThreshold && deltaT < jQTSettings.pressDelay) {
                // e.preventDefault();
                // e.stopImmediatePropagation();
                if (SUPPORT_TOUCH && jQTSettings.useFastTouch) {
                    $el.trigger('tap', e);
                }
            } else {
                $el.unselect();
            }
        }

        function touchMoveHandler(e) {
            // _debug();
            updateChanges();
            var absX = Math.abs(deltaX);
            var absY = Math.abs(deltaY);
            var direction;
            if (absX > absY && (absX > 35) && deltaT < 1000) {
                if (deltaX < 0) {
                    direction = 'left';
                } else {
                    direction = 'right';
                }
                unbindEvents($el);
                $el.trigger('swipe', {direction:direction, deltaX:deltaX, deltaY: deltaY});
            }
            $el.unselect();
            clearTimeout(hoverTimeout);
            if (absX > jQTSettings.moveThreshold || absY > jQTSettings.moveThreshold) {
                clearTimeout(pressTimeout);
            }
        }

        function updateChanges() {
            // _debug();
            var firstFinger = SUPPORT_TOUCH? event.changedTouches[0]: event;
            deltaX = firstFinger.pageX - startX;
            deltaY = firstFinger.pageY - startY;
            deltaT = new Date().getTime() - startTime;
            // _debug('deltaX:'+deltaX+';deltaY:'+deltaY+';');
        }

        function bindEvents($el) {
            $el.bind(MOVE_EVENT, touchMoveHandler).bind(END_EVENT, touchEndHandler);
            if (SUPPORT_TOUCH) {
                $el.bind(CANCEL_EVENT, touchCancelHandler);
            } else {
                $(document).bind('mouseout', touchCancelHandler);
            }
        }

        function unbindEvents($el) {
            if (!$el) {
                return;
            }

            $el.unbind(MOVE_EVENT, touchMoveHandler).unbind(END_EVENT, touchEndHandler);
            if (SUPPORT_TOUCH) {
                $el.unbind(CANCEL_EVENT, touchCancelHandler);
            } else {
                $(document).unbind('mouseout', touchCancelHandler);
            }
        }
    } // End touch handler

    $.jQTouch = function(options) {

        // take in options
        for (var i in options) {
            jQTSettings[i] = options[i];
        }

        $(document).bind('ready', function() {
            $('#jqt').bind(START_EVENT, touchStartHandler);
        });

        $.fn.press = function(fn) {
            if ($.isFunction(fn)) {
                return $(this).live('press', fn);
            } else {
                return $(this).trigger('press');
            }
        };
        $.fn.swipe = function(fn) {
            if ($.isFunction(fn)) {
                return $(this).live('swipe', fn);
            } else {
                return $(this).trigger('swipe');
            }
        };
        $.fn.tap = function(fn) {
            if ($.isFunction(fn)) {
                return $(this).live('tap', fn);
            } else {
                return $(this).trigger('tap');
            }
        };

        options.framework = $;

        options.serialize = function($form) {
            return $form.serialize();
        };

        var core = jQTouchCore(options);

        return core;
    };

    // Extensions directly manipulate the jQTouch object, before it's initialized.
    $.jQTouch.addExtension = function(extension) {
        jQTouchCore.prototype.extensions.push(extension);
    };

})(jQuery);<|endoftext|>


<commit_before>var lastControllerLocation = "";

controllers.index = function(search, sort, sortDirection) {
  var _this = this;

  function sortFor(type) {
    if(type == "publishedOn") return function(video) {
      return video.publishedOn;
    };
/*    if(type == "pages") return function(video) {
      return video.pageUrls.length;
    };*/
    if(type == "title") return function(video) {
      return video.title.toLowerCase();
    };
  }

  var videos = store;
  if(search && search != "") {
    var words = search.split(/\s+/);
    _.each(words, function(word) {
      regex = RegExp(word, "i");
      videos = _.filter(videos, function(video) {
        return video.title.match(regex);
      });
    });
  }
  if(!sort) sort = "publishedOn";
  videos = _.sortBy(videos, sortFor(sort));

  if(!sortDirection) sortDirection = "desc";
  if(sortDirection == "desc") videos = videos.reverse();

  function perPageFromWindow() {
    var windowWidth = $(window).width();
    if(windowWidth < 1000) return 16;
    else if(windowWidth > 1000 && windowWidth < 1500) return 21;
    else if(windowWidth > 1500) return 25;
  }

  var perPage = perPageFromWindow();
  var pages = utils.pages(videos, perPage);

  this.init = function() {
    console.log("starting index");

    $("#search").bind("keydown", function(event) {
      event.stopPropagation();
      if(event.keyCode == 13) {
        event.preventDefault();
        utils.location({ params: [$("#search").val(), sort, sortDirection], hash: "1" });
      }
    });

    $("#clear-search").bind("click", function() {
      $("#search").val("");
      event.preventDefault();
      location.href = "#index!1";
    });

    $(".sort button").bind("click", function(event) {
      event.preventDefault();
      utils.location({ params: [search, $(this).data("sort"), sortDirection], hash: "1" });
    });

    $(".sort button").removeClass("active");
    $(".sort button[data-sort=" + sort + "]").addClass("active");

    $(".sort-direction button").bind("click", function(event) {
      event.preventDefault();
      utils.location({ params: [search, sort, $(this).data("sort-direction")], hash: "1" });
    });

    $(".sort-direction button").removeClass("active");
    $(".sort-direction button[data-sort-direction=" + sortDirection + "]").addClass("active");

    $("#view-index").show().addClass("current-view");
    $("title").text("Videos");
  }

  function addVideos(videos) {
    $("#items").empty();

    _.each(videos, function(video) {
      var item = $("
");
      var link = $("");
      link.attr("href", video.url);
      link.attr("target", "_blank");
      var img = $("");
      img.attr("src", video.thumbnailUrl);
      link.append(img);
      item.append(link);

      item.append('

' + video.title + '

');

      $("#items").append(item);
    });
  }

  this.render = function() {
    console.log("rendering");
    window.scrollTo(0, 0);

    var videosPage = utils.paginate(videos, perPage);
    addVideos(videosPage);
    lastControllerLocation = location.hash;
  }

  this.destroy = function() {
    console.log("destroying index");
    $("#search").unbind("keydown");
    $("#clear-search").unbind("click");
    $(".sort button").unbind("click");
    $(".sort-direction button").unbind("click");
    $("#items").empty();
    $("#view-index").hide().removeClass("current-view");
  }
}
<commit_msg>Use the play URL protocol<commit_after>var lastControllerLocation = "";

controllers.index = function(search, sort, sortDirection) {
  var _this = this;

  function sortFor(type) {
    if(type == "publishedOn") return function(video) {
      return video.publishedOn;
    };
/*    if(type == "pages") return function(video) {
      return video.pageUrls.length;
    };*/
    if(type == "title") return function(video) {
      return video.title.toLowerCase();
    };
  }

  var videos = store;
  if(search && search != "") {
    var words = search.split(/\s+/);
    _.each(words, function(word) {
      regex = RegExp(word, "i");
      videos = _.filter(videos, function(video) {
        return video.title.match(regex);
      });
    });
  }
  if(!sort) sort = "publishedOn";
  videos = _.sortBy(videos, sortFor(sort));

  if(!sortDirection) sortDirection = "desc";
  if(sortDirection == "desc") videos = videos.reverse();

  function perPageFromWindow() {
    var windowWidth = $(window).width();
    if(windowWidth < 1000) return 16;
    else if(windowWidth > 1000 && windowWidth < 1500) return 21;
    else if(windowWidth > 1500) return 25;
  }

  var perPage = perPageFromWindow();
  var pages = utils.pages(videos, perPage);

  this.init = function() {
    console.log("starting index");

    $("#search").bind("keydown", function(event) {
      event.stopPropagation();
      if(event.keyCode == 13) {
        event.preventDefault();
        utils.location({ params: [$("#search").val(), sort, sortDirection], hash: "1" });
      }
    });

    $("#clear-search").bind("click", function() {
      $("#search").val("");
      event.preventDefault();
      location.href = "#index!1";
    });

    $(".sort button").bind("click", function(event) {
      event.preventDefault();
      utils.location({ params: [search, $(this).data("sort"), sortDirection], hash: "1" });
    });

    $(".sort button").removeClass("active");
    $(".sort button[data-sort=" + sort + "]").addClass("active");

    $(".sort-direction button").bind("click", function(event) {
      event.preventDefault();
      utils.location({ params: [search, sort, $(this).data("sort-direction")], hash: "1" });
    });

    $(".sort-direction button").removeClass("active");
    $(".sort-direction button[data-sort-direction=" + sortDirection + "]").addClass("active");

    $("#view-index").show().addClass("current-view");
    $("title").text("Videos");
  }

  function absoluteURL(url) {
	  var a = document.createElement("a");
	  a.href = url;
	  return a.href;
  }

  function addVideos(videos) {
    $("#items").empty();

    _.each(videos, function(video) {
      var item = $("
");
      var link = $("");
      link.attr("href", "play://" + absoluteURL(video.url));
      //link.attr("target", "_blank");
      var img = $("");
      img.attr("src", video.thumbnailUrl);
      link.append(img);
      item.append(link);

      item.append('

' + video.title + '

');

      $("#items").append(item);
    });
  }

  this.render = function() {
    console.log("rendering");
    window.scrollTo(0, 0);

    var videosPage = utils.paginate(videos, perPage);
    addVideos(videosPage);
    lastControllerLocation = location.hash;
  }

  this.destroy = function() {
    console.log("destroying index");
    $("#search").unbind("keydown");
    $("#clear-search").unbind("click");
    $(".sort button").unbind("click");
    $(".sort-direction button").unbind("click");
    $("#items").empty();
    $("#view-index").hide().removeClass("current-view");
  }
}
<|endoftext|>


<commit_before>(function($) {
	$.fn.aeImageResize = function(options) {
		var strHeight = 'height',
			strWidth = 'width',
			browser = $.browser,
			mathFloor = Math.floor,
			params = $.extend({
				height: 0,
				width: 0
			}, options),
			isIE6 = browser.msie && (parseInt(browser.version) == 6),
			aspectRatio = params[strWidth] / params[strHeight];

		// We cannot do much unless we have one of these
		if ( !params[strHeight] && !params[strWidth] ) {
			return;
		}

		// Calculate aspect ratio now, if possible
		if ( params[strHeight] && params[strWidth] ) {
			aspectRatio = params[strWidth] / params[strHeight];
		}

		// Attach handler to load
		// Handler is executed just once per element
		// Load event required for Webkit browsers
		$(this).one('load', function() {

			// Remove all attributes and CSS rules
			$(this).removeAttr(strHeight)
				   .removeAttr(strWidth)
				   .css({height: '', width: ''});

			var imgHeight = this[strHeight],
				imgWidth = this[strWidth],
				imgAspectRatio = imgWidth / imgHeight,
				bxHeight = params[strHeight],
				bxWidth = params[strWidth],
				bxAspectRatio = aspectRatio;

			// Work the magic!
			// If one parameter is missing, we just force calculate it
			if ( !bxAspectRatio ) {
				if (bxHeight === 0) {
					bxAspectRatio = imgAspectRatio - 1;
				} else {
					bxAspectRatio = imgAspectRatio + 1;
				}
			}

			// Only resize the images that need resizing
			if ( (bxHeight && imgHeight > bxHeight) || (bxWidth && imgWidth > bxWidth) ) {

				if (imgAspectRatio > aspectRatio) {
					bxHeight = mathFloor(imgHeight / imgWidth * bxWidth);
				} else {
					bxWidth = mathFloor(imgWidth / imgHeight * bxHeight);
				}

				$(this).attr({
					'height': bxHeight,
					'width': bxWidth
				});
			}
		})
		.each(function() {

			// Trigger load event (for Gecko and MSIE)
			if (this.complete || isIE6)
			{
				$(this).trigger('load');
			}
		});
	};
})(jQuery);<commit_msg>Some clean up<commit_after>(function($) {

	$.fn.aeImageResize = function( options ) {

		var strHeight = "height"
		,	strWidth = "width"
		,	mathFloor = Math.floor
		,	browser = $.browser
		,	isIE6 = browser.msie && (parseInt(browser.version) == 6)
		,	aspectRatio = 0
		,	params = $.extend({
				height: 0,
				width: 0
			}, options)
		;

		// We cannot do much unless we have one of these
		if ( !params[strHeight] && !params[strWidth] ) {
			return;
		}

		// Calculate aspect ratio now, if possible
		if ( params[strHeight] && params[strWidth] ) {
			aspectRatio = params[strWidth] / params[strHeight];
		}

		// Attach handler to load
		// Handler is executed just once per element
		// Load event required for Webkit browsers
		$( this ).one( "load", function() {

			// Remove all attributes and CSS rules
			$( this ).removeAttr( strHeight )
					 .removeAttr( strWidth )
					 .css({
						 height: '',
						 width: ''
					 });

			var imgHeight = this[strHeight]
			,	imgWidth = this[strWidth]
			,	imgAspectRatio = imgWidth / imgHeight
			,	bxHeight = params[strHeight]
			,	bxWidth = params[strWidth]
			,	bxAspectRatio = aspectRatio;

			// Work the magic!
			// If one parameter is missing, we just force calculate it
			if ( !bxAspectRatio ) {
				if ( bxHeight === 0 ) {
					bxAspectRatio = imgAspectRatio - 1;
				} else {
					bxAspectRatio = imgAspectRatio + 1;
				}
			}

			// Only resize the images that need resizing
			if ( (bxHeight && imgHeight > bxHeight) || (bxWidth && imgWidth > bxWidth) ) {

				if ( imgAspectRatio > aspectRatio ) {
					bxHeight = mathFloor( imgHeight / imgWidth * bxWidth );
				} else {
					bxWidth = mathFloor( imgWidth / imgHeight * bxHeight );
				}

				$( this ).attr({
					"height": bxHeight,
					"width": bxWidth
				});
			}
		})
		.each(function() {

			// Trigger load event (for Gecko and MSIE)
			if ( this.complete || isIE6 ) {
				$( this ).trigger( "load" );
			}
		});
	};
})(jQuery);<|endoftext|>


<commit_before>'use strict';

var directivesModule = require('./_index.js');

/**
 * @ngInject
 */
function statusDirective($timeout) {

  return {
    scope: {
    	data: '=',
    	highlight: '=',
    	openSwipe: '=',
    	showModal: '=',
    },
    templateUrl: 'status.html',
    controller: function($scope, $element) {
        // Toggle show-hide detail when clicked
        // execept when clicked on "Details"
        $scope.showDetail = false;
        $scope.toggleDetail = function(event) {
            if (!(event.target.className === "link-to-tweet"))
                $scope.showDetail = !$scope.showDetail;
        };
    },
    link: function(scope, element, attrs) {
        console.log(scope.$parent.$last);
        if (scope.$parent.$last) {
            $timeout(function() {
                var imgs = angular.element('.triple-masonry-item.first-item').find('img')   ;
                angular.forEach(imgs, function(value, key) {
                    var height = value.clientHeight;
                    var width = value.clientWidth;
                    var classToAdd = (height >= width) ? 'vertical' : 'landscape';
                    angular.element(value).addClass(classToAdd);
                });
            }, 0);
        };

    }
  };

}

directivesModule.directive('status', statusDirective);<commit_msg>Rm  solution with proper 'load' event solution<commit_after>'use strict';

var directivesModule = require('./_index.js');

/**
 * @ngInject
 */
function statusDirective($timeout) {

  return {
    scope: {
    	data: '=',
    	highlight: '=',
    	openSwipe: '=',
    	showModal: '=',
    },
    templateUrl: 'status.html',
    controller: function($scope, $element) {
        // Toggle show-hide detail when clicked
        // execept when clicked on "Details"
        $scope.showDetail = false;
        $scope.toggleDetail = function(event) {
            if (!(event.target.className === "link-to-tweet"))
                $scope.showDetail = !$scope.showDetail;
        };
    },
    link: function(scope, element, attrs) {
        console.log(scope.$parent.$last);
        if (scope.$parent.$last) {
            var imgEle = angular.element('img');
            imgEle.bind('load', function() {
                var imgs = angular.element('.triple-masonry-item.first-item').find('img')   ;
                angular.forEach(imgs, function(value, key) {
                    var height = value.clientHeight;
                    var width = value.clientWidth;
                    var classToAdd = (height >= width) ? 'vertical' : 'landscape';
                    angular.element(value).addClass(classToAdd);
                });
            });

        };

    }
  };

}

directivesModule.directive('status', statusDirective);<|endoftext|>


<commit_before>/*
* .serializeObject (c) Dan Heberden
* danheberden.com
*
* Gives you a pretty object for your form elements
*/
(function($){
  $.fn.serializeObject = function() {
    if ( !this.length ) { return false; }

    var $el = this,
      data = {},
	    lookup = data; //current reference of data

      $el.find(':input[type!="checkbox"][type!="radio"], input:checked').each(function() {
        // data[a][b] becomes [ data, a, b ]
        var named = this.name.replace(/\[([^\]]+)?\]/g, ',$1').split(','),
            cap = named.length - 1,
            i = 0;

        for ( ; i < cap; i++ ) {
            // move down the tree - create objects or array if necessary
            lookup = lookup[ named[i] ] = lookup[ named[i] ] ||
                ( named[i+1] == "" ? [] : {} );
        }

        // at the end, psuh or assign the value
        if ( lookup.length != undefined ) {
             lookup.push( $(this).val() );
        }else {
              lookup[ named[ cap ] ]  = $(this).val();
        }

        // assign the reference back to root
        lookup = data;
      });

    return data;
  };
})(jQuery);<commit_msg>Fix rogue tab<commit_after>/*
* .serializeObject (c) Dan Heberden
* danheberden.com
*
* Gives you a pretty object for your form elements
*/
(function($){
  $.fn.serializeObject = function() {
    if ( !this.length ) { return false; }

    var $el = this,
      data = {},
      lookup = data; //current reference of data

      $el.find(':input[type!="checkbox"][type!="radio"], input:checked').each(function() {
        // data[a][b] becomes [ data, a, b ]
        var named = this.name.replace(/\[([^\]]+)?\]/g, ',$1').split(','),
            cap = named.length - 1,
            i = 0;

        for ( ; i < cap; i++ ) {
            // move down the tree - create objects or array if necessary
            lookup = lookup[ named[i] ] = lookup[ named[i] ] ||
                ( named[i+1] == "" ? [] : {} );
        }

        // at the end, psuh or assign the value
        if ( lookup.length != undefined ) {
             lookup.push( $(this).val() );
        }else {
              lookup[ named[ cap ] ]  = $(this).val();
        }

        // assign the reference back to root
        lookup = data;
      });

    return data;
  };
})(jQuery);<|endoftext|>


<commit_before>#!/usr/bin/env node

process.on('uncaughtException', error => {
  consol.error(error);

  process.exit(1)
});

process.on('unhandledRejection', error => {
  consol.error(error);

  process.exit(1)
});

const program = require('commander');

const YoutubeChannelCrawler = require('../lib');

let apiKey;
let username;

program
  .version('1.0.0')
  .arguments('<apiKey> <username>')
  .action(function (a, u) {
    apiKey = a;
    username = u
  })
  .parse(process.argv);

if (!username) {
  console.error('Correct usage: youtube-channel-crawler <apiKey> <username>');
  process.exit(1);
}

// noinspection JSUnusedAssignment
YoutubeChannelCrawler.getChannelStatisticsByUsername(apiKey, username)
  .then((statistics) => {
    console.log(JSON.stringify(statistics, null, 2))
  })
  .catch((error) => console.error(error));<commit_msg>Fixed typo.<commit_after>#!/usr/bin/env node

process.on('uncaughtException', error => {
  console.error(error);

  process.exit(1)
});

process.on('unhandledRejection', error => {
  console.error(error);

  process.exit(1)
});

const program = require('commander');

const YoutubeChannelCrawler = require('../lib');

let apiKey;
let username;

program
  .version('1.0.0')
  .arguments('<apiKey> <username>')
  .action(function (a, u) {
    apiKey = a;
    username = u
  })
  .parse(process.argv);

if (!username) {
  console.error('Correct usage: youtube-channel-crawler <apiKey> <username>');
  process.exit(1);
}

// noinspection JSUnusedAssignment
YoutubeChannelCrawler.getChannelStatisticsByUsername(apiKey, username)
  .then((statistics) => {
    console.log(JSON.stringify(statistics, null, 2))
  })
  .catch((error) => console.error(error));<|endoftext|>