<commit_before>var reverseIndex = Object.create(null);

function createReverseIndex() {
  videoCaptions.forEach(function (captions, i) {
    var currentTime = 0;
    var prevWord = "";
    var prevprevWord = "";
    captions.forEach(function (caption) {
      caption.text.split(/\s+/).forEach(function (word) {
        word = word.replace(/[\W_]+/g,"").toLowerCase(); // Remove all non-alphanumeric characters
        if (word) {
          reverseIndex[word] = (reverseIndex[word] || []);
          reverseIndex[word].push({
            videoIndex: i,
            startTime: currentTime,
            snippet: caption.text
          });
          if (prevWord.length) {
            reverseIndex[prevWord + " " + word] = (reverseIndex[prevWord + " " + word] || []);
            reverseIndex[prevWord + " " + word].push({
              videoIndex: i,
              startTime: currentTime,
              snippet: caption.text
            });
            if (prevprevWord.length) {
              reverseIndex[prevprevWord + " " + prevWord + " " + word] = (reverseIndex[prevprevWord + " " + prevWord + " " + word] || []);
              reverseIndex[prevprevWord + " " + prevWord + " " + word].push({
                videoIndex: i,
                startTime: currentTime,
                snippet: caption.text
              });
            }
            prevprevWord = prevWord;
          }
          prevWord = word;
        }
      });
      prevWord = "";
      currentTime += (caption.width / 64) + (2/64);
    });
  });
}

a = new Date();
createReverseIndex();
console.log (new Date() - a);

$(document).ready(function () {
  bindEventListeners();
  $(".search-box").focus();
});

/*
  Binds event listeners on input elements
*/
function bindEventListeners() {
  var debouncedInputKeypress = debounce(inputKeypress, 200);
  $(".search-box").off().keyup(debouncedInputKeypress);
  $(".search-box").keyup(); // Trigger event to account for auto fill
}

/*
  Helper debounce function
*/
function debounce (func, wait, immediate) {
  var timeout;
  return function() {
    var context = this, args = arguments;
    var later = function() {
      timeout = null;
      if (!immediate) func.apply(context, args);
    };
    var callNow = immediate && !timeout;
    clearTimeout(timeout);
    timeout = setTimeout(later, wait);
    if (callNow) func.apply(context, args);
  };
}

/*
  Send a search event to GA
*/
function sendGAEvent() {
  var searchQuery = $(".search-box").val();
  if (searchQuery.length) {
    ga('send', 'event', 'homepage', 'search', searchQuery);
  }
}

var debouncedSendGAEvent = debounce(sendGAEvent, 1000);

/*
  Captures the input keypresses and reacts accordingly
*/
function inputKeypress(e) {
  debouncedSendGAEvent();
  $(".search-results-container").empty();
  var query = $(".search-box").val().toLowerCase();

  query = query.trim().replace(/[^a-zA-Z\d\s:]+/g,""); // Remove all non-alphanumeric characters
  var results = Object.create(null);
  if (reverseIndex[query]) {
    reverseIndex[query].forEach(function (match) {
      if (!results[match.snippet]) {
        var snippet = match.snippet.toLowerCase();
        var query = $(".search-box").val().toLowerCase();
        query.trim().split(/\s+/).forEach(function (word) {
          snippet = updateHaystack(snippet, word);
        });
        var template = '
' + snippet + '
';
        $(".search-results-container").append(template);
        results[match.snippet] = true;
      }
    });
  }

  query = query.trim().split(/\s+/);

  var subStrings = [];
  for (var i = 0; i < query.length; i++) {
    for (var j = i; j < query.length; j++) {
      subStrings.push(query.slice(i, j+1).join(" "));
    }
  }

  subStrings = subStrings.sort(function (a,b) {
    return b.length - a.length;
  });

  subStrings.forEach(function (subString) {
    var query = subString;
    if (reverseIndex[query]) {
      reverseIndex[query].forEach(function (match) {
        if (!results[match.snippet]) {
          var snippet = match.snippet.toLowerCase();
          var query = $(".search-box").val().toLowerCase();
          query.trim().split(/\s+/).forEach(function (word) {
            snippet = updateHaystack(snippet, word);
          });
          var template = '
' + snippet + '
';
          $(".search-results-container").append(template);
          results[match.snippet] = true;
        }
      });
    }
  });
}

/*
  Bolds a needle in the input
*/
function updateHaystack(input, needle) {
  return input.replace(new RegExp('(^|[^a-zA-Z\d\s:])(' + escapeRegExp(needle) + ')([^a-zA-Z\d\s:]|$)','ig'), '$1$2$3');
}

/*
  Escapes a regular expression string
*/
function escapeRegExp(str) {
  return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
}<commit_msg>Cap results at 100 for performance reasons<commit_after>var reverseIndex = Object.create(null);

function createReverseIndex() {
  videoCaptions.forEach(function (captions, i) {
    var currentTime = 0;
    var prevWord = "";
    var prevprevWord = "";
    captions.forEach(function (caption) {
      caption.text.split(/\s+/).forEach(function (word) {
        word = word.replace(/[\W_]+/g,"").toLowerCase(); // Remove all non-alphanumeric characters
        if (word) {
          reverseIndex[word] = (reverseIndex[word] || []);
          reverseIndex[word].push({
            videoIndex: i,
            startTime: currentTime,
            snippet: caption.text
          });
          if (prevWord.length) {
            reverseIndex[prevWord + " " + word] = (reverseIndex[prevWord + " " + word] || []);
            reverseIndex[prevWord + " " + word].push({
              videoIndex: i,
              startTime: currentTime,
              snippet: caption.text
            });
            if (prevprevWord.length) {
              reverseIndex[prevprevWord + " " + prevWord + " " + word] = (reverseIndex[prevprevWord + " " + prevWord + " " + word] || []);
              reverseIndex[prevprevWord + " " + prevWord + " " + word].push({
                videoIndex: i,
                startTime: currentTime,
                snippet: caption.text
              });
            }
            prevprevWord = prevWord;
          }
          prevWord = word;
        }
      });
      prevWord = "";
      currentTime += (caption.width / 64) + (2/64);
    });
  });
}

a = new Date();
createReverseIndex();
console.log (new Date() - a);

$(document).ready(function () {
  bindEventListeners();
  $(".search-box").focus();
});

/*
  Binds event listeners on input elements
*/
function bindEventListeners() {
  var debouncedInputKeypress = debounce(inputKeypress, 200);
  $(".search-box").off().keyup(debouncedInputKeypress);
  $(".search-box").keyup(); // Trigger event to account for auto fill
}

/*
  Helper debounce function
*/
function debounce (func, wait, immediate) {
  var timeout;
  return function() {
    var context = this, args = arguments;
    var later = function() {
      timeout = null;
      if (!immediate) func.apply(context, args);
    };
    var callNow = immediate && !timeout;
    clearTimeout(timeout);
    timeout = setTimeout(later, wait);
    if (callNow) func.apply(context, args);
  };
}

/*
  Send a search event to GA
*/
function sendGAEvent() {
  var searchQuery = $(".search-box").val();
  if (searchQuery.length) {
    ga('send', 'event', 'homepage', 'search', searchQuery);
  }
}

var debouncedSendGAEvent = debounce(sendGAEvent, 1000);

/*
  Captures the input keypresses and reacts accordingly
*/
function inputKeypress(e) {
  debouncedSendGAEvent();
  $(".search-results-container").empty();
  var query = $(".search-box").val().toLowerCase();

  query = query.trim().replace(/[^a-zA-Z\d\s:]+/g,""); // Remove all non-alphanumeric characters
  var results = Object.create(null);
  if (reverseIndex[query]) {
    reverseIndex[query].forEach(function (match) {
      if (!results[match.snippet]) {
        var snippet = match.snippet.toLowerCase();
        var query = $(".search-box").val().toLowerCase();
        query.trim().split(/\s+/).forEach(function (word) {
          snippet = updateHaystack(snippet, word);
        });
        var template = '
' + snippet + '
';
        $(".search-results-container").append(template);
        results[match.snippet] = true;
      }
    });
  }

  query = query.trim().split(/\s+/);

  var subStrings = [];
  for (var i = 0; i < query.length; i++) {
    for (var j = i; j < query.length; j++) {
      subStrings.push(query.slice(i, j+1).join(" "));
    }
  }

  subStrings = subStrings.sort(function (a,b) {
    return b.length - a.length;
  });

  var numResults = 0;
  subStrings.forEach(function (subString) {
    var query = subString;
    if (reverseIndex[query]) {
      reverseIndex[query].forEach(function (match) {
        if (!results[match.snippet] && numResults < 100) {
          var snippet = match.snippet.toLowerCase();
          var query = $(".search-box").val().toLowerCase();
          query.trim().split(/\s+/).forEach(function (word) {
            snippet = updateHaystack(snippet, word);
          });
          var template = '
' + snippet + '
';
          $(".search-results-container").append(template);
          results[match.snippet] = true;
          numResults++;
        }
      });
    }
  });
}

/*
  Bolds a needle in the input
*/
function updateHaystack(input, needle) {
  return input.replace(new RegExp('(^|[^a-zA-Z\d\s:])(' + escapeRegExp(needle) + ')([^a-zA-Z\d\s:]|$)','ig'), '$1$2$3');
}

/*
  Escapes a regular expression string
*/
function escapeRegExp(str) {
  return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
}<|endoftext|>


<commit_before>module.exports = [
  {text: '首页', link: '/'},
  {
    text: '前端',
    link: '/web/',  //目录页，vdoing主题新增的配置项，有二级导航时，可以点击一级导航跳到目录页
    items: [
      {text: '前端文章', items: [
        {text: 'JavaScript', link: '/pages/8143cc480faf9a11/'}, // 注意link结尾有斜杠和没有斜杠的区别
        {text: 'Vue', link: '/pages/802a1ca6f7b71c59/'},
      ]},
      {text: '学习笔记', items:[
        {text: '《JavaScript教程》笔记', link: '/note/javascript/'},
        {text: '《JavaScript高级程序设计》笔记', link: '/note/js/'},
        {text: '《ES6 教程》笔记', link: '/note/es6/'},
        {text: '《Vue》笔记', link: '/note/vue/'},
        {text: '《TypeScript 从零实现 axios》', link: '/note/typescript-axios/'},
        {text: '小程序笔记', link: '/note/wx-miniprogram/'},
      ]}
    ]
  },
  {
    text: '页面',
    link: '/ui/',
    items: [
      {text: 'HTML', link: '/pages/8309a5b876fc95e3/'},
      {text: 'CSS', link: '/pages/0a83b083bdf257cb/'},
    ]
  },
  {
    text: '技术',
    link: '/technology/',
    items: [
      {text: '技术文档', link: '/pages/9a7ee40fc232253e/'},
      {text: 'GitHub技巧', link: '/pages/4c778760be26d8b3/'},
      {text: 'Nodejs', link: '/pages/117708e0af7f0bd9/'},
      {text: '博客搭建', link: '/pages/41f87d890d0a02af/'},
    ]
  },
  {
    text: '更多',
    link: '/more/',
    items: [
      {text: '学习', link: '/pages/f2a556/'},
      {text: '面试', link: '/pages/aea6571b7a8bae86/'},
      {text: '心情杂货', link: '/pages/2d615df9a36a98ed/'},
      {text: '友情链接', link: '/friends/'},
    ]
  },
  {text: '关于', link: '/about/'},
  {
    text: '收藏',
    link: '/pages/beb6c0bd8a66cea6/',
    items: [
      {text: '网站', link: '/pages/beb6c0bd8a66cea6/'},
      {text: '资源', link: '/pages/eee83a9211a70f9d/'},
      {text: 'Vue资源', link: '/pages/12df8ace52d493f6/'},
    ]
  },
  {
    text: '索引',
    link: '/archives/',
    items: [
      {text: '分类', link: '/categories/'},
      {text: '标签', link: '/tags/'},
      {text: '归档', link: '/archives/'},
    ]
  }
]<commit_msg>Update nav.js<commit_after>module.exports = [
  {text: '首页', link: '/'},
  {
    text: '前端',
    link: '/web/',  //目录页链接，此处link是vdoing主题新增的配置项，有二级导航时，可以点击一级导航跳到目录页
    items: [
      {text: '前端文章', items: [
        {text: 'JavaScript', link: '/pages/8143cc480faf9a11/'}, // 这些link是在相应md文件定义的永久链接。另外，注意结尾是有斜杠的
        {text: 'Vue', link: '/pages/802a1ca6f7b71c59/'},
      ]},
      {text: '学习笔记', items:[
        {text: '《JavaScript教程》笔记', link: '/note/javascript/'},
        {text: '《JavaScript高级程序设计》笔记', link: '/note/js/'},
        {text: '《ES6 教程》笔记', link: '/note/es6/'},
        {text: '《Vue》笔记', link: '/note/vue/'},
        {text: '《TypeScript 从零实现 axios》', link: '/note/typescript-axios/'},
        {text: '小程序笔记', link: '/note/wx-miniprogram/'},
      ]}
    ]
  },
  {
    text: '页面',
    link: '/ui/',
    items: [
      {text: 'HTML', link: '/pages/8309a5b876fc95e3/'},
      {text: 'CSS', link: '/pages/0a83b083bdf257cb/'},
    ]
  },
  {
    text: '技术',
    link: '/technology/',
    items: [
      {text: '技术文档', link: '/pages/9a7ee40fc232253e/'},
      {text: 'GitHub技巧', link: '/pages/4c778760be26d8b3/'},
      {text: 'Nodejs', link: '/pages/117708e0af7f0bd9/'},
      {text: '博客搭建', link: '/pages/41f87d890d0a02af/'},
    ]
  },
  {
    text: '更多',
    link: '/more/',
    items: [
      {text: '学习', link: '/pages/f2a556/'},
      {text: '面试', link: '/pages/aea6571b7a8bae86/'},
      {text: '心情杂货', link: '/pages/2d615df9a36a98ed/'},
      {text: '友情链接', link: '/friends/'},
    ]
  },
  {text: '关于', link: '/about/'},
  {
    text: '收藏',
    link: '/pages/beb6c0bd8a66cea6/',
    items: [
      {text: '网站', link: '/pages/beb6c0bd8a66cea6/'},
      {text: '资源', link: '/pages/eee83a9211a70f9d/'},
      {text: 'Vue资源', link: '/pages/12df8ace52d493f6/'},
    ]
  },
  {
    text: '索引',
    link: '/archives/',
    items: [
      {text: '分类', link: '/categories/'},
      {text: '标签', link: '/tags/'},
      {text: '归档', link: '/archives/'},
    ]
  }
]
<|endoftext|>


<commit_before>"use strict"
var process = require('child_process');
var assert = require('assert');

module.exports = function() {
  return new constructor;
}

var constructor = function() {
  this.options = {};
  this.expectations = [];
};

constructor.prototype.cmd = buildSetter("cmd");
constructor.prototype.cwd = buildSetter("cwd");
constructor.prototype.env = buildSetter("env");
constructor.prototype.timeout = buildSetter("timeout");
constructor.prototype.uid = buildSetter("uid");
constructor.prototype.gid = buildSetter("gid");

constructor.prototype.expect = function(var1, var2) {
  if (arguments.length > 1) {
    this.expectations.push({ "type": var2.constructor.name, "matcher": var1, "value": var2 });
  } else {
    this.expectations.push({ "type": var1.constructor.name, "value": var1 });
  }
  return this;
};

constructor.prototype.end = function(cb) {
  var expectations = this.expectations;
  if (this.cmd === null) { throw new Error(".end called before command set") }
  process.exec(this.cmd, this.options, function(err, stdout, stderr){
    try {
      runAllAsserts(expectations, err, stdout, stderr)
    } catch (e) {
      if (cb) {
        cb(e, stdout, stderr);
        return
      } else {
        throw e
      }
    }
    if (cb) {
      cb(err ? err : null, stdout, stderr);
    }
  });
  return this;
};

// buildSetter returns a function that
// takes a value and assigns it to the
// key on the object.
function buildSetter(key) {
  // If the key is cmd, set the cmd var
  // not the cmd key on the options obj
  if (key === "cmd") {
    return function(val) {
      this.cmd = val;
      return this;
    }
  } else {
    return function(val) {
      this.options[key] = val;
      return this;
    }
  }
}

function runAllAsserts (expectations, err, stdout, stderr) {
  expectations.forEach(function(exp){
    // Set value
    if (exp.matcher === 'stdout') { var value = stdout; }
    if (exp.matcher === 'stderr') { var value = stderr; }
    // Make assertions
    if (exp.type === 'Number' && err) { assert.equal(err.code, exp.value,
      "Expected exit code of "+exp.value+" got "+err.code); }
    if (exp.type === 'String') { assert.equal(value, exp.value,
      "Expected "+exp.matcher+" to equal "+exp.value+" got "+value); }
    if (exp.type === 'RegExp') { assert(exp.value.test(value),
      "Expected "+exp.matcher+" to match "+exp.value+" got "+value) }
  });
}
<commit_msg>Alias constructor.prototype to proto for readability<commit_after>"use strict"
var process = require('child_process');
var assert = require('assert');

module.exports = function() {
  return new constructor;
}

var constructor = function() {
  this.options = {};
  this.expectations = [];
};

var proto = constructor.prototype;

proto.cmd = buildSetter("cmd");
proto.cwd = buildSetter("cwd");
proto.env = buildSetter("env");
proto.timeout = buildSetter("timeout");
proto.uid = buildSetter("uid");
proto.gid = buildSetter("gid");

proto.expect = function(var1, var2) {
  if (arguments.length > 1) {
    this.expectations.push({ "type": var2.constructor.name, "matcher": var1, "value": var2 });
  } else {
    this.expectations.push({ "type": var1.constructor.name, "value": var1 });
  }
  return this;
};

proto.end = function(cb) {
  var expectations = this.expectations;
  if (this.cmd === null) { throw new Error(".end called before command set") }
  process.exec(this.cmd, this.options, function(err, stdout, stderr){
    try {
      runAllAsserts(expectations, err, stdout, stderr)
    } catch (e) {
      if (cb) {
        cb(e, stdout, stderr);
        return
      } else {
        throw e
      }
    }
    if (cb) {
      cb(err ? err : null, stdout, stderr);
    }
  });
  return this;
};

// buildSetter returns a function that
// takes a value and assigns it to the
// key on the object.
function buildSetter(key) {
  // If the key is cmd, set the cmd var
  // not the cmd key on the options obj
  if (key === "cmd") {
    return function(val) {
      this.cmd = val;
      return this;
    }
  } else {
    return function(val) {
      this.options[key] = val;
      return this;
    }
  }
}

function runAllAsserts (expectations, err, stdout, stderr) {
  expectations.forEach(function(exp){
    // Set value
    if (exp.matcher === 'stdout') { var value = stdout; }
    if (exp.matcher === 'stderr') { var value = stderr; }
    // Make assertions
    if (exp.type === 'Number' && err) { assert.equal(err.code, exp.value,
      "Expected exit code of "+exp.value+" got "+err.code); }
    if (exp.type === 'String') { assert.equal(value, exp.value,
      "Expected "+exp.matcher+" to equal "+exp.value+" got "+value); }
    if (exp.type === 'RegExp') { assert(exp.value.test(value),
      "Expected "+exp.matcher+" to match "+exp.value+" got "+value) }
  });
}
<|endoftext|>


<commit_before>window.SHOPIFYTIMBER = window.SHOPIFYTIMBER || {};

jQuery(function($){

  // requires jQuery 1.8
  (function ( app, undefined ) {

    var timber = {

      browserProperties: {
        touch: Modernizr.touch
      },
      $body: $('body'),
      $repoContainer: $('#repos'),
      $preventApiCalls: false,
      $ignoreForks: true,

      init : function() {

        this.getCustomRepos();
        this.addMembers();
        this.tracking();

        $('a[href="#"]').on('click',function(e){e.preventDefault()});

      },

      addMembers: function(members, page) {
        var o = this,
            members = members || [],
            page = page || 1,
            perPage = 100;

        if (this.$preventApiCalls) return false;

        var uri = 'https://api.github.com/orgs/Shopify/members?callback=?'
                + '&per_page='+perPage
                + '&page='+page;

        $.getJSON(uri, function(result) {
          if (result.meta.status == 403) {
            return;
          }

          // Add new members to local object
          members = members.concat(result.data);

          if (result.data && result.data.length == perPage) {
            // Pagination wall. Do another call on the next page
            o.addMembers(members, page+1);
          } else {
            $("#countMembers").removeClass('is-loading').text(members.length);
          }
        });
      },

      getCustomRepos: function() {
        var o = this;

        for (var i = customRepos.length - 1; i >= 0; i--) {
          repo = customRepos[i];

          var uri = 'https://api.github.com/repos/'+ repo +'?callback=?';

          $.getJSON(uri, function(result) {
            if (result.meta.status == 403) {
              // If we hit the limit, just pass on the current repos we have
              o.addRepos(repos);
              return;
            }

            // Add api data to repos array
            repos = repos.concat(result.data);

            customApiCalls++;
            if (customApiCalls == customRepos.length) {
              // If the custom repo ajax calls are done, move one
              o.addRepos(repos);
            }
          });
        };

      },

      addRepos: function(repos) {
        var o = this,
            repoCount = 0;

        var items = [],
            item = {},
            data = {}
            source   = $('#repoTemplate').html(),
            template = Handlebars.compile(source);

        $.each(repos, function (i, repo) {

          // Ignore forked repos
          if (o.$ignoreForks && repo.fork) {
            return;
          }

          // Opt-in repos (name) and custom repos (full_name) only
          if ( optInRepos.indexOf(repo.name) > -1 || customRepos.indexOf(repo.full_name) > -1) {
            repoCount = repoCount + 1;
          } else {
            return;
          }

          // Update repo language if manually defined
          if ( repo.name in customRepoLanguage ) {
            repo.language = customRepoLanguage[repo.name];
            repo.languageClass = (customRepoLanguage[repo.name] || '').toLowerCase();
          } else {
            repo.languageClass = (repo.language || '').toLowerCase();
          }

          // Make sure homepage URLs start with http. If not, add them
          if (repo.homepage && repo.homepage.substring(0, 4) != "http") {
            repo.homepage = 'http://' + repo.homepage;
          }

          item = {
            url: repo.html_url,
            name: repo.name,
            language: repo.language,
            languageClass: repo.languageClass,
            description: repo.description,
            stars: repo.stargazers_count ? repo.stargazers_count : 0,
            forks: repo.forks_count ? repo.forks_count : 0,
            avatar: repo.name in customRepoAvatar ? customRepoAvatar[repo.name] : null,
            homepage: repo.homepage
          };

          items.push(item);
        });

        // Sort by stars
        items.sort(function(a,b) {
          if (a.stars < b.stars) return 1;
          if (b.stars < a.stars) return -1;
          return 0;
        });

        // Create handlebars.js data
        data = { items: items };

        // Append handlebars templates
        o.$repoContainer.addClass('is-loaded').append(template(data));

        // Display public repo count of opt-in repos (minus forks)
        $('#countRepos').removeClass('is-loading').text(repoCount);

        // Setup isotope
        o.flowyGrid();
      },

      flowyGrid: function() {
        var o = this;

        this.$repoContainer.isotope({
          itemSelector: '.repo'
        });

        // bind filter button click
        var filterButtons = $('#filters button');
        filterButtons.on( 'click', function() {
          filterButtons.removeClass('is-active');
          $(this).addClass('is-active');

          var filterValue = $(this).attr('data-filter');
          o.$repoContainer.isotope({ filter: filterValue });
        });
      },

      tracking: function() {
        $('a[data-track]').on('click', function(e) {
          var data = $(this).data('track');
          // switch(data) {
          //  case 'Demo Empty':
          //    _gaq.push(['_trackEvent', 'Open Source', 'Click', 'Demo Store Empty']);
          //    break;
          // }
        });
      }

    };
    $.extend(app, timber);

  }( window.SHOPIFYTIMBER = window.SHOPIFYTIMBER || {} ));

  SHOPIFYTIMBER.init();
});<commit_msg>Readded missing variable<commit_after>window.SHOPIFYTIMBER = window.SHOPIFYTIMBER || {};

jQuery(function($){

  // requires jQuery 1.8
  (function ( app, undefined ) {

    var timber = {

      browserProperties: {
        touch: Modernizr.touch
      },
      $body: $('body'),
      $repoContainer: $('#repos'),
      $preventApiCalls: false,
      $ignoreForks: true,

      init : function() {

        this.getCustomRepos();
        this.addMembers();
        this.tracking();

        $('a[href="#"]').on('click',function(e){e.preventDefault()});

      },

      addMembers: function(members, page) {
        var o = this,
            members = members || [],
            page = page || 1,
            perPage = 100;

        if (this.$preventApiCalls) return false;

        var uri = 'https://api.github.com/orgs/Shopify/members?callback=?'
                + '&per_page='+perPage
                + '&page='+page;

        $.getJSON(uri, function(result) {
          if (result.meta.status == 403) {
            return;
          }

          // Add new members to local object
          members = members.concat(result.data);

          if (result.data && result.data.length == perPage) {
            // Pagination wall. Do another call on the next page
            o.addMembers(members, page+1);
          } else {
            $("#countMembers").removeClass('is-loading').text(members.length);
          }
        });
      },

      getCustomRepos: function() {
        var o = this,
            customApiCalls = 0;

        for (var i = customRepos.length - 1; i >= 0; i--) {
          repo = customRepos[i];

          var uri = 'https://api.github.com/repos/'+ repo +'?callback=?';

          $.getJSON(uri, function(result) {
            if (result.meta.status == 403) {
              // If we hit the limit, just pass on the current repos we have
              o.addRepos(repos);
              return;
            }

            // Add api data to repos array
            repos = repos.concat(result.data);

            customApiCalls++;
            if (customApiCalls == customRepos.length) {
              // If the custom repo ajax calls are done, move one
              o.addRepos(repos);
            }
          });
        };

      },

      addRepos: function(repos) {
        var o = this,
            repoCount = 0;

        var items = [],
            item = {},
            data = {}
            source   = $('#repoTemplate').html(),
            template = Handlebars.compile(source);

        $.each(repos, function (i, repo) {

          // Ignore forked repos
          if (o.$ignoreForks && repo.fork) {
            return;
          }

          // Opt-in repos (name) and custom repos (full_name) only
          if ( optInRepos.indexOf(repo.name) > -1 || customRepos.indexOf(repo.full_name) > -1) {
            repoCount = repoCount + 1;
          } else {
            return;
          }

          // Update repo language if manually defined
          if ( repo.name in customRepoLanguage ) {
            repo.language = customRepoLanguage[repo.name];
            repo.languageClass = (customRepoLanguage[repo.name] || '').toLowerCase();
          } else {
            repo.languageClass = (repo.language || '').toLowerCase();
          }

          // Make sure homepage URLs start with http. If not, add them
          if (repo.homepage && repo.homepage.substring(0, 4) != "http") {
            repo.homepage = 'http://' + repo.homepage;
          }

          item = {
            url: repo.html_url,
            name: repo.name,
            language: repo.language,
            languageClass: repo.languageClass,
            description: repo.description,
            stars: repo.stargazers_count ? repo.stargazers_count : 0,
            forks: repo.forks_count ? repo.forks_count : 0,
            avatar: repo.name in customRepoAvatar ? customRepoAvatar[repo.name] : null,
            homepage: repo.homepage
          };

          items.push(item);
        });

        // Sort by stars
        items.sort(function(a,b) {
          if (a.stars < b.stars) return 1;
          if (b.stars < a.stars) return -1;
          return 0;
        });

        // Create handlebars.js data
        data = { items: items };

        // Append handlebars templates
        o.$repoContainer.addClass('is-loaded').append(template(data));

        // Display public repo count of opt-in repos (minus forks)
        $('#countRepos').removeClass('is-loading').text(repoCount);

        // Setup isotope
        o.flowyGrid();
      },

      flowyGrid: function() {
        var o = this;

        this.$repoContainer.isotope({
          itemSelector: '.repo'
        });

        // bind filter button click
        var filterButtons = $('#filters button');
        filterButtons.on( 'click', function() {
          filterButtons.removeClass('is-active');
          $(this).addClass('is-active');

          var filterValue = $(this).attr('data-filter');
          o.$repoContainer.isotope({ filter: filterValue });
        });
      },

      tracking: function() {
        $('a[data-track]').on('click', function(e) {
          var data = $(this).data('track');
          // switch(data) {
          //  case 'Demo Empty':
          //    _gaq.push(['_trackEvent', 'Open Source', 'Click', 'Demo Store Empty']);
          //    break;
          // }
        });
      }

    };
    $.extend(app, timber);

  }( window.SHOPIFYTIMBER = window.SHOPIFYTIMBER || {} ));

  SHOPIFYTIMBER.init();
});<|endoftext|>


<commit_before>var time = 0,
    score = 0,
    minutes, seconds, miliseconds,
    running = false,
    score = 0,
    currentSpeed = speed;

function increment() {
    if (running) {
        setTimeout(function () {
            time += 1;
            minutes = Math.floor(time / 10 / 60);
            seconds = Math.floor(time / 10);
            miliseconds = time % 10;

            if (minutes < 10) {
                minutes = "0" + minutes;
            }

            if (seconds < 10) {
                seconds = "0" + seconds;
            }

            document.getElementById('timer').innerHTML = minutes + ':' + seconds + ':' + "0" + miliseconds;
            if (seconds < 10) {
                progressBar(seconds | 0);
            } else {
                progressBar(seconds);
            }

            increment();
        }, 100);
    }
}

function progressBar(al) {
    var bar = document.getElementById('progressBar');
    var status = document.getElementById('status');

    status.innerHTML = al + "%";
    bar.value = al;

    al++;
    var sim = setTimeout("progressBarSim(" + al + ")", 0);

    if (al == 100) {
        status.innerHTML = "100%";
        bar.value = 100;
        clearTimeout(sim);
        var finalMessage = document.getElementById('gameOver');
        finalMessage.style.display = 'inline';
        enemyCarsAnimation.stop();
        anim.stop();
        document.getElementById('timerContainter').style.dispay = 'none';
        document.getElementById('progressBar').stytle.display = 'none';
    }
}

window.addEventListener('keydown', function(escapeGame) {
    if (escapeGame.keyCode == 27) {//Escape
        anim.stop();
        enemyCarsAnimation.stop();
        document.getElementById('gameOver').style.display = 'block';
        document.getElementById('timer').style.dispay = 'none';
        document.getElementById('progressBar').style.display = 'none';
    }
});
running = true;
increment();<commit_msg>modified escape<commit_after>var time = 0,
    score = 0,
    minutes, seconds, miliseconds,
    running = false,
    score = 0,
    currentSpeed = speed;

function increment() {
    if (running) {
        setTimeout(function () {
            time += 1;
            minutes = Math.floor(time / 10 / 60);
            seconds = Math.floor(time / 10);
            miliseconds = time % 10;

            if (minutes < 10) {
                minutes = "0" + minutes;
            }

            if (seconds < 10) {
                seconds = "0" + seconds;
            }

            document.getElementById('timer').innerHTML = minutes + ':' + seconds + ':' + "0" + miliseconds;
            if (seconds < 10) {
                progressBar(seconds | 0);
            } else {
                progressBar(seconds);
            }

            increment();
        }, 100);
    }
}

function progressBar(al) {
    var bar = document.getElementById('progressBar');
    var status = document.getElementById('status');

    status.innerHTML = al + "%";
    bar.value = al;

    al++;
    var sim = setTimeout("progressBarSim(" + al + ")", 0);

    if (al == 100) {
        status.innerHTML = "100%";
        bar.value = 100;
        clearTimeout(sim);
        var finalMessage = document.getElementById('gameOver');
        finalMessage.style.display = 'inline';
        enemyCarsAnimation.stop();
        anim.stop();
        document.getElementById('timerContainter').style.dispay = 'none';
        document.getElementById('progressBar').stytle.display = 'none';
    }
}

window.addEventListener('keydown', function(escapeGame) {
    if (escapeGame.keyCode == 27) {//Escape
        anim.stop();
        enemyCarsAnimation.stop();
        document.getElementById('gameOver').style.display = 'block';
        document.getElementById('timerContainer').style.dispay = 'none';
        document.getElementById('timer').style.dispay = 'none';
        document.getElementById('progressContainer').style.display = 'none';
    }
});
running = true;
increment();<|endoftext|>


<commit_before>/*
 * Copyright 2013 Jive Software
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

var fs = require('fs-extra');
var q = require('q');
var path = require('path');
var jive = require('../api');
var _ = require("underscore");

/**
 * jive-sdk create -type
 */

var argv = require('optimist').argv;

var validCommands = ['create','help','list', 'createExtension'];
var groups = ['tiles', "apps", 'services', 'storages', 'cartridges'];

var styles = [];
var examples = [];
var groupedExamples = {};
_.each(groups, function(group) { groupedExamples[group] = [] });

function validate(options) {
    var err = [];

    if ( validCommands.indexOf(options['cmd']) < 0 ) {
        err.push('Invalid comamnd ' + options['cmd'] + ', must be one of ' + validCommands );
    }

    if ( options['cmd'] === 'create' ) {
        if ( styles.concat(examples).indexOf(options['subject']) < 0 &&  options['subject']  != 'all' ) {
            if ( options['subject'] ) {
                err.push('Invalid item ' + options['subject'] + ', must be one of ' + styles.concat(examples) + ", or 'all'.");
            } else {
                err.push('You must create one of ' + styles.concat(examples) + ", or 'all'.");
            }
        }
    }

    if ( options.cmd === 'list' ) {
        if( options.subject ) {
            if(groups.indexOf( options.subject ) == -1) {
                err.push('Invalid list type ' + options.subject + ', must be one of ' + groups + ", empty, or 'all'");
            }
        }
    }

    return err;
}

var conditionalMkdir = function(target, force) {
    return jive.util.fsexists(target).then( function(exists) {
        if ( !exists || force ) {
            return jive.util.fsmkdir(target);
        } else {
            console.log(target,'already exists, skipping');
            return q.fcall(function(){});
        }
    });
};

function mergeRecursive(original, newcommer) {

    for (var p in newcommer) {
        try {
            if ( newcommer[p].constructor==Object ) {
                original[p] = mergeRecursive(original[p], newcommer[p]);

            } else {
                if ( !original[p] )
                    original[p] = newcommer[p];
            }

        } catch(e) {
            original[p] = newcommer[p];

        }
    }
    return original;
}

function processExample(target, example, name, force) {
    console.log('Preparing example ', example, target );

    var root = __dirname;
    var uniqueUUID = jive.util.guid();

    var processSubRootFolder = function( sourceSubRoot, targetSubRoot, doSubstitutions ){
        return jive.util.fsexists(targetSubRoot).then( function(exists) {
            return !exists ? jive.util.fsmkdir(targetSubRoot) : q.resolve();
        }).then( function() {
                return jive.util.fsreaddir(sourceSubRoot).then( function(subDirs) {
                var promises = [];
                if ( subDirs && subDirs['forEach'] ) {
                    subDirs.forEach(function(subDir) {
                        var sourceSubRootEntry = sourceSubRoot + '/' + subDir;
                        var tileName = subDirs.length > 1 ? subDir : name;
                        var targetSubRootEntry =
                            targetSubRoot + '/' + tileName;

                        var substitutions = !doSubstitutions ? undefined : {
                            'TILE_NAME': tileName,
                            'GENERATED_UUID' : uniqueUUID,
                            'host': '{{{host}}}'
                        };
                        promises.push( jive.util.recursiveCopy(sourceSubRootEntry, targetSubRootEntry, force, substitutions ) );
                    });
                }
                return q.all(promises);
            });
        });
    };

    var processSubRootFile = function(sourceSubRoot, targetSubRoot, baseSubstitutions, force) {
        return jive.util.fsexists(targetSubRoot).then(function (exists) {
            if (!exists || force === 'true') {
                return jive.util.fsTemplateCopy(sourceSubRoot, targetSubRoot, baseSubstitutions);
            } else {
                if (!force) {
                    // it exists, but force is not specified; try to merge if .json object
                    var extension = path.extname(sourceSubRoot);
                    if (extension && extension.toLowerCase() === '.json') {
                        return jive.util.fsreadJson(targetSubRoot).then(function (originJson) {
                            return jive.util.fsreadJson(sourceSubRoot).then(function (incomingJson) {
                                var mergedTxt = JSON.stringify(mergeRecursive(originJson, incomingJson), null, 4);
                                return jive.util.fsTemplateWrite(mergedTxt, targetSubRoot, baseSubstitutions);
                            });
                        });
                    }
                }

                return q.resolve();
            }
        });
    };

    var baseSubstitutions = {
        'TILE_NAME': name,
        'host': '{{{host}}}'
    };

    return jive.util.recursiveCopy(root + '/base', target, force, baseSubstitutions).then( function() {
        var promises = [];
        var sourceRootDir = root + '/examples/' + example;
            return jive.util.fsreaddir(sourceRootDir).then( function(subDirs) {
            subDirs.forEach(function(subDir) {
                var sourceSubRoot = sourceRootDir + '/' + subDir;
                var targetSubRoot = target + '/' + subDir;
                promises.push( jive.util.fsisdir(sourceSubRoot).then( function(isDir) {
                    if ( isDir ) {
                        var doSubstitutions = subDir != 'cartridges';   // don't do substitutions on cartridges
                        return processSubRootFolder( sourceSubRoot, targetSubRoot, doSubstitutions );
                    } else {
                        return processSubRootFile( sourceSubRoot, targetSubRoot, baseSubstitutions, force );
                    }
                }) );
            });
            return q.all(promises);
        });
    })
}

function processDefinition(target, type, name, style, force) {

    console.log('Preparing', type == 'all' ? '' : type,
        '"' + name + '"',
        (type !== 'activity' ? 'of style ' + style : ''));

    var root = __dirname;

    var substitutions = {
        'TILE_NAME': name,
        'TILE_STYLE': style,
        'host': '{{{host}}}'
    };

    var promises = [];

    // copy base
    promises.push(
        jive.util.recursiveCopy(root + '/base', target, force, substitutions )
    );

    promises.push(
        conditionalMkdir(target + '/tiles/' + name, force)
    );

    // copy definition
    promises.push(
        jive.util.recursiveCopy(root + '/definition', target + '/tiles/' + name, force )
    );

    // copy style
    promises.push(
        jive.util.recursiveCopy(
            root + '/styles' + '/' + style,
            target + '/tiles/' + name,
            force, substitutions )
    );

    return q.all(promises);
}

function listDirectory(dirName, dirPath) {
    console.log('\nContents of ' + dirName + ' directory (', dirPath, '):\n' );

    return q.nfcall(fs.readdir, dirPath ).then(function(dirContents){
        dirContents.forEach(function(item) {
            console.log(item);
        });
    })
}

function finish(target) {
    var definitionsDir = target + '/tiles';
    var appsDir = target + '/apps';
    var servicesDir = target + '/services';
    var storagesDir = target + '/storages';
    var cartridgesDir = target + '/cartridges';

    var configurationFile =  target + '/jiveclientconfiguration.json';

    console.log('\n... Done!\n');

    // tiles
    jive.util.fsexists(definitionsDir).then( function(exists) {
        if ( exists ) {
            return listDirectory('tiles', definitionsDir);
        } else {
            return q.resolve(true);
        }
    }).then( function() {
        return jive.util.fsexists( appsDir ).then( function(exists) {
            if ( exists ) {
                return listDirectory('apps', appsDir);

            } else {
                return q.resolve();
            }
        });
    }).then( function() {
        return jive.util.fsexists( cartridgesDir ).then( function(exists) {
            if ( exists ) {
                return listDirectory('cartridges', cartridgesDir);

            } else {
                return q.resolve();
            }
        });
    }).then( function() {
        return jive.util.fsexists( servicesDir ).then( function(exists) {
            if ( exists ) {
                return listDirectory('services', servicesDir);

            } else {
                return q.resolve();
            }
        });
    }).then( function() {
        return jive.util.fsexists( storagesDir ).then( function(exists) {
            if ( exists ) {
                return listDirectory('storages', storagesDir);

            } else {
                return q.resolve();
            }
        });
    }).then( function() {
        console.log("\nThings you should do now, if you haven't done them already.");
        console.log();
        console.log('(1) Install dependent modules:');
        console.log('   npm update ');
        console.log('(2) Don\'t forget to edit', configurationFile, 'to specify your clientID, ' +
            'clientSecret, clientUrl, and other important setup options!');
        console.log();
        console.log('When done, run your service:');
        console.log();
        console.log('   node app.js');
        console.log();
    });
}

function doStyle( options ) {
    var force = options['force'];
    var target = options['target'] || process.cwd();

    var style =  options['subject'];
    var name = options['name'] || 'sample' + style;
    var type = style == 'activity' ? 'activity' : style;
    processDefinition(target, type, name, style, force).then( function() {
        finish(target);
    });
}

function doExample( options ) {
    var force = options['force'];
    var target = options['target'] || process.cwd();

    var example =  options['subject'];
    var name = options['name'] ? options['name'] : example;
    processExample(target, example, name, force).then( function() {
        finish(target);
    });
}

function doAll( options ) {
    var force = options['force'];
    var target = options['target'] || process.cwd();

    var promises = [];
    styles.forEach( function(style) {
        var name = 'sample' + style + (options['name'] ? '-' + options['name'] : '' );
        var type = style == 'activity' ? 'activity' : style;
        promises.push( processDefinition(target, type, name, style, force));
    });

    examples.forEach( function( example ) {
        var name = example + ( options['name'] ? ('-' + options['name'] ) : '');
        promises.push(processExample(target, example, name, force));
    });

    q.all(promises).then( function() {
        var root = __dirname;
        return jive.util.fsTemplateCopy( root + '/base/package.json', target + '/package.json', { 'TILE_NAME': 'jive-examples-all' } )
            .then( function() { return finish(target); });
    });
}

function doHelp() {
    console.log('Usage: jive-sdk [cmd] [item] [--options ...]\n');
    console.log('where cmd include:');
    console.log('   help');
    console.log('   create');
    console.log('   list\n');

    console.log('where item for create include:');
    examples.concat(styles).forEach( function(item) {
        console.log('   ' + item );
    });

    console.log('');
    console.log('where item for list include:');
    _.each(groups, function(group) {
        console.log('   ' + group);
    });

    console.log();
    console.log('where options include:');
    console.log('   --force=<one of [true,false]>           Defaults to false, overrwrites existing if true');
    console.log('   --name=<string>                         Defaults to [item]');
}

function execute(options) {
    var cmd = options['cmd'];
    options.target = options.target || process.cwd();

    if ( cmd === 'help' ) {
        doHelp();
    }

    if ( cmd == 'create') {
        var subject = options['subject'];

        if ( subject == 'all' ) {
            doAll( options );
            return;
        }

        if ( styles.indexOf( subject ) > -1 ) {
            doStyle( options );
            return;
        }

        if ( examples.indexOf( subject ) > -1 ) {
            doExample( options );
            return;
        }
    }

    if ( cmd === 'list' ) {
        if( !options.subject ) {
            options.subject = 'all';
        }
        var printGroup = function( group ) {
            console.log(group + ":");
            _.each(groupedExamples[group], function( example ) {
                console.log("    " + example);
            });
        };

        if( options.subject === 'all' ) {
            _.each(groupedExamples, function( exampleArray, group ) {
                printGroup(group);
                console.log("");
            });

        } else {
            printGroup(options.subject);
        }
    }

    if ( cmd === 'createExtension' ) {
        doCreateExtension( options );
    }
}

function doCreateExtension( options ) {
    jive.service.init({use: function() {}}).then(function() {
        var extension = require("../lib/extension/extension.js");

        extension.prepare(options.target + "/tiles", options.target + "/apps", options.target + "/cartridges", options.target + "/storages").then(function(){
            var persistence = jive.service.persistence();

            persistence.close().then(function() {
                process.nextTick(function() {
                    process.exit(0);
                });
            })
        });
    });
}

function prepare() {
    var root = __dirname;

    return jive.util.fsreaddir( root + '/styles').then(function(items) {
        styles = styles.concat( items );
    }).then( function() {
            return jive.util.fsreaddir( root + '/examples').then(function(items) {
                var deferreds = [];
                examples = examples.concat( items );
                _.each(items, function( item ) {
                    _.each(groups, function( group ) {
                        var deferred = q.defer();
                        deferreds.push(deferred);
                        jive.util.fsexists( root + '/examples/' + item + "/" + group).then(function(exists) {
                            if(exists) {
                                groupedExamples[group].push(item);
                            }
                            deferred.resolve();
                        });
                    });
                });
                return q.allResolved(deferreds);
            } );
        });
}

exports.init = function(target) {
    // init lists
    prepare().then( function() {

        // default command to help
        var cmd = argv._.length > 0 ? argv._[0] : 'help';
        var subject = argv._[1];

        var name = argv['name'];
        var force = argv['force'] || false;

        if (name) {
            name = name.replace(/[^\S]+/, '');
            name = name.replace(/[^a-zA-Z0-9]/, '-');
        }

        var options = {
            'name'      : name,
            'cmd'       : cmd,
            'subject'   : subject,
            'force'     : force,
            'target'    : target
        };

        var err = validate(options);
        if ( err.length > 0 ) {
            console.log('Could not execute command, errors were found:');
            err.forEach( function(err) {
                console.log('   ', err);
            });

            console.log();

            doHelp();

            process.exit(-1);
        }

        execute(options);
    });
};
<commit_msg>Include the base styles in the 'tiles' list.<commit_after>/*
 * Copyright 2013 Jive Software
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

var fs = require('fs-extra');
var q = require('q');
var path = require('path');
var jive = require('../api');
var _ = require("underscore");

/**
 * jive-sdk create -type
 */

var argv = require('optimist').argv;

var validCommands = ['create','help','list', 'createExtension'];
var groups = ['tiles', "apps", 'services', 'storages', 'cartridges'];

var styles = [];
var examples = [];
var groupedExamples = {};
_.each(groups, function(group) { groupedExamples[group] = [] });

function validate(options) {
    var err = [];

    if ( validCommands.indexOf(options['cmd']) < 0 ) {
        err.push('Invalid comamnd ' + options['cmd'] + ', must be one of ' + validCommands );
    }

    if ( options['cmd'] === 'create' ) {
        if ( styles.concat(examples).indexOf(options['subject']) < 0 &&  options['subject']  != 'all' ) {
            if ( options['subject'] ) {
                err.push('Invalid item ' + options['subject'] + ', must be one of ' + styles.concat(examples) + ", or 'all'.");
            } else {
                err.push('You must create one of ' + styles.concat(examples) + ", or 'all'.");
            }
        }
    }

    if ( options.cmd === 'list' ) {
        if( options.subject ) {
            if(groups.indexOf( options.subject ) == -1) {
                err.push('Invalid list type ' + options.subject + ', must be one of ' + groups + ", empty, or 'all'");
            }
        }
    }

    return err;
}

var conditionalMkdir = function(target, force) {
    return jive.util.fsexists(target).then( function(exists) {
        if ( !exists || force ) {
            return jive.util.fsmkdir(target);
        } else {
            console.log(target,'already exists, skipping');
            return q.fcall(function(){});
        }
    });
};

function mergeRecursive(original, newcommer) {

    for (var p in newcommer) {
        try {
            if ( newcommer[p].constructor==Object ) {
                original[p] = mergeRecursive(original[p], newcommer[p]);

            } else {
                if ( !original[p] )
                    original[p] = newcommer[p];
            }

        } catch(e) {
            original[p] = newcommer[p];

        }
    }
    return original;
}

function processExample(target, example, name, force) {
    console.log('Preparing example ', example, target );

    var root = __dirname;
    var uniqueUUID = jive.util.guid();

    var processSubRootFolder = function( sourceSubRoot, targetSubRoot, doSubstitutions ){
        return jive.util.fsexists(targetSubRoot).then( function(exists) {
            return !exists ? jive.util.fsmkdir(targetSubRoot) : q.resolve();
        }).then( function() {
                return jive.util.fsreaddir(sourceSubRoot).then( function(subDirs) {
                var promises = [];
                if ( subDirs && subDirs['forEach'] ) {
                    subDirs.forEach(function(subDir) {
                        var sourceSubRootEntry = sourceSubRoot + '/' + subDir;
                        var tileName = subDirs.length > 1 ? subDir : name;
                        var targetSubRootEntry =
                            targetSubRoot + '/' + tileName;

                        var substitutions = !doSubstitutions ? undefined : {
                            'TILE_NAME': tileName,
                            'GENERATED_UUID' : uniqueUUID,
                            'host': '{{{host}}}'
                        };
                        promises.push( jive.util.recursiveCopy(sourceSubRootEntry, targetSubRootEntry, force, substitutions ) );
                    });
                }
                return q.all(promises);
            });
        });
    };

    var processSubRootFile = function(sourceSubRoot, targetSubRoot, baseSubstitutions, force) {
        return jive.util.fsexists(targetSubRoot).then(function (exists) {
            if (!exists || force === 'true') {
                return jive.util.fsTemplateCopy(sourceSubRoot, targetSubRoot, baseSubstitutions);
            } else {
                if (!force) {
                    // it exists, but force is not specified; try to merge if .json object
                    var extension = path.extname(sourceSubRoot);
                    if (extension && extension.toLowerCase() === '.json') {
                        return jive.util.fsreadJson(targetSubRoot).then(function (originJson) {
                            return jive.util.fsreadJson(sourceSubRoot).then(function (incomingJson) {
                                var mergedTxt = JSON.stringify(mergeRecursive(originJson, incomingJson), null, 4);
                                return jive.util.fsTemplateWrite(mergedTxt, targetSubRoot, baseSubstitutions);
                            });
                        });
                    }
                }

                return q.resolve();
            }
        });
    };

    var baseSubstitutions = {
        'TILE_NAME': name,
        'host': '{{{host}}}'
    };

    return jive.util.recursiveCopy(root + '/base', target, force, baseSubstitutions).then( function() {
        var promises = [];
        var sourceRootDir = root + '/examples/' + example;
            return jive.util.fsreaddir(sourceRootDir).then( function(subDirs) {
            subDirs.forEach(function(subDir) {
                var sourceSubRoot = sourceRootDir + '/' + subDir;
                var targetSubRoot = target + '/' + subDir;
                promises.push( jive.util.fsisdir(sourceSubRoot).then( function(isDir) {
                    if ( isDir ) {
                        var doSubstitutions = subDir != 'cartridges';   // don't do substitutions on cartridges
                        return processSubRootFolder( sourceSubRoot, targetSubRoot, doSubstitutions );
                    } else {
                        return processSubRootFile( sourceSubRoot, targetSubRoot, baseSubstitutions, force );
                    }
                }) );
            });
            return q.all(promises);
        });
    })
}

function processDefinition(target, type, name, style, force) {

    console.log('Preparing', type == 'all' ? '' : type,
        '"' + name + '"',
        (type !== 'activity' ? 'of style ' + style : ''));

    var root = __dirname;

    var substitutions = {
        'TILE_NAME': name,
        'TILE_STYLE': style,
        'host': '{{{host}}}'
    };

    var promises = [];

    // copy base
    promises.push(
        jive.util.recursiveCopy(root + '/base', target, force, substitutions )
    );

    promises.push(
        conditionalMkdir(target + '/tiles/' + name, force)
    );

    // copy definition
    promises.push(
        jive.util.recursiveCopy(root + '/definition', target + '/tiles/' + name, force )
    );

    // copy style
    promises.push(
        jive.util.recursiveCopy(
            root + '/styles' + '/' + style,
            target + '/tiles/' + name,
            force, substitutions )
    );

    return q.all(promises);
}

function listDirectory(dirName, dirPath) {
    console.log('\nContents of ' + dirName + ' directory (', dirPath, '):\n' );

    return q.nfcall(fs.readdir, dirPath ).then(function(dirContents){
        dirContents.forEach(function(item) {
            console.log(item);
        });
    })
}

function finish(target) {
    var definitionsDir = target + '/tiles';
    var appsDir = target + '/apps';
    var servicesDir = target + '/services';
    var storagesDir = target + '/storages';
    var cartridgesDir = target + '/cartridges';

    var configurationFile =  target + '/jiveclientconfiguration.json';

    console.log('\n... Done!\n');

    // tiles
    jive.util.fsexists(definitionsDir).then( function(exists) {
        if ( exists ) {
            return listDirectory('tiles', definitionsDir);
        } else {
            return q.resolve(true);
        }
    }).then( function() {
        return jive.util.fsexists( appsDir ).then( function(exists) {
            if ( exists ) {
                return listDirectory('apps', appsDir);

            } else {
                return q.resolve();
            }
        });
    }).then( function() {
        return jive.util.fsexists( cartridgesDir ).then( function(exists) {
            if ( exists ) {
                return listDirectory('cartridges', cartridgesDir);

            } else {
                return q.resolve();
            }
        });
    }).then( function() {
        return jive.util.fsexists( servicesDir ).then( function(exists) {
            if ( exists ) {
                return listDirectory('services', servicesDir);

            } else {
                return q.resolve();
            }
        });
    }).then( function() {
        return jive.util.fsexists( storagesDir ).then( function(exists) {
            if ( exists ) {
                return listDirectory('storages', storagesDir);

            } else {
                return q.resolve();
            }
        });
    }).then( function() {
        console.log("\nThings you should do now, if you haven't done them already.");
        console.log();
        console.log('(1) Install dependent modules:');
        console.log('   npm update ');
        console.log('(2) Don\'t forget to edit', configurationFile, 'to specify your clientID, ' +
            'clientSecret, clientUrl, and other important setup options!');
        console.log();
        console.log('When done, run your service:');
        console.log();
        console.log('   node app.js');
        console.log();
    });
}

function doStyle( options ) {
    var force = options['force'];
    var target = options['target'] || process.cwd();

    var style =  options['subject'];
    var name = options['name'] || 'sample' + style;
    var type = style == 'activity' ? 'activity' : style;
    processDefinition(target, type, name, style, force).then( function() {
        finish(target);
    });
}

function doExample( options ) {
    var force = options['force'];
    var target = options['target'] || process.cwd();

    var example =  options['subject'];
    var name = options['name'] ? options['name'] : example;
    processExample(target, example, name, force).then( function() {
        finish(target);
    });
}

function doAll( options ) {
    var force = options['force'];
    var target = options['target'] || process.cwd();

    var promises = [];
    styles.forEach( function(style) {
        var name = 'sample' + style + (options['name'] ? '-' + options['name'] : '' );
        var type = style == 'activity' ? 'activity' : style;
        promises.push( processDefinition(target, type, name, style, force));
    });

    examples.forEach( function( example ) {
        var name = example + ( options['name'] ? ('-' + options['name'] ) : '');
        promises.push(processExample(target, example, name, force));
    });

    q.all(promises).then( function() {
        var root = __dirname;
        return jive.util.fsTemplateCopy( root + '/base/package.json', target + '/package.json', { 'TILE_NAME': 'jive-examples-all' } )
            .then( function() { return finish(target); });
    });
}

function doHelp() {
    console.log('Usage: jive-sdk [cmd] [item] [--options ...]\n');
    console.log('where cmd include:');
    console.log('   help');
    console.log('   create');
    console.log('   list\n');

    console.log('where item for create include:');
    examples.concat(styles).forEach( function(item) {
        console.log('   ' + item );
    });

    console.log('');
    console.log('where item for list include:');
    _.each(groups, function(group) {
        console.log('   ' + group);
    });

    console.log();
    console.log('where options include:');
    console.log('   --force=<one of [true,false]>           Defaults to false, overrwrites existing if true');
    console.log('   --name=<string>                         Defaults to [item]');
}

function execute(options) {
    var cmd = options['cmd'];
    options.target = options.target || process.cwd();

    if ( cmd === 'help' ) {
        doHelp();
    }

    if ( cmd == 'create') {
        var subject = options['subject'];

        if ( subject == 'all' ) {
            doAll( options );
            return;
        }

        if ( styles.indexOf( subject ) > -1 ) {
            doStyle( options );
            return;
        }

        if ( examples.indexOf( subject ) > -1 ) {
            doExample( options );
            return;
        }
    }

    if ( cmd === 'list' ) {
        if( !options.subject ) {
            options.subject = 'all';
        }
        var printGroup = function( group ) {
            console.log(group + ":");
            _.each(groupedExamples[group], function( example ) {
                console.log("    " + example);
            });
        };

        if( options.subject === 'all' ) {
            _.each(groupedExamples, function( exampleArray, group ) {
                printGroup(group);
                console.log("");
            });

        } else {
            printGroup(options.subject);
        }
    }

    if ( cmd === 'createExtension' ) {
        doCreateExtension( options );
    }
}

function doCreateExtension( options ) {
    jive.service.init({use: function() {}}).then(function() {
        var extension = require("../lib/extension/extension.js");

        extension.prepare(options.target + "/tiles", options.target + "/apps", options.target + "/cartridges", options.target + "/storages").then(function(){
            var persistence = jive.service.persistence();

            persistence.close().then(function() {
                process.nextTick(function() {
                    process.exit(0);
                });
            })
        });
    });
}

function prepare() {
    var root = __dirname;

    return jive.util.fsreaddir( root + '/styles').then(function(items) {
        styles = styles.concat( items );
        _.each(styles, function( item ) {
            groupedExamples['tiles'].push(item);
        });
    }).then( function() {
            return jive.util.fsreaddir( root + '/examples').then(function(items) {
                var deferreds = [];
                examples = examples.concat( items );
                _.each(examples, function( item ) {
                    _.each(groups, function( group ) {
                        var deferred = q.defer();
                        deferreds.push(deferred);
                        jive.util.fsexists( root + '/examples/' + item + "/" + group).then(function(exists) {
                            if(exists) {
                                groupedExamples[group].push(item);
                            }
                            deferred.resolve();
                        });
                    });
                });
                return q.allResolved(deferreds);
            } );
        });
}

exports.init = function(target) {
    // init lists
    prepare().then( function() {

        // default command to help
        var cmd = argv._.length > 0 ? argv._[0] : 'help';
        var subject = argv._[1];

        var name = argv['name'];
        var force = argv['force'] || false;

        if (name) {
            name = name.replace(/[^\S]+/, '');
            name = name.replace(/[^a-zA-Z0-9]/, '-');
        }

        var options = {
            'name'      : name,
            'cmd'       : cmd,
            'subject'   : subject,
            'force'     : force,
            'target'    : target
        };

        var err = validate(options);
        if ( err.length > 0 ) {
            console.log('Could not execute command, errors were found:');
            err.forEach( function(err) {
                console.log('   ', err);
            });

            console.log();

            doHelp();

            process.exit(-1);
        }

        execute(options);
    });
};
<|endoftext|>


<commit_before>module.exports = function(babel) {

  var t = babel.types;

  function isGoogDefineClass(path) {
    try {
      const callee = path.node.declarations[0].init.callee;
      return callee.object.name === 'goog' &&
          callee.property.name === 'defineClass';
    } catch (e) {
      return false;
    }
  }

  function getParams(prop) {
    return prop.value.params;
  }

  function getBody(prop) {
    let body = t.blockStatement([]);
    if (prop.value.body) {
      body = prop.value.body;
    }
    return body;
  }

  function createExpressionStatementForStatics(className, objProp) {
    // Generate ClassName.staticName
    let left = t.MemberExpression(className, objProp.key);
    // Assign the key and value defined in the statics.
    const expressionStatement = t.expressionStatement(
        t.assignmentExpression('=', left, objProp.value));
    // Comments?
    if (objProp.leadingComments) {
      expressionStatement.leadingComments = objProp.leadingComments;
    }
    return expressionStatement;
  }

  /**
   * t.classMethod(kind, key, params, body, computed, static)
   * @param prop
   * @return {*}
   */
  function toClassMethod(prop) {

    const name = prop.key.name;
    const kind = name === 'constructor' ? 'constructor' : 'method';

    const method = t.classMethod(kind, prop.key, getParams(prop), getBody(prop));

    // Copy comments, if any.
    const comments = prop.leadingComments;
    if (comments) {
      method.leadingComments = comments;
    }

    return method
  }

  return {
    visitor: {
      VariableDeclaration: function(path) {
        if (path.parentKey !== 'body' || !isGoogDefineClass(path)) {
          return;
        }

        const declaration = path.node.declarations[0];
        const objectExpression = declaration.init.arguments[1];
        const className = t.Identifier(declaration.id.name);

        // Turn all the properties in the goog.defineClass object arg into
        // ClassMethod methods. Filter out statics.
        let statics = null;
        let classMethods = [];
        objectExpression.properties.forEach(prop => {
          if (t.isFunctionExpression(prop.value)) {
            classMethods.push(toClassMethod(prop));
          } else if (prop.key.name === 'statics') {
            statics = prop.value.properties;
          }
        });

        const classBody = t.ClassBody(classMethods);
        const superClass = null;
        const decorators = [];

        const classDeclaration = t.classDeclaration(className,
            superClass,
            classBody,
            decorators
        );
        path.replaceWith(classDeclaration);

        if (statics) {
          // Reverse the order so when we add the elements they are in the
          // correct order.
          statics.slice(0).reverse().forEach(objProp => {
            let expressionStatement =
                createExpressionStatementForStatics(className, objProp);
            path.insertAfter(expressionStatement);
          });
        }
      }
    }
  };
};

class Foo {
  constructor() {
  }
}
<commit_msg>remove class Foo<commit_after>module.exports = function(babel) {

  var t = babel.types;

  function isGoogDefineClass(path) {
    try {
      const callee = path.node.declarations[0].init.callee;
      return callee.object.name === 'goog' &&
          callee.property.name === 'defineClass';
    } catch (e) {
      return false;
    }
  }

  function getParams(prop) {
    return prop.value.params;
  }

  function getBody(prop) {
    let body = t.blockStatement([]);
    if (prop.value.body) {
      body = prop.value.body;
    }
    return body;
  }

  function createExpressionStatementForStatics(className, objProp) {
    // Generate ClassName.staticName
    let left = t.MemberExpression(className, objProp.key);
    // Assign the key and value defined in the statics.
    const expressionStatement = t.expressionStatement(
        t.assignmentExpression('=', left, objProp.value));
    // Comments?
    if (objProp.leadingComments) {
      expressionStatement.leadingComments = objProp.leadingComments;
    }
    return expressionStatement;
  }

  /**
   * t.classMethod(kind, key, params, body, computed, static)
   * @param prop
   * @return {*}
   */
  function toClassMethod(prop) {

    const name = prop.key.name;
    const kind = name === 'constructor' ? 'constructor' : 'method';

    const method = t.classMethod(kind, prop.key, getParams(prop), getBody(prop));

    // Copy comments, if any.
    const comments = prop.leadingComments;
    if (comments) {
      method.leadingComments = comments;
    }

    return method
  }

  return {
    visitor: {
      VariableDeclaration: function(path) {
        if (path.parentKey !== 'body' || !isGoogDefineClass(path)) {
          return;
        }

        const declaration = path.node.declarations[0];
        const objectExpression = declaration.init.arguments[1];
        const className = t.Identifier(declaration.id.name);

        // Turn all the properties in the goog.defineClass object arg into
        // ClassMethod methods. Filter out statics.
        let statics = null;
        let classMethods = [];
        objectExpression.properties.forEach(prop => {
          if (t.isFunctionExpression(prop.value)) {
            classMethods.push(toClassMethod(prop));
          } else if (prop.key.name === 'statics') {
            statics = prop.value.properties;
          }
        });

        const classBody = t.ClassBody(classMethods);
        const superClass = null;
        const decorators = [];

        const classDeclaration = t.classDeclaration(className,
            superClass,
            classBody,
            decorators
        );
        path.replaceWith(classDeclaration);

        if (statics) {
          // Reverse the order so when we add the elements they are in the
          // correct order.
          statics.slice(0).reverse().forEach(objProp => {
            let expressionStatement =
                createExpressionStatementForStatics(className, objProp);
            path.insertAfter(expressionStatement);
          });
        }
      }
    }
  };
};
<|endoftext|>


<commit_before>// Copyright 2022, University of Colorado Boulder

/**
 * QUnit tests for ScientificNotationNode.toScientificNotation, the part of ScientificNotationNode that is unit-testable.
 *
 * @author Chris Malley (PixelZoom, Inc.)
 */

import ScientificNotationNode from './ScientificNotationNode.js';

QUnit.module( 'ScientificNotationNode' );

/**
 * Tests for the 'if ( value === 0 )' code path in toScientificNotation
 */
QUnit.test( 'value === 0', assert => {

  // For value === 0, the specified exponent should be used.
  assert.deepEqual( ScientificNotationNode.toScientificNotation( 0, {
    exponent: 2,
    mantissaDecimalPlaces: 1
  } ), { mantissa: '0.0', exponent: '2' } );

  // For value === 0, if no exponent is requested, exponent should be 0.
  assert.deepEqual( ScientificNotationNode.toScientificNotation( 0, {
    exponent: null,
    mantissaDecimalPlaces: 1
  } ), { mantissa: '0.0', exponent: '0' } );
} );

/**
 * Tests for the 'if ( options.exponent === 0 )' code path in toScientificNotation
 */
QUnit.test( 'exponent === 0', assert => {

  // For exponent === 0, we use dot.Utils.toFixed to create the mantissa. This example adds zeros to decimal places.
  assert.deepEqual( ScientificNotationNode.toScientificNotation( 424.8, {
    exponent: 0,
    mantissaDecimalPlaces: 3
  } ), { mantissa: '424.800', exponent: '0' } );

  // For exponent === 0, we use dot.Utils.toFixed to create the mantissa. This example rounds decimal places.
  assert.deepEqual( ScientificNotationNode.toScientificNotation( 424.856, {
    exponent: 0,
    mantissaDecimalPlaces: 1
  } ), { mantissa: '424.9', exponent: '0' } );
} );

/**
 * Tests for the 'if ( options.exponent !== null )' code path in toScientificNotation
 */
QUnit.test( 'exponent !== 0 && exponent !== null', assert => {

  assert.deepEqual( ScientificNotationNode.toScientificNotation( 9648, {
    exponent: 1,
    mantissaDecimalPlaces: 1
  } ), { mantissa: '964.8', exponent: '1' } );

  assert.deepEqual( ScientificNotationNode.toScientificNotation( 9648, {
    exponent: 2,
    mantissaDecimalPlaces: 1
  } ), { mantissa: '96.5', exponent: '2' } );

  assert.deepEqual( ScientificNotationNode.toScientificNotation( 9648, {
    exponent: 3,
    mantissaDecimalPlaces: 1
  } ), { mantissa: '9.6', exponent: '3' } );

  assert.deepEqual( ScientificNotationNode.toScientificNotation( 9648, {
    exponent: 3,
    mantissaDecimalPlaces: 2
  } ), { mantissa: '9.65', exponent: '3' } );

  assert.deepEqual( ScientificNotationNode.toScientificNotation( 9648, {
    exponent: 4,
    mantissaDecimalPlaces: 1
  } ), { mantissa: '1.0', exponent: '4' } );

  assert.deepEqual( ScientificNotationNode.toScientificNotation( 9648, {
    exponent: 4,
    mantissaDecimalPlaces: 3
  } ), { mantissa: '0.965', exponent: '4' } );

  assert.deepEqual( ScientificNotationNode.toScientificNotation( 9648, {
    exponent: 5,
    mantissaDecimalPlaces: 1
  } ), { mantissa: '0.1', exponent: '5' } );
} );

/**
 * Tests for the 'else {...}' code path in toScientificNotation
 */
QUnit.test( 'rounding', assert => {

  // This case was reported in https://github.com/phetsims/build-a-nucleus/issues/24 with bad mantissa '4.3'
  assert.deepEqual( ScientificNotationNode.toScientificNotation( 424.8, {
    exponent: null,
    mantissaDecimalPlaces: 1
  } ), { mantissa: '4.2', exponent: '2' } );

  assert.deepEqual( ScientificNotationNode.toScientificNotation( 425.8, {
    exponent: null,
    mantissaDecimalPlaces: 2
  } ), { mantissa: '4.26', exponent: '2' } );

  // This case was reported in https://github.com/phetsims/build-a-nucleus/issues/24, with bad mantissa '9.7'
  assert.deepEqual( ScientificNotationNode.toScientificNotation( 9648, {
    exponent: null,
    mantissaDecimalPlaces: 1
  } ), { mantissa: '9.6', exponent: '3' } );

  assert.deepEqual( ScientificNotationNode.toScientificNotation( 9658, {
    exponent: null,
    mantissaDecimalPlaces: 2
  } ), { mantissa: '9.66', exponent: '3' } );

  // This case was reported in https://github.com/phetsims/scenery-phet/issues/747, with bad mantissa '35.85'
  // assert.deepEqual( ScientificNotationNode.toScientificNotation( 35.855, {
  //   exponent: 0,
  //   mantissaDecimalPlaces: 2
  // } ), { mantissa: '35.86', exponent: '0' } );
} );<commit_msg>clean up unit tests, https://github.com/phetsims/scenery-phet/issues/747<commit_after>// Copyright 2022, University of Colorado Boulder

/**
 * QUnit tests for ScientificNotationNode.toScientificNotation, the part of ScientificNotationNode that is unit-testable.
 *
 * @author Chris Malley (PixelZoom, Inc.)
 */

import ScientificNotationNode from './ScientificNotationNode.js';

QUnit.module( 'ScientificNotationNode' );

QUnit.test( 'value === 0', assert => {

  // For value === 0, the specified exponent should be used.
  assert.deepEqual( ScientificNotationNode.toScientificNotation( 0, {
    exponent: 2,
    mantissaDecimalPlaces: 1
  } ), { mantissa: '0.0', exponent: '2' } );

  // For value === 0, if no exponent is requested, exponent should be 0.
  assert.deepEqual( ScientificNotationNode.toScientificNotation( 0, {
    exponent: null,
    mantissaDecimalPlaces: 1
  } ), { mantissa: '0.0', exponent: '0' } );
} );

QUnit.test( 'exponent === 0', assert => {

  const ZERO_EXPONENT = 0;

  // For exponent === 0, we use dot.Utils.toFixed to create the mantissa. This example adds zeros to decimal places.
  assert.deepEqual( ScientificNotationNode.toScientificNotation( 424.8, {
    exponent: ZERO_EXPONENT,
    mantissaDecimalPlaces: 3
  } ), { mantissa: '424.800', exponent: '0' } );

  // For exponent === 0, we use dot.Utils.toFixed to create the mantissa. This example rounds decimal places.
  assert.deepEqual( ScientificNotationNode.toScientificNotation( 424.856, {
    exponent: ZERO_EXPONENT,
    mantissaDecimalPlaces: 1
  } ), { mantissa: '424.9', exponent: '0' } );

  // This case was reported in https://github.com/phetsims/scenery-phet/issues/747, with bad mantissa '35.85'
  // assert.deepEqual( ScientificNotationNode.toScientificNotation( 35.855, {
  //   exponent: ZERO_EXPONENT,
  //   mantissaDecimalPlaces: 2
  // } ), { mantissa: '35.86', exponent: '0' } );
} );

QUnit.test( 'exponent === null', assert => {

  const NULL_EXPONENT = null;

  // This case was reported in https://github.com/phetsims/build-a-nucleus/issues/24 with bad mantissa '4.3'
  assert.deepEqual( ScientificNotationNode.toScientificNotation( 424.8, {
    exponent: NULL_EXPONENT,
    mantissaDecimalPlaces: 1
  } ), { mantissa: '4.2', exponent: '2' } );

  assert.deepEqual( ScientificNotationNode.toScientificNotation( 425.8, {
    exponent: NULL_EXPONENT,
    mantissaDecimalPlaces: 2
  } ), { mantissa: '4.26', exponent: '2' } );

  // This case was reported in https://github.com/phetsims/build-a-nucleus/issues/24, with bad mantissa '9.7'
  assert.deepEqual( ScientificNotationNode.toScientificNotation( 9648, {
    exponent: NULL_EXPONENT,
    mantissaDecimalPlaces: 1
  } ), { mantissa: '9.6', exponent: '3' } );

  assert.deepEqual( ScientificNotationNode.toScientificNotation( 9658, {
    exponent: NULL_EXPONENT,
    mantissaDecimalPlaces: 2
  } ), { mantissa: '9.66', exponent: '3' } );
} );

QUnit.test( 'exponent !== 0 && exponent !== null', assert => {

  assert.deepEqual( ScientificNotationNode.toScientificNotation( 9648, {
    exponent: 1,
    mantissaDecimalPlaces: 1
  } ), { mantissa: '964.8', exponent: '1' } );

  assert.deepEqual( ScientificNotationNode.toScientificNotation( 9648, {
    exponent: 2,
    mantissaDecimalPlaces: 1
  } ), { mantissa: '96.5', exponent: '2' } );

  assert.deepEqual( ScientificNotationNode.toScientificNotation( 9648, {
    exponent: 3,
    mantissaDecimalPlaces: 1
  } ), { mantissa: '9.6', exponent: '3' } );

  assert.deepEqual( ScientificNotationNode.toScientificNotation( 9648, {
    exponent: 3,
    mantissaDecimalPlaces: 2
  } ), { mantissa: '9.65', exponent: '3' } );

  assert.deepEqual( ScientificNotationNode.toScientificNotation( 9648, {
    exponent: 4,
    mantissaDecimalPlaces: 1
  } ), { mantissa: '1.0', exponent: '4' } );

  assert.deepEqual( ScientificNotationNode.toScientificNotation( 9648, {
    exponent: 4,
    mantissaDecimalPlaces: 3
  } ), { mantissa: '0.965', exponent: '4' } );

  assert.deepEqual( ScientificNotationNode.toScientificNotation( 9648, {
    exponent: 5,
    mantissaDecimalPlaces: 1
  } ), { mantissa: '0.1', exponent: '5' } );
} );<|endoftext|>


<commit_before>// Copyright 2017-2021, University of Colorado Boulder

/**
 * Collection of utility constants and functions for managing keyboard input. Constants are values of Event.key, as
 * well as helper functions and collections.
 *
 * @author Jesse Greenberg
 * @author Michael Kauzmann (PhET Interactive Simulations)
 */

import validate from '../../../axon/js/validate.js';
import scenery from '../scenery.js';

const KEY_RIGHT_ARROW = 'arrowright';
const KEY_LEFT_ARROW = 'arrowleft';
const KEY_UP_ARROW = 'arrowup';
const KEY_DOWN_ARROW = 'arrowdown';
const KEY_SHIFT = 'shift';
const KEY_CTRL = 'control';
const KEY_ALT = 'alt';
const KEY_W = 'w';
const KEY_A = 'a';
const KEY_S = 's';
const KEY_D = 'd';

const ARROW_KEYS = [ KEY_RIGHT_ARROW, KEY_LEFT_ARROW, KEY_UP_ARROW, KEY_DOWN_ARROW ];
const WASD_KEYS = [ KEY_W, KEY_S, KEY_A, KEY_D ];

const DOM_EVENT_VALIDATOR = { valueType: Event };

// constants
var KeyboardUtils = {
  KEY_SPACE: ' ',
  KEY_ENTER: 'enter',
  KEY_TAB: 'tab',
  KEY_RIGHT_ARROW: KEY_RIGHT_ARROW,
  KEY_LEFT_ARROW: KEY_LEFT_ARROW,
  KEY_UP_ARROW: KEY_UP_ARROW,
  KEY_DOWN_ARROW: KEY_DOWN_ARROW,
  KEY_SHIFT: KEY_SHIFT,
  KEY_CTRL: KEY_CTRL,
  KEY_ALT: KEY_ALT,
  KEY_ESCAPE: 'escape',
  KEY_DELETE: 'delete',
  KEY_BACKSPACE: 'backspace',
  KEY_PAGE_UP: 'pageup',
  KEY_PAGE_DOWN: 'pagedown',
  KEY_END: 'end',
  KEY_HOME: 'home',
  KEY_0: '0',
  KEY_1: '1',
  KEY_2: '2',
  KEY_3: '3',
  KEY_4: '4',
  KEY_5: '5',
  KEY_6: '6',
  KEY_7: '7',
  KEY_8: '8',
  KEY_9: '9',
  KEY_A: 'a',
  KEY_B: 'b',
  KEY_C: 'c',
  KEY_D: 'd',
  KEY_E: 'e',
  KEY_F: 'f',
  KEY_G: 'g',
  KEY_H: 'h',
  KEY_I: 'I',
  KEY_J: 'j',
  KEY_K: 'k',
  KEY_L: 'l',
  KEY_M: 'm',
  KEY_N: 'n',
  KEY_O: 'o',
  KEY_P: 'p',
  KEY_Q: 'q',
  KEY_R: 'r',
  KEY_S: 's',
  KEY_T: 't',
  KEY_U: 'u',
  KEY_V: 'v',
  KEY_W: 'w',
  KEY_X: 'x',
  KEY_Y: 'y',
  KEY_Z: 'z',

  KEY_EQUALS: '=',
  KEY_PLUS: '+',
  KEY_MINUS: '-',

  ARROW_KEYS: ARROW_KEYS,
  WASD_KEYS: WASD_KEYS,
  MOVEMENT_KEYS: ARROW_KEYS.concat( WASD_KEYS ),

  /**
   * Returns whether or not the key corresponds to pressing an arrow key
   * @param {Event} domEvent
   * @returns {boolean}
   */
  isArrowKey( domEvent ) {
    return KeyboardUtils.isAnyKeyEvent( domEvent, ARROW_KEYS );
  },

  /**
   * Returns true if key is one of keys used for range inputs
   * @param {Event} domEvent
   * @returns {boolean}
   */
  isRangeKey( domEvent ) {
    return KeyboardUtils.isArrowKey( domEvent ) ||
           KeyboardUtils.isAnyKeyEvent( domEvent, [
             KeyboardUtils.KEY_PAGE_UP,
             KeyboardUtils.KEY_PAGE_DOWN,
             KeyboardUtils.KEY_HOME,
             KeyboardUtils.KEY_END
           ] );
  },

  /**
   * Returns whether or not the key corresponds to pressing a number key
   * @param {Event} domEvent
   * @returns {boolean}
   */
  isNumberKey( domEvent ) {
    return !isNaN( parseInt( KeyboardUtils.getKeyDef( domEvent ), 10 ) );
  },

  /**
   * Returns whether or not the key corresponds to one of the WASD movement keys
   * @param {Event} domEvent
   * @returns {boolean}
   */
  isWASDKey( domEvent ) {
    return KeyboardUtils.isAnyKeyEvent( domEvent, WASD_KEYS );
  },

  /**
   * Returns true if the key indicates a 'movement' key in keyboard dragging
   * @param {Event} domEvent
   * @returns {boolean}
   */
  isMovementKey( domEvent ) {
    return KeyboardUtils.isAnyKeyEvent( domEvent, KeyboardUtils.MOVEMENT_KEYS );
  },

  /**
   * If the domEvent cooresponds to any of the probided keys in the list
   * @param {Event} domEvent
   * @param {KeyDef[]} keyboardUtilsKeys
   * @returns {*}
   */
  isAnyKeyEvent( domEvent, keyboardUtilsKeys ) {
    validate( domEvent, DOM_EVENT_VALIDATOR );
    return keyboardUtilsKeys.includes( KeyboardUtils.getKeyDef( domEvent ) );
  },

  /**
   * Whether or not the event was of the provided KeyboardUtils KeyDef.
   * @param {Event} domEvent
   * @param {KeyDef} keyboardUtilsKey
   * @returns {boolean}
   */
  isKeyEvent( domEvent, keyboardUtilsKey ) {
    return KeyboardUtils.getKeyDef( domEvent ) === keyboardUtilsKey;
  },

  /**
   *
   * @param {Event} domEvent
   * @returns {KeyDef|null} - null if there is no `key` property on the provided Event.
   */
  getKeyDef( domEvent ) {
    validate( domEvent, DOM_EVENT_VALIDATOR );
    return domEvent.key ? domEvent.key.toLowerCase() : null;
  },

  /**
   * Return true if the param is of type KeyDef
   * @param {*} key
   * @returns {boolean}
   */
  isKeyDef( key ) {
    return typeof key === 'string' && key.toLowerCase() === key;
  }
};

const ALL_KEYS = [];
for ( const keyKey in KeyboardUtils ) {

  // No functions or key-groups allowed
  if ( KeyboardUtils.hasOwnProperty( keyKey ) && typeof KeyboardUtils[ keyKey ] === 'string' ) {
    ALL_KEYS.push( KeyboardUtils[ keyKey ] );
  }
}

// @public - Not really all of them, but all that are in the above list. If you see one you wish was in here, then add it!
KeyboardUtils.ALL_KEYS = ALL_KEYS;

/**
 * @typedef KeyDef
 * @extends {String}
 * @public
 *
 * The value of KeyboardEvent.key, but lower case for easy comparison independent of modifier keys,
 * see https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key
 *
 * In general, it is best to use globalKeyStateTracker or a similar KeyStateTracker to determine if modifier keys are
 * down.
 */

scenery.register( 'KeyboardUtils', KeyboardUtils );

export default KeyboardUtils;<commit_msg>typo fix, scenery#1053<commit_after>// Copyright 2017-2021, University of Colorado Boulder

/**
 * Collection of utility constants and functions for managing keyboard input. Constants are values of Event.key, as
 * well as helper functions and collections.
 *
 * @author Jesse Greenberg
 * @author Michael Kauzmann (PhET Interactive Simulations)
 */

import validate from '../../../axon/js/validate.js';
import scenery from '../scenery.js';

const KEY_RIGHT_ARROW = 'arrowright';
const KEY_LEFT_ARROW = 'arrowleft';
const KEY_UP_ARROW = 'arrowup';
const KEY_DOWN_ARROW = 'arrowdown';
const KEY_SHIFT = 'shift';
const KEY_CTRL = 'control';
const KEY_ALT = 'alt';
const KEY_W = 'w';
const KEY_A = 'a';
const KEY_S = 's';
const KEY_D = 'd';

const ARROW_KEYS = [ KEY_RIGHT_ARROW, KEY_LEFT_ARROW, KEY_UP_ARROW, KEY_DOWN_ARROW ];
const WASD_KEYS = [ KEY_W, KEY_S, KEY_A, KEY_D ];

const DOM_EVENT_VALIDATOR = { valueType: Event };

// constants
var KeyboardUtils = {
  KEY_SPACE: ' ',
  KEY_ENTER: 'enter',
  KEY_TAB: 'tab',
  KEY_RIGHT_ARROW: KEY_RIGHT_ARROW,
  KEY_LEFT_ARROW: KEY_LEFT_ARROW,
  KEY_UP_ARROW: KEY_UP_ARROW,
  KEY_DOWN_ARROW: KEY_DOWN_ARROW,
  KEY_SHIFT: KEY_SHIFT,
  KEY_CTRL: KEY_CTRL,
  KEY_ALT: KEY_ALT,
  KEY_ESCAPE: 'escape',
  KEY_DELETE: 'delete',
  KEY_BACKSPACE: 'backspace',
  KEY_PAGE_UP: 'pageup',
  KEY_PAGE_DOWN: 'pagedown',
  KEY_END: 'end',
  KEY_HOME: 'home',
  KEY_0: '0',
  KEY_1: '1',
  KEY_2: '2',
  KEY_3: '3',
  KEY_4: '4',
  KEY_5: '5',
  KEY_6: '6',
  KEY_7: '7',
  KEY_8: '8',
  KEY_9: '9',
  KEY_A: 'a',
  KEY_B: 'b',
  KEY_C: 'c',
  KEY_D: 'd',
  KEY_E: 'e',
  KEY_F: 'f',
  KEY_G: 'g',
  KEY_H: 'h',
  KEY_I: 'I',
  KEY_J: 'j',
  KEY_K: 'k',
  KEY_L: 'l',
  KEY_M: 'm',
  KEY_N: 'n',
  KEY_O: 'o',
  KEY_P: 'p',
  KEY_Q: 'q',
  KEY_R: 'r',
  KEY_S: 's',
  KEY_T: 't',
  KEY_U: 'u',
  KEY_V: 'v',
  KEY_W: 'w',
  KEY_X: 'x',
  KEY_Y: 'y',
  KEY_Z: 'z',

  KEY_EQUALS: '=',
  KEY_PLUS: '+',
  KEY_MINUS: '-',

  ARROW_KEYS: ARROW_KEYS,
  WASD_KEYS: WASD_KEYS,
  MOVEMENT_KEYS: ARROW_KEYS.concat( WASD_KEYS ),

  /**
   * Returns whether or not the key corresponds to pressing an arrow key
   * @param {Event} domEvent
   * @returns {boolean}
   */
  isArrowKey( domEvent ) {
    return KeyboardUtils.isAnyKeyEvent( domEvent, ARROW_KEYS );
  },

  /**
   * Returns true if key is one of keys used for range inputs
   * @param {Event} domEvent
   * @returns {boolean}
   */
  isRangeKey( domEvent ) {
    return KeyboardUtils.isArrowKey( domEvent ) ||
           KeyboardUtils.isAnyKeyEvent( domEvent, [
             KeyboardUtils.KEY_PAGE_UP,
             KeyboardUtils.KEY_PAGE_DOWN,
             KeyboardUtils.KEY_HOME,
             KeyboardUtils.KEY_END
           ] );
  },

  /**
   * Returns whether or not the key corresponds to pressing a number key
   * @param {Event} domEvent
   * @returns {boolean}
   */
  isNumberKey( domEvent ) {
    return !isNaN( parseInt( KeyboardUtils.getKeyDef( domEvent ), 10 ) );
  },

  /**
   * Returns whether or not the key corresponds to one of the WASD movement keys
   * @param {Event} domEvent
   * @returns {boolean}
   */
  isWASDKey( domEvent ) {
    return KeyboardUtils.isAnyKeyEvent( domEvent, WASD_KEYS );
  },

  /**
   * Returns true if the key indicates a 'movement' key in keyboard dragging
   * @param {Event} domEvent
   * @returns {boolean}
   */
  isMovementKey( domEvent ) {
    return KeyboardUtils.isAnyKeyEvent( domEvent, KeyboardUtils.MOVEMENT_KEYS );
  },

  /**
   * If the domEvent corresponds to any of the provided keys in the list.
   *
   * @param {Event} domEvent
   * @param {KeyDef[]} keyboardUtilsKeys
   * @returns {*}
   */
  isAnyKeyEvent( domEvent, keyboardUtilsKeys ) {
    validate( domEvent, DOM_EVENT_VALIDATOR );
    return keyboardUtilsKeys.includes( KeyboardUtils.getKeyDef( domEvent ) );
  },

  /**
   * Whether or not the event was of the provided KeyboardUtils KeyDef.
   * @param {Event} domEvent
   * @param {KeyDef} keyboardUtilsKey
   * @returns {boolean}
   */
  isKeyEvent( domEvent, keyboardUtilsKey ) {
    return KeyboardUtils.getKeyDef( domEvent ) === keyboardUtilsKey;
  },

  /**
   *
   * @param {Event} domEvent
   * @returns {KeyDef|null} - null if there is no `key` property on the provided Event.
   */
  getKeyDef( domEvent ) {
    validate( domEvent, DOM_EVENT_VALIDATOR );
    return domEvent.key ? domEvent.key.toLowerCase() : null;
  },

  /**
   * Return true if the param is of type KeyDef
   * @param {*} key
   * @returns {boolean}
   */
  isKeyDef( key ) {
    return typeof key === 'string' && key.toLowerCase() === key;
  }
};

const ALL_KEYS = [];
for ( const keyKey in KeyboardUtils ) {

  // No functions or key-groups allowed
  if ( KeyboardUtils.hasOwnProperty( keyKey ) && typeof KeyboardUtils[ keyKey ] === 'string' ) {
    ALL_KEYS.push( KeyboardUtils[ keyKey ] );
  }
}

// @public - Not really all of them, but all that are in the above list. If you see one you wish was in here, then add it!
KeyboardUtils.ALL_KEYS = ALL_KEYS;

/**
 * @typedef KeyDef
 * @extends {String}
 * @public
 *
 * The value of KeyboardEvent.key, but lower case for easy comparison independent of modifier keys,
 * see https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key
 *
 * In general, it is best to use globalKeyStateTracker or a similar KeyStateTracker to determine if modifier keys are
 * down.
 */

scenery.register( 'KeyboardUtils', KeyboardUtils );

export default KeyboardUtils;<|endoftext|>