<commit_before>var drawScrollBar = function(canvas, context, scrollPosition){
	var height = 400;
	var width = 20;
	scrollPosition = 50;

	context.rect(20,20,150,100);
	context.stroke();
	context.beginPath();
	context.moveTo(canvas.width - width, scrollPosition);
	context.lineTo(canvas.width, scrollPosition);
	context.stroke();
}
<commit_msg>Update scrollbar.js<commit_after>var drawScrollBar = function(canvas, context, scrollPosition){
	var height = 400;
	var width = 20;
	var distanceFromTop = 100;
	scrollPosition = 50;

	context.rect(canvas.width - width, distanceFromTop, canvas.width, distanceFromTop + height);
	context.stroke();
	context.beginPath();
	context.moveTo(canvas.width - width, scrollPosition + distanceFromTop);
	context.lineTo(canvas.width, scrollPosition + distanceFromTop);
	context.stroke();
}
<|endoftext|>


<commit_before>/**
 * Using gulp to update these dirs because we need to parse patternlab-config.json to know their destinations.
 */
'use strict';

const https = require('https');
const spawnSync = require('child_process').spawnSync;

const fs = require('fs-extra');
const gulp = require('gulp');
const runSequence = require('run-sequence');
const utils = require('fepper-utils');

const enc = global.conf.enc;
const extendDir = global.conf.extend_dir;
const publicDir = global.conf.ui.paths.public.root;
const rootDir = global.rootDir;

const isWindows = (
  global.conf.is_windows ||
  process.env.ComSpec && process.env.ComSpec.toLowerCase() === 'c:\\windows\\system32\\cmd.exe' // Deprecated condition.
);

let binNpm = 'npm';

// Spawn npm.cmd if Windows and not BASH.
if (isWindows) {
  binNpm = 'npm.cmd';
}

function downloadFileFromRepo(file) {
  const repoDir = 'https://raw.githubusercontent.com/electric-eloquence/fepper/release';
  const writeStream = fs.createWriteStream(`${rootDir}/${file}`);

  https.get(`${repoDir}/${file}`, (res) => {
    res.pipe(writeStream);
  }).on('error', (err) => {
    utils.error(err);
  });
}

function parseNpmOutdated(npmPackage, addlArgsArr = []) {
  const spawnObj = spawnSync(binNpm, ['outdated', npmPackage].concat(addlArgsArr));
  const stdoutStr = spawnObj.stdout.toString(enc).trim();
  const stdoutRows = stdoutStr.split('\n');

  if (stdoutRows.length > 1) {
    utils.log(stdoutStr);

    const stdoutCols = stdoutRows[1].split(/ +/);

    if (stdoutCols[1] && stdoutCols[3]) {
      return {
        current: stdoutCols[1],
        latest: stdoutCols[3]
      };
    }
  }

  return null;
}

function fpUpdate(cb) {
  // Update global npm.
  utils.log('Running `npm --global update` on fepper-cli...');

  const fepperCliVersions = parseNpmOutdated('fepper-cli', ['--global']);

  if (fepperCliVersions && fepperCliVersions.current !== fepperCliVersions.latest) {
    const spawnObj = spawnSync(binNpm, ['uninstall', '--global', 'fepper-cli']);

    if (isWindows || spawnObj.status === 0) {
      spawnSync(binNpm, ['install', '--global', 'fepper-cli'], {stdio: 'inherit'});
    }
    else {
      utils.log('Running this command again as root/Administrator...');
      spawnSync('sudo', [binNpm, 'uninstall', '--global', 'fepper-cli']);
      spawnSync('sudo', [binNpm, 'install', '--global', 'fepper-cli'], {stdio: 'inherit'});
    }
  }

  // Update core npms.
  process.chdir(rootDir);
  utils.log(`Running \`npm update\` in ${rootDir}...`);

  // Find the latest fepper-npm release and update if updatable.
  const fepperVersions = parseNpmOutdated('fepper');

  if (fepperVersions && fepperVersions.current !== fepperVersions.latest) {
    spawnSync(binNpm, ['uninstall', '--save-dev', 'fepper']);
    spawnSync(binNpm, ['install', '--save-dev', 'fepper'], {stdio: 'inherit'});
  }

  // Find the latest fepper-utils release and update if updatable.
  const fepperUtilsVersions = parseNpmOutdated('fepper-utils');

  if (fepperUtilsVersions && fepperUtilsVersions.current !== fepperUtilsVersions.latest) {
    spawnSync(binNpm, ['uninstall', '--save-dev', 'fepper-utils']);
    spawnSync(binNpm, ['install', '--save-dev', 'fepper-utils'], {stdio: 'inherit'});
  }

  spawnSync(binNpm, ['update'], {stdio: 'inherit'});

  // Update distro files.
  downloadFileFromRepo('CHANGELOG.md');
  downloadFileFromRepo('LICENSE');
  downloadFileFromRepo('README.md');
  downloadFileFromRepo('fepper.command');
  downloadFileFromRepo('fepper.ps1');
  downloadFileFromRepo('fepper.vbs');

  const runDir = 'run';

  if (!fs.existsSync(runDir)) {
    fs.ensureDirSync(runDir);
  }

  downloadFileFromRepo(`${runDir}/install-base.js`);
  downloadFileFromRepo(`${runDir}/install.js`);

  // Update extension npms.
  if (fs.existsSync(extendDir)) {
    process.chdir(extendDir);
    utils.log(`Running \`npm update\` in ${extendDir}...`);

    // If the fp-stylus extension is installed, find the latest release and update if updatable.
    const extendPackages = fs.readFileSync('package.json', global.conf.enc);

    if (extendPackages.indexOf('fp-stylus') > -1) {
      const fpStylusVersions = parseNpmOutdated('fp-stylus');

      if (fpStylusVersions && fpStylusVersions.current !== fpStylusVersions.latest) {
        spawnSync(binNpm, ['uninstall', '--save-dev', 'fp-stylus']);
        spawnSync(binNpm, ['install', '--save-dev', 'fp-stylus'], {stdio: 'inherit'});
      }
    }

    spawnSync(binNpm, ['update'], {stdio: 'inherit'});
  }

  // Update public dir npms.
  process.chdir(publicDir);
  utils.log(`Running \`npm update\` in ${publicDir}...`);

  // Find the latest feplet release and update if updatable.
  const fepletVersions = parseNpmOutdated('feplet');

  if (fepletVersions && fepletVersions.current !== fepletVersions.latest) {
    spawnSync(binNpm, ['uninstall', '--save-dev', 'feplet']);
    spawnSync(binNpm, ['install', '--save-dev', 'feplet'], {stdio: 'inherit'});
  }

  // Find the latest feplet release and update if updatable.
  const fepperUiVersions = parseNpmOutdated('fepper-ui');

  if (fepperUiVersions && fepperUiVersions.current !== fepperUiVersions.latest) {
    spawnSync(binNpm, ['uninstall', '--save-dev', 'fepper-ui']);
    spawnSync(binNpm, ['install', '--save-dev', 'fepper-ui'], {stdio: 'inherit'});
  }

  spawnSync(binNpm, ['update', '--no-package-lock'], {stdio: 'inherit'});
  spawnSync(binNpm, ['install', '--ignore-scripts', '--no-package-lock'], {stdio: 'inherit'});

  // Finish up.
  process.chdir(global.appDir);
  runSequence(
    'ui:compile',
    cb
  );
}

gulp.task('up', cb => {
  fpUpdate(cb);
});

gulp.task('update', cb => {
  fpUpdate(cb);
});
<commit_msg>`fp update` gets direct downloads from distro repo<commit_after>/**
 * Using gulp to update these dirs because we need to parse patternlab-config.json to know their destinations.
 */
'use strict';

const https = require('https');
const spawnSync = require('child_process').spawnSync;

const fs = require('fs-extra');
const gulp = require('gulp');
const runSequence = require('run-sequence');
const utils = require('fepper-utils');

const enc = global.conf.enc;
const extendDir = global.conf.extend_dir;
const publicDir = global.conf.ui.paths.public.root;
const rootDir = global.rootDir;

const isWindows = (
  global.conf.is_windows ||
  process.env.ComSpec && process.env.ComSpec.toLowerCase() === 'c:\\windows\\system32\\cmd.exe' // Deprecated condition.
);

let binNpm = 'npm';

// Spawn npm.cmd if Windows and not BASH.
if (isWindows) {
  binNpm = 'npm.cmd';
}

function downloadFileFromRepo(file, repoDir) {
  const writeStream = fs.createWriteStream(`${rootDir}/${file}`);

  https.get(`${repoDir}/${file}`, (res) => {
    res.pipe(writeStream);
  }).on('error', (err) => {
    utils.error(err);
  });
}

function parseNpmOutdated(npmPackage, addlArgsArr = []) {
  const spawnObj = spawnSync(binNpm, ['outdated', npmPackage].concat(addlArgsArr));
  const stdoutStr = spawnObj.stdout.toString(enc).trim();
  const stdoutRows = stdoutStr.split('\n');

  if (stdoutRows.length > 1) {
    utils.log(stdoutStr);

    const stdoutCols = stdoutRows[1].split(/ +/);

    if (stdoutCols[1] && stdoutCols[3]) {
      return {
        current: stdoutCols[1],
        latest: stdoutCols[3]
      };
    }
  }

  return null;
}

function fpUpdate(cb) {
  // Update global npm.
  utils.log('Running `npm --global update` on fepper-cli...');

  const fepperCliVersions = parseNpmOutdated('fepper-cli', ['--global']);

  if (fepperCliVersions && fepperCliVersions.current !== fepperCliVersions.latest) {
    const spawnObj = spawnSync(binNpm, ['uninstall', '--global', 'fepper-cli']);

    if (isWindows || spawnObj.status === 0) {
      spawnSync(binNpm, ['install', '--global', 'fepper-cli'], {stdio: 'inherit'});
    }
    else {
      utils.log('Running this command again as root/Administrator...');
      spawnSync('sudo', [binNpm, 'uninstall', '--global', 'fepper-cli']);
      spawnSync('sudo', [binNpm, 'install', '--global', 'fepper-cli'], {stdio: 'inherit'});
    }
  }

  // Update core npms.
  process.chdir(rootDir);
  utils.log(`Running \`npm update\` in ${rootDir}...`);

  // Find the latest fepper-npm release and update if updatable.
  const fepperVersions = parseNpmOutdated('fepper');

  if (fepperVersions && fepperVersions.current !== fepperVersions.latest) {
    spawnSync(binNpm, ['uninstall', '--save-dev', 'fepper']);
    spawnSync(binNpm, ['install', '--save-dev', 'fepper'], {stdio: 'inherit'});
  }

  // Find the latest fepper-utils release and update if updatable.
  const fepperUtilsVersions = parseNpmOutdated('fepper-utils');

  if (fepperUtilsVersions && fepperUtilsVersions.current !== fepperUtilsVersions.latest) {
    spawnSync(binNpm, ['uninstall', '--save-dev', 'fepper-utils']);
    spawnSync(binNpm, ['install', '--save-dev', 'fepper-utils'], {stdio: 'inherit'});
  }

  spawnSync(binNpm, ['update'], {stdio: 'inherit'});

  const rootPackageJson = fs.readJsonSync('./package.json');

  if (rootPackageJson.repository && rootPackageJson.repository.url) {
    let repoDir = rootPackageJson.repository.url.replace('git+', '');
    repoDir = repoDir.replace('github', 'raw.githubusercontent');
    repoDir = repoDir.replace('.git', '/release');
  }

  // Update distro files.
  downloadFileFromRepo('CHANGELOG.md', repoDir);
  downloadFileFromRepo('LICENSE', repoDir);
  downloadFileFromRepo('README.md', repoDir);
  downloadFileFromRepo('fepper.command', repoDir);
  downloadFileFromRepo('fepper.ps1', repoDir);
  downloadFileFromRepo('fepper.vbs', repoDir);

  const runDir = 'run';

  if (!fs.existsSync(runDir)) {
    fs.ensureDirSync(runDir);
  }

  downloadFileFromRepo(`${runDir}/install-base.js`);
  downloadFileFromRepo(`${runDir}/install.js`);

  // Update extension npms.
  if (fs.existsSync(extendDir)) {
    process.chdir(extendDir);
    utils.log(`Running \`npm update\` in ${extendDir}...`);

    // If the fp-stylus extension is installed, find the latest release and update if updatable.
    const extendPackageJson = fs.readJsonSync('./package.json');

    if (
      extendPackageJson.devDependencies &&
      Object.keys(extendPackageJson.devDependencies).indexOf('fp-stylus') > -1
    ) {
      const fpStylusVersions = parseNpmOutdated('fp-stylus');

      if (fpStylusVersions && fpStylusVersions.current !== fpStylusVersions.latest) {
        spawnSync(binNpm, ['uninstall', '--save-dev', 'fp-stylus']);
        spawnSync(binNpm, ['install', '--save-dev', 'fp-stylus'], {stdio: 'inherit'});
      }
    }

    spawnSync(binNpm, ['update'], {stdio: 'inherit'});
  }

  // Update public dir npms.
  process.chdir(publicDir);
  utils.log(`Running \`npm update\` in ${publicDir}...`);

  // Find the latest feplet release and update if updatable.
  const fepletVersions = parseNpmOutdated('feplet');

  if (fepletVersions && fepletVersions.current !== fepletVersions.latest) {
    spawnSync(binNpm, ['uninstall', '--save-dev', 'feplet']);
    spawnSync(binNpm, ['install', '--save-dev', 'feplet'], {stdio: 'inherit'});
  }

  // Find the latest feplet release and update if updatable.
  const fepperUiVersions = parseNpmOutdated('fepper-ui');

  if (fepperUiVersions && fepperUiVersions.current !== fepperUiVersions.latest) {
    spawnSync(binNpm, ['uninstall', '--save-dev', 'fepper-ui']);
    spawnSync(binNpm, ['install', '--save-dev', 'fepper-ui'], {stdio: 'inherit'});
  }

  spawnSync(binNpm, ['update', '--no-package-lock'], {stdio: 'inherit'});
  spawnSync(binNpm, ['install', '--ignore-scripts', '--no-package-lock'], {stdio: 'inherit'});

  // Finish up.
  process.chdir(global.appDir);
  runSequence(
    'ui:compile',
    cb
  );
}

gulp.task('up', cb => {
  fpUpdate(cb);
});

gulp.task('update', cb => {
  fpUpdate(cb);
});
<|endoftext|>


<commit_before>/*
 * grunt-docbase
 * https://github.com/mateus/DocbaseGrunt
 *
 * Copyright (c) 2015 Mateus Freira
 * Licensed under the MIT license.
 */

'use strict';

module.exports = function(grunt) {

  // Please see the Grunt documentation for more information regarding task
  // creation: http://gruntjs.com/creating-tasks

  grunt.registerMultiTask('docbase', 'Grunt plugin to generate html files from your docbase project.', function() {
    var ProgressBar = require('progress');
    var done = this.async();
    var options = this.options({
      generatePath: 'html/',
      //mapFile: 'docbase.json',
      configJsFile: 'docbase-config.js',
      baseUrl: '',
      checkLoadedSelector: "[role='flatdoc-menu']",
      checkNavbar: ".map_folder",
      urlToAccess: "http://localhost:9001/",
      assets: ['bower_components', 'styles', 'scripts', 'images'],
      linksSelector: '[ng-href]',
      linksVersions: '.version-switcher a',
      rootDocument: 'html',
      generateSearchIndex: true,
      onlysearchIndex: false,
      generateHtml: true,
      startDocument: '',
      endDocument: '',
      searchIndexSelector: "h1, h2, h3, p, ul",
      operation: 'series'
    });
    grunt.log.writeln("starting ");
    var util = require("./lib/util.js");
    var fs = require("fs");
    var termsToBaseURLReplace = ['src="', 'href="', "src=", "href="];
    var baseReplace = ['base href="'];
    var urlToFielName = util.urlToFielName;
    var getPageLinks = util.getPageLinks;
    var inQuotes = util.inQuotes;
    var mapFile = null;
    var configData = null;
    var currentLinksIn = [];
    var currentId = 0;
    var makeCrawlercount = 0;
    var currentLinksTemp = [];
    var progressStart = false;
    var bar;
    var versionsLink = [];
    var pageInfo = {
      pageSize: 3,
      totalPage: 0,
      currentPage: 0,
      pageCounter: 0,
      totalCounter: 0
    };

    if (options.mapFile) {
      mapFile = grunt.file.readJSON(options.mapFile);
    } else {
      eval(fs.readFileSync(options.configJsFile) + " configData = docbaseConfig;");
    }
    if (configData.versions) {
      mapFile = configData.versions;
    }
    versionsLink = util.versionLinks(mapFile);
    var phantom = require('phantom');
    var pages = [];
    var links = [];
    var crawled = {};
    var searchIndex = [];
    var indexdLinks = [];
    var moveAssets = function(srcpath) {
      if (grunt.file.isDir(srcpath)) {
        var files = grunt.file.expand(srcpath + "/*");
        files.forEach(moveAssets);
      } else {
        grunt.file.copy(srcpath, options.generatePath + srcpath)
      }
    };
    var clearFolder = function(srcpath) {
      if (grunt.file.isDir(srcpath)) {
        var files = grunt.file.expand(srcpath + "/*");
        files.forEach(clearFolder);
      } else {
        grunt.file.delete(srcpath);
      }
    };
    var prepareAssets = function() {
      options.assets.forEach(function(srcpath) {
        grunt.log.writeln("Moving:", srcpath);
        moveAssets(srcpath);
      });
    }
    var checkQueueProcess = function(page, ph) {
      page.close();
      pages.shift();
      if (pages.length === 0) {
        if (!options.onlysearchIndex) {
          prepareAssets();
        }
        setTimeout(function() {
          ph.exit();
          done();
        }, 0);
      }
    };
    var replaceBaseUrl = function(documentContent, fileName) {
      var nPaths = (fileName.match(/\//g) || []).length;
      var baseUrl = "";
      for (var i = nPaths - 2; i >= 0; i--) {
        baseUrl += "../";
      }
      var result = documentContent;
      baseReplace.forEach(function(term) {
        result = result.replace(new RegExp(term + './', 'g'), term + baseUrl);
      });
      return result;
    };
    var replaceLink = function(documentContent, from, to) {
      documentContent = documentContent.replace(new RegExp(inQuotes(from), 'g'), to);
      documentContent = documentContent.replace(new RegExp(from + "\#", 'g'), to + "#");
      return documentContent;
    };
    var replacePageLinks = function(documentContent) {
      versionsLink.forEach(function(version) {
        documentContent = replaceLink(documentContent, version.link, urlToFielName(version.realLink));
        documentContent = replaceLink(documentContent, urlToFielName(version.link), urlToFielName(version.realLink));
      });
      currentLinksIn.forEach(function(link) {
        var url = urlToFielName(link);
        documentContent = replaceLink(documentContent, link, url);
        documentContent = documentContent.replace(new RegExp(options.urlToAccess, 'g'), "");
      });
      return documentContent;
    };
    var makeCrawler = function(findLinks, once) {
      return function(currentLinks) {

        if (!findLinks) {
          currentLinksTemp = currentLinksTemp.concat(currentLinks);
          currentLinks.forEach(function(link) {
            links.push(link);
          });
          if (versionsLink.length == makeCrawlercount) {

            currentLinksTemp.forEach(function(v1, k1) {
              var flag = true;
              versionsLink.forEach(function(v2, k2) {
                if (v1 == v2.link) {
                  flag = false;
                }
              });
              if (flag && currentLinksIn.indexOf(v1) == -1) {
                currentLinksIn.push(v1);
              }
            });
            versionsLink.forEach(function(v2, k2) {
              currentLinksIn.push(v2.link);
            });
            crawlPage(options.urlToAccess, false, true, function(ph) {
              crawlChain(findLinks, once, ph);
            });
          }
        }
        if (findLinks) {
          makeCrawlercount++;
          currentLinks.forEach(function(link) {
            if (!once || !crawled[link]) {
              if (once) {
                crawled[link] = true;
              }
              links.push(link);
              crawlPage(options.urlToAccess + link, findLinks);
            }
          });
        }
      };
    };
    var makeGitCrawler = function(findLinks, once) {
      return function(currentLinks) {
        currentLinksIn = currentLinks;
        versionsLink.forEach(function(version) {
          currentLinksIn.push(version.link);
        });
        crawlPage(options.urlToAccess, false, true, function(ph) {
          crawlChain(findLinks, once, ph);
        });
      };
    };
    var chainEnd = function(ph) {
      prepareAssets();
      setTimeout(function() {
        ph.exit();
        done();
      }, 0);
    }
    var crawlChain = function(findLinks, once, ph) {
      if (!progressStart) {
        progressStart = true;
        bar = new ProgressBar('Progress ╢:bar╟ :percent :etas', {
          complete: '█',
          incomplete: '░',
          width: 50,
          total: currentLinksIn.length
        });

        pageInfo.totalPage = Math.floor(currentLinksIn.length / pageInfo.pageSize);
        pageInfo.totalCounter = currentLinksIn.length;
      }

      //Parallel Operaion
      if (options.operation == 'parallel') {
        if(pageInfo.currentPage <= pageInfo.totalPage) {
          var templLinks = currentLinksIn.slice(pageInfo.currentPage * pageInfo.pageSize, (pageInfo.currentPage + 1) * pageInfo.pageSize);
          templLinks.forEach(function(link, linkKey) {
            if (!once || !crawled[link]) {
              if (once) {
                crawled[link] = true;
              }
              links.push(link);

              var versionFlag = false;
              versionsLink.forEach(function(version) {
                if (version.link == link) {
                  versionFlag = true;
                }
              });
              if (!versionFlag) {
                versionFlag = link.indexOf('/index') == -1 ? false : true;
              }

              //if (linkKey == templLinks.length - 1) {
                crawlPage(options.urlToAccess + link, findLinks, versionFlag, function(ph, url, page) {
                    pageInfo.pageCounter++;
                    console.log(pageInfo.pageCounter, 'Done : '+ urlToFielName(url));
                    if(pageInfo.pageCounter == (pageInfo.currentPage+1)*pageInfo.pageSize) {
                      pageInfo.currentPage++;
                      crawlChain(findLinks, once, ph);
                    }
                    if(pageInfo.pageCounter == pageInfo.totalCounter) {
                      chainEnd(ph);
                    }
                    //page.close();
                    setTimeout(function() {
                      ph.exit();
                    }, 100);
                });

            }
          });
        }
      }

      //Series Operaion
      else if (options.operation == 'series') {
        var link = currentLinksIn[currentId];
        if (currentId < currentLinksIn.length) {
          if (!once || !crawled[link]) {
            if (once) {
              crawled[link] = true;
            }
            links.push(link);

            var versionFlag = false;
            versionsLink.forEach(function(version) {
              if (version.link == link) {
                versionFlag = true;
              }
            });
            if (!versionFlag) {
              versionFlag = link.indexOf('/index') == -1 ? false : true;
            }
            crawlPage(options.urlToAccess + link, findLinks, versionFlag, function(ph) {
              process.stdout.write("\u001b[2J\u001b[0;0H");
              bar.tick();
              setTimeout(function() {
                ph.exit();
              }, 100);
              crawlChain(findLinks, once, ph);
            });
          }
          currentId++;
        } else {
          chainEnd(ph);
        }
      }
    }
    var generateSearchIndex = function(page, url, ph, buildIndex, callback) {
      page.evaluate(function(selector, url) {
        var HEADER = ['H2', 'H1', 'H3'];
        var elements = Array.prototype.slice.call(document.querySelectorAll(selector));
        var h2s = elements.filter(function(element) {
          return HEADER.indexOf(element.tagName) !== -1;
        });
        return h2s.map(function(element, index) {
          var h2Index = elements.indexOf(element);
          var nextH2 = h2s[index + 1];
          var nextH2Index = !!nextH2 ? elements.indexOf(nextH2) : elements.length;
          var elementsBetween = elements.slice(h2Index, nextH2Index);
          var path = url.substr(url.indexOf('#'));
          var spaLink = url.substr(url.indexOf('#'));
          var link = element.id ? path + "/#" + element.id : path;

          return {
            link: link,
            spaLink: spaLink,
            title: element.innerText,
            content: elementsBetween.reduce(function(text, current) {
              return text += current.outerHTML;
            }, "")
          }
        });
      }, function(elements) {
        var missingLinks = elements.filter(function(element) {
          var has = !!indexdLinks[element.link];
          if (!has) {
            indexdLinks[element.link] = true;
          }
          return !has;
        });
        searchIndex = searchIndex.concat(missingLinks.map(function(link) {
          link.link = options.generateHtml ? urlToFielName(link.link) : link.link;
          return link;
        }));
        if (buildIndex) {
          if (progressStart) {
            grunt.log.writeln("Creating index for: " + url);
          }
          grunt.file.write("search-index.json", JSON.stringify(searchIndex), 'w');
          setTimeout(function(){
            if(callback) {
              callback(ph, url);
            }
          });
        }
      }, options.searchIndexSelector, url);
    };
    var generatePage = function(page, url, ph, callback) {
      page.evaluate(function(rootDocument) {
        return document.querySelector(rootDocument).innerHTML;
      }, function(documentContent) {

        var fileName = urlToFielName(url);
        documentContent = replaceBaseUrl(replacePageLinks(documentContent), fileName);
        if (options.generateHtml)
          grunt.file.write(options.generatePath + fileName, options.startDocument + documentContent + options.endDocument, 'w');
        var path = options.generateHtml ? options.generatePath : '';
        grunt.file.write(path + "search-index.json", JSON.stringify(searchIndex), 'w');
        if (progressStart) {
          grunt.log.writeln("Generating:", options.generatePath + urlToFielName(url));
        }
        setTimeout(function(){
          if(callback) {
            callback(ph, url, page);
          }
        });
      }, options.rootDocument);

    };
    var crawlPage = function(url, findLinks, versionFlag, callback) {
      pages.push(url);
      phantom.create(function(ph) {
        ph.createPage(function(page) {
          page.set('settings.userAgent', 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.120 Safari/537.36');
          page.open(url, function() {
            if (progressStart) {
              // process.stdout.write("\u001b[2J\u001b[0;0H");
              // bar.tick();
              console.log('\r\n');
              grunt.log.writeln("Reading: " + url);
            }
            util.waitFor({
              debug: false,
              interval: 100,
              timeout: 50000,
              checkLoadedSelector: options.checkLoadedSelector,
              checkNavbar: options.checkNavbar,
              check: function(check) {
                return !!document.querySelector(check);
              },
              success: function() {

                if (findLinks) {
                  getPageLinks(page, options.linksSelector, makeCrawler(false, false));
                  getPageLinks(page, options.linksVersions, makeCrawler(true, true));
                };
                if (!options.onlysearchIndex) {
                  generatePage(page, url, ph, callback);
                  if (options.generateSearchIndex) {
                    if (progressStart && !versionFlag)
                      generateSearchIndex(page, url);
                  }
                } else {
                  if (progressStart && !versionFlag) {
                    generateSearchIndex(page, url, ph, true, callback);
                  }
                  else {
                    if (callback) {
                      callback(ph, url);
                    }
                  }
                }

              },
              error: function(e) {
                  grunt.log.writeln("Erro generating page:", options.generatePath + urlToFielName(url));
                } // optional
            }, page);
          });
        });
      }, {
        parameters: {
          'ignore-ssl-errors': 'yes',
          'ssl-protocol': 'tlsv1',
          'web-security': false,
          //'debug' : 'true'
        }
      });
    };

    var getGitMap = function(url) {
      phantom.create(function(ph) {
        ph.createPage(function(page) {
          page.set('settings.userAgent', 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.120 Safari/537.36');
          page.open(url, function() {
            readGitMap(page);
          });
        });
      }, {
        parameters: {
          'ignore-ssl-errors': 'yes',
          'ssl-protocol': 'tlsv1',
          'web-security': false,
          //'debug' : 'true'
        }
      });
    }

    function readGitMap(page) {
      setTimeout(function() {
        util.getGitMap(page, options.linksSelector, function(map_data) {
          if (map_data == "") {
            grunt.log.writeln('waiting for github response');
            readGitMap(page);
          } else {
            configData.versions = map_data;
            var docbaseConfigWrite = "var docbaseConfig = " + JSON.stringify(configData, null, 2) + ";";
            grunt.file.write(options.configJsFile, docbaseConfigWrite, 'w');
            mapFile = configData.versions;
            versionsLink = util.versionLinks(mapFile);
            getPageLinks(page, options.linksSelector, makeGitCrawler(false, false));
          }
        });
      }, 500);
    }

    clearFolder(options.generatePath);
    if (configData.method == 'github') {
      getGitMap(options.urlToAccess + 'getGitMap.html');
    } else {
      crawlPage(options.urlToAccess, true);
    }
  });
};
<commit_msg>Check manual_override option before fetching github data<commit_after>/*
 * grunt-docbase
 * https://github.com/mateus/DocbaseGrunt
 *
 * Copyright (c) 2015 Mateus Freira
 * Licensed under the MIT license.
 */

'use strict';

module.exports = function(grunt) {

  // Please see the Grunt documentation for more information regarding task
  // creation: http://gruntjs.com/creating-tasks

  grunt.registerMultiTask('docbase', 'Grunt plugin to generate html files from your docbase project.', function() {
    var ProgressBar = require('progress');
    var done = this.async();
    var options = this.options({
      generatePath: 'html/',
      //mapFile: 'docbase.json',
      configJsFile: 'docbase-config.js',
      baseUrl: '',
      checkLoadedSelector: "[role='flatdoc-menu']",
      checkNavbar: ".map_folder",
      urlToAccess: "http://localhost:9001/",
      assets: ['bower_components', 'styles', 'scripts', 'images'],
      linksSelector: '[ng-href]',
      linksVersions: '.version-switcher a',
      rootDocument: 'html',
      generateSearchIndex: true,
      onlysearchIndex: false,
      generateHtml: true,
      startDocument: '',
      endDocument: '',
      searchIndexSelector: "h1, h2, h3, p, ul",
      operation: 'series'
    });
    grunt.log.writeln("starting ");
    var util = require("./lib/util.js");
    var fs = require("fs");
    var termsToBaseURLReplace = ['src="', 'href="', "src=", "href="];
    var baseReplace = ['base href="'];
    var urlToFielName = util.urlToFielName;
    var getPageLinks = util.getPageLinks;
    var inQuotes = util.inQuotes;
    var mapFile = null;
    var configData = null;
    var currentLinksIn = [];
    var currentId = 0;
    var makeCrawlercount = 0;
    var currentLinksTemp = [];
    var progressStart = false;
    var bar;
    var versionsLink = [];
    var pageInfo = {
      pageSize: 3,
      totalPage: 0,
      currentPage: 0,
      pageCounter: 0,
      totalCounter: 0
    };

    if (options.mapFile) {
      mapFile = grunt.file.readJSON(options.mapFile);
    } else {
      eval(fs.readFileSync(options.configJsFile) + " configData = docbaseConfig;");
    }
    if (configData.versions) {
      mapFile = configData.versions;
    }
    versionsLink = util.versionLinks(mapFile);
    var phantom = require('phantom');
    var pages = [];
    var links = [];
    var crawled = {};
    var searchIndex = [];
    var indexdLinks = [];
    var moveAssets = function(srcpath) {
      if (grunt.file.isDir(srcpath)) {
        var files = grunt.file.expand(srcpath + "/*");
        files.forEach(moveAssets);
      } else {
        grunt.file.copy(srcpath, options.generatePath + srcpath)
      }
    };
    var clearFolder = function(srcpath) {
      if (grunt.file.isDir(srcpath)) {
        var files = grunt.file.expand(srcpath + "/*");
        files.forEach(clearFolder);
      } else {
        grunt.file.delete(srcpath);
      }
    };
    var prepareAssets = function() {
      options.assets.forEach(function(srcpath) {
        grunt.log.writeln("Moving:", srcpath);
        moveAssets(srcpath);
      });
    }
    var checkQueueProcess = function(page, ph) {
      page.close();
      pages.shift();
      if (pages.length === 0) {
        if (!options.onlysearchIndex) {
          prepareAssets();
        }
        setTimeout(function() {
          ph.exit();
          done();
        }, 0);
      }
    };
    var replaceBaseUrl = function(documentContent, fileName) {
      var nPaths = (fileName.match(/\//g) || []).length;
      var baseUrl = "";
      for (var i = nPaths - 2; i >= 0; i--) {
        baseUrl += "../";
      }
      var result = documentContent;
      baseReplace.forEach(function(term) {
        result = result.replace(new RegExp(term + './', 'g'), term + baseUrl);
      });
      return result;
    };
    var replaceLink = function(documentContent, from, to) {
      documentContent = documentContent.replace(new RegExp(inQuotes(from), 'g'), to);
      documentContent = documentContent.replace(new RegExp(from + "\#", 'g'), to + "#");
      return documentContent;
    };
    var replacePageLinks = function(documentContent) {
      versionsLink.forEach(function(version) {
        documentContent = replaceLink(documentContent, version.link, urlToFielName(version.realLink));
        documentContent = replaceLink(documentContent, urlToFielName(version.link), urlToFielName(version.realLink));
      });
      currentLinksIn.forEach(function(link) {
        var url = urlToFielName(link);
        documentContent = replaceLink(documentContent, link, url);
        documentContent = documentContent.replace(new RegExp(options.urlToAccess, 'g'), "");
      });
      return documentContent;
    };
    var makeCrawler = function(findLinks, once) {
      return function(currentLinks) {

        if (!findLinks) {
          currentLinksTemp = currentLinksTemp.concat(currentLinks);
          currentLinks.forEach(function(link) {
            links.push(link);
          });
          if (versionsLink.length == makeCrawlercount) {

            currentLinksTemp.forEach(function(v1, k1) {
              var flag = true;
              versionsLink.forEach(function(v2, k2) {
                if (v1 == v2.link) {
                  flag = false;
                }
              });
              if (flag && currentLinksIn.indexOf(v1) == -1) {
                currentLinksIn.push(v1);
              }
            });
            versionsLink.forEach(function(v2, k2) {
              currentLinksIn.push(v2.link);
            });
            crawlPage(options.urlToAccess, false, true, function(ph) {
              crawlChain(findLinks, once, ph);
            });
          }
        }
        if (findLinks) {
          makeCrawlercount++;
          currentLinks.forEach(function(link) {
            if (!once || !crawled[link]) {
              if (once) {
                crawled[link] = true;
              }
              links.push(link);
              crawlPage(options.urlToAccess + link, findLinks);
            }
          });
        }
      };
    };
    var makeGitCrawler = function(findLinks, once) {
      return function(currentLinks) {
        currentLinksIn = currentLinks;
        versionsLink.forEach(function(version) {
          currentLinksIn.push(version.link);
        });
        crawlPage(options.urlToAccess, false, true, function(ph) {
          crawlChain(findLinks, once, ph);
        });
      };
    };
    var chainEnd = function(ph) {
      prepareAssets();
      setTimeout(function() {
        ph.exit();
        done();
      }, 0);
    }
    var crawlChain = function(findLinks, once, ph) {
      if (!progressStart) {
        progressStart = true;
        bar = new ProgressBar('Progress ╢:bar╟ :percent :etas', {
          complete: '█',
          incomplete: '░',
          width: 50,
          total: currentLinksIn.length
        });

        pageInfo.totalPage = Math.floor(currentLinksIn.length / pageInfo.pageSize);
        pageInfo.totalCounter = currentLinksIn.length;
      }

      //Parallel Operaion
      if (options.operation == 'parallel') {
        if(pageInfo.currentPage <= pageInfo.totalPage) {
          var templLinks = currentLinksIn.slice(pageInfo.currentPage * pageInfo.pageSize, (pageInfo.currentPage + 1) * pageInfo.pageSize);
          templLinks.forEach(function(link, linkKey) {
            if (!once || !crawled[link]) {
              if (once) {
                crawled[link] = true;
              }
              links.push(link);

              var versionFlag = false;
              versionsLink.forEach(function(version) {
                if (version.link == link) {
                  versionFlag = true;
                }
              });
              if (!versionFlag) {
                versionFlag = link.indexOf('/index') == -1 ? false : true;
              }

              //if (linkKey == templLinks.length - 1) {
                crawlPage(options.urlToAccess + link, findLinks, versionFlag, function(ph, url, page) {
                    pageInfo.pageCounter++;
                    console.log(pageInfo.pageCounter, 'Done : '+ urlToFielName(url));
                    if(pageInfo.pageCounter == (pageInfo.currentPage+1)*pageInfo.pageSize) {
                      pageInfo.currentPage++;
                      crawlChain(findLinks, once, ph);
                    }
                    if(pageInfo.pageCounter == pageInfo.totalCounter) {
                      chainEnd(ph);
                    }
                    //page.close();
                    setTimeout(function() {
                      ph.exit();
                    }, 100);
                });

            }
          });
        }
      }

      //Series Operaion
      else if (options.operation == 'series') {
        var link = currentLinksIn[currentId];
        if (currentId < currentLinksIn.length) {
          if (!once || !crawled[link]) {
            if (once) {
              crawled[link] = true;
            }
            links.push(link);

            var versionFlag = false;
            versionsLink.forEach(function(version) {
              if (version.link == link) {
                versionFlag = true;
              }
            });
            if (!versionFlag) {
              versionFlag = link.indexOf('/index') == -1 ? false : true;
            }
            crawlPage(options.urlToAccess + link, findLinks, versionFlag, function(ph) {
              process.stdout.write("\u001b[2J\u001b[0;0H");
              bar.tick();
              setTimeout(function() {
                ph.exit();
              }, 100);
              crawlChain(findLinks, once, ph);
            });
          }
          currentId++;
        } else {
          chainEnd(ph);
        }
      }
    }
    var generateSearchIndex = function(page, url, ph, buildIndex, callback) {
      page.evaluate(function(selector, url) {
        var HEADER = ['H2', 'H1', 'H3'];
        var elements = Array.prototype.slice.call(document.querySelectorAll(selector));
        var h2s = elements.filter(function(element) {
          return HEADER.indexOf(element.tagName) !== -1;
        });
        return h2s.map(function(element, index) {
          var h2Index = elements.indexOf(element);
          var nextH2 = h2s[index + 1];
          var nextH2Index = !!nextH2 ? elements.indexOf(nextH2) : elements.length;
          var elementsBetween = elements.slice(h2Index, nextH2Index);
          var path = url.substr(url.indexOf('#'));
          var spaLink = url.substr(url.indexOf('#'));
          var link = element.id ? path + "/#" + element.id : path;

          return {
            link: link,
            spaLink: spaLink,
            title: element.innerText,
            content: elementsBetween.reduce(function(text, current) {
              return text += current.outerHTML;
            }, "")
          }
        });
      }, function(elements) {
        var missingLinks = elements.filter(function(element) {
          var has = !!indexdLinks[element.link];
          if (!has) {
            indexdLinks[element.link] = true;
          }
          return !has;
        });
        searchIndex = searchIndex.concat(missingLinks.map(function(link) {
          link.link = options.generateHtml ? urlToFielName(link.link) : link.link;
          return link;
        }));
        if (buildIndex) {
          if (progressStart) {
            grunt.log.writeln("Creating index for: " + url);
          }
          grunt.file.write("search-index.json", JSON.stringify(searchIndex), 'w');
          setTimeout(function(){
            if(callback) {
              callback(ph, url);
            }
          });
        }
      }, options.searchIndexSelector, url);
    };
    var generatePage = function(page, url, ph, callback) {
      page.evaluate(function(rootDocument) {
        return document.querySelector(rootDocument).innerHTML;
      }, function(documentContent) {

        var fileName = urlToFielName(url);
        documentContent = replaceBaseUrl(replacePageLinks(documentContent), fileName);
        if (options.generateHtml)
          grunt.file.write(options.generatePath + fileName, options.startDocument + documentContent + options.endDocument, 'w');
        var path = options.generateHtml ? options.generatePath : '';
        grunt.file.write(path + "search-index.json", JSON.stringify(searchIndex), 'w');
        if (progressStart) {
          grunt.log.writeln("Generating:", options.generatePath + urlToFielName(url));
        }
        setTimeout(function(){
          if(callback) {
            callback(ph, url, page);
          }
        });
      }, options.rootDocument);

    };
    var crawlPage = function(url, findLinks, versionFlag, callback) {
      pages.push(url);
      phantom.create(function(ph) {
        ph.createPage(function(page) {
          page.set('settings.userAgent', 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.120 Safari/537.36');
          page.open(url, function() {
            if (progressStart) {
              // process.stdout.write("\u001b[2J\u001b[0;0H");
              // bar.tick();
              console.log('\r\n');
              grunt.log.writeln("Reading: " + url);
            }
            util.waitFor({
              debug: false,
              interval: 100,
              timeout: 50000,
              checkLoadedSelector: options.checkLoadedSelector,
              checkNavbar: options.checkNavbar,
              check: function(check) {
                return !!document.querySelector(check);
              },
              success: function() {

                if (findLinks) {
                  getPageLinks(page, options.linksSelector, makeCrawler(false, false));
                  getPageLinks(page, options.linksVersions, makeCrawler(true, true));
                };
                if (!options.onlysearchIndex) {
                  generatePage(page, url, ph, callback);
                  if (options.generateSearchIndex) {
                    if (progressStart && !versionFlag)
                      generateSearchIndex(page, url);
                  }
                } else {
                  if (progressStart && !versionFlag) {
                    generateSearchIndex(page, url, ph, true, callback);
                  }
                  else {
                    if (callback) {
                      callback(ph, url);
                    }
                  }
                }

              },
              error: function(e) {
                  grunt.log.writeln("Erro generating page:", options.generatePath + urlToFielName(url));
                } // optional
            }, page);
          });
        });
      }, {
        parameters: {
          'ignore-ssl-errors': 'yes',
          'ssl-protocol': 'tlsv1',
          'web-security': false,
          //'debug' : 'true'
        }
      });
    };

    var getGitMap = function(url) {
      phantom.create(function(ph) {
        ph.createPage(function(page) {
          page.set('settings.userAgent', 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.120 Safari/537.36');
          page.open(url, function() {
            readGitMap(page);
          });
        });
      }, {
        parameters: {
          'ignore-ssl-errors': 'yes',
          'ssl-protocol': 'tlsv1',
          'web-security': false,
          //'debug' : 'true'
        }
      });
    }

    function readGitMap(page) {
      setTimeout(function() {
        util.getGitMap(page, options.linksSelector, function(map_data) {
          if (map_data == "") {
            grunt.log.writeln('waiting for github response');
            readGitMap(page);
          } else {
            configData.versions = map_data;
            var docbaseConfigWrite = "var docbaseConfig = " + JSON.stringify(configData, null, 2) + ";";
            grunt.file.write(options.configJsFile, docbaseConfigWrite, 'w');
            mapFile = configData.versions;
            versionsLink = util.versionLinks(mapFile);
            getPageLinks(page, options.linksSelector, makeGitCrawler(false, false));
          }
        });
      }, 500);
    }

    clearFolder(options.generatePath);
    var manual_override = configData.hasOwnProperty('manual_override') ? configData.manual_override : false;
    if (configData.method == 'github' && !manual_override) {
      getGitMap(options.urlToAccess + 'getGitMap.html');
    } else {
      crawlPage(options.urlToAccess, true);
    }
  });
};
<|endoftext|>


<commit_before>/*
 * grunt-docbase
 * https://github.com/mateus/DocbaseGrunt
 *
 * Copyright (c) 2015 Mateus Freira
 * Licensed under the MIT license.
 */

'use strict';

module.exports = function(grunt) {

  // Please see the Grunt documentation for more information regarding task
  // creation: http://gruntjs.com/creating-tasks

  grunt.registerMultiTask('docbase', 'Grunt plugin to generate html files from your docbase project.', function() {
    var done = this.async();
    var options = this.options({
      generatePath: 'html/',
      mapFile: 'map.json',
      baseUrl: '',
      checkLoadedSelector: "[role='flatdoc-menu']",
      urlToAccess: "http://localhost:9001/",
      assets: ['bower_components', 'styles', 'scripts', 'images'],
      linksSelector: '[ng-href]:not(.dropdown-toggle)',
      linksVersions: '.version-switcher a',
      rootDocument: 'html',
      startDocument: '',
      endDocument: ''
    });
    var util = require("./lib/util.js");
    var termsToBaseURLReplace = ['src="', 'href="', "src=", "href="];
    var urlToFielName = util.urlToFielName;
    var getPageLinks = util.getPageLinks;
    var inQuotes = util.inQuotes;
    var mapFile = grunt.file.readJSON(options.mapFile);
    var versionsLink = util.versionLinks(mapFile);
    var phantom = require('phantom');
    var pages = [];
    var links = [];
    var crawled = {};
    var fs = require('fs');
    var moveAssets = function(srcpath) {
      if (grunt.file.isDir(srcpath)) {
        var files = grunt.file.expand(srcpath + "/*");
        files.forEach(moveAssets);
      } else {
        grunt.file.copy(srcpath, options.generatePath + srcpath)
      }
    };
    var clearFolder = function(srcpath) {
      if (grunt.file.isDir(srcpath)) {
        var files = grunt.file.expand(srcpath + "/*");
        files.forEach(clearFolder);
      } else {
        grunt.file.delete(srcpath);
      }
    };
    var prepareAssets = function() {
      options.assets.forEach(function(srcpath) {
        grunt.log.writeln("Moving:", srcpath);
        moveAssets(srcpath);
      });
    }
    var checkQueueProcess = function(page, ph) {
      page.close();
      pages.shift();
      if (pages.length === 0) {
        prepareAssets();
        setTimeout(function() {
          ph.exit();
          done();
        }, 0);
      }
    };
    var replaceBaseUrl = function(documentContent) {
      var result = documentContent;
      termsToBaseURLReplace.forEach(function(term) {
        result = result.replace(new RegExp(term + '/', 'g'), term + options.baseUrl);
      });
      return result;
    }
    var replaceLink = function(documentContent, from, to) {
      documentContent = documentContent.replace(new RegExp(inQuotes(from), 'g'), to);
      documentContent = documentContent.replace(new RegExp(from + "\#", 'g'), to + "#");
      return documentContent;
    };
    var replacePageLinks = function(documentContent) {
      versionsLink.forEach(function(version) {
        documentContent = replaceLink(documentContent, version.link, urlToFielName(version.realLink));
        documentContent = replaceLink(documentContent, urlToFielName(version.link), urlToFielName(version.realLink));
      });
      links.forEach(function(link) {
        var url = urlToFielName(link);
        documentContent = replaceLink(documentContent, link, url);
        documentContent = documentContent.replace(new RegExp(options.urlToAccess, 'g'), "");
      });
      return documentContent;
    };
    var makeCrawler = function(findLinks, once) {
      return function(currentLinks) {
        currentLinks.forEach(function(link) {
          if (!once || !crawled[link]) {
            if (once) {
              crawled[link] = true;
            }
            links.push(link);
            crawlPage(options.urlToAccess + link, findLinks);
          }
        });
      };
    };
    var crawlPage = function(url, findLinks) {
      pages.push(url);
      phantom.create(function(ph) {
        ph.createPage(function(page) {
          page.open(url, function() {
            util.waitFor({
              debug: true,
              interval: 100,
              timeout: 1000,
              checkLoadedSelector: options.checkLoadedSelector,
              check: function(check) {
                return !!document.querySelector(check);
              },
              success: function() {

                if (findLinks) {
                  getPageLinks(page, options.linksSelector, makeCrawler(false, false));
                  getPageLinks(page, options.linksVersions, makeCrawler(true, true));
                };
                page.evaluate(function(rootDocument) {
                  return document.querySelector(rootDocument).innerHTML;
                }, function(documentContent) {
                  documentContent = replaceBaseUrl(replacePageLinks(documentContent));
                  grunt.file.write(options.generatePath + urlToFielName(url), options.startDocument + documentContent + options.endDocument, 'w');
                  grunt.log.writeln("Generating:", options.generatePath + urlToFielName(url));
                  checkQueueProcess(page, ph);
                }, options.rootDocument);
              },
              error: function() {
                  grunt.log.writeln("Erro generating page:", options.generatePath + urlToFielName(url));
                } // optional
            }, page);
          });
        });
      });
    };
    clearFolder(options.generatePath);
    crawlPage(options.urlToAccess, true);
  });

};<commit_msg>Debug false<commit_after>/*
 * grunt-docbase
 * https://github.com/mateus/DocbaseGrunt
 *
 * Copyright (c) 2015 Mateus Freira
 * Licensed under the MIT license.
 */

'use strict';

module.exports = function(grunt) {

  // Please see the Grunt documentation for more information regarding task
  // creation: http://gruntjs.com/creating-tasks

  grunt.registerMultiTask('docbase', 'Grunt plugin to generate html files from your docbase project.', function() {
    var done = this.async();
    var options = this.options({
      generatePath: 'html/',
      mapFile: 'map.json',
      baseUrl: '',
      checkLoadedSelector: "[role='flatdoc-menu']",
      urlToAccess: "http://localhost:9001/",
      assets: ['bower_components', 'styles', 'scripts', 'images'],
      linksSelector: '[ng-href]:not(.dropdown-toggle)',
      linksVersions: '.version-switcher a',
      rootDocument: 'html',
      startDocument: '',
      endDocument: ''
    });
    var util = require("./lib/util.js");
    var termsToBaseURLReplace = ['src="', 'href="', "src=", "href="];
    var urlToFielName = util.urlToFielName;
    var getPageLinks = util.getPageLinks;
    var inQuotes = util.inQuotes;
    var mapFile = grunt.file.readJSON(options.mapFile);
    var versionsLink = util.versionLinks(mapFile);
    var phantom = require('phantom');
    var pages = [];
    var links = [];
    var crawled = {};
    var fs = require('fs');
    var moveAssets = function(srcpath) {
      if (grunt.file.isDir(srcpath)) {
        var files = grunt.file.expand(srcpath + "/*");
        files.forEach(moveAssets);
      } else {
        grunt.file.copy(srcpath, options.generatePath + srcpath)
      }
    };
    var clearFolder = function(srcpath) {
      if (grunt.file.isDir(srcpath)) {
        var files = grunt.file.expand(srcpath + "/*");
        files.forEach(clearFolder);
      } else {
        grunt.file.delete(srcpath);
      }
    };
    var prepareAssets = function() {
      options.assets.forEach(function(srcpath) {
        grunt.log.writeln("Moving:", srcpath);
        moveAssets(srcpath);
      });
    }
    var checkQueueProcess = function(page, ph) {
      page.close();
      pages.shift();
      if (pages.length === 0) {
        prepareAssets();
        setTimeout(function() {
          ph.exit();
          done();
        }, 0);
      }
    };
    var replaceBaseUrl = function(documentContent) {
      var result = documentContent;
      termsToBaseURLReplace.forEach(function(term) {
        result = result.replace(new RegExp(term + '/', 'g'), term + options.baseUrl);
      });
      return result;
    }
    var replaceLink = function(documentContent, from, to) {
      documentContent = documentContent.replace(new RegExp(inQuotes(from), 'g'), to);
      documentContent = documentContent.replace(new RegExp(from + "\#", 'g'), to + "#");
      return documentContent;
    };
    var replacePageLinks = function(documentContent) {
      versionsLink.forEach(function(version) {
        documentContent = replaceLink(documentContent, version.link, urlToFielName(version.realLink));
        documentContent = replaceLink(documentContent, urlToFielName(version.link), urlToFielName(version.realLink));
      });
      links.forEach(function(link) {
        var url = urlToFielName(link);
        documentContent = replaceLink(documentContent, link, url);
        documentContent = documentContent.replace(new RegExp(options.urlToAccess, 'g'), "");
      });
      return documentContent;
    };
    var makeCrawler = function(findLinks, once) {
      return function(currentLinks) {
        currentLinks.forEach(function(link) {
          if (!once || !crawled[link]) {
            if (once) {
              crawled[link] = true;
            }
            links.push(link);
            crawlPage(options.urlToAccess + link, findLinks);
          }
        });
      };
    };
    var crawlPage = function(url, findLinks) {
      pages.push(url);
      phantom.create(function(ph) {
        ph.createPage(function(page) {
          page.open(url, function() {
            util.waitFor({
              debug: false,
              interval: 100,
              timeout: 1000,
              checkLoadedSelector: options.checkLoadedSelector,
              check: function(check) {
                return !!document.querySelector(check);
              },
              success: function() {
                if (findLinks) {
                  getPageLinks(page, options.linksSelector, makeCrawler(false, false));
                  getPageLinks(page, options.linksVersions, makeCrawler(true, true));
                };
                page.evaluate(function(rootDocument) {
                  return document.querySelector(rootDocument).innerHTML;
                }, function(documentContent) {
                  documentContent = replaceBaseUrl(replacePageLinks(documentContent));
                  grunt.file.write(options.generatePath + urlToFielName(url), options.startDocument + documentContent + options.endDocument, 'w');
                  grunt.log.writeln("Generating:", options.generatePath + urlToFielName(url));
                  checkQueueProcess(page, ph);
                }, options.rootDocument);
              },
              error: function() {
                  grunt.log.writeln("Erro generating page:", options.generatePath + urlToFielName(url));
                } // optional
            }, page);
          });
        });
      });
    };
    clearFolder(options.generatePath);
    crawlPage(options.urlToAccess, true);
  });

};<|endoftext|>


<commit_before>'use strict';

var Promise = require('pinkie-promise');
var objectAssign = require('object-assign');
var openUrl = require('openurl').open;
var blessed = require('blessed');
var spinner = require('./spinner');
var Renderer = require('./renderer');
var renderer = new Renderer({
  onTableSelect: onTableSelect
});
var cache = {};
var options = {
  limit: 5,
  fetch: {
    json: true,
    headers: {
      'user-agent': 'https://github.com/rafaelrinaldi/hn-cli'
    }
  }
};
var api = require('./api')(options.fetch);

function limitResults(results, limit) {
  return results.slice(0, limit || 30);
}

function fetchTopStories() {
  spinner.start('Fetching top stories');
  return api.fetch(api.stories());
}

function parseTopStories(stories) {
  spinner.start('Loading top stories details');

  return Promise.all(
      stories.map(function(id) {
        return fetchStory(id);
      })
    );
}

function fetchStory(id) {
  return api.fetch(api.story(id));
}

function refresh() {
  return fetchTopStories()
    .then(function(response) {
      return limitResults(response.body, options.limit);
    })
    .then(function(response) {
      return parseTopStories(response);
    })
    .then(function(response) {
      return response.map(function(item) {
        return item.body;
      })
    })
    .then(function(response) {
      // Store data to the cache
      cache = objectAssign(cache, response);

      spinner.stop();

      return [[
        'Title',
        'Score',
        'Comments',
        'Author'
      ]].concat(
        response.map(function(item) {
          return [
            String(item.title),
            String(item.score),
            String(item.descendants),
            String(item.by)
          ];
        })
      );
    });
}

function onTableSelect(index) {
  var selected = cache[index - 1];
  openUrl(selected.url);
}

function render(data) {
  renderer.render(data);
}

refresh().then(render);
<commit_msg>refactor(readability): better naming<commit_after>'use strict';

var Promise = require('pinkie-promise');
var objectAssign = require('object-assign');
var openUrl = require('openurl').open;
var blessed = require('blessed');
var spinner = require('./spinner');
var Renderer = require('./renderer');
var renderer = new Renderer({
  onTableSelect: onTableSelect
});
var cache = {};
var options = {
  limit: 5,
  fetch: {
    json: true,
    headers: {
      'user-agent': 'https://github.com/rafaelrinaldi/hn-cli'
    }
  }
};
var api = require('./api')(options.fetch);

function limitResults(results, limit) {
  return results.slice(0, limit || 30);
}

function fetchTopStories() {
  spinner.start('Fetching top stories');
  return api.fetch(api.stories());
}

function fetchTopStoriesDetails(stories) {
  spinner.start('Loading top stories details');

  return Promise.all(
      stories.map(function(id) {
        return api.fetch(api.story(id));
      })
    );
}

function refresh() {
  return fetchTopStories()
    // Limit results before requests are fired
    .then(function(response) {
      return limitResults(response.body, options.limit);
    })
    // Fires all requests to top stories
    .then(function(response) {
      return fetchTopStoriesDetails(response);
    })
    // Returns a formatted array with the request response
    .then(function(response) {
      return response.map(function(item) {
        return item.body;
      })
    })
    .then(function(response) {
      // Finally loaded
      spinner.stop();

      // Store data to the cache so it can be used later
      return cache = response;
    })
    // Format the result to a data format compatible with the table widget
    .then(function(response) {
      return [[
        'Title',
        'Score',
        'Comments',
        'Author'
      ]].concat(
        response.map(function(item) {
          return [
            String(item.title),
            String(item.score),
            String(item.descendants),
            String(item.by)
          ];
        })
      );
    });
}

function onTableSelect(index) {
  var selected = cache[index - 1];
  openUrl(selected.url);
}

function render(data) {
  renderer.render(data);
}

refresh().then(render);
<|endoftext|>


<commit_before>import React from 'react';
import throttle from 'lodash.throttle';
import raf from 'raf';

const DEFAULT_BUFFER = 150;

export function createHorizontalStrength(_buffer) {
  return function defaultHorizontalStrength({ x, w }, point) {
    const buffer = Math.min(w / 2, _buffer);

    if (point.x >= x && point.x <= x + w) {
      if (point.x < x + buffer) {
        return (point.x - x - buffer) / buffer;
      } else if (point.x > (x + w - buffer)) {
        return -(x + w - point.x - buffer) / buffer;
      }
    }

    return 0;
  };
}

export function createVerticalStrength(_buffer) {
  return function defaultVerticalStrength({ y, h }, point) {
    const buffer = Math.min(h / 2, _buffer);

    if (point.y >= y && point.y <= y + h) {
      if (point.y < y + buffer) {
        return (point.y - y - buffer) / buffer;
      } else if (point.y > (y + h - buffer)) {
        return -(y + h - point.y - buffer) / buffer;
      }
    }

    return 0;
  };
}

export const defaultHorizontalStrength = createHorizontalStrength(DEFAULT_BUFFER);

export const defaultVerticalStrength = createVerticalStrength(DEFAULT_BUFFER);

export default class Scrollzone extends React.Component {

  static propTypes = {
    verticalStrength: React.PropTypes.func,
    horizontalStrength: React.PropTypes.func,
    tag: React.PropTypes.string,
    speed: React.PropTypes.number,
  }

  static defaultProps = {
    verticalStrength: defaultVerticalStrength,
    horizontalStrength: defaultHorizontalStrength,
    speed: 30,
    tag: 'div',
  };

  constructor(props, ctx) {
    super(props, ctx);

    this.scaleX = 0;
    this.scaleY = 0;
    this.frame = null;
    this.attached = false;
  }

  componentWillUnmount() {
    if (this.frame) raf.cancel(this.frame);
    this.detach();
  }

  attach() {
    window.document.body.addEventListener('dragover', this.updateScrolling);
    window.document.body.addEventListener('dragend', this.stopScrolling);
    window.document.body.addEventListener('drop', this.stopScrolling);
    this.attached = true;
  }

  detach() {
    window.document.body.removeEventListener('dragover', this.updateScrolling);
    window.document.body.removeEventListener('dragend', this.stopScrolling);
    window.document.body.removeEventListener('drop', this.stopScrolling);
    this.attached = false;
  }

  // we don't care about the body's dragover events until this
  // component gets dragged over for the first time
  handleDragOver = (evt) => {
    // give users a chance to preventDefault
    if (typeof this.props.onDragOver === 'function') this.props.onDragOver(evt);

    if (!this.attached) {
      this.attach();
      this.updateScrolling(evt);
    }
  }

  // Update scaleX and scaleY every 100ms or so
  // and start scrolling if necessary
  updateScrolling = throttle(evt => {
    const { container } = this.refs;
    const { left: x, top: y, width: w, height: h } = container.getBoundingClientRect();
    const box = { x, y, w, h };
    const coords = { x: evt.clientX, y: evt.clientY };

    // calculate strength
    this.scaleX = this.props.horizontalStrength(box, coords);
    this.scaleY = this.props.verticalStrength(box, coords);

    // start scrolling if we need to
    if (!this.frame && (this.scaleX || this.scaleY)) this.startScrolling();
  }, 100, { trailing: false })

  startScrolling() {
    const { speed } = this.props;
    const { container } = this.refs;

    let i = 0;
    const tick = () => {
      const { scaleX, scaleY } = this;
      if (scaleX || scaleY) {
        // there's a bug in safari where it seems like we can't get
        // dragover events from a container that also emits a scroll
        // event that same frame. So we double the speed and only adjust
        // the scroll position at 30fps
        if (i++ % 2) {
          if (scaleX) container.scrollLeft += Math.floor(scaleX * speed);
          if (scaleY) container.scrollTop += Math.floor(scaleY * speed);
        }
        this.frame = raf(tick);
      } else {
        this.stopScrolling();
      }
    };

    tick();
  }

  stopScrolling = () => {
    if (this.frame) {
      this.detach();
      raf.cancel(this.frame);
      this.frame = null;
      this.scaleX = 0;
      this.scaleY = 0;
    }
  }

  render() {
    const { tag: Tag, speed, className, ...props } = this.props;
    const compClass = className ? `${className} scrollzone` : 'scrollzone';

    return (
      <Tag
        {...props}
        className={compClass}
        onDragOver={this.handleDragOver}
        ref="container"
      />
    );
  }
}
<commit_msg>Stop passing down invalid props to tag<commit_after>import React from 'react';
import throttle from 'lodash.throttle';
import raf from 'raf';

const DEFAULT_BUFFER = 150;

export function createHorizontalStrength(_buffer) {
  return function defaultHorizontalStrength({ x, w }, point) {
    const buffer = Math.min(w / 2, _buffer);

    if (point.x >= x && point.x <= x + w) {
      if (point.x < x + buffer) {
        return (point.x - x - buffer) / buffer;
      } else if (point.x > (x + w - buffer)) {
        return -(x + w - point.x - buffer) / buffer;
      }
    }

    return 0;
  };
}

export function createVerticalStrength(_buffer) {
  return function defaultVerticalStrength({ y, h }, point) {
    const buffer = Math.min(h / 2, _buffer);

    if (point.y >= y && point.y <= y + h) {
      if (point.y < y + buffer) {
        return (point.y - y - buffer) / buffer;
      } else if (point.y > (y + h - buffer)) {
        return -(y + h - point.y - buffer) / buffer;
      }
    }

    return 0;
  };
}

export const defaultHorizontalStrength = createHorizontalStrength(DEFAULT_BUFFER);

export const defaultVerticalStrength = createVerticalStrength(DEFAULT_BUFFER);

export default class Scrollzone extends React.Component {

  static propTypes = {
    verticalStrength: React.PropTypes.func,
    horizontalStrength: React.PropTypes.func,
    tag: React.PropTypes.string,
    speed: React.PropTypes.number,
  }

  static defaultProps = {
    verticalStrength: defaultVerticalStrength,
    horizontalStrength: defaultHorizontalStrength,
    speed: 30,
    tag: 'div',
  };

  constructor(props, ctx) {
    super(props, ctx);

    this.scaleX = 0;
    this.scaleY = 0;
    this.frame = null;
    this.attached = false;
  }

  componentWillUnmount() {
    if (this.frame) raf.cancel(this.frame);
    this.detach();
  }

  attach() {
    window.document.body.addEventListener('dragover', this.updateScrolling);
    window.document.body.addEventListener('dragend', this.stopScrolling);
    window.document.body.addEventListener('drop', this.stopScrolling);
    this.attached = true;
  }

  detach() {
    window.document.body.removeEventListener('dragover', this.updateScrolling);
    window.document.body.removeEventListener('dragend', this.stopScrolling);
    window.document.body.removeEventListener('drop', this.stopScrolling);
    this.attached = false;
  }

  // we don't care about the body's dragover events until this
  // component gets dragged over for the first time
  handleDragOver = (evt) => {
    // give users a chance to preventDefault
    if (typeof this.props.onDragOver === 'function') this.props.onDragOver(evt);

    if (!this.attached) {
      this.attach();
      this.updateScrolling(evt);
    }
  }

  // Update scaleX and scaleY every 100ms or so
  // and start scrolling if necessary
  updateScrolling = throttle(evt => {
    const { container } = this.refs;
    const { left: x, top: y, width: w, height: h } = container.getBoundingClientRect();
    const box = { x, y, w, h };
    const coords = { x: evt.clientX, y: evt.clientY };

    // calculate strength
    this.scaleX = this.props.horizontalStrength(box, coords);
    this.scaleY = this.props.verticalStrength(box, coords);

    // start scrolling if we need to
    if (!this.frame && (this.scaleX || this.scaleY)) this.startScrolling();
  }, 100, { trailing: false })

  startScrolling() {
    const { speed } = this.props;
    const { container } = this.refs;

    let i = 0;
    const tick = () => {
      const { scaleX, scaleY } = this;
      if (scaleX || scaleY) {
        // there's a bug in safari where it seems like we can't get
        // dragover events from a container that also emits a scroll
        // event that same frame. So we double the speed and only adjust
        // the scroll position at 30fps
        if (i++ % 2) {
          if (scaleX) container.scrollLeft += Math.floor(scaleX * speed);
          if (scaleY) container.scrollTop += Math.floor(scaleY * speed);
        }
        this.frame = raf(tick);
      } else {
        this.stopScrolling();
      }
    };

    tick();
  }

  stopScrolling = () => {
    if (this.frame) {
      this.detach();
      raf.cancel(this.frame);
      this.frame = null;
      this.scaleX = 0;
      this.scaleY = 0;
    }
  }

  render() {
    const {
      // not passing down these props
      tag: Tag,
      speed,
      verticalStrength,
      horizontalStrength,

      className,
      ...props,
    } = this.props;
    const compClass = className ? `${className} scrollzone` : 'scrollzone';

    return (
      <Tag
        {...props}
        className={compClass}
        onDragOver={this.handleDragOver}
        ref="container"
      />
    );
  }
}
<|endoftext|>


<commit_before>$(function(){
	$('table.statistics-confusion').each(function(){
		var tableNode=$(this);
		tableNode.children('caption').append(
			$("<button type='button' class='swap-rc'>↻</button>")
		).append(
			$("<button type='button' class='swap-c'>↔</button>").click(function(){
				tableNode.find('tr').each(function(){
					var cell1Node=$(this).children().eq(1);
					var cell2Node=$(this).children().eq(2);
					cell1Node.before(cell2Node);
				});
			})
		).append(
			$("<button type='button' class='swap-r'>↕</button>").click(function(){
				var row1Node=tableNode.find('tr').eq(1);
				var row2Node=tableNode.find('tr').eq(2);
				row1Node.before(row2Node);
			})
		);
	});
});
<commit_msg>orientation swap<commit_after>$(function(){
	$('table.statistics-confusion').each(function(){
		var tableNode=$(this);
		var tbodyNode=tableNode.children('tbody');
		tableNode.children('caption').append(
			$("<button type='button' class='swap-rc'>↻</button>").click(function(){
				var n=tbodyNode.children().length;
				for (var i=0;i<n;i++) {
					for (var j=0;j<i;j++) {
						var c1=tbodyNode.children().eq(i).children().eq(j);
						var c2=tbodyNode.children().eq(j).children().eq(i);
						var c2p=c2.prev();
						c1.after(c2);
						c2p.after(c1);
					}
				}
			})
		).append(
			$("<button type='button' class='swap-c'>↔</button>").click(function(){
				tbodyNode.children().each(function(){
					var c1=$(this).children().eq(1);
					var c2=$(this).children().eq(2);
					c1.before(c2);
				});
			})
		).append(
			$("<button type='button' class='swap-r'>↕</button>").click(function(){
				var r1=tbodyNode.children().eq(1);
				var r2=tbodyNode.children().eq(2);
				r1.before(r2);
			})
		);
	});
});
<|endoftext|>


<commit_before>/**
 * Copyright 2014-2015 Francesco Camarlinghi
 *
 * 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.
 */

module.exports = function (grunt)
{
    'use strict';
    var path = require('path');
    var _ = require('lodash');
    var cep = require('../lib/cep.js')(grunt);

    /**
     * Creates a CSXS manifest file from template.
     */
    var manifest = function (callback, build)
    {
        var bundle = build.bundle;

        // Validate manifest
        grunt.verbose.or.write('Generating bundle manifest...');

        if (!bundle.manifest)
        {
            grunt.verbose.or.error();
            grunt.fatal('No bundle manifest file specified.');
        }
        else if (!grunt.file.exists(bundle.manifest))
        {
            grunt.verbose.or.error();
            grunt.fatal('Unable to read bundle manifest file template at ' + bundle.manifest.cyan + '.');
        }

        // Generate manifest data for each extension
        var extension_list_manifest = [],
            extensions_manifest = [];

        build.extensions.forEach(function (extension)
        {
            //<CEFCommandLine>
            var cef_params = [];
            extension.cef_params.forEach(function(cef_param)
            {
                cef_params.push('<Parameter>'+ cef_param +'</Parameter>')
            });
            extension.cef_params = cef_params.join('\n\t\t\t\t\t');

            var data = _.extend({}, { 'extension': extension, 'build': build, });

            // <ExtensionList>
            extension_list_manifest.push(grunt.template.process('<Extension Id="<%= extension.id %>" Version="<%= extension.version %>" />', { data: data }));

            // <Extensions>
            if (!extension.manifest)
            {
                grunt.verbose.or.error();
                grunt.fatal('No extension manifest file specified for ' + extension.id + '.');
            }
            else if (!grunt.file.exists(extension.manifest))
            {
                grunt.verbose.or.error();
                grunt.fatal('Unable to read extension manifest file template at ' + extension.manifest.cyan + ' for ' + extension.id + '.');
            }

            extensions_manifest.push(grunt.template.process(grunt.file.read(extension.manifest), { data: data }));
        });

        // Generate bundle manifest
        // <Host> list
        var list_hosts = [],
            products = build.products,
            families = build.families;

        if (products)
        {
            for (var i = 0, n = products.length; i < n; i++)
            {
                var host = cep.hosts.getProduct(products[i]);
                var range = cep.hosts.getVersionRange(products[i], families);

                for (var j = 0; j < host.ids.length; j++)
                {
                    list_hosts.push('<Host Name="' + host.ids[j] + '" Version="[' + range.min + ',' + range.max + ']" />');
                }
            }
        }

        // Templating
        var dest = path.join(build.staging, '/CSXS/manifest.xml');

        var data = _.extend({},
            {
                'bundle': bundle,
                'extension_list': extension_list_manifest.join('\n\t\t\t'),
                'extensions': extensions_manifest.join('\n\t\t\t'),
                'hosts': list_hosts.join('\n\t\t\t'),
            });

        var processed = grunt.template.process(grunt.file.read(bundle.manifest), { data: data });
        grunt.file.write(dest, processed);

        grunt.verbose.or.ok();
        callback();
    };

    /**
     * Populates extension MXI file template.
     */
    var mxi = function (callback, options)
    {
        var builds = options.builds,
            product_versions = {},
            data = {
                files: [],
                products: []
            },
            mxi_filename = options.bundle.basename + '.mxi';

        grunt.log.write('Generating ' + mxi_filename.cyan + ' file from template...');

        function get_version_range(product, families)
        {
            var range = cep.hosts.getVersionRange(product, families);

            // Store version range
            if (!product_versions.hasOwnProperty(product))
                product_versions[product] = {};

            // If current range values are higher or lower than
            // the stored ones, save them
            if (!product_versions[product].min || parseFloat(range.min) < parseFloat(product_versions[product].min))
                product_versions[product].min = range.min;

            if (!product_versions[product].max || parseFloat(range.max) > parseFloat(product_versions[product].max))
                product_versions[product].max = range.max;

            return range;
        };

        // Create <files> list
        for (var i = 0, n = builds.length; i < n; i++)
        {
            // Parse CC products
            builds[i].products.forEach(function (product)
            {
                var version_range = get_version_range(product, builds[i].families);
                data.files.push('<file destination="" file-type="CSXS" products="' + cep.hosts.get_cc_family_name(cep.hosts.getProduct(product).familyname) + '" maxVersion="' + version_range.max + '" minVersion="' + version_range.min + '" source="' + path.basename(builds[i].output_file) + '" />');
            });
        }

        // Create <product> list
        for (var product in product_versions)
        {
            data.products.push('<product familyname="' + cep.hosts.getProduct(product).familyname + '" maxversion="' + product_versions[product].max + '" primary="true" version="' + product_versions[product].min + '" />');
        }

        // Fill in .mxi template
        data.files = data.files.join('\n\t\t');
        data.products = data.products.join('\n\t\t');
        data = _.merge(_.extend({}, data), options);

        // Setup 'update.xml', if needed
        if (options['package'].update.enabled)
            data.bundle.update_url += 'update.xml';

        // Process template
        var processed = grunt.template.process(grunt.file.read(options['package'].mxi), { data: data });
        grunt.file.write(path.resolve(options.staging, mxi_filename), processed);

        grunt.log.ok();
        callback();
    };

    /**
     * Populates extension "update.xml" file template.
     */
    var update = function (callback, options)
    {
        grunt.log.write('Generating ' + 'update.xml'.cyan + ' file...');

        var changes_path = path.join(options['package'].update.changelog_folder, options.bundle.version + options['package'].update.changelog_extension),
            description;

        if (grunt.file.exists(changes_path))
        {
            // Parse changelog txt and generate description in update.xml file
            description = '
';
            description += '
' + path.basename(changes_path, '.txt') + '
';
            description += '
' + grunt.file.read(changes_path).replace(/\r?\n/g, '
') + '
';
            description += '
';
        }

        // Put templating data together
        var update_data = _.extend({}, options, {
            'download_url': options.bundle.update_url + options.bundle.name.replace(/[\s]+/g, '_').toLowerCase() + '_' + options.bundle.version + '.zxp',
            'update_description': description,
        });

        // Process template and save result
        var processed = grunt.template.process(grunt.file.read(options['package'].update.file), { data: update_data });
        grunt.file.write(path.join(options.staging, '../', 'update.xml'), processed);
        grunt.log.ok();

        callback();
    };

    // Public interface
    var xml = {};
    xml.manifest = manifest;
    xml.mxi = mxi;
    xml.update = update;
    return xml;
};
<commit_msg>Added fix for "familyname" products<commit_after>/**
 * Copyright 2014-2015 Francesco Camarlinghi
 *
 * 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.
 */

module.exports = function (grunt)
{
    'use strict';
    var path = require('path');
    var _ = require('lodash');
    var cep = require('../lib/cep.js')(grunt);

    /**
     * Creates a CSXS manifest file from template.
     */
    var manifest = function (callback, build)
    {
        var bundle = build.bundle;

        // Validate manifest
        grunt.verbose.or.write('Generating bundle manifest...');

        if (!bundle.manifest)
        {
            grunt.verbose.or.error();
            grunt.fatal('No bundle manifest file specified.');
        }
        else if (!grunt.file.exists(bundle.manifest))
        {
            grunt.verbose.or.error();
            grunt.fatal('Unable to read bundle manifest file template at ' + bundle.manifest.cyan + '.');
        }

        // Generate manifest data for each extension
        var extension_list_manifest = [],
            extensions_manifest = [];

        build.extensions.forEach(function (extension)
        {
            //<CEFCommandLine>
            var cef_params = [];
            extension.cef_params.forEach(function(cef_param)
            {
                cef_params.push('<Parameter>'+ cef_param +'</Parameter>')
            });
            extension.cef_params = cef_params.join('\n\t\t\t\t\t');

            var data = _.extend({}, { 'extension': extension, 'build': build, });

            // <ExtensionList>
            extension_list_manifest.push(grunt.template.process('<Extension Id="<%= extension.id %>" Version="<%= extension.version %>" />', { data: data }));

            // <Extensions>
            if (!extension.manifest)
            {
                grunt.verbose.or.error();
                grunt.fatal('No extension manifest file specified for ' + extension.id + '.');
            }
            else if (!grunt.file.exists(extension.manifest))
            {
                grunt.verbose.or.error();
                grunt.fatal('Unable to read extension manifest file template at ' + extension.manifest.cyan + ' for ' + extension.id + '.');
            }

            extensions_manifest.push(grunt.template.process(grunt.file.read(extension.manifest), { data: data }));
        });

        // Generate bundle manifest
        // <Host> list
        var list_hosts = [],
            products = build.products,
            families = build.families;

        if (products)
        {
            for (var i = 0, n = products.length; i < n; i++)
            {
                var host = cep.hosts.getProduct(products[i]);
                var range = cep.hosts.getVersionRange(products[i], families);

                for (var j = 0; j < host.ids.length; j++)
                {
                    list_hosts.push('<Host Name="' + host.ids[j] + '" Version="[' + range.min + ',' + range.max + ']" />');
                }
            }
        }

        // Templating
        var dest = path.join(build.staging, '/CSXS/manifest.xml');

        var data = _.extend({},
            {
                'bundle': bundle,
                'extension_list': extension_list_manifest.join('\n\t\t\t'),
                'extensions': extensions_manifest.join('\n\t\t\t'),
                'hosts': list_hosts.join('\n\t\t\t'),
            });

        var processed = grunt.template.process(grunt.file.read(bundle.manifest), { data: data });
        grunt.file.write(dest, processed);

        grunt.verbose.or.ok();
        callback();
    };

    /**
     * Populates extension MXI file template.
     */
    var mxi = function (callback, options)
    {
        var builds = options.builds,
            product_versions = {},
            data = {
                files: [],
                products: []
            },
            mxi_filename = options.bundle.basename + '.mxi';

        grunt.log.write('Generating ' + mxi_filename.cyan + ' file from template...');

        function get_version_range(product, families)
        {
            var range = cep.hosts.getVersionRange(product, families);

            // Store version range
            if (!product_versions.hasOwnProperty(product))
                product_versions[product] = {};

            // If current range values are higher or lower than
            // the stored ones, save them
            if (!product_versions[product].min || parseFloat(range.min) < parseFloat(product_versions[product].min))
                product_versions[product].min = range.min;

            if (!product_versions[product].max || parseFloat(range.max) > parseFloat(product_versions[product].max))
                product_versions[product].max = range.max;

            return range;
        };

        // Create <files> list
        for (var i = 0, n = builds.length; i < n; i++)
        {
            // Parse CC products
            builds[i].products.forEach(function (product)
            {
                var version_range = get_version_range(product, builds[i].families);
                data.files.push('<file destination="" file-type="CSXS" products="' + cep.hosts.get_cc_family_name(cep.hosts.getProduct(product).familyname) + '" maxVersion="' + version_range.max + '" minVersion="' + version_range.min + '" source="' + path.basename(builds[i].output_file) + '" />');
            });
        }

        // Create <product> list
        // NOTE: only some products supports the "familyname" attribute so we should filter them out
        // (see https://helpx.adobe.com/extension-manager/kb/general-mxi-elements.html#id_64891)
        var familyname_products = ['illustrator', 'photoshop', 'incopy', 'indesign'];

        for (var product in product_versions)
        {
            if (familyname_products.indexOf(familyname_products))
            {
                data.products.push('<product familyname="' + cep.hosts.getProduct(product).familyname + '" maxversion="' + product_versions[product].max + '" primary="true" version="' + product_versions[product].min + '" />');
            }
            else
            {
                data.products.push('<product name="' + cep.hosts.getProduct(product).name + '" maxversion="' + product_versions[product].max + '" primary="true" version="' + product_versions[product].min + '" />');
            }
        }

        // Fill in .mxi template
        data.files = data.files.join('\n\t\t');
        data.products = data.products.join('\n\t\t');
        data = _.merge(_.extend({}, data), options);

        // Setup 'update.xml', if needed
        if (options['package'].update.enabled)
            data.bundle.update_url += 'update.xml';

        // Process template
        var processed = grunt.template.process(grunt.file.read(options['package'].mxi), { data: data });
        grunt.file.write(path.resolve(options.staging, mxi_filename), processed);

        grunt.log.ok();
        callback();
    };

    /**
     * Populates extension "update.xml" file template.
     */
    var update = function (callback, options)
    {
        grunt.log.write('Generating ' + 'update.xml'.cyan + ' file...');

        var changes_path = path.join(options['package'].update.changelog_folder, options.bundle.version + options['package'].update.changelog_extension),
            description;

        if (grunt.file.exists(changes_path))
        {
            // Parse changelog txt and generate description in update.xml file
            description = '
';
            description += '
' + path.basename(changes_path, '.txt') + '
';
            description += '
' + grunt.file.read(changes_path).replace(/\r?\n/g, '
') + '
';
            description += '
';
        }

        // Put templating data together
        var update_data = _.extend({}, options, {
            'download_url': options.bundle.update_url + options.bundle.name.replace(/[\s]+/g, '_').toLowerCase() + '_' + options.bundle.version + '.zxp',
            'update_description': description,
        });

        // Process template and save result
        var processed = grunt.template.process(grunt.file.read(options['package'].update.file), { data: update_data });
        grunt.file.write(path.join(options.staging, '../', 'update.xml'), processed);
        grunt.log.ok();

        callback();
    };

    // Public interface
    var xml = {};
    xml.manifest = manifest;
    xml.mxi = mxi;
    xml.update = update;
    return xml;
};
<|endoftext|>


<commit_before>#!/usr/bin/env node
const fs = require('fs-promise');
const path = require('path');
const jsdoc2md = require('jsdoc-to-markdown');
const Documentation = require('./documentation');
const config = require('./config');

if(config.verbose) console.log('Running with config: ', config);
const mainPromises = [null, null];

// Parse the JSDocs in all source directories
console.log('Parsing JSDocs in source files...');
const files = [];
for(const dir of config.source) files.push(`${dir}/*.js`, `${dir}/**/*.js`);
mainPromises[0] = jsdoc2md.getTemplateData({ files, configure: config.jsdoc }).then(data => {
	console.log(`${data.length} JSDoc items parsed.`);
	return data;
});

// Load the custom docs
if(config.custom) {
	console.log('Loading custom docs files...');
	const customDir = path.dirname(config.custom);

	// Figure out what type of definitions file we're loading
	let type;
	const defExtension = path.extname(config.custom).toLowerCase();
	if(defExtension === '.json') type = 'json';
	else if(defExtension === '.yml' || defExtension === '.yaml') type = 'yaml';
	else throw new TypeError('Unknown custom docs definition file type.');

	mainPromises[1] = fs.readFile(config.custom, 'utf-8').then(defContent => {
		// Parse the definition file
		let definitions;
		if(type === 'json') definitions = JSON.parse(defContent);
		else definitions = require('js-yaml').safeLoad(defContent);

		const custom = {};
		const filePromises = [];

		for(const cat of definitions) {
			// Add the category to the custom docs
			const catID = cat.id || cat.name.toLowerCase();
			const dir = path.join(customDir, cat.path || catID);
			const category = {
				name: cat.name || cat.id,
				files: {}
			};
			custom[catID] = category;

			// Add every file in the category
			for(const file of cat.files) {
				const fileRootPath = path.join(dir, file.path);
				filePromises.push(fs.readFile(fileRootPath, 'utf-8').then(content => {
					const extension = path.extname(file.path);
					const fileID = file.id || path.basename(file.path, extension);
					category.files[fileID] = {
						name: file.name,
						type: extension.toLowerCase().replace(/^\./, ''),
						content,
						path: path.relative(config.root, fileRootPath).replace(/\\/g, '/')
					};
					if(config.verbose) console.log(`Loaded custom docs file ${catID}/${fileID}`);
				}));
			}
		}

		return Promise.all(filePromises).then(() => {
			const fileCount = Object.keys(custom).map(k => Object.keys(custom[k])).reduce((prev, c) => prev + c.length, 0);
			const categoryCount = Object.keys(custom).length;
			console.log(
				`${fileCount} custom docs file${fileCount !== 1 ? 's' : ''} in ` +
				`${categoryCount} categor${categoryCount !== 1 ? 'ies' : 'y'} loaded.`
			);
			return custom;
		});
	});
}

Promise.all(mainPromises).then(results => {
	const data = results[0];
	const custom = results[1];

	console.log(`Serializing documentation with format version ${Documentation.FORMAT_VERSION}...`);
	const docs = new Documentation(data, custom);
	let output = JSON.stringify(docs.serialize(), null, config.spaces);

	if(config.compress) {
		console.log('Compressing...');
		output = require('zlib').deflateSync(output).toString('utf8');
	}

	if(config.output) {
		console.log(`Writing to ${config.output}...`);
		fs.writeFileSync(config.output, output);
	}

	console.log('Done!');
	process.exit(0);
}).catch(err => {
	console.error(err);
	process.exit(1);
});
<commit_msg>Fix files being out of order based on load order<commit_after>#!/usr/bin/env node
const fs = require('fs-promise');
const path = require('path');
const jsdoc2md = require('jsdoc-to-markdown');
const Documentation = require('./documentation');
const config = require('./config');

if(config.verbose) console.log('Running with config: ', config);
const mainPromises = [null, null];

// Parse the JSDocs in all source directories
console.log('Parsing JSDocs in source files...');
const files = [];
for(const dir of config.source) files.push(`${dir}/*.js`, `${dir}/**/*.js`);
mainPromises[0] = jsdoc2md.getTemplateData({ files, configure: config.jsdoc }).then(data => {
	console.log(`${data.length} JSDoc items parsed.`);
	return data;
});

// Load the custom docs
if(config.custom) {
	console.log('Loading custom docs files...');
	const customDir = path.dirname(config.custom);

	// Figure out what type of definitions file we're loading
	let type;
	const defExtension = path.extname(config.custom).toLowerCase();
	if(defExtension === '.json') type = 'json';
	else if(defExtension === '.yml' || defExtension === '.yaml') type = 'yaml';
	else throw new TypeError('Unknown custom docs definition file type.');

	mainPromises[1] = fs.readFile(config.custom, 'utf-8').then(defContent => {
		// Parse the definition file
		let definitions;
		if(type === 'json') definitions = JSON.parse(defContent);
		else definitions = require('js-yaml').safeLoad(defContent);

		const custom = {};
		const filePromises = [];

		for(const cat of definitions) {
			// Add the category to the custom docs
			const catID = cat.id || cat.name.toLowerCase();
			const dir = path.join(customDir, cat.path || catID);
			const category = {
				name: cat.name || cat.id,
				files: {}
			};
			custom[catID] = category;

			// Add every file in the category
			for(const file of cat.files) {
				const fileRootPath = path.join(dir, file.path);
				const extension = path.extname(file.path);
				const fileID = file.id || path.basename(file.path, extension);
				category.files[fileID] = null;

				filePromises.push(fs.readFile(fileRootPath, 'utf-8').then(content => {
					category.files[fileID] = {
						name: file.name,
						type: extension.toLowerCase().replace(/^\./, ''),
						content,
						path: path.relative(config.root, fileRootPath).replace(/\\/g, '/')
					};
					if(config.verbose) console.log(`Loaded custom docs file ${catID}/${fileID}`);
				}));
			}
		}

		return Promise.all(filePromises).then(() => {
			const fileCount = Object.keys(custom).map(k => Object.keys(custom[k])).reduce((prev, c) => prev + c.length, 0);
			const categoryCount = Object.keys(custom).length;
			console.log(
				`${fileCount} custom docs file${fileCount !== 1 ? 's' : ''} in ` +
				`${categoryCount} categor${categoryCount !== 1 ? 'ies' : 'y'} loaded.`
			);
			return custom;
		});
	});
}

Promise.all(mainPromises).then(results => {
	const data = results[0];
	const custom = results[1];

	console.log(`Serializing documentation with format version ${Documentation.FORMAT_VERSION}...`);
	const docs = new Documentation(data, custom);
	let output = JSON.stringify(docs.serialize(), null, config.spaces);

	if(config.compress) {
		console.log('Compressing...');
		output = require('zlib').deflateSync(output).toString('utf8');
	}

	if(config.output) {
		console.log(`Writing to ${config.output}...`);
		fs.writeFileSync(config.output, output);
	}

	console.log('Done!');
	process.exit(0);
}).catch(err => {
	console.error(err);
	process.exit(1);
});
<|endoftext|>