<commit_before>// js for example page

const isMobile = (function() {
  let check = false;
  (function(a){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4))) check = true;})(navigator.userAgent||navigator.vendor||window.opera);
  return check;
})();

// SIDEBAR
if (isMobile) {
  new Slideout({
    panel: document.getElementById('panel'),
    menu: document.getElementById('sidebar'),
    padding: 320,
    tolerance: 70
  });
}

// Filter

const filter = document.getElementById('filter');
const items = document.querySelectorAll('#sidebar .item .minor');
const categories = document.querySelectorAll('#sidebar .item.category');

filter.addEventListener('keyup', e => {
  items.forEach(item => {
    if (
      item.innerText.indexOf(e.target.value) > -1
      || e.target.value === ''
    ) item.style.display = 'block';
    else item.style.display = 'none';
  });

  categories.forEach(cat => {
    const isHidden = [].slice.call(cat.querySelectorAll('.minor')).every(item => item.style.display === 'none');

    console.log(isHidden);

    if (isHidden) cat.style.display = 'none';
    else cat.style.display = 'block';
  })
});
<commit_msg>Remove log, fix es6 -> es5 (safari)<commit_after>// js for example page

const isMobile = (function() {
  let check = false;
  (function(a){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4))) check = true;})(navigator.userAgent||navigator.vendor||window.opera);
  return check;
})();

// SIDEBAR
if (isMobile) {
  new Slideout({
    panel: document.getElementById('panel'),
    menu: document.getElementById('sidebar'),
    padding: 320,
    tolerance: 70
  });
}

// Filter

const filter = document.getElementById('filter');
const items = document.querySelectorAll('#sidebar .item .minor');
const categories = document.querySelectorAll('#sidebar .item.category');

filter.addEventListener('keyup', function (e) {
  items.forEach(item => {
    if (
      item.innerText.indexOf(e.target.value) > -1
      || e.target.value === ''
    ) item.style.display = 'block';
    else item.style.display = 'none';
  });

  categories.forEach(function (cat) {
    const isHidden = [].slice.call(cat.querySelectorAll('.minor')).every(item => item.style.display === 'none');

    if (isHidden) cat.style.display = 'none';
    else cat.style.display = 'block';
  });
});
<|endoftext|>


<commit_before>const {combine, fromPromise} = require('most');
const io = require('socket.io-client');
const {fromJS, Map, List, is} = require('immutable');
const logger = require('../../common/core/logger');
const {connect} = require('../../common/sockets/cryptoCompare');
const Maybe = require('folktale/data/maybe');
const {getAllPartialInvestments} = require('../../common/data/investmentRepository');
const calculateTotalPortfolioValue = require('../../common/aggregators');
const {getPriceObjFromStreamData} = require('../../common/aggregators/common');
const {getInvestmentValues} = require('../../common/aggregators/investmentValues');

const createInvestmentReportObj = (percentage, investment) => investment.set('current', percentage)

const checkInvestmentLimit = (investment, prices) => {
  // getInvestmentValues expects a Map<InvestmentId, Investement>
  const investmentValue = getInvestmentValues(
    Map({[investment.get('id')]: investment}),
    prices
  );

  const percentage = investmentValue.getIn([investment.get('id'), 'percentage']);
  const lowerLimit = Number(investment.get('lowerLimit'));
  const upperLimit = Number(investment.get('upperLimit'));

  if(percentage <= lowerLimit) {
    return Maybe.Just(createInvestmentReportObj(percentage, investment));
  }
  else if(percentage >= upperLimit) {
    return Maybe.Just(createInvestmentReportObj(percentage, investment));
  }

  return Maybe.Nothing();
};

const checkLimits = ({investments, prices}) => investments.reduce(
  (acc, userInvestments, userId) => {
    const userWarnings = userInvestments.reduce(
      (warnings, investment) =>
        checkInvestmentLimit(investment, prices)
          .matchWith({
            Just: ({value}) => warnings.push(value),
            Nothing: () => warnings
          }),
      List()
    );

    return acc.set(userId, userWarnings)
  },
  Map()
)

const getInvestments = async unwrapCypherResult => {
  const actionResult = await getAllPartialInvestments();

  return unwrapCypherResult(actionResult)
    .matchWith({
      Just: ({value: investments}) => investments,
      Nothing: () => Map()
    });
}

const filterCurrency = (investments, currency, unwrapCypherListNodeResult, send) =>
  investments
    .map(
      i => i
        .update('investments', userInvestments =>
          unwrapCypherListNodeResult(userInvestments)
            .matchWith({
              Just: ({value: unwrapedInvestments}) => unwrapedInvestments.filter(v => v.get('currency') === currency),
              Nothing: () => userInvestments
            })
        )
        .get('investments')
    );
const start = async (currency, unwrapCypherResult, unwrapCypherListNodeResult, getAllPartialInvestments, send) => {
  try{
    const btc$ = connect(io, 'BTC', 'Coinfloor', currency);
    const eth$ = connect(io, 'ETH', 'Kraken', currency);

    const observer = {
      next: send,
      error: errorValue => console.log(`Error in the observer of the investment values stream: ${errorValue}`)
    }

    const getPrices = (investments, btc, eth) => ({
        investments: filterCurrency(investments, currency, unwrapCypherListNodeResult),
        prices: fromJS({
          BTX: getPriceObjFromStreamData(btc),
          ETH: getPriceObjFromStreamData(eth)
        })
      })

    return combine(getPrices, fromPromise(getInvestments(unwrapCypherResult)), btc$, eth$)
      .map(checkLimits)
      .skipRepeatsWith((a, b) => is(a, b))
      .subscribe(observer);
  }
  catch(error) {
    logger.error(error);
  }
}

module.exports = {start};
<commit_msg>remove semicolon<commit_after>const {combine, fromPromise} = require('most');
const io = require('socket.io-client');
const {fromJS, Map, List, is} = require('immutable');
const logger = require('../../common/core/logger');
const {connect} = require('../../common/sockets/cryptoCompare');
const Maybe = require('folktale/data/maybe');
const {getAllPartialInvestments} = require('../../common/data/investmentRepository');
const calculateTotalPortfolioValue = require('../../common/aggregators');
const {getPriceObjFromStreamData} = require('../../common/aggregators/common');
const {getInvestmentValues} = require('../../common/aggregators/investmentValues');

const createInvestmentReportObj = (percentage, investment) => investment.set('current', percentage)

const checkInvestmentLimit = (investment, prices) => {
  // getInvestmentValues expects a Map<InvestmentId, Investement>
  const investmentValue = getInvestmentValues(
    Map({[investment.get('id')]: investment}),
    prices
  );

  const percentage = investmentValue.getIn([investment.get('id'), 'percentage']);
  const lowerLimit = Number(investment.get('lowerLimit'));
  const upperLimit = Number(investment.get('upperLimit'));

  if(percentage <= lowerLimit) {
    return Maybe.Just(createInvestmentReportObj(percentage, investment));
  }
  else if(percentage >= upperLimit) {
    return Maybe.Just(createInvestmentReportObj(percentage, investment));
  }

  return Maybe.Nothing();
};

const checkLimits = ({investments, prices}) => investments.reduce(
  (acc, userInvestments, userId) => {
    const userWarnings = userInvestments.reduce(
      (warnings, investment) =>
        checkInvestmentLimit(investment, prices)
          .matchWith({
            Just: ({value}) => warnings.push(value),
            Nothing: () => warnings
          }),
      List()
    );

    return acc.set(userId, userWarnings)
  },
  Map()
)

const getInvestments = async unwrapCypherResult => {
  const actionResult = await getAllPartialInvestments();

  return unwrapCypherResult(actionResult)
    .matchWith({
      Just: ({value: investments}) => investments,
      Nothing: () => Map()
    });
}

const filterCurrency = (investments, currency, unwrapCypherListNodeResult, send) =>
  investments
    .map(
      i => i
        .update('investments', userInvestments =>
          unwrapCypherListNodeResult(userInvestments)
            .matchWith({
              Just: ({value: unwrapedInvestments}) => unwrapedInvestments.filter(v => v.get('currency') === currency),
              Nothing: () => userInvestments
            })
        )
        .get('investments')
    )

const start = async (currency, unwrapCypherResult, unwrapCypherListNodeResult, getAllPartialInvestments, send) => {
  try{
    const btc$ = connect(io, 'BTC', 'Coinfloor', currency);
    const eth$ = connect(io, 'ETH', 'Kraken', currency);

    const observer = {
      next: send,
      error: errorValue => console.log(`Error in the observer of the investment values stream: ${errorValue}`)
    }

    const getPrices = (investments, btc, eth) => ({
        investments: filterCurrency(investments, currency, unwrapCypherListNodeResult),
        prices: fromJS({
          BTX: getPriceObjFromStreamData(btc),
          ETH: getPriceObjFromStreamData(eth)
        })
      })

    return combine(getPrices, fromPromise(getInvestments(unwrapCypherResult)), btc$, eth$)
      .map(checkLimits)
      .skipRepeatsWith(is)
      .subscribe(observer);
  }
  catch(error) {
    logger.error(error);
  }
}

module.exports = {start};
<|endoftext|>


<commit_before>'use strict';

module.exports = {
  coveragePathIgnorePatterns: ['/node_modules/', '<rootDir>/packages/react-native-web/src/vendor/'],
  modulePathIgnorePatterns: ['<rootDir>/packages/react-native-web/dist/'],
  rootDir: process.cwd(),
  roots: ['<rootDir>/packages'],
  setupFiles: ['jest-canvas-mock'],
  setupTestFrameworkScriptFile: require.resolve('./setupFramework.js'),
  snapshotSerializers: ['enzyme-to-json/serializer'],
  testEnvironment: 'jsdom',
  timers: 'fake'
};
<commit_msg>Add more paths to jest ignore<commit_after>'use strict';

module.exports = {
  coveragePathIgnorePatterns: ['/node_modules/', '<rootDir>/packages/react-native-web/src/vendor/'],
  modulePathIgnorePatterns: [
    '<rootDir>/packages/benchmarks/',
    '<rootDir>/packages/examples/',
    '<rootDir>/packages/react-native-web/dist/',
    '<rootDir>/packages/website/'
  ],
  rootDir: process.cwd(),
  roots: ['<rootDir>/packages'],
  setupFiles: ['jest-canvas-mock'],
  setupTestFrameworkScriptFile: require.resolve('./setupFramework.js'),
  snapshotSerializers: ['enzyme-to-json/serializer'],
  testEnvironment: 'jsdom',
  timers: 'fake'
};
<|endoftext|>


<commit_before>$(document).ready(function(){

    // Resize embedded video on detail page to match container size
    $('div.videoembed-detail').each(function(){
        var el = $(this);
        var iframe = $('iframe', el);
        var wo = iframe.width();
        var ho = iframe.height();
        var w = el.width();
        var h = (ho * w * 1.0) / wo;
        iframe.attr('width', w);
        iframe.attr('height', h);
    });

});
<commit_msg>Resize embedded video in listings<commit_after>$(document).ready(function(){

    // Resize embedded video on detail page to match container size
    $('div.videoembed-detail, div.foundry-listing div.item-videoembed').each(function(){
        var el = $(this);
        var iframe = $('iframe', el);
        var wo = iframe.width();
        var ho = iframe.height();
        var w = el.width();
        var h = (ho * w * 1.0) / wo;
        iframe.attr('width', w);
        iframe.attr('height', h);
    });

});
<|endoftext|>


<commit_before>'use strict';

var express = require('express'),
  router = express.Router();

var db = require('../db.js')();

router.get('/', function(req, res) {
  db.people.find({}, function(err, docs) {
    res.render('admin/people_list', { "people": docs });
  });
});

router.get('/delete/:id', function (req, res) {
  let personId = req.params.id;
  db.people.remove({ "_id": personId }, {}, function (error) {
    res.redirect('/people');
  })
});

router.get('/form', function (req, res) {
  res.render('admin/people');
});

module.exports = router;
<commit_msg>added db persistence and remvoed image file<commit_after>'use strict';

var express = require('express'),
  router = express.Router();

var path = require('path');
var db = require('../db.js')();
var fs = require('fs');

router.get('/', function (req, res) {
  db.people.find({}, function (err, docs) {
    res.render('admin/people_list', { "people": docs });
  });
});

router.get('/delete/:id', function (req, res) {
  let personId = req.params.id;
  db.people.findOne({ "_id": personId }, {}, function (error, doc) {

    if (!error) {
      db.people.remove({ "_id": personId }, {}, function (error, numRemoved) {
        if (!error) {
          db.people.persistence.compactDatafile();
          fs.exists(doc.file.path, function (exists) {
            if (exists) {
              fs.unlink(doc.file.path, function (error) {
                let feedback = error ? error : 'image deleted as well';
                console.log(feedback);
              })
            }
          })
        }
      });
    }
  })
  res.redirect('/people');
});

router.get('/form', function (req, res) {
  res.render('admin/people');
});

module.exports = router;
<|endoftext|>


<commit_before>/**
 * destroyedNum: 被踩踏的稻草的总数
 * row: 稻草的总种植行数
 * column: 稻草的总种植列数
 * maxDestroyedNum: 被破坏最多的稻草数目
 */

let destroyedNum = 14, row = 6, column = 7, maxDestroyedNum = 2,

plants = [
  {x: 2, y: 1},
  {x: 6, y: 6},
  {x: 4, y: 2},
  {x: 2, y: 5},
  {x: 2, y: 6},
  {x: 2, y: 7},
  {x: 3, y: 4},
  {x: 6, y: 1},
  {x: 6, y: 2},
  {x: 2, y: 3},
  {x: 6, y: 3},
  {x: 6, y: 4},
  {x: 6, y: 5},
  {x: 6, y: 7}
]

/**
 * 输入的稻草位置进行排序
 */
const dotSort = (plants) => plants.sort((a, b) => {
  if (a.x == b.x) {
    return a.y - b.y
  }
  return a.x - b.x
})

const dotSearch = (plants, plant) => {
  let start = 0,
    end = plants.length - 1

  while (start < end) {
    let middle = Math.floor((start + end)/2)
    if (plants[middle]['x'] == plant.x && plants[middle]['y'] == plant.y) {
      return true
    }
    if (plant.x < plants[middle]['x']) {
      end = middle - 1
    } else if (plant.x > plants[middle]['x']) {
      start = middle + 1
    } else {
      if (plant.y < plants[middle]['y']) {
        end = middle - 1
      } else {
        start = middle + 1
      }
    }
  }
  return false
}

/**
 * 判断从第二点开始，步长为distanceX,distanceY，那么最多能走几步
 */
const serachPath = (secPlant, distanceX, distanceY) => {
  let steps = 2,
  plant = {
    x: undefined,
    y: undefined
  }

  plant.x = secPlant.x + distanceX
  plant.y = secPlant.y + distanceY

  while (plant.x <= row && plant.x >= 1 && plant.y <= column && plant.y >= 1) {
    if (!dotSearch(plants, plant)) {
      steps = 0
      break
    }
    plant.x += distanceX
    plant.y += distanceY
    steps++
  }

  return steps
}

/**
 * 找到踩踏稻草最多的路径，返回踩踏次数
 */
const findMax = () => {

  let steps

  for (let i = 0; i < destroyedNum - 2; i++) {
    for (let j = i + 1; j < destroyedNum; j++) {
      distanceX = plants[j].x - plants[i].x
      distanceY = plants[j].y - plants[j].y
      previousX = plants[i].x - distanceX
      previousY = plants[i].y - distanceY

      /**
       * 第一个点前面一个点在稻田里面
       * 说明本次选的第二点导致的x方向步长不合理（太小）
       * 取下一个点作为第二点
       */
      if (previousX <= row && previousX >= 1 && previousY <= column && previousY >= 1) {
        continue
      }

      /**
       * x方向过早越界了，说明本次选的第二点不成立
       * 如果换下一个点作为第二点，x方向的步长只会更大，更不成立
       * 所以，应该认为本次选取的第一点必然是不成立的，
       * 那么取下一个点作为第一点再试
       */
      if (plants[i].x + (maxDestroyedNum - 1) * distanceX > row) {
        break
      }

      previousY = plants[i].y + (maxDestroyedNum - 1) * distanceY
      /**
       * y 方向过早越界了，应换一个点作为第二点再试
       */
      if (previousY > column || previousY < 1) {
        continue
      }

      steps = serachPath(plants[j], distanceX, distanceY)

      if (steps > maxDestroyedNum) {
        maxDestroyedNum = steps
      }

      if (maxDestroyedNum == 2) {
        maxDestroyedNum = 0
      }
    }
  }
  console.log('maxDestroyedNum', maxDestroyedNum)
}
plants = dotSort(plants)
findMax()<commit_msg>add some code<commit_after>/**
 * destroyedNum: 被踩踏的稻草的总数
 * row: 稻草的总种植行数
 * column: 稻草的总种植列数
 * maxDestroyedNum: 被破坏最多的稻草数目
 */

let destroyedNum = 14, row = 6, column = 7, maxDestroyedNum = 2,

plants = [
  {x: 2, y: 1},
  {x: 6, y: 6},
  {x: 4, y: 2},
  {x: 2, y: 5},
  {x: 2, y: 6},
  {x: 2, y: 7},
  {x: 3, y: 4},
  {x: 6, y: 1},
  {x: 6, y: 2},
  {x: 2, y: 3},
  {x: 6, y: 3},
  {x: 6, y: 4},
  {x: 6, y: 5},
  {x: 6, y: 7}
]

/**
 * 输入的稻草位置进行排序
 */
const dotSort = (plants) => plants.sort((a, b) => {
  if (a.x == b.x) {
    return a.y - b.y
  }
  return a.x - b.x
})

const dotSearch = (plants, plant) => {
  let start = 0,
    end = plants.length - 1

  while (start < end) {
    let middle = Math.floor((start + end)/2)
    if (plants[middle]['x'] == plant.x && plants[middle]['y'] == plant.y) {
      return true
    }
    if (plant.x < plants[middle]['x']) {
      end = middle - 1
    } else if (plant.x > plants[middle]['x']) {
      start = middle + 1
    } else {
      if (plant.y < plants[middle]['y']) {
        end = middle - 1
      } else {
        start = middle + 1
      }
    }
  }
  return false
}

/**
 * 判断从第二点开始，步长为distanceX,distanceY，那么最多能走几步
 */
const serachPath = (secPlant, distanceX, distanceY) => {
  let steps = 2,
  plant = {
    x: undefined,
    y: undefined
  }

  plant.x = secPlant.x + distanceX
  plant.y = secPlant.y + distanceY

  while (plant.x <= row && plant.x >= 1 && plant.y <= column && plant.y >= 1) {
    if (!dotSearch(plants, plant)) {
      steps = 0
      break
    }

    plant.x += distanceX
    plant.y += distanceY
    steps++
  }

  return steps
}

/**
 * 找到踩踏稻草最多的路径，返回踩踏次数
 */
const findMax = () => {

  let steps

  for (let i = 0; i < destroyedNum - 2; i++) {
    for (let j = i + 1; j < destroyedNum - 1; j++) {
      distanceX = plants[j].x - plants[i].x
      distanceY = plants[j].y - plants[i].y
      previousX = plants[i].x - distanceX
      previousY = plants[i].y - distanceY

      /**
       * 第一个点前面一个点在稻田里面
       * 说明本次选的第二点导致的x方向步长不合理（太小）
       * 取下一个点作为第二点
       */
      if (previousX <= row && previousX >= 1 && previousY <= column && previousY >= 1) {
        continue
      }

      /**
       * x方向过早越界了，说明本次选的第二点不成立
       * 如果换下一个点作为第二点，x方向的步长只会更大，更不成立
       * 所以，应该认为本次选取的第一点必然是不成立的，
       * 那么取下一个点作为第一点再试
       */
      if (plants[i].x + (maxDestroyedNum - 1) * distanceX > row) {
        break
      }

      previousY = plants[i].y + (maxDestroyedNum - 1) * distanceY
      /**
       * y 方向过早越界了，应换一个点作为第二点再试
       */
      if (previousY > column || previousY < 1) {
        continue
      }

      steps = serachPath(plants[j], distanceX, distanceY)

      if (steps > maxDestroyedNum) {
        maxDestroyedNum = steps
      }

      if (maxDestroyedNum == 2) {
        maxDestroyedNum = 0
      }
    }
  }
  console.log('maxDestroyedNum', maxDestroyedNum)
}
plants = dotSort(plants)
findMax()<|endoftext|>


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

var fs = require('fs');
var nearley = require('../lib/nearley.js');
var nomnom = require('nomnom');
var randexp = require('randexp');

var opts = nomnom
	.script('nearley-unparse')
	.option('file', {
		position: 0,
		help: "A grammar .js file",
        required: true,
	})
	.option('start', {
		abbr: 's',
		help: "An optional start symbol (if not provided then use the parser start symbol)",
	})
	.option('out', {
		abbr: 'o',
		help: "File to output to (defaults to stdout)",
	})
	.option('version', {
		abbr: 'v',
		flag: true,
		help: "Print version and exit",
		callback: function() {
			return require('../package.json').version;
		}
	})
	.parse();

var output = opts.out ? fs.createWriteStream(opts.out) : process.stdout;

var grammar = new require(require('path').resolve(opts.file));

function gen(grammar, name) {
    var stack = [name];
    var rules = grammar.ParserRules;

    while (stack.length > 0) {
        var currentname = stack.pop();
        if (typeof(currentname) === 'string') {
            var goodrules = grammar.ParserRules.filter(function(x) {
                return x.name === currentname;
            });
            if (goodrules.length > 0) {
                var chosen = goodrules[
                    Math.floor(Math.random()*goodrules.length)
                ];
                for (var i=chosen.symbols.length-1; i>=0; i--) {
                    stack.push(chosen.symbols[i]);
                }
            } else {
                throw new Error("Nothing matches rule: "+currentname+"!");
            }
        } else if (currentname.test) {
            var c = new randexp(currentname).gen();
            output.write(c);
            continue;
        } else if (currentname.literal) {
            var c = currentname.literal;
            output.write(c);
            continue;
        }
    }
}

gen(grammar, opts.start ? opts.start : grammar.ParserStart);
output.write("\n");
<commit_msg>add -n option to unparse<commit_after>#!/usr/bin/env node

var fs = require('fs');
var nearley = require('../lib/nearley.js');
var nomnom = require('nomnom');
var randexp = require('randexp');

var opts = nomnom
	.script('nearley-unparse')
	.option('file', {
		position: 0,
		help: "A grammar .js file",
        required: true,
	})
	.option('start', {
		abbr: 's',
		help: "An optional start symbol (if not provided then use the parser start symbol)",
	})
    .option('count', {
        abbr: 'n',
        help: 'The number of samples to generate (separated by \n).',
        default: 1
    })
	.option('out', {
		abbr: 'o',
		help: "File to output to (defaults to stdout)",
	})
	.option('version', {
		abbr: 'v',
		flag: true,
		help: "Print version and exit",
		callback: function() {
			return require('../package.json').version;
		}
	})
	.parse();

var output = opts.out ? fs.createWriteStream(opts.out) : process.stdout;

var grammar = new require(require('path').resolve(opts.file));

function gen(grammar, name) {
    var stack = [name];
    var rules = grammar.ParserRules;

    while (stack.length > 0) {
        var currentname = stack.pop();
        if (typeof(currentname) === 'string') {
            var goodrules = grammar.ParserRules.filter(function(x) {
                return x.name === currentname;
            });
            if (goodrules.length > 0) {
                var chosen = goodrules[
                    Math.floor(Math.random()*goodrules.length)
                ];
                for (var i=chosen.symbols.length-1; i>=0; i--) {
                    stack.push(chosen.symbols[i]);
                }
            } else {
                throw new Error("Nothing matches rule: "+currentname+"!");
            }
        } else if (currentname.test) {
            var c = new randexp(currentname).gen();
            output.write(c);
            continue;
        } else if (currentname.literal) {
            var c = currentname.literal;
            output.write(c);
            continue;
        }
    }
}

for (var i=0; i<parseInt(opts.count); i++) {
    gen(grammar, opts.start ? opts.start : grammar.ParserStart);
    output.write("\n");
}
<|endoftext|>


<commit_before>
// Those are a few hundred lines of highly questionable JS.
// They are not representative of state-of-the-art frontend practices.

// Workflow B1: use Cloud Storage.
//
// 1) The page displays a File input/Drag'n'drop zone
// 2) The User drops a file F
// 4) The page asks the backend for a Signed URLs U, D
// 5) The page uploads F to U
// 6) The page encodes and displays D inside a QR-code
// 7) The user scans the QR-code with their mobile
// 8) The mobile downloads F at URL D

// var backend = "https://hot-maze.uc.r.appspot.com";
// Frontend and Backend hosted at the same domain on App Engine.
var backend = "";

let resourceFile;
let qrText;

function showError(errmsg) {
  console.log("Error: " + errmsg)
  clearQR();
  freezeResize();
  errorZone.innerHTML = errmsg;
  errorZone.style.display = "block";
  return false;
}

let qrHundredth = 40;

function render(colorDark, clickCallback){
  // qrHundredth == 95 is a "big QR-code" (almost fullscreen)
  // qrHundredth == 50 is a "medium-size QR-code"

  // -50 is for the small [?] box on the left
  var w = Math.max(document.documentElement.clientWidth -50, (window.innerWidth || 0) -50) * qrHundredth / 100;
  var h = Math.max(document.documentElement.clientHeight, window.innerHeight || 0) * qrHundredth / 100;
  var c = 400;
  if ( w>0 )
    c = w;
  if ( h>0 && h<c )
    c = h;

  clearQR();
  console.log("Rendering QR data ", qrText);
  console.log(`${qrText.length} characters`);
  // The limit seems to be 2328 characters.
  // If the qrText exceeds, we get TypeError: Cannot read property '1' of undefined
  try {
    new QRCode("qrcode", {
      text: qrText,
      width: c,
      height: c,
      colorDark : colorDark,
      colorLight : "white",
      correctLevel : QRCode.CorrectLevel.M
    });
  } catch(e) {
    showError("Could not render QR-code: " + e);
    return;
  }

  // The QR-code contents is clickable to embiggen, not the whole qr-zone
  if (clickCallback)
    for(var i=0; i < qrcode.childNodes.length; i++)
      qrcode.childNodes[i].onclick = clickCallback;
}

// Go fullscreen -> bigger QR
var resizeTimeOut = null;
window.onresize = function(){
    if (resizeTimeOut != null)
        clearTimeout(resizeTimeOut);
    resizeTimeOut = setTimeout(function(){
        render("black", embiggen);
    }, 300);
};
function freezeResize(){
  // after scan, or on fatal error, we don't need/want to
  // redisplay a fresh black QR-code again.
  window.onresize = function(){ return false; }
}

function clearQR() {
  var node = qrcode;
  while (node.firstChild) {
      node.removeChild(node.firstChild);
  }
}

questionMark.onclick = function(event) {
    if ( helpContents.style.display === "none" ){
      helpContents.style.display = "block";
      questionMark.style.display = "none";
    }
}
helpClose.onclick = function(event) {
    helpContents.style.display = "none";
    questionMark.style.display = "";
}
document.onkeydown = function(evt) {
  evt = evt || window.event;
  var isEscape = false;
  if ("key" in evt) {
    isEscape = (evt.key == "Escape" || evt.key == "Esc");
  } else {
    isEscape = (evt.keyCode == 27);
  }
  if (isEscape) {
    questionMark.style.display = "";
    helpContents.style.display = "none";
  }
};

function embiggen(event) {
    // Change size on each click
    // 40, 68, 96, 40, 60, 96 ...
    qrHundredth += 28;
    if ( qrHundredth>100 )
      qrHundredth = 40;
    render("black", embiggen);
}

function displayGetQrCode() {
  formZone.style.display = "none";
  render("black", embiggen);
}

function processResourceFile() {
   // Here, resourceFile has been set either through the file select input,
   // or through a drag'n'drop.
   // What happens next with resourceFile is the same in both use cases.

   requestGcsUrls()
    .catch(showError)
    .then(doUpload)
    .catch(showError)
    .then(displayGetQrCode);
}

resourceInput.onchange = function(e) {
    resourceFile = resourceInput.files[0];
    processResourceFile();
};

function handleDnd(){
  // See https://css-tricks.com/drag-and-drop-file-uploading/
  var div = document.createElement('div');
  var dndFileSupported = (('draggable' in div)
    || ('ondragstart' in div && 'ondrop' in div))
    && 'FormData' in window && 'FileReader' in window;
  if (!dndFileSupported)
    return;

  dropInvite.style.display = "block";

  var dropZone = resourceUpload;

  function highlightDropZone(){
    dropZone.style.border = 'red dotted 10px';
  }

  function unhighlightDropZone(){
    dropZone.style.border = 'rgba(255, 255, 255, 0) solid 10px';
  }

  dropZone.addEventListener('dragover', function(evt){
    evt.stopPropagation();
    evt.preventDefault();
    highlightDropZone()
    evt.dataTransfer.dropEffect = 'copy';
  }, false);

  dropZone.addEventListener('drop', function(evt){
    evt.stopPropagation();
    evt.preventDefault();
    helpContents.style.display = "none";
    unhighlightDropZone();

    var files = evt.dataTransfer.files;
    if( files.length>1 ){
      showError("Multiple upload not supported (yet)");
      return;
    }

    // Upload 1st file only.
    resourceFile = files[0];
    processResourceFile();
  }, false);

  dropZone.addEventListener('dragleave', function(evt){
    unhighlightDropZone();
  }, false);
}

async function requestGcsUrls() {
  console.log("requestGcsUrls");
  let endpoint = `${backend}/secure-urls`;
  let params = `filetype=${encodeURIComponent(resourceFile.type)}`
               + `&filesize=${resourceFile.size}`
               + `&filename=${encodeURIComponent(resourceFile.name)}`;
  let url = `${endpoint}?${params}`
  return fetch(url, {method:"POST"})
    .catch(showError)
    .then(response => response.json());
}

async function doUpload(gcsUrls) {
  console.debug("URL GET =", gcsUrls.downloadURL);
  qrText = gcsUrls.downloadURL;
  console.debug("URL PUT =", gcsUrls.uploadURL);
  return fetch(gcsUrls.uploadURL, {
      method:"PUT",
      headers: {
        'Content-Type': resourceFile.type
      },
      body: resourceFile
    });
}

//
// Let's start: init, then wait for user file selection.
//

handleDnd();<commit_msg>Hot Maze B1: upload progress bar.<commit_after>
// Those are a few hundred lines of highly questionable JS.
// They are not representative of state-of-the-art frontend practices.

// Workflow B1: use Cloud Storage.
//
// 1) The page displays a File input/Drag'n'drop zone
// 2) The User drops a file F
// 4) The page asks the backend for a Signed URLs U, D
// 5) The page uploads F to U
// 6) The page encodes and displays D inside a QR-code
// 7) The user scans the QR-code with their mobile
// 8) The mobile downloads F at URL D

// var backend = "https://hot-maze.uc.r.appspot.com";
// Frontend and Backend hosted at the same domain on App Engine.
var backend = "";

let resourceFile;
let qrText;

function showError(errmsg) {
  console.log("Error: " + errmsg)
  clearQR();
  freezeResize();
  errorZone.innerHTML = errmsg;
  errorZone.style.display = "block";
  return false;
}

let qrHundredth = 40;

function render(colorDark, clickCallback){
  // qrHundredth == 95 is a "big QR-code" (almost fullscreen)
  // qrHundredth == 50 is a "medium-size QR-code"

  // -50 is for the small [?] box on the left
  var w = Math.max(document.documentElement.clientWidth -50, (window.innerWidth || 0) -50) * qrHundredth / 100;
  var h = Math.max(document.documentElement.clientHeight, window.innerHeight || 0) * qrHundredth / 100;
  var c = 400;
  if ( w>0 )
    c = w;
  if ( h>0 && h<c )
    c = h;

  clearQR();
  console.log("Rendering QR data ", qrText);
  console.log(`${qrText.length} characters`);
  // The limit seems to be 2328 characters.
  // If the qrText exceeds, we get TypeError: Cannot read property '1' of undefined
  try {
    new QRCode("qrcode", {
      text: qrText,
      width: c,
      height: c,
      colorDark : colorDark,
      colorLight : "white",
      correctLevel : QRCode.CorrectLevel.M
    });
  } catch(e) {
    showError("Could not render QR-code: " + e);
    return;
  }

  // The QR-code contents is clickable to embiggen, not the whole qr-zone
  if (clickCallback)
    for(var i=0; i < qrcode.childNodes.length; i++)
      qrcode.childNodes[i].onclick = clickCallback;
}

// Go fullscreen -> bigger QR
var resizeTimeOut = null;
window.onresize = function(){
    if (resizeTimeOut != null)
        clearTimeout(resizeTimeOut);
    resizeTimeOut = setTimeout(function(){
        render("black", embiggen);
    }, 300);
};
function freezeResize(){
  // after scan, or on fatal error, we don't need/want to
  // redisplay a fresh black QR-code again.
  window.onresize = function(){ return false; }
}

function clearQR() {
  var node = qrcode;
  while (node.firstChild) {
      node.removeChild(node.firstChild);
  }
}

questionMark.onclick = function(event) {
    if ( helpContents.style.display === "none" ){
      helpContents.style.display = "block";
      questionMark.style.display = "none";
    }
}
helpClose.onclick = function(event) {
    helpContents.style.display = "none";
    questionMark.style.display = "";
}
document.onkeydown = function(evt) {
  evt = evt || window.event;
  var isEscape = false;
  if ("key" in evt) {
    isEscape = (evt.key == "Escape" || evt.key == "Esc");
  } else {
    isEscape = (evt.keyCode == 27);
  }
  if (isEscape) {
    questionMark.style.display = "";
    helpContents.style.display = "none";
  }
};

function embiggen(event) {
    // Change size on each click
    // 40, 68, 96, 40, 60, 96 ...
    qrHundredth += 28;
    if ( qrHundredth>100 )
      qrHundredth = 40;
    render("black", embiggen);
}

function displayGetQrCode() {
  formZone.style.display = "none";
  render("black", embiggen);
}

function processResourceFile() {
   // Here, resourceFile has been set either through the file select input,
   // or through a drag'n'drop.
   // What happens next with resourceFile is the same in both use cases.

   requestGcsUrls()
    .catch(showError)
    .then(doUpload)
    .catch(showError)
    .then(progressSuccess)
    .then(displayGetQrCode);
}

resourceInput.onchange = function(e) {
    resourceFile = resourceInput.files[0];
    processResourceFile();
};

function handleDnd(){
  // See https://css-tricks.com/drag-and-drop-file-uploading/
  var div = document.createElement('div');
  var dndFileSupported = (('draggable' in div)
    || ('ondragstart' in div && 'ondrop' in div))
    && 'FormData' in window && 'FileReader' in window;
  if (!dndFileSupported)
    return;

  dropInvite.style.display = "block";

  var dropZone = resourceUpload;

  function highlightDropZone(){
    dropZone.style.border = 'red dotted 10px';
  }

  function unhighlightDropZone(){
    dropZone.style.border = 'rgba(255, 255, 255, 0) solid 10px';
  }

  dropZone.addEventListener('dragover', function(evt){
    evt.stopPropagation();
    evt.preventDefault();
    highlightDropZone()
    evt.dataTransfer.dropEffect = 'copy';
  }, false);

  dropZone.addEventListener('drop', function(evt){
    evt.stopPropagation();
    evt.preventDefault();
    helpContents.style.display = "none";
    unhighlightDropZone();

    var files = evt.dataTransfer.files;
    if( files.length>1 ){
      showError("Multiple upload not supported (yet)");
      return;
    }

    // Upload 1st file only.
    resourceFile = files[0];
    processResourceFile();
  }, false);

  dropZone.addEventListener('dragleave', function(evt){
    unhighlightDropZone();
  }, false);
}

async function requestGcsUrls() {
  console.debug("requestGcsUrls");
  fileForm.style.display = "none";
  let endpoint = `${backend}/secure-urls`;
  let params = `filetype=${encodeURIComponent(resourceFile.type)}`
               + `&filesize=${resourceFile.size}`
               + `&filename=${encodeURIComponent(resourceFile.name)}`;
  let url = `${endpoint}?${params}`
  return fetch(url, {method:"POST"})
    .catch(showError)
    .then(response => response.json());
}

async function doUpload(gcsUrls) {
  console.debug("URL GET =", gcsUrls.downloadURL);
  qrText = gcsUrls.downloadURL;
  console.debug("URL PUT =", gcsUrls.uploadURL);
  uploadProgress.style.display = "inline";
  uploadProgress.value = 0.05;

  // XMLHttpRequest instead of fetch: be cause we use
  // the 'progress' event.
  return new Promise(function (resolve, reject) {
    var xhr = new XMLHttpRequest();
    xhr.open("PUT", gcsUrls.uploadURL);
    xhr.onload = function () {
      if (this.status >= 200 && this.status < 300) {
        resolve(xhr.response);
      } else {
        reject({
          status: this.status,
          statusText: xhr.statusText
        });
      }
    };
    xhr.onerror = function () {
      reject({
        status: this.status,
        statusText: xhr.statusText
      });
    };
    (xhr.upload || xhr).addEventListener('progress', function(e) {
        var done = e.position || e.loaded;
        var total = e.totalSize || e.total;
        var ratio = done/total;
        console.debug("Upload ratio:", ratio);
        uploadProgress.value = 0.05 + 0.85*ratio;
    });
    xhr.setRequestHeader("Content-Type", resourceFile.type);
    if(resourceFile.name) {
      xhr.setRequestHeader("Content-Disposition", `filename="${encodeURIComponent(resourceFile.name)}"`);
    }
    xhr.send(resourceFile);
  });
}

async function progressSuccess() {
  uploadProgress.value = 1;
  window.setTimeout( () => {
    uploadProgress.style.display = "none";
  }, 800);
}

//
// Let's start: init, then wait for user file selection.
//

handleDnd();<|endoftext|>


<commit_before>// run `node syncContextDocs.js` from the lib folder to update/add the context docs that we specify here
// note the relative path to nano module from where this doc is stored.
// currently this script requires the context docs to already exist in couchdb
// if creating/defining a brand new context doc - use futon or curl to create an otherwise empty doc with the needed "_id" first.

var nano = require('../node_modules/nano')('http://127.0.0.1:5984');
var db = nano.use('patterns');

// specifies the @contex json to be included / mapped to bibTEX docs
var bibTEXContext = {
	"_id": "bibTEX",
	"doctype": "context",
	"@context": {
	"address": "http://purl.org/net/nknouf/ns/bibtex#hasAddress",
	"author": "http://purl.org/dc/terms/creator",
	"booktitle": "http://purl.org/net/nknouf/ns/bibtex#hasBookTitle",
	"chapter": "http://purl.org/ontology/bibo/chapter",
	"doi": "http://purl.org/ontology/bibo/doi",
	"edition": "http://purl.org/ontology/bibo/edition",
	"editor": "http://purl.org/ontology/bibo/editor",
	"entrytype": "http://purl.org/net/nknouf/ns/bibtex#hasType",
	"journal": "http://purl.org/net/nknouf/ns/bibtex#hasJournal",
	"month": "http://purl.org/net/nknouf/ns/bibtex#hasMonth",
	"number": "http://purl.org/net/nknouf/ns/bibtex#hasNumber",
	"pages": "http://purl.org/net/nknouf/ns/bibtex#hasPages",
	"publisher": "http://purl.org/dc/terms/publisher",
	"series": "http://purl.org/net/nknouf/ns/bibtex#hasSeries",
	"title": "http://purl.org/dc/terms/title",
	"url": {"@id": "http://purl.org/spar/fabio/hasURL",
		"@type": "@id"
		},
	"volume": "http://sw-portal.deri.org/ontologies/swportal#isVolume",
	"year": "http://purl.org/spar/fabio/hasPublicationYear",
	"partOf": { "@id": "http://purl.org/dc/terms/isPartOf",
		"@type": "@id"
	    }
	}
};

// specifies the @contex json to be included / mapped to contributor (author) docs
var contributorContext = {
	"_id": "contributor",
	"doctype": "context",
	"@context": {
	"ORCID": { "@id": "http://vivoweb.org/ontology/core#orcidId",
			   "@type": "@id"
			 },
	"authorName": "http://xmlns.com/foaf/0.1/name"
	}
};

// specifies the @contex json to be included / mapped to pattern docs
//note that whole pattern represenations served by the API will include merged contributor, evidence, force context docs
var patternContext = {
	"_id": "pattern",
	"doctype": "context",
	"@context": {
	"name": "http://schema.org/name",
	"context": "http://purl/NET/labpatterns#hasContext",
	"problem": "http://purl/NET/labpatterns#hasProblem",
	"force": "http://purl/NET/labpatterns#hasForce",
	"solution": "http://purl/NET/labpatterns#hasSolution",
	"rationale": "http://purl/NET/labpatterns#hasRationale",
	"diagram": {"@id": "http://schema.org/image",
		"@type": "@id"
	    },
	"evidence": "http://purl.org/spar/cito/citesAsEvidence",
	"author": "http://purl.org/dc/terms/creator",
	"pic": {"@id": "http://xmlns.com/foaf/0.1/depiction",
	"@type": "@id"
	 	}
	}
};

// specifies the @contex json to be included / mapped to force docs
var forceContext = {
	"_id": "force",
	"doctype": "context",
	"@context": {
	"forceName": "http://schema.org/name",
	"description": "http://purl.org/dc/terms/description",
	"pic": {"@id": "http://xmlns.com/foaf/0.1/depiction",
	"@type": "@id"
	 	},
	"partOf": { "@id": "http://purl.org/dc/terms/isPartOf",
	"@type": "@id"
	    }
	}
};

//
var exemplarContext = {
	"_id": "exemplar",
	"doctype": "context",
	"@context": {
		"comment": "http://purl.org/NET/exemplr#hasComment",
		"targetURL": { "@id": "http://purl.org/NET/exemplr#hasTargetURL",
		"@type": "@id"
		},
		"pageName": "http://purl.org/NET/exemplr#hasTargetTitle",
		"exemplifiedBy": "http://purl.org/NET/exemplr#exemplifiedBy",
		"targetDetail": "http://purl.org/NET/exemplr#hasTargetDetail",
		"creatorORCID": { "@id": "http://purl.org/NET/exemplr#creatorORCID",
		"@type": "@id"
		},
		"concernsForce": { "@id": "http://purl.org/NET/exemplr#concernsForce",
		"@type": "@id"
		},
		"concernsPattern": { "@id": "http://purl.org/NET/exemplr#concernsPattern",
		"@type": "@id"
		}
	}
};

var contextDocs = [bibTEXContext, contributorContext, patternContext, forceContext, exemplarContext];

//note this function uses an Immediately Invoked Function expression to
// allow async call-back funtions to close properly within the
// for loop. see
// http://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example/19323214#19323214
// http://learn.jquery.com/javascript-101/functions/#immediately-invoked-function-expression-iife
// http://en.wikipedia.org/wiki/Immediately-invoked_function_expression

function syncDocs() {
	for (var x = 0; x < contextDocs.length; x++) {
		//IIFE - anon function will be called on each iteration of the for loop
		// we pass in the value of for loop x as index within the anon funct
		(function(index){
			//we copy the contents of the JSON objects specified above into the temp var doc here
			var doc = JSON.parse(JSON.stringify(contextDocs[index]));
			//retreive the doc from couch db
			db.get(doc['_id'], function(err, body){
				if(!err){
					//if OK, set/create temp doc "_rev" field to match current db rev
					doc['_rev'] = body['_rev'];
					//write the doc
					db.insert(doc, function(err, body){
						console.log(body);
					})
				}
				else{
					// if the db.get fails
					console.log(err);
				}
				//console.log("doc id is "+doc['_id']+" and doc rev is set to "+doc['_rev']);
			})
		})(x); // we send the for loop iterator x to the (IIFE) anon function above, where it is defined as 'index'
			   // see IIFE links above
	}
}

syncDocs();
<commit_msg>fixed missing .org from purl URIs in context docs<commit_after>// run `node syncContextDocs.js` from the lib folder to update/add the context docs that we specify here
// note the relative path to nano module from where this doc is stored.
// currently this script requires the context docs to already exist in couchdb
// if creating/defining a brand new context doc - use futon or curl to create an otherwise empty doc with the needed "_id" first.

var nano = require('../node_modules/nano')('http://127.0.0.1:5984');
var db = nano.use('patterns');

// specifies the @contex json to be included / mapped to bibTEX docs
var bibTEXContext = {
	"_id": "bibTEX",
	"doctype": "context",
	"@context": {
	"address": "http://purl.org/net/nknouf/ns/bibtex#hasAddress",
	"author": "http://purl.org/dc/terms/creator",
	"booktitle": "http://purl.org/net/nknouf/ns/bibtex#hasBookTitle",
	"chapter": "http://purl.org/ontology/bibo/chapter",
	"doi": "http://purl.org/ontology/bibo/doi",
	"edition": "http://purl.org/ontology/bibo/edition",
	"editor": "http://purl.org/ontology/bibo/editor",
	"entrytype": "http://purl.org/net/nknouf/ns/bibtex#hasType",
	"journal": "http://purl.org/net/nknouf/ns/bibtex#hasJournal",
	"month": "http://purl.org/net/nknouf/ns/bibtex#hasMonth",
	"number": "http://purl.org/net/nknouf/ns/bibtex#hasNumber",
	"pages": "http://purl.org/net/nknouf/ns/bibtex#hasPages",
	"publisher": "http://purl.org/dc/terms/publisher",
	"series": "http://purl.org/net/nknouf/ns/bibtex#hasSeries",
	"title": "http://purl.org/dc/terms/title",
	"url": {"@id": "http://purl.org/spar/fabio/hasURL",
		"@type": "@id"
		},
	"volume": "http://sw-portal.deri.org/ontologies/swportal#isVolume",
	"year": "http://purl.org/spar/fabio/hasPublicationYear",
	"partOf": { "@id": "http://purl.org/dc/terms/isPartOf",
		"@type": "@id"
	    }
	}
};

// specifies the @contex json to be included / mapped to contributor (author) docs
var contributorContext = {
	"_id": "contributor",
	"doctype": "context",
	"@context": {
	"ORCID": { "@id": "http://vivoweb.org/ontology/core#orcidId",
			   "@type": "@id"
			 },
	"authorName": "http://xmlns.com/foaf/0.1/name"
	}
};

// specifies the @contex json to be included / mapped to pattern docs
//note that whole pattern represenations served by the API will include merged contributor, evidence, force context docs
var patternContext = {
	"_id": "pattern",
	"doctype": "context",
	"@context": {
	"name": "http://schema.org/name",
	"context": "http://purl.org/NET/labpatterns#hasContext",
	"problem": "http://purl.org/NET/labpatterns#hasProblem",
	"force": "http://purl.org/NET/labpatterns#hasForce",
	"solution": "http://purl.org/NET/labpatterns#hasSolution",
	"rationale": "http://purl.org/NET/labpatterns#hasRationale",
	"diagram": {"@id": "http://schema.org/image",
		"@type": "@id"
	    },
	"evidence": "http://purl.org/spar/cito/citesAsEvidence",
	"author": "http://purl.org/dc/terms/creator",
	"pic": {"@id": "http://xmlns.com/foaf/0.1/depiction",
	"@type": "@id"
	 	}
	}
};

// specifies the @contex json to be included / mapped to force docs
var forceContext = {
	"_id": "force",
	"doctype": "context",
	"@context": {
	"forceName": "http://schema.org/name",
	"description": "http://purl.org/dc/terms/description",
	"pic": {"@id": "http://xmlns.com/foaf/0.1/depiction",
	"@type": "@id"
	 	},
	"partOf": { "@id": "http://purl.org/dc/terms/isPartOf",
	"@type": "@id"
	    }
	}
};

//
var exemplarContext = {
	"_id": "exemplar",
	"doctype": "context",
	"@context": {
		"comment": "http://purl.org/NET/exemplr#hasComment",
		"targetURL": { "@id": "http://purl.org/NET/exemplr#hasTargetURL",
		"@type": "@id"
		},
		"pageName": "http://purl.org/NET/exemplr#hasTargetTitle",
		"exemplifiedBy": "http://purl.org/NET/exemplr#exemplifiedBy",
		"targetDetail": "http://purl.org/NET/exemplr#hasTargetDetail",
		"creatorORCID": { "@id": "http://purl.org/NET/exemplr#creatorORCID",
		"@type": "@id"
		},
		"concernsForce": { "@id": "http://purl.org/NET/exemplr#concernsForce",
		"@type": "@id"
		},
		"concernsPattern": { "@id": "http://purl.org/NET/exemplr#concernsPattern",
		"@type": "@id"
		}
	}
};

var contextDocs = [bibTEXContext, contributorContext, patternContext, forceContext, exemplarContext];

//note this function uses an Immediately Invoked Function expression to
// allow async call-back funtions to close properly within the
// for loop. see
// http://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example/19323214#19323214
// http://learn.jquery.com/javascript-101/functions/#immediately-invoked-function-expression-iife
// http://en.wikipedia.org/wiki/Immediately-invoked_function_expression

function syncDocs() {
	for (var x = 0; x < contextDocs.length; x++) {
		//IIFE - anon function will be called on each iteration of the for loop
		// we pass in the value of for loop x as index within the anon funct
		(function(index){
			//we copy the contents of the JSON objects specified above into the temp var doc here
			var doc = JSON.parse(JSON.stringify(contextDocs[index]));
			//retreive the doc from couch db
			db.get(doc['_id'], function(err, body){
				if(!err){
					//if OK, set/create temp doc "_rev" field to match current db rev
					doc['_rev'] = body['_rev'];
					//write the doc
					db.insert(doc, function(err, body){
						console.log(body);
					})
				}
				else{
					// if the db.get fails
					console.log(err);
				}
				//console.log("doc id is "+doc['_id']+" and doc rev is set to "+doc['_rev']);
			})
		})(x); // we send the for loop iterator x to the (IIFE) anon function above, where it is defined as 'index'
			   // see IIFE links above
	}
}

syncDocs();
<|endoftext|>


<commit_before>(function () {
  atc = function (elementID) {
    var Timeline = function (elementID) {
      this.element = typeof elementID === "string" ? document.getElementById(elementID) : elementID || {};

      this.defaults = {
        frameRate: atc.defaults.frameRate,
        pauseDuration: atc.defaults.pauseDuration,
        loop: atc.defaults.loop
      };
    };

    var private = {};

    private.addToQueue = function (funktion, duration, endText) {
      private.duration += duration;
      private.endText = endText;
      private.queue.push({ funktion: funktion, duration: duration, endText: endText });
    };

    private.findText = function () {
      var text;

      try {
        text = private.queue[private.queue.length - 1].endText;
      } catch (e) {
        text = this.element.textContent;
      }

      return text;
    };

    private.queue = [];
    private.queueIndex = 0;
    private.stopped = false;
    private.duration = 0;
    private.endText = "";

    Timeline.prototype.go = function (timelineObj) {
      var thiz = this,
          funktion,
          len,
          nextAnimation;

      if (timelineObj) {
        funktion = function () {
          timelineObj.go();
        };

        private.addToQueue(funktion, timelineObj.duration, timelineObj.endText);
      } else {
        len = private.queue.length;
        private.stopped = false;

        nextAnimation = function () {
          if (private.queueIndex < len && !private.stopped) {
            private.queue[private.queueIndex].funktion();
            private.timeout = setTimeout(nextAnimation, private.queue[private.queueIndex].duration);
            private.queueIndex += 1;
          } else if (!private.stopped) {
            private.queueIndex = 0;
            if (thiz.defaults.loop) {
              nextAnimation();
            }
          }
        };

        nextAnimation();
      }

      return this;
    };

    Timeline.prototype.stop = function (now) {
      if (now) {
        private.stopped = true;
        clearTimeout(private.timeout);
      } else {
        var thiz = this,
        funktion = function () {
          private.stopped = true;
        };

        private.addToQueue(funktion, 0, private.findText.apply(this));
      }

      return this;
    };

    Timeline.prototype.frameRate = function (frameRate) {
      this.defaults.frameRate = frameRate || this.defaults.frameRate;

      return this;
    };

    Timeline.prototype.pauseDuration = function (duration) {
      this.defaults.pauseDuration = duration || this.defaults.pauseDuration;

      return this;
    };

    Timeline.prototype.loop = function (bool) {
      this.defaults.loop = typeof bool === "undefined" ? true : bool;

      return this;
    };

    Timeline.prototype.on = function (eventType, funktion, useCapture) {
      useCapture = useCapture || false;
      this.element.addEventListener(eventType, funktion, useCapture);

      return this;
    };

    Timeline.prototype.text = function (text) {
      if (text) {
        var thiz = this,
            funktion;

        funktion = function () {
          thiz.element.textContent = text;
        };

        private.addToQueue(funktion, 0, text);

        return this;
      } else {
        return this.element.textContent;
      }
    };

    Timeline.prototype.html = function (html) {
      var thiz = this,
      funktion = function () {
        thiz.element.innerHTML = html;
      };

      private.addToQueue(funktion, 0, html);

      return this;
    };

    Timeline.prototype.switchElement = function (elementID) {
      var thiz = this,
      funktion = function () {
        thiz.element = typeof elementID === "string" ? document.getElementById(elementID) : elementID;
      };

      private.addToQueue(funktion, 0, this.element.textContent); // TODO fix endText value

      return this;
    };

    Timeline.prototype.custom = function (funktion, duration, endText) {
      duration = duration || 0;
      endText = endText || private.findText.apply(this);

      private.addToQueue(funktion, duration, endText);

      return this;
    };

    Timeline.prototype.frameByFrame = function (frames, loops, duration) {
      var thiz = this,
          len = frames.length,
          lastFrame = frames[len - 1],
          totalFrames,
          frameRate,
          funktion,
          i = 0;

      loops = loops || 1;
      totalFrames = len * loops;
      duration = duration || totalFrames * this.defaults.frameRate;
      frameRate = duration / totalFrames;

      funktion = function () {
        if (i < totalFrames && !private.stopped) {
          thiz.element.textContent = frames[i % len];

          private.timeout = setTimeout(funktion, frameRate);
          i++;
        } else {
          i = 0;
        }
      };

      private.addToQueue(funktion, duration, lastFrame);

      return this;
    };

    Timeline.prototype.rollNumbers = function (startValue, endValue, increment, duration) {
      var thiz = this,
          difference = endValue - startValue,
          newValue = startValue,
          addFrame,
          totalFrames,
          frameRate,
          funktion,
          i = 0;

      increment = increment || 1;
      addFrame = increment;

      if (difference < 0) {
        difference = -difference;
        addFrame = -addFrame;
      }

      totalFrames = difference / increment;
      frameRate = duration / totalFrames || this.defaults.frameRate;
      duration = duration || this.defaults.frameRate * totalFrames;

      funktion = function () {
        if (i < totalFrames && !private.stopped) {
          newValue += addFrame;
          thiz.element.textContent = newValue;

          private.timeout = setTimeout(funktion, frameRate);
          i++;
        } else {
          thiz.element.textContent = endValue;
          newValue = startValue;
          i = 0;
        }
      };

      private.addToQueue(funktion, duration, endValue);

      return this;
    };

    Timeline.prototype.erase = function (duration) {
      var thiz = this,
          originalText = private.findText.apply(this),
          textArray = originalText.split(''),
          len = originalText.length,
          frameRate = duration / len || this.defaults.frameRate,
          funktion,
          i = 0;

      duration = duration || this.defaults.frameRate * len;

      funktion = function () {
        if (i < len && !private.stopped) {
          textArray.pop();
          thiz.element.textContent = textArray.join('');

          private.timeout = setTimeout(funktion, frameRate);
          i++;
        } else {
          textArray = originalText.split('');
          i = 0;
        }
      };

      private.addToQueue(funktion, duration, "");

      return this;
    };

    Timeline.prototype.typeIn = function (text, duration) {
      var thiz = this,
          textArray = text.split(''),
          displayTextArray = [],
          len = text.length,
          frameRate = duration / len || this.defaults.frameRate,
          funktion,
          i = 0;

      duration = duration || this.defaults.frameRate * len;

      funktion = function () {
        if (i < len && !private.stopped) {
          displayTextArray.push(textArray.shift());
          thiz.element.textContent = displayTextArray.join('');

          private.timeout = setTimeout(funktion, frameRate);
          i++;
        } else {
          textArray = displayTextArray;
          displayTextArray = [];
          i = 0;
        }
      };

      private.addToQueue(funktion, duration, text);

      return this;
    };

    Timeline.prototype.pause = function (duration) {
      var endText = private.findText.apply(this),
          funktion = function () {};

      duration = duration || this.defaults.pauseDuration;
      private.addToQueue(funktion, duration, endText);

      return this;
    };

    Timeline.prototype.clearTimeline = function () {
      private.queue = [];
      private.duration = 0;
      private.endText = "";

      return this;
    };

    return new Timeline(elementID);
  };

  atc.defaults = {
    frameRate: 1000/24,
    pauseDuration: 2000,
    loop: false
  };

  atc.frameRate = function (frameRate) {
    atc.defaults.frameRate = frameRate || atc.defaults.frameRate;

    return atc;
  };

  atc.pauseDuration = function (duration) {
    atc.defaults.pauseDuration = duration || atc.defaults.pauseDuration;

    return atc;
  };

  atc.loop = function (bool) {
    atc.defaults.loop = typeof bool === "undefined" ? true : bool;

    return atc;
  };
}());
<commit_msg>private is potentially a future reserved word<commit_after>(function () {
  atc = function (elementID) {
    var Timeline = function (elementID) {
      this.element = typeof elementID === "string" ? document.getElementById(elementID) : elementID || {};

      this.defaults = {
        frameRate: atc.defaults.frameRate,
        pauseDuration: atc.defaults.pauseDuration,
        loop: atc.defaults.loop
      };
    },

    privut = {};

    privut.addToQueue = function (funktion, duration, endText) {
      privut.duration += duration;
      privut.endText = endText;
      privut.queue.push({ funktion: funktion, duration: duration, endText: endText });
    };

    privut.findText = function () {
      var text;

      try {
        text = privut.queue[privut.queue.length - 1].endText;
      } catch (e) {
        text = this.element.textContent;
      }

      return text;
    };

    privut.queue = [];
    privut.queueIndex = 0;
    privut.stopped = false;
    privut.duration = 0;
    privut.endText = "";

    Timeline.prototype.go = function (timelineObj) {
      var thiz = this,
          funktion,
          len,
          nextAnimation;

      if (timelineObj) {
        funktion = function () {
          timelineObj.go();
        };

        privut.addToQueue(funktion, timelineObj.duration, timelineObj.endText);
      } else {
        len = privut.queue.length;
        privut.stopped = false;

        nextAnimation = function () {
          if (privut.queueIndex < len && !privut.stopped) {
            privut.queue[privut.queueIndex].funktion();
            privut.timeout = setTimeout(nextAnimation, privut.queue[privut.queueIndex].duration);
            privut.queueIndex += 1;
          } else if (!privut.stopped) {
            privut.queueIndex = 0;
            if (thiz.defaults.loop) {
              nextAnimation();
            }
          }
        };

        nextAnimation();
      }

      return this;
    };

    Timeline.prototype.stop = function (now) {
      if (now) {
        privut.stopped = true;
        clearTimeout(privut.timeout);
      } else {
        var funktion = function () {
          privut.stopped = true;
        };

        privut.addToQueue(funktion, 0, privut.findText.apply(this));
      }

      return this;
    };

    Timeline.prototype.frameRate = function (frameRate) {
      this.defaults.frameRate = frameRate || this.defaults.frameRate;

      return this;
    };

    Timeline.prototype.pauseDuration = function (duration) {
      this.defaults.pauseDuration = duration || this.defaults.pauseDuration;

      return this;
    };

    Timeline.prototype.loop = function (bool) {
      this.defaults.loop = typeof bool === "undefined" ? true : bool;

      return this;
    };

    Timeline.prototype.on = function (eventType, funktion, useCapture) {
      useCapture = useCapture || false;
      this.element.addEventListener(eventType, funktion, useCapture);

      return this;
    };

    Timeline.prototype.text = function (text) {
      if (text) {
        var thiz = this,
            funktion;

        funktion = function () {
          thiz.element.textContent = text;
        };

        privut.addToQueue(funktion, 0, text);

        return this;
      } else {
        return this.element.textContent;
      }
    };

    Timeline.prototype.html = function (html) {
      var thiz = this,
      funktion = function () {
        thiz.element.innerHTML = html;
      };

      privut.addToQueue(funktion, 0, html);

      return this;
    };

    Timeline.prototype.switchElement = function (elementID) {
      var thiz = this,
      funktion = function () {
        thiz.element = typeof elementID === "string" ? document.getElementById(elementID) : elementID;
      };

      privut.addToQueue(funktion, 0, this.element.textContent); // TODO fix endText value

      return this;
    };

    Timeline.prototype.custom = function (funktion, duration, endText) {
      duration = duration || 0;
      endText = endText || privut.findText.apply(this);

      privut.addToQueue(funktion, duration, endText);

      return this;
    };

    Timeline.prototype.frameByFrame = function (frames, loops, duration) {
      var thiz = this,
          len = frames.length,
          lastFrame = frames[len - 1],
          totalFrames,
          frameRate,
          funktion,
          i = 0;

      loops = loops || 1;
      totalFrames = len * loops;
      duration = duration || totalFrames * this.defaults.frameRate;
      frameRate = duration / totalFrames;

      funktion = function () {
        if (i < totalFrames && !privut.stopped) {
          thiz.element.textContent = frames[i % len];

          privut.timeout = setTimeout(funktion, frameRate);
          i++;
        } else {
          i = 0;
        }
      };

      privut.addToQueue(funktion, duration, lastFrame);

      return this;
    };

    Timeline.prototype.rollNumbers = function (startValue, endValue, increment, duration) {
      var thiz = this,
          difference = endValue - startValue,
          newValue = startValue,
          addFrame,
          totalFrames,
          frameRate,
          funktion,
          i = 0;

      increment = increment || 1;
      addFrame = increment;

      if (difference < 0) {
        difference = -difference;
        addFrame = -addFrame;
      }

      totalFrames = difference / increment;
      frameRate = duration / totalFrames || this.defaults.frameRate;
      duration = duration || this.defaults.frameRate * totalFrames;

      funktion = function () {
        if (i < totalFrames && !privut.stopped) {
          newValue += addFrame;
          thiz.element.textContent = newValue;

          privut.timeout = setTimeout(funktion, frameRate);
          i++;
        } else {
          thiz.element.textContent = endValue;
          newValue = startValue;
          i = 0;
        }
      };

      privut.addToQueue(funktion, duration, endValue);

      return this;
    };

    Timeline.prototype.erase = function (duration) {
      var thiz = this,
          originalText = privut.findText.apply(this),
          textArray = originalText.split(''),
          len = originalText.length,
          frameRate = duration / len || this.defaults.frameRate,
          funktion,
          i = 0;

      duration = duration || this.defaults.frameRate * len;

      funktion = function () {
        if (i < len && !privut.stopped) {
          textArray.pop();
          thiz.element.textContent = textArray.join('');

          privut.timeout = setTimeout(funktion, frameRate);
          i++;
        } else {
          textArray = originalText.split('');
          i = 0;
        }
      };

      privut.addToQueue(funktion, duration, "");

      return this;
    };

    Timeline.prototype.typeIn = function (text, duration) {
      var thiz = this,
          textArray = text.split(''),
          displayTextArray = [],
          len = text.length,
          frameRate = duration / len || this.defaults.frameRate,
          funktion,
          i = 0;

      duration = duration || this.defaults.frameRate * len;

      funktion = function () {
        if (i < len && !privut.stopped) {
          displayTextArray.push(textArray.shift());
          thiz.element.textContent = displayTextArray.join('');

          privut.timeout = setTimeout(funktion, frameRate);
          i++;
        } else {
          textArray = displayTextArray;
          displayTextArray = [];
          i = 0;
        }
      };

      privut.addToQueue(funktion, duration, text);

      return this;
    };

    Timeline.prototype.pause = function (duration) {
      var endText = privut.findText.apply(this),
          funktion = function () {};

      duration = duration || this.defaults.pauseDuration;
      privut.addToQueue(funktion, duration, endText);

      return this;
    };

    Timeline.prototype.clearTimeline = function () {
      privut.queue = [];
      privut.duration = 0;
      privut.endText = "";

      return this;
    };

    return new Timeline(elementID);
  };

  atc.defaults = {
    frameRate: 1000/24,
    pauseDuration: 2000,
    loop: false
  };

  atc.frameRate = function (frameRate) {
    atc.defaults.frameRate = frameRate || atc.defaults.frameRate;

    return atc;
  };

  atc.pauseDuration = function (duration) {
    atc.defaults.pauseDuration = duration || atc.defaults.pauseDuration;

    return atc;
  };

  atc.loop = function (bool) {
    atc.defaults.loop = typeof bool === "undefined" ? true : bool;

    return atc;
  };
}());
<|endoftext|>


<commit_before>module.exports = function(grunt) {
	"use strict";

	var cssModule = require('../lib/css');
	var crypto = require('crypto');
	var path = require('path');
	var csso = require('csso');
	var fs = require('fs');
	var _ = require('underscore');

	var catalogFile = '.build-catalog.json';
	var reSkipCSSFileName = /^_/;

	function md5(str) {
		return crypto.createHash('md5').update(str).digest("hex");
	}

	function padNumber(num) {
		return (num < 10 ? '0' : '') + num;
	}

	function timestamp() {
		var now = new Date();
		return [now.getFullYear(),
			padNumber(now.getMonth() + 1),
			padNumber(now.getDate()),
			padNumber(now.getHours()),
			padNumber(now.getMinutes()),
			padNumber(now.getSeconds())
		].join('');
	}

	function makeAbsPath(file) {
		return path.resolve(process.cwd(), file);
	}

	function createPathResolver(webroot) {
		return function(file, originalFile) {
			var dirname = originalFile ? path.dirname(originalFile) : __dirname;
			if (file.charAt(0) == '/') {
				// resolve absolute file include
				file = file.replace(/^\/+/, '');
				dirname = webroot;
			}

			return path.resolve(dirname, file);
		};
	}

	function loadCatalog(config) {
		if (fs.existsSync(catalogFile)) {
			return grunt.file.readJSON(catalogFile);
		}

		return {};
	}

	function saveCatalog(json) {
		// update catalog
		grunt.file.write(catalogFile, JSON.stringify(json, null, '\t'));
	}

	/**
	 * Returns file path for catalog entry
	 * @param  {String} filePath
	 * @param  {String} webroot
	 * @return {String}
	 */
	function filePathForCatalog(filePath, webroot) {
		var len = webroot.length;
		if (filePath.substring(0, len) == webroot) {
			filePath = filePath.substring(len);
			if (filePath.charAt(0) != '/') {
				filePath = '/' + filePath;
			}
		}

		return filePath;
	}

	// function getConfig(ctx) {
	// 	var keyName = 'frontendConfig';
	// 	ctx.requiresConfig(keyName);
	// 	var config = grunt.config.get(keyName);
	// 	if (!config.webroot) {
	// 		return grunt.fail.fatal('You shoud specify "webroot" property in "' + keyName + '" section', 100);
	// 	}

	// 	var force = false;
	// 	if ('force' in config) {
	// 		force = !!config.force;
	// 	}

	// 	if (ctx.args && ~ctx.args.indexOf('force')) {
	// 		force = true;
	// 	}

	// 	return _.extend(config, {
	// 		force: force,
	// 		webroot: makeAbsPath(config.webroot),
	// 		srcWebroot: makeAbsPath(config.srcWebroot || config.webroot)
	// 	});
	// }

	function validateConfig(config) {
		if (!config.webroot) {
			return grunt.fail.fatal('You shoud specify "webroot" property in frontend config', 100);
		}

		var force = false;
		if ('force' in config) {
			force = !!config.force;
		}

		return _.extend(config, {
			force: force,
			webroot: makeAbsPath(config.webroot),
			srcWebroot: makeAbsPath(config.srcWebroot || config.webroot)
		});
	}

	function shouldCompileJSFile(file, deps, catalog, config) {
		var catalogName = filePathForCatalog(file, config.webroot);
		var shouldCompile = config.force || !(catalogName in catalog) || !fs.existsSync(file);
		if (!shouldCompile) {
			// we should compare a list length, file order and md5 of children files
			var prevList = catalog[catalogName].files;
			shouldCompile = prevList.length !== deps.length;

			// compare lib content and file order
			if (!shouldCompile) {
				shouldCompile = !!_.reject(deps, function(f, i) {
					var cf = filePathForCatalog(makeAbsPath(f), config.srcWebroot);
					return cf === prevList[i].file;
				}).length;
			}

			// compare md5 of files
			if (!shouldCompile) {
				shouldCompile = !!_.find(deps, function(f, i) {
					return md5(grunt.file.read(f)) !== prevList[i].md5;
				});
			}
		}

		return shouldCompile;
	}

	/**
	 * Check if passed path is a file
	 * @param  {String}  path
	 * @return {Boolean}
	 */
	function isFile(path) {
		if (fs.existsSync(path)) {
			return fs.statSync(path).isFile();
		} else {
			return (/\.\w+$/).test(path);
		}
	}

	/**
	 * Register reusable CSS compiler helper
	 * @param {Object} data Task payload
	 * @param {Object} config Task config (can be obtained from getConfig() method)
	 * @param {Object} catalog Pointer resources to catalog (can be obtained from loadCatalog())
	 */
	grunt.registerHelper('frontend-css', function(data, config, catalog) {
		if (!('src' in data)) {
			return grunt.fail('No "src" property specified for "css" task');
		}

		if (!('dest' in data)) {
			return grunt.fail('No "dest" property specified for "css" task');
		}

		catalog = catalog || {};

		var srcDir =  makeAbsPath(data.src);
		var destDir = makeAbsPath(data.dest);

		// read all css files
		var reCSSFile = /\.css$/i;
		var reSkip = config.skipNames || reSkipCSSFileName;
		var resolver = createPathResolver(config.srcWebroot);
		grunt.file.recurse(srcDir, function(abspath, rootdir, subdir, filename) {
			if (reCSSFile.test(abspath) && !reSkip.test(filename)) {
				var payload = {};
				payload[path.join(destDir, subdir, filename)] = abspath;
				grunt.helper('frontend-css-file', payload, config, catalog);
			}
		});

		return catalog;
	});

	/**
	 * Compiles single CSS file
	 * @param {Object} data Task payload
	 * @param {Object} config Task config (can be obtained from getConfig() method)
	 * @param {Object} catalog Pointer resources to catalog (can be obtained from loadCatalog())
	 */
	grunt.registerHelper('frontend-css-file', function(data, config, catalog) {
		catalog = catalog || {};

		var resolver = createPathResolver(config.srcWebroot);

		_.each(data, function(src, dest) {
			var destFile = makeAbsPath(dest);
			grunt.file.mkdir(path.dirname(destFile));

			var imports = {};
			var keepImports = [];
			var srcCatalogFiles = [];

			// sequentially inline all source CSS files into a singe one
			var max = _.map(grunt.file.expandFiles(src), function(f) {
				var srcFile = makeAbsPath(f);
				srcCatalogFiles.push(filePathForCatalog(srcFile, config.srcWebroot));
				grunt.log.writeln('\nReading ' + _.last(srcCatalogFiles));

				return cssModule.inlineCSSFile(srcFile, resolver, keepImports, imports);
			}).join('');

			// create file header with @imports that should be kept
			var header = _.map(keepImports, function(imp) {
				return imp.value;
			}).join(';\n') + '\n';

			// minify CSS
			var min = csso.justDoIt(header + max, true);

			// check if we should re-save compiled file
			// thus change its content and modification date
			var hash = md5(min);
			var catalogName = filePathForCatalog(destFile, config.webroot);
			if (!config.force && catalogName in catalog && catalog[catalogName].md5 === hash && fs.existsSync(destFile)) {
				grunt.log.writeln('File is not modified, skipping');
				return;
			}

			grunt.log.writeln('Saving minified version to ' + catalogName);
			grunt.file.write(destFile, min);

			catalog[catalogName] = {
				md5: hash,
				date: timestamp(),
				files: srcCatalogFiles
			};
		});

		return catalog;
	});

	grunt.registerHelper('frontend-js', function(data, config, catalog) {
		catalog = catalog || {};

		var failed = _.find(data, function(src, dest) {
			// a copy on "min" task
			var files = grunt.file.expandFiles(src);
			var absDestPath = makeAbsPath(dest, config.webroot);

			var catalogName = filePathForCatalog(absDestPath, config.webroot);
			grunt.log.writeln('\nReading ' + catalogName);

			// Get banner, if specified. It would be nice if UglifyJS supported ignoring
			// all comments matching a certain pattern, like /*!...*/, but it doesn't.
			var banner = grunt.task.directive(files[0], function() { return null; });
			if (banner === null) {
				banner = '';
			} else {
				files.shift();
			}

			// check if current file should be compiled
			if (!shouldCompileJSFile(absDestPath, files, catalog, config)) {
				grunt.log.writeln('File is not modified, skipping\n');
				return false;
			}

			// Concat specified files. This should really be a single, pre-built (and
			// linted) file, but it supports any number of files.
			var max = grunt.helper('concat', files);

			// Concat banner + minified source.
			var min = banner + grunt.helper('uglify', max, grunt.config('uglify'));
			grunt.file.write(dest, min);

			// Fail task if errors were logged.
			if (grunt.fail.errorcount) {
				return true;
			}

			// Otherwise, print a success message....
			grunt.log.writeln('File "' + catalogName + '" created.');
			// ...and report some size information.
			grunt.helper('min_max_info', min, max);

			// update catalog entry
			catalog[catalogName] = {
				md5: md5(min),
				date: timestamp(),
				files: _.map(files, function(f) {
					return {
						file: filePathForCatalog(makeAbsPath(f), config.srcWebroot),
						md5: md5(grunt.file.read(f))
					};
				})
			};
		});

		if (failed) {
			return false;
		}

		return catalog;
	});

	grunt.registerMultiTask('frontend', 'Builds font-end part of your web-site: compiles CSS and JS files', function() {
		grunt.log.writeln('Compiling ' + this.target.toUpperCase());
		var data = this.data;
		var catalog = loadCatalog();
		var config = validateConfig(_.extend({}, grunt.config.get('frontendConfig') || {}, this.data.options || {}));

		['css', 'css-single', 'js'].forEach(function(h) {
			if (h in data) {
				grunt.helper('frontend-' + h, data[h], config, catalog);
			}
		});

		// update catalog
		return saveCatalog(catalog);
	});
};<commit_msg>Fixed helper name<commit_after>module.exports = function(grunt) {
	"use strict";

	var cssModule = require('../lib/css');
	var crypto = require('crypto');
	var path = require('path');
	var csso = require('csso');
	var fs = require('fs');
	var _ = require('underscore');

	var catalogFile = '.build-catalog.json';
	var reSkipCSSFileName = /^_/;

	function md5(str) {
		return crypto.createHash('md5').update(str).digest("hex");
	}

	function padNumber(num) {
		return (num < 10 ? '0' : '') + num;
	}

	function timestamp() {
		var now = new Date();
		return [now.getFullYear(),
			padNumber(now.getMonth() + 1),
			padNumber(now.getDate()),
			padNumber(now.getHours()),
			padNumber(now.getMinutes()),
			padNumber(now.getSeconds())
		].join('');
	}

	function makeAbsPath(file) {
		return path.resolve(process.cwd(), file);
	}

	function createPathResolver(webroot) {
		return function(file, originalFile) {
			var dirname = originalFile ? path.dirname(originalFile) : __dirname;
			if (file.charAt(0) == '/') {
				// resolve absolute file include
				file = file.replace(/^\/+/, '');
				dirname = webroot;
			}

			return path.resolve(dirname, file);
		};
	}

	function loadCatalog(config) {
		if (fs.existsSync(catalogFile)) {
			return grunt.file.readJSON(catalogFile);
		}

		return {};
	}

	function saveCatalog(json) {
		// update catalog
		grunt.file.write(catalogFile, JSON.stringify(json, null, '\t'));
	}

	/**
	 * Returns file path for catalog entry
	 * @param  {String} filePath
	 * @param  {String} webroot
	 * @return {String}
	 */
	function filePathForCatalog(filePath, webroot) {
		var len = webroot.length;
		if (filePath.substring(0, len) == webroot) {
			filePath = filePath.substring(len);
			if (filePath.charAt(0) != '/') {
				filePath = '/' + filePath;
			}
		}

		return filePath;
	}

	// function getConfig(ctx) {
	// 	var keyName = 'frontendConfig';
	// 	ctx.requiresConfig(keyName);
	// 	var config = grunt.config.get(keyName);
	// 	if (!config.webroot) {
	// 		return grunt.fail.fatal('You shoud specify "webroot" property in "' + keyName + '" section', 100);
	// 	}

	// 	var force = false;
	// 	if ('force' in config) {
	// 		force = !!config.force;
	// 	}

	// 	if (ctx.args && ~ctx.args.indexOf('force')) {
	// 		force = true;
	// 	}

	// 	return _.extend(config, {
	// 		force: force,
	// 		webroot: makeAbsPath(config.webroot),
	// 		srcWebroot: makeAbsPath(config.srcWebroot || config.webroot)
	// 	});
	// }

	function validateConfig(config) {
		if (!config.webroot) {
			return grunt.fail.fatal('You shoud specify "webroot" property in frontend config', 100);
		}

		var force = false;
		if ('force' in config) {
			force = !!config.force;
		}

		return _.extend(config, {
			force: force,
			webroot: makeAbsPath(config.webroot),
			srcWebroot: makeAbsPath(config.srcWebroot || config.webroot)
		});
	}

	function shouldCompileJSFile(file, deps, catalog, config) {
		var catalogName = filePathForCatalog(file, config.webroot);
		var shouldCompile = config.force || !(catalogName in catalog) || !fs.existsSync(file);
		if (!shouldCompile) {
			// we should compare a list length, file order and md5 of children files
			var prevList = catalog[catalogName].files;
			shouldCompile = prevList.length !== deps.length;

			// compare lib content and file order
			if (!shouldCompile) {
				shouldCompile = !!_.reject(deps, function(f, i) {
					var cf = filePathForCatalog(makeAbsPath(f), config.srcWebroot);
					return cf === prevList[i].file;
				}).length;
			}

			// compare md5 of files
			if (!shouldCompile) {
				shouldCompile = !!_.find(deps, function(f, i) {
					return md5(grunt.file.read(f)) !== prevList[i].md5;
				});
			}
		}

		return shouldCompile;
	}

	/**
	 * Check if passed path is a file
	 * @param  {String}  path
	 * @return {Boolean}
	 */
	function isFile(path) {
		if (fs.existsSync(path)) {
			return fs.statSync(path).isFile();
		} else {
			return (/\.\w+$/).test(path);
		}
	}

	/**
	 * Register reusable CSS compiler helper
	 * @param {Object} data Task payload
	 * @param {Object} config Task config (can be obtained from getConfig() method)
	 * @param {Object} catalog Pointer resources to catalog (can be obtained from loadCatalog())
	 */
	grunt.registerHelper('frontend-css', function(data, config, catalog) {
		if (!('src' in data)) {
			return grunt.fail('No "src" property specified for "css" task');
		}

		if (!('dest' in data)) {
			return grunt.fail('No "dest" property specified for "css" task');
		}

		catalog = catalog || {};

		var srcDir =  makeAbsPath(data.src);
		var destDir = makeAbsPath(data.dest);

		// read all css files
		var reCSSFile = /\.css$/i;
		var reSkip = config.skipNames || reSkipCSSFileName;
		var resolver = createPathResolver(config.srcWebroot);
		grunt.file.recurse(srcDir, function(abspath, rootdir, subdir, filename) {
			if (reCSSFile.test(abspath) && !reSkip.test(filename)) {
				var payload = {};
				payload[path.join(destDir, subdir, filename)] = abspath;
				grunt.helper('frontend-css-file', payload, config, catalog);
			}
		});

		return catalog;
	});

	/**
	 * Compiles single CSS file
	 * @param {Object} data Task payload
	 * @param {Object} config Task config (can be obtained from getConfig() method)
	 * @param {Object} catalog Pointer resources to catalog (can be obtained from loadCatalog())
	 */
	grunt.registerHelper('frontend-css-file', function(data, config, catalog) {
		catalog = catalog || {};

		var resolver = createPathResolver(config.srcWebroot);

		_.each(data, function(src, dest) {
			var destFile = makeAbsPath(dest);
			grunt.file.mkdir(path.dirname(destFile));

			var imports = {};
			var keepImports = [];
			var srcCatalogFiles = [];

			// sequentially inline all source CSS files into a singe one
			var max = _.map(grunt.file.expandFiles(src), function(f) {
				var srcFile = makeAbsPath(f);
				srcCatalogFiles.push(filePathForCatalog(srcFile, config.srcWebroot));
				grunt.log.writeln('\nReading ' + _.last(srcCatalogFiles));

				return cssModule.inlineCSSFile(srcFile, resolver, keepImports, imports);
			}).join('');

			// create file header with @imports that should be kept
			var header = _.map(keepImports, function(imp) {
				return imp.value;
			}).join(';\n') + '\n';

			// minify CSS
			var min = csso.justDoIt(header + max, true);

			// check if we should re-save compiled file
			// thus change its content and modification date
			var hash = md5(min);
			var catalogName = filePathForCatalog(destFile, config.webroot);
			if (!config.force && catalogName in catalog && catalog[catalogName].md5 === hash && fs.existsSync(destFile)) {
				grunt.log.writeln('File is not modified, skipping');
				return;
			}

			grunt.log.writeln('Saving minified version to ' + catalogName);
			grunt.file.write(destFile, min);

			catalog[catalogName] = {
				md5: hash,
				date: timestamp(),
				files: srcCatalogFiles
			};
		});

		return catalog;
	});

	grunt.registerHelper('frontend-js', function(data, config, catalog) {
		catalog = catalog || {};

		var failed = _.find(data, function(src, dest) {
			// a copy on "min" task
			var files = grunt.file.expandFiles(src);
			var absDestPath = makeAbsPath(dest, config.webroot);

			var catalogName = filePathForCatalog(absDestPath, config.webroot);
			grunt.log.writeln('\nReading ' + catalogName);

			// Get banner, if specified. It would be nice if UglifyJS supported ignoring
			// all comments matching a certain pattern, like /*!...*/, but it doesn't.
			var banner = grunt.task.directive(files[0], function() { return null; });
			if (banner === null) {
				banner = '';
			} else {
				files.shift();
			}

			// check if current file should be compiled
			if (!shouldCompileJSFile(absDestPath, files, catalog, config)) {
				grunt.log.writeln('File is not modified, skipping\n');
				return false;
			}

			// Concat specified files. This should really be a single, pre-built (and
			// linted) file, but it supports any number of files.
			var max = grunt.helper('concat', files);

			// Concat banner + minified source.
			var min = banner + grunt.helper('uglify', max, grunt.config('uglify'));
			grunt.file.write(dest, min);

			// Fail task if errors were logged.
			if (grunt.fail.errorcount) {
				return true;
			}

			// Otherwise, print a success message....
			grunt.log.writeln('File "' + catalogName + '" created.');
			// ...and report some size information.
			grunt.helper('min_max_info', min, max);

			// update catalog entry
			catalog[catalogName] = {
				md5: md5(min),
				date: timestamp(),
				files: _.map(files, function(f) {
					return {
						file: filePathForCatalog(makeAbsPath(f), config.srcWebroot),
						md5: md5(grunt.file.read(f))
					};
				})
			};
		});

		if (failed) {
			return false;
		}

		return catalog;
	});

	grunt.registerMultiTask('frontend', 'Builds font-end part of your web-site: compiles CSS and JS files', function() {
		grunt.log.writeln('Compiling ' + this.target.toUpperCase());
		var data = this.data;
		var catalog = loadCatalog();
		var config = validateConfig(_.extend({}, grunt.config.get('frontendConfig') || {}, this.data.options || {}));

		['css', 'css-file', 'js'].forEach(function(h) {
			if (h in data) {
				grunt.helper('frontend-' + h, data[h], config, catalog);
			}
		});

		// update catalog
		return saveCatalog(catalog);
	});
};<|endoftext|>


<commit_before>var path = require('canonical-path');
var Q = require('q');
var gfs = require('graceful-fs');
var qfs = require('q-io/fs');
var _ = require('lodash');
var glob = require('glob');
var log = require('winston');

module.exports = function fileReaderFactory(extractors) {
  /**
   * Read the documents from aspecified files
   * @param  {Array} files                      Array of glob patterns or objects containing a glob pattern and basePath
   * @return {promise}                          A promise to an array of docs that have been extracted
   */
  return function(files) {

    return Q.all(_.map(files, function(fileInfo) {
      var basePath, files;

      if ( _.isString(fileInfo) ) {
        basePath = process.cwd();
        files = glob.sync(fileInfo);
      } else if ( _.isObject(fileInfo) ) {
        basePath = fileInfo.basePath || process.cwd();
        files = glob.sync(fileInfo.pattern, { cwd: basePath });
      } else {
        throw new Error('Invalid files parameter. ' +
          'You must pass an array of items, each of which is either a string or an object of the form ' +
          '{ pattern: "...", basePath: "..." }');
      }

      var docPromises = [];
      _.forEach(files, function(file) {
        _.any(extractors, function(extractor) {
          if ( extractor.pattern.test(file) ) {
            docPromises.push(qfs.read(path.resolve(basePath, file)).then(function(content) {
              return extractor.processFile(file, content, basePath);
            }));
            return true;
          }
        });
      });

      return Q.all(docPromises).then(_.flatten);
    }))

    .then(_.flatten);
  };
};<commit_msg>refact(doc-extractor): consolidate globbing<commit_after>var path = require('canonical-path');
var Q = require('q');
var gfs = require('graceful-fs');
var qfs = require('q-io/fs');
var _ = require('lodash');
var glob = require('glob');
var log = require('winston');

module.exports = function fileReaderFactory(extractors) {
  /**
   * Read the documents from aspecified files
   * @param  {Array} files                      Array of glob patterns or objects containing a glob pattern and basePath
   * @return {promise}                          A promise to an array of docs that have been extracted
   */
  return function(files) {

    return Q.all(_.map(files, function(fileInfo) {
      var basePath, pattern, files;

      if ( _.isString(fileInfo) ) {
        basePath = process.cwd();
        pattern = fileInfo;
      } else if ( _.isObject(fileInfo) ) {
        basePath = fileInfo.basePath || process.cwd();
        pattern = fileInfo.pattern;
      } else {
        throw new Error('Invalid files parameter. ' +
          'You must pass an array of items, each of which is either a string or an object of the form ' +
          '{ pattern: "...", basePath: "..." }');
      }

      files = glob.sync(pattern, { cwd: basePath });

      var docPromises = [];
      _.forEach(files, function(file) {
        _.any(extractors, function(extractor) {
          if ( extractor.pattern.test(file) ) {
            docPromises.push(qfs.read(path.resolve(basePath, file)).then(function(content) {
              return extractor.processFile(file, content, basePath);
            }));
            return true;
          }
        });
      });

      return Q.all(docPromises).then(_.flatten);
    }))

    .then(_.flatten);
  };
};<|endoftext|>