<commit_before>import {
  littleEndian, toBitsStr, fromNumber, fromBitsStr, toFloatStr, fromFloatStr, nextFloat, prevFloat, evalFloatStr
} from './float'
import state from './state'

const $bits = document.getElementById('bits')
const $float = document.getElementById('float')
const $numberList = document.getElementById('number-list')
$numberList.innerHTML = '' // Assure no child nodes
const $byteOrder = document.getElementById('byte-order')
const $bitCount = document.querySelectorAll('input[type=radio]') // Assume 32-bit radio comes first

const numberListHeight = () => $numberList.clientHeight + $numberList.offsetTop

let changeBits = () => {}

const updateChangeBits = (f64) => {
  changeBits = bitsStr => {
    if (bitsStr.length !== (f64 ? 8 : 4) * 8) {
      // Assure correct length and fill with trailing zeros if neccesary
      bitsStr = bitsStr.concat(Array(65).join('0')).slice(0, (f64 ? 8 : 4) * 8)
    }
    set({ fStr: toFloatStr(f64)(fromBitsStr(bitsStr)) })
  }
}

// Init dom state

$byteOrder.innerHTML = `${littleEndian ? 'little' : 'big'} endian`

const classSelected = 'selected'

const clickOnNumber = e => { set({ fStr: e.target.innerText }) }

const createNumberElement = (floatStr, selected) => {
  let div = document.createElement('div')
  div.innerHTML = `<div class="number${selected ? ` ${classSelected}` : ''}">${floatStr}</div>`
  div = div.childNodes[0]
  div.addEventListener('click', clickOnNumber)
  return div
}

const updateNumbers = (f64, bytes) => {
  // Assure there are enough number elments
  while ($numberList.clientHeight < window.innerHeight * 2) {
    $numberList.appendChild(createNumberElement('0'))
  }
  // Set content
  window.scrollTo(0, Math.floor((numberListHeight() - window.innerHeight) / 2)) // Scroll to center of numbers
  const $numbers = $numberList.childNodes
  const centerIdx = Math.floor($numbers.length / 2)
  const fStr = toFloatStr(f64)(bytes)
  $numbers[centerIdx].innerText = fStr
  $numbers[centerIdx].classList.add(classSelected)
  let nbs = bytes
  for (let i = centerIdx + 1; i < $numbers.length; i++) {
    nbs = prevFloat(nbs)
    $numbers[i].innerText = toFloatStr(f64)(nbs)
    $numbers[i].classList.remove(classSelected)
  }
  nbs = bytes
  for (let i = centerIdx - 1; i >= 0; i--) {
    nbs = nextFloat(nbs)
    $numbers[i].innerText = toFloatStr(f64)(nbs)
    $numbers[i].classList.remove(classSelected)
  }
}

const setFloatValue = (() => {
  let previousf64
  let previousEvaledFloatStr
  return (f64, floatStr, evaledFloatStr) => {
    if ($float.value !== floatStr) {
      $float.value = floatStr
    } else if (previousf64 && !f64 && previousEvaledFloatStr !== evaledFloatStr) {
      $float.value = evaledFloatStr
    }
    previousf64 = f64
    previousEvaledFloatStr = evaledFloatStr
  }
})()

const setFloatOrJs = floatStrOrJs => {
  set({ fStr: floatStrOrJs })
}

let applyFloat = () => {}

const updateApplyFloat = f64 => {
  applyFloat = (floatStrOrJs) => {
    const floatStr = evalFloatStr(f64)(floatStrOrJs)
    set({ fStr: floatStr })
  }
}

// Add event listeners
Array.prototype.slice.call($bitCount).forEach((r, i) => {
  r.addEventListener('change', () => { set({ f64: !!i }) }, 0)
})
$float.addEventListener('input', e => { setFloatOrJs(e.target.value) })
$float.addEventListener('keydown', e => {
  if (e.keyCode === 13) { // On Enter
    applyFloat(e.target.value)
  }
})
$bits.addEventListener('input', e => { changeBits(e.target.value) })
$bits.addEventListener('keydown', e => {
  if (e.keyCode === 13) { // On Enter
    changeBits(e.target.value)
  }
})

const getScrollY = () => window.pageYOffset

const scrolled = (up, bytes, f64) => () => {
  const scrollY = getScrollY()
  const height = $numberList.clientHeight // Height of number
  const nbrs = $numberList.childNodes
  const count = Math.round(nbrs.length * 0.25) // Count of numbers to add/remove
  let float = fromFloatStr(f64)((up ? $numberList.firstChild : $numberList.lastChild).innerText)
  const fStrSel = toFloatStr(f64)(bytes)
  // Add some numbers
  for (let i = 0; i < count; i++) {
    float = (up ? nextFloat : prevFloat)(float)
    const fStr = toFloatStr(f64)(float)
    const nbrEl = createNumberElement(fStr, fStrSel === fStr)
    if (up) {
      $numberList.insertBefore(nbrEl, $numberList.firstChild)
    } else {
      $numberList.appendChild(nbrEl)
    }
  }
  const heightDiff = $numberList.clientHeight - height
  // Remove some numbers
  for (let i = 0; i < count; i++) {
    $numberList.removeChild(up ? $numberList.lastChild : $numberList.firstChild)
  }
  const scrollDiff = getScrollY() - scrollY
  const scroll = heightDiff + scrollDiff
  window.scrollBy(0, up ? scroll : -scroll)
}

let scrolledUp = () => {}
let scrolledDown = scrolledUp

const updateScrolled = (bytes, f64) => {
  scrolledUp = scrolled(true, bytes, f64)
  scrolledDown = scrolled(false, bytes, f64)
}

window.addEventListener('scroll', () => {
  if (getScrollY() <= 0) { // Scrolled up
    scrolledUp()
  } else if (getScrollY() + window.innerHeight >= numberListHeight()) { // Scrolled down
    scrolledDown()
  }
})

window.addEventListener('resize', updateNumbers)

;(() => { // Apply styling
  // Center inputs
  const $inputs = document.getElementById('inputs')
  $inputs.style.marginLeft = `-${Math.round($inputs.offsetWidth / 2)}px`
  $inputs.style.marginTop = `-${Math.round($inputs.offsetHeight / 2)}px`
  $inputs.style.left = $inputs.style.top = '50%'
})()

const set = state(({ fStr, f64 }) => { // On state change
  const floatStr = evalFloatStr(f64)(fStr)
  const bytes = fromFloatStr(f64)(floatStr)
  updateChangeBits(f64)
  updateApplyFloat(f64)
  updateScrolled(bytes, f64)
  setFloatValue(f64, fStr, floatStr)
  $bits.value = toBitsStr(bytes)
  $bitCount[+f64].checked = true
  updateNumbers(f64, bytes)
})

set({ fStr: toFloatStr(true)(fromNumber(true)(Math.PI)), f64: true })
<commit_msg>Fix resize handler<commit_after>import {
  littleEndian, toBitsStr, fromNumber, fromBitsStr, toFloatStr, fromFloatStr, nextFloat, prevFloat, evalFloatStr
} from './float'
import state from './state'

const $bits = document.getElementById('bits')
const $float = document.getElementById('float')
const $numberList = document.getElementById('number-list')
$numberList.innerHTML = '' // Assure no child nodes
const $byteOrder = document.getElementById('byte-order')
const $bitCount = document.querySelectorAll('input[type=radio]') // Assume 32-bit radio comes first

const numberListHeight = () => $numberList.clientHeight + $numberList.offsetTop

let changeBits = () => {}

const updateChangeBits = (f64) => {
  changeBits = bitsStr => {
    if (bitsStr.length !== (f64 ? 8 : 4) * 8) {
      // Assure correct length and fill with trailing zeros if neccesary
      bitsStr = bitsStr.concat(Array(65).join('0')).slice(0, (f64 ? 8 : 4) * 8)
    }
    set({ fStr: toFloatStr(f64)(fromBitsStr(bitsStr)) })
  }
}

// Init dom state

$byteOrder.innerHTML = `${littleEndian ? 'little' : 'big'} endian`

const classSelected = 'selected'

const clickOnNumber = e => { set({ fStr: e.target.innerText }) }

const createNumberElement = (floatStr, selected) => {
  let div = document.createElement('div')
  div.innerHTML = `<div class="number${selected ? ` ${classSelected}` : ''}">${floatStr}</div>`
  div = div.childNodes[0]
  div.addEventListener('click', clickOnNumber)
  return div
}

const updateNumbers = (f64, bytes) => {
  // Assure there are enough number elments
  while ($numberList.clientHeight < window.innerHeight * 2) {
    $numberList.appendChild(createNumberElement('0'))
  }
  // Set content
  window.scrollTo(0, Math.floor((numberListHeight() - window.innerHeight) / 2)) // Scroll to center of numbers
  const $numbers = $numberList.childNodes
  const centerIdx = Math.floor($numbers.length / 2)
  const fStr = toFloatStr(f64)(bytes)
  $numbers[centerIdx].innerText = fStr
  $numbers[centerIdx].classList.add(classSelected)
  let nbs = bytes
  for (let i = centerIdx + 1; i < $numbers.length; i++) {
    nbs = prevFloat(nbs)
    $numbers[i].innerText = toFloatStr(f64)(nbs)
    $numbers[i].classList.remove(classSelected)
  }
  nbs = bytes
  for (let i = centerIdx - 1; i >= 0; i--) {
    nbs = nextFloat(nbs)
    $numbers[i].innerText = toFloatStr(f64)(nbs)
    $numbers[i].classList.remove(classSelected)
  }
}

const setFloatValue = (() => {
  let previousf64
  let previousEvaledFloatStr
  return (f64, floatStr, evaledFloatStr) => {
    if ($float.value !== floatStr) {
      $float.value = floatStr
    } else if (previousf64 && !f64 && previousEvaledFloatStr !== evaledFloatStr) {
      $float.value = evaledFloatStr
    }
    previousf64 = f64
    previousEvaledFloatStr = evaledFloatStr
  }
})()

const setFloatOrJs = floatStrOrJs => {
  set({ fStr: floatStrOrJs })
}

let applyFloat = () => {}

const updateApplyFloat = f64 => {
  applyFloat = (floatStrOrJs) => {
    const floatStr = evalFloatStr(f64)(floatStrOrJs)
    set({ fStr: floatStr })
  }
}

// Add event listeners
Array.prototype.slice.call($bitCount).forEach((r, i) => {
  r.addEventListener('change', () => { set({ f64: !!i }) }, 0)
})
$float.addEventListener('input', e => { setFloatOrJs(e.target.value) })
$float.addEventListener('keydown', e => {
  if (e.keyCode === 13) { // On Enter
    applyFloat(e.target.value)
  }
})
$bits.addEventListener('input', e => { changeBits(e.target.value) })
$bits.addEventListener('keydown', e => {
  if (e.keyCode === 13) { // On Enter
    changeBits(e.target.value)
  }
})

const getScrollY = () => window.pageYOffset

const scrolled = (up, bytes, f64) => () => {
  const scrollY = getScrollY()
  const height = $numberList.clientHeight // Height of number
  const nbrs = $numberList.childNodes
  const count = Math.round(nbrs.length * 0.25) // Count of numbers to add/remove
  let float = fromFloatStr(f64)((up ? $numberList.firstChild : $numberList.lastChild).innerText)
  const fStrSel = toFloatStr(f64)(bytes)
  // Add some numbers
  for (let i = 0; i < count; i++) {
    float = (up ? nextFloat : prevFloat)(float)
    const fStr = toFloatStr(f64)(float)
    const nbrEl = createNumberElement(fStr, fStrSel === fStr)
    if (up) {
      $numberList.insertBefore(nbrEl, $numberList.firstChild)
    } else {
      $numberList.appendChild(nbrEl)
    }
  }
  const heightDiff = $numberList.clientHeight - height
  // Remove some numbers
  for (let i = 0; i < count; i++) {
    $numberList.removeChild(up ? $numberList.lastChild : $numberList.firstChild)
  }
  const scrollDiff = getScrollY() - scrollY
  const scroll = heightDiff + scrollDiff
  window.scrollBy(0, up ? scroll : -scroll)
}

let scrolledUp = () => {}
let scrolledDown = scrolledUp

const updateScrolled = (bytes, f64) => {
  scrolledUp = scrolled(true, bytes, f64)
  scrolledDown = scrolled(false, bytes, f64)
}

window.addEventListener('scroll', () => {
  if (getScrollY() <= 0) { // Scrolled up
    scrolledUp()
  } else if (getScrollY() + window.innerHeight >= numberListHeight()) { // Scrolled down
    scrolledDown()
  }
})

let resizedWindow = () => {}

const updateResizedWindow = (f64, bytes) => {
  resizedWindow = () => updateNumbers(f64, bytes)
}

window.addEventListener('resize', () => resizedWindow())

;(() => { // Apply styling
  // Center inputs
  const $inputs = document.getElementById('inputs')
  $inputs.style.marginLeft = `-${Math.round($inputs.offsetWidth / 2)}px`
  $inputs.style.marginTop = `-${Math.round($inputs.offsetHeight / 2)}px`
  $inputs.style.left = $inputs.style.top = '50%'
})()

const set = state(({ fStr, f64 }) => { // On state change
  const floatStr = evalFloatStr(f64)(fStr)
  const bytes = fromFloatStr(f64)(floatStr)
  updateChangeBits(f64)
  updateApplyFloat(f64)
  updateScrolled(bytes, f64)
  updateResizedWindow(f64, bytes)
  setFloatValue(f64, fStr, floatStr)
  $bits.value = toBitsStr(bytes)
  $bitCount[+f64].checked = true
  updateNumbers(f64, bytes)
})

set({ fStr: toFloatStr(true)(fromNumber(true)(Math.PI)), f64: true })
<|endoftext|>


<commit_before>/**
 * @name jsondir
 * @description Convert JSON objects to directories and back again.
 *
 * @author Daniel Imhoff
 */

'use strict';

var ASYNC = require('async');
var FS = require('fs');

var File = require('./File').File;

var knownAttributes = Object.freeze([
  '-name',
  '-type',
  '-path',
  '-mode',
  '-owner',
  '-group',
  '-dest',
  '-content'
]);

var inheritableAttributes = Object.freeze([
  '-mode',
  '-owner',
  '-group'
]);

/**
 * Split up given object into children and valid attributes that are ready for
 * the File constructor.
 *
 * @param  {object} options
 * @param  {object} parentAttributes Normalized attributes of the parent.
 * @return {object}
 */
var normalizeOptions = function(options, parentAttributes) {
  var opts = {
    attributes: {},
    inheritedAttributes: [],
    children: {}
  };

  if (typeof options === 'object') {
    for (var i in options) {
      // If the starting character is a hyphen, the option is an attribute,
      // because having files prepended with a hyphen in Unix is a terrible
      // idea: http://www.dwheeler.com/essays/fixing-unix-linux-filenames.html#dashes
      if (i.indexOf('-') === 0) {
        if (knownAttributes.indexOf(i) === -1) {
          throw new Error("Unknown attribute '" + i + "' in object.");
        }

        // Attributes can have objects as values, for attributes of the attributes,
        // such as inherit. In that case, the value attribute is taken as the value.
        if (typeof options[i] === 'object') {
          if (!('value' in options[i])) {
            throw new Error("Attribute object '" + i + "' needs 'value'.");
          }

          if ('inherit' in options[i] && options[i].inherit) {
            if (inheritableAttributes.indexOf(i) === -1) {
              throw new Error("Unknown inheritable attribute '" + i + "' in object.");
            }

            opts.inheritedAttributes.push(i);
          }

          opts.attributes[i.substring(1)] = options[i].value;
        }
        else {
          opts.attributes[i.substring(1)] = options[i];
        }
      }
      else {
        opts.children[i] = options[i];
      }
    }

    if ('owner' in opts.attributes && opts.attributes.owner !== process.env.USER && opts.attributes.owner !== 'root') {
      throw new Error("Must be run as root if owner differs from you.");
    }

    if (!('path' in opts.attributes)) {
      if (typeof parentAttributes === 'object') {
        opts.attributes.path = parentAttributes.path + File.DIRECTORY_SEPARATOR + opts.attributes.name;
      }
      else {
        opts.attributes.path = '.';
      }
    }

    if (!('type' in opts.attributes)) {
      if ('dest' in opts.attributes) {
        opts.attributes.type = 'l';
      }
      else if (Object.keys(opts.children).length > 0) {
        opts.attributes.type = 'd';
      }
      else {
        opts.attributes.type = '-';
      }
    }
  }

  return opts;
};

/**
 * Converts a formatted, structured object to a directory structure.
 *
 * @param  {object} json
 * @param  {object} options
 * @param  {Function} callback
 */
var json2dir = function(json, options, callback) {
  options = options || {};

  // Keeps track of the number of child keys in the object. When count
  // returns to 0, we know the object has been exhausted.
  var count = 0;

  /**
   * The handler for determining when everything is finished.
   *
   * @param  {Error} err
   */
  var done = function(err) {
    if (err) callback(err);

    if (count === 0) {
      callback();
    }
  };

  /**
   * Recursive function which recurses through the object and asynchronously
   * creates the directory structure based upon normalized options.
   *
   * @param  {object} json
   * @param  {object} parentAttributes
   */
  var _json2dir = function(json, parentAttributes) {
    if (typeof json === 'object') {
      // Validate and normalize the options into children and attributes.
      var options = normalizeOptions(json, parentAttributes),
          childKeys = Object.keys(options.children);

      // First count the number of children.
      count += childKeys.length;

      // Create the File object given the set of attributes parsed which
      // represents the file in question.
      var f = new File(options.attributes);

      f.create(function(err) {
        if (err) done(err);

        // When IO is finished for this file, we mark it as done.
        --count;

        // For each of the children parsed, call this function in parallel.
        ASYNC.each(childKeys, function(name, callback) {
          // normalizeOptions() needs the key of the child object, which is the name.
          options.children[name]['-name'] = name;

          // If there are any inherited attributes of the parent, we need to add
          // them to the child object.
          if (options.inheritedAttributes.length > 0) {
            for (var i in options.inheritedAttributes) {
              options.children[name][options.inheritedAttributes[i]] = { value: options.attributes[options.inheritedAttributes[i].substring(1)], inherit: true };
            }
          }

          // Recurse, given the unnormalized options of the child and normalized
          // attributes of the parent.
          _json2dir(options.children[name], options.attributes);

          // Async has us call callback() to know when this function is done.
          callback();
        }, function(err) {
          if (err) done(err);
          done();
        });
      });
    }
  };

  _json2dir(json);
};

/**
 * Converts a given directory structure to a formatted, structured object.
 *
 * @param  {string} path
 * @param  {object} options
 * @param  {Function} callback
 */
var dir2json = function(path, options, callback) {
  options = options || {};

  var json = {
    "-path": path
  };

  var done = function(err) {
    if (err) callback(err);

    if (typeof callback === 'function') {
      callback(null, json);
    }
  };

  var _dir2json = function(json) {
    console.log("new File object from file at " + json['-path']);
    var f = new File({
      path: json['-path']
    });

    if (f.type === File.Types.directory) {
      FS.readdir(f.path, function(err, files) {
        if (err) done(err);

        if (files.length === 0) {
          done();
        }
        else {
          ASYNC.each(files, function(name, callback) {
            json[name] = {
              "-path": json['-path'] + File.DIRECTORY_SEPARATOR + name
            };
            _dir2json(json[name]);
            callback();
          }, function(err) {
            if (err) done(err);
            done();
          });
        }
      });
    }
  };

  _dir2json(json);
};

dir2json("output", {}, function(err, results) {
  if (err) throw err;
  console.log(results);
});

module.exports = {
  json2dir: json2dir,
  dir2json: dir2json
};
<commit_msg>fixed _dir2json!<commit_after>/**
 * @name jsondir
 * @description Convert JSON objects to directories and back again.
 *
 * @author Daniel Imhoff
 */

'use strict';

var ASYNC = require('async');
var FS = require('fs');

var File = require('./File').File;

var knownAttributes = Object.freeze([
  '-name',
  '-type',
  '-path',
  '-mode',
  '-owner',
  '-group',
  '-dest',
  '-content'
]);

var inheritableAttributes = Object.freeze([
  '-mode',
  '-owner',
  '-group'
]);

/**
 * Split up given object into children and valid attributes that are ready for
 * the File constructor.
 *
 * @param  {object} options
 * @param  {object} parentAttributes Normalized attributes of the parent.
 * @return {object}
 */
var normalizeOptions = function(options, parentAttributes) {
  var opts = {
    attributes: {},
    inheritedAttributes: [],
    children: {}
  };

  if (typeof options === 'object') {
    for (var i in options) {
      // If the starting character is a hyphen, the option is an attribute,
      // because having files prepended with a hyphen in Unix is a terrible
      // idea: http://www.dwheeler.com/essays/fixing-unix-linux-filenames.html#dashes
      if (i.indexOf('-') === 0) {
        if (knownAttributes.indexOf(i) === -1) {
          throw new Error("Unknown attribute '" + i + "' in object.");
        }

        // Attributes can have objects as values, for attributes of the attributes,
        // such as inherit. In that case, the value attribute is taken as the value.
        if (typeof options[i] === 'object') {
          if (!('value' in options[i])) {
            throw new Error("Attribute object '" + i + "' needs 'value'.");
          }

          if ('inherit' in options[i] && options[i].inherit) {
            if (inheritableAttributes.indexOf(i) === -1) {
              throw new Error("Unknown inheritable attribute '" + i + "' in object.");
            }

            opts.inheritedAttributes.push(i);
          }

          opts.attributes[i.substring(1)] = options[i].value;
        }
        else {
          opts.attributes[i.substring(1)] = options[i];
        }
      }
      else {
        opts.children[i] = options[i];
      }
    }

    if ('owner' in opts.attributes && opts.attributes.owner !== process.env.USER && opts.attributes.owner !== 'root') {
      throw new Error("Must be run as root if owner differs from you.");
    }

    if (!('path' in opts.attributes)) {
      if (typeof parentAttributes === 'object') {
        opts.attributes.path = parentAttributes.path + File.DIRECTORY_SEPARATOR + opts.attributes.name;
      }
      else {
        opts.attributes.path = '.';
      }
    }

    if (!('type' in opts.attributes)) {
      if ('dest' in opts.attributes) {
        opts.attributes.type = 'l';
      }
      else if (Object.keys(opts.children).length > 0) {
        opts.attributes.type = 'd';
      }
      else {
        opts.attributes.type = '-';
      }
    }
  }

  return opts;
};

/**
 * Converts a formatted, structured object to a directory structure.
 *
 * @param  {object} json
 * @param  {object} options
 * @param  {Function} callback
 */
var json2dir = function(json, options, callback) {
  options = options || {};

  // Keeps track of the number of child keys in the object. When count
  // returns to 0, we know the object has been exhausted.
  var count = 0;

  /**
   * The handler for determining when everything is finished.
   *
   * @param  {Error} err
   */
  var done = function(err) {
    if (err) return callback(err);

    if (count === 0) {
      return callback();
    }
  };

  /**
   * Recursive function which recurses through the object and asynchronously
   * creates the directory structure based upon normalized options.
   *
   * @param  {object} json
   * @param  {object} parentAttributes
   */
  var _json2dir = function(json, parentAttributes) {
    if (typeof json === 'object') {
      // Validate and normalize the options into children and attributes.
      var options = normalizeOptions(json, parentAttributes),
          childKeys = Object.keys(options.children);

      // First count the number of children.
      count += childKeys.length;

      // Create the File object given the set of attributes parsed which
      // represents the file in question.
      var f = new File(options.attributes);

      f.create(function(err) {
        if (err) return done(err);

        // When IO is finished for this file, we mark it as done.
        --count;

        // For each of the children parsed, call this function in parallel.
        ASYNC.each(childKeys, function(name, callback) {
          // normalizeOptions() needs the key of the child object, which is the name.
          options.children[name]['-name'] = name;

          // If there are any inherited attributes of the parent, we need to add
          // them to the child object.
          if (options.inheritedAttributes.length > 0) {
            for (var i in options.inheritedAttributes) {
              options.children[name][options.inheritedAttributes[i]] = { value: options.attributes[options.inheritedAttributes[i].substring(1)], inherit: true };
            }
          }

          // Recurse, given the unnormalized options of the child and normalized
          // attributes of the parent.
          _json2dir(options.children[name], options.attributes);

          // Async has us call callback() to know when this function is done.
          callback();
        }, function(err) {
          if (err) return done(err);
          done();
        });
      });
    }
  };

  _json2dir(json);
};

/**
 * Converts a given directory structure to a formatted, structured object.
 *
 * @param  {string} path
 * @param  {object} options
 * @param  {Function} callback
 */
var dir2json = function(path, options, callback) {
  options = options || {};

  var json = {
    "-path": path
  };

  var _dir2json = function(jsonPart, done) {
    FS.readdir(jsonPart['-path'], function(err, results) {
      if (err) return done(err);

      var pending = results.length;

      if (pending === 0) return done(null, json);

      results.forEach(function(file) {
        jsonPart[file] = {
          "-path": jsonPart['-path'] + File.DIRECTORY_SEPARATOR + file
        };

        var options = normalizeOptions(jsonPart[file]);
        var f = new File(options.attributes);

        if (f.type === File.Types.directory) {
          _dir2json(jsonPart[file], function(err) {
            if (--pending === 0) return done(null, json);
          });
        }
        else {
          if (--pending === 0) return done(null, json);
        }
      });
    });
  };

  _dir2json(json, function(err, results) {
    if (err) return callback(err);
    callback(null, results);
  });
};

dir2json("output", {}, function(err, results) {
  if (err) throw err;
  console.log(results);
});

module.exports = {
  json2dir: json2dir,
  dir2json: dir2json
};
<|endoftext|>


<commit_before>import Helper from '@ember/component/helper';
import moment from 'moment';
import {assert} from '@ember/debug';
import {inject as service} from '@ember/service';

export function formatPostTime(timeago, {timezone = 'ect/UTC', draft, scheduled, published}) {
    if (draft) {
        // No special handling for drafts, just use moment.from
        return moment(timeago).from(moment.utc());
    }

    let time = moment.tz(timeago, timezone);
    let now = moment.tz(moment.utc(), timezone);

    let utcOffset;
    if (time.utcOffset() === 0) {
        utcOffset = '(UTC)';
    } else {
        utcOffset = `(UTC${time.format('Z').replace(/([+-])0/, '$1').replace(/:00/, '')})`;
    }

    // If not a draft and post was published <= 12 hours ago
    // or scheduled to be published <= 12 hours from now, use moment.from
    if (Math.abs(now.diff(time, 'hours')) <= 12) {
        return time.from(now);
    }

    // If scheduled for or published on the same day, render the time + Today
    if (time.isSame(now, 'day')) {
        let formatted = time.format(`HH:mm [${utcOffset}] [Today]`);
        return scheduled ? `at ${formatted}` : formatted;
    }

    // if published yesterday, render time + yesterday
    // This check comes before scheduled, because there are likely to be more published
    // posts than scheduled posts.
    if (published && time.isSame(now.clone().subtract(1, 'days').startOf('day'), 'day')) {
        return time.format(`HH:mm [${utcOffset}] [Yesterday]`);
    }

    // if scheduled for tomorrow, render the time + tomorrow
    if (scheduled && time.isSame(now.clone().add(1, 'days').startOf('day'), 'day')) {
        return time.format(`[at] HH:mm [${utcOffset}] [tomorrow]`);
    }

    // Else, render just the date if published, or the time & date if scheduled
    let format = scheduled ? `[at] HH:mm [${utcOffset}] [on] DD MMM YYYY` : 'DD MMM YYYY';
    return time.format(format);
}

export default class GhFormatPostTimeHelper extends Helper {
    @service settings;

    compute([timeago], options) {
        assert('You must pass a time to the gh-format-post-time helper', timeago);

        return formatPostTime(timeago, Object.assign({}, options, {timezone: this.settings.get('timezone')}));
    }
}
<commit_msg>Fixed typo in default UTC timezone of `{{gh-format-post-time}}` helper<commit_after>import Helper from '@ember/component/helper';
import moment from 'moment';
import {assert} from '@ember/debug';
import {inject as service} from '@ember/service';

export function formatPostTime(timeago, {timezone = 'etc/UTC', draft, scheduled, published}) {
    if (draft) {
        // No special handling for drafts, just use moment.from
        return moment(timeago).from(moment.utc());
    }

    let time = moment.tz(timeago, timezone);
    let now = moment.tz(moment.utc(), timezone);

    let utcOffset;
    if (time.utcOffset() === 0) {
        utcOffset = '(UTC)';
    } else {
        utcOffset = `(UTC${time.format('Z').replace(/([+-])0/, '$1').replace(/:00/, '')})`;
    }

    // If not a draft and post was published <= 12 hours ago
    // or scheduled to be published <= 12 hours from now, use moment.from
    if (Math.abs(now.diff(time, 'hours')) <= 12) {
        return time.from(now);
    }

    // If scheduled for or published on the same day, render the time + Today
    if (time.isSame(now, 'day')) {
        let formatted = time.format(`HH:mm [${utcOffset}] [Today]`);
        return scheduled ? `at ${formatted}` : formatted;
    }

    // if published yesterday, render time + yesterday
    // This check comes before scheduled, because there are likely to be more published
    // posts than scheduled posts.
    if (published && time.isSame(now.clone().subtract(1, 'days').startOf('day'), 'day')) {
        return time.format(`HH:mm [${utcOffset}] [Yesterday]`);
    }

    // if scheduled for tomorrow, render the time + tomorrow
    if (scheduled && time.isSame(now.clone().add(1, 'days').startOf('day'), 'day')) {
        return time.format(`[at] HH:mm [${utcOffset}] [tomorrow]`);
    }

    // Else, render just the date if published, or the time & date if scheduled
    let format = scheduled ? `[at] HH:mm [${utcOffset}] [on] DD MMM YYYY` : 'DD MMM YYYY';
    return time.format(format);
}

export default class GhFormatPostTimeHelper extends Helper {
    @service settings;

    compute([timeago], options) {
        assert('You must pass a time to the gh-format-post-time helper', timeago);

        return formatPostTime(timeago, Object.assign({}, options, {timezone: this.settings.get('timezone')}));
    }
}
<|endoftext|>


<commit_before>import React, {PureComponent} from 'react';
import {Image as RNImage} from 'react-native';
import PropTypes from 'prop-types';
import Svg, {Defs, G, Rect, Path, Image, ClipPath, LinearGradient, Stop} from 'react-native-svg';
import genMatrix from './genMatrix';

const DEFAULT_SIZE = 100;
const DEFAULT_BG_COLOR = 'white';

/* calculate the size of the cell and draw the path */
function calculateMatrix(props) {
  const {value, size, ecl, onError} = props;
  try {
    const matrix = genMatrix(value, ecl);
    const cellSize = size / matrix.length;
    return {
      value,
      size,
      cellSize,
      path: transformMatrixIntoPath(cellSize, matrix)
    };
  } catch (error) {
    if (onError && typeof onError === 'function') {
      onError(error);
    } else {
      // Pass the error when no handler presented
      throw error;
    }
  }
  return {};
}

/* project the matrix into path draw */
function transformMatrixIntoPath(cellSize, matrix) {
  // adjust origin
  let d = '';
  matrix.forEach((row, i) => {
    let needDraw = false;
    row.forEach((column, j) => {
      if (column) {
        if (!needDraw) {
          d += `M${cellSize * j} ${cellSize / 2 + cellSize * i} `;
          needDraw = true;
        }
        if (needDraw && j === matrix.length - 1) {
          d += `L${cellSize * (j + 1)} ${cellSize / 2 + cellSize * i} `;
        }
      } else {
        if (needDraw) {
          d += `L${cellSize * j} ${cellSize / 2 + cellSize * i} `;
          needDraw = false;
        }
      }
    });
  });
  return d;
}

/**
 * A simple component for displaying QR Code using svg
 */
export default class QRCode extends PureComponent {
  static propTypes = {
    /* what the qr code stands for */
    value: PropTypes.string,
    /* the whole component size */
    size: PropTypes.number,
    /* the color of the cell */
    color: PropTypes.string,
    /* the color of the background */
    backgroundColor: PropTypes.string,
    /* an image source object. example {uri: 'base64string'} or {require('pathToImage')} */
    logo: RNImage.propTypes.source,
    /* logo size in pixels */
    logoSize: PropTypes.number,
    /* the logo gets a filled rectangular background with this color. Use 'transparent'
         if your logo already has its own backdrop. Default = same as backgroundColor */
    logoBackgroundColor: PropTypes.string,
    /* logo's distance to its wrapper */
    logoMargin: PropTypes.number,
    /* the border-radius of logo image */
    logoBorderRadius: PropTypes.number,
    /* get svg ref for further usage */
    getRef: PropTypes.func,
    /* error correction level */
    ecl: PropTypes.oneOf(['L', 'M', 'Q', 'H']),
    /* Callback function that's called in case if any errors
     * appeared during the process of code generating.
     * Error object is passed to the callback.
     */
    onError: PropTypes.func
  };

  static defaultProps = {
    value: 'This is a QR Code.',
    size: DEFAULT_SIZE,
    color: 'black',
    backgroundColor: DEFAULT_BG_COLOR,
    logoSize: DEFAULT_SIZE * 0.2,
    logoBackgroundColor: DEFAULT_BG_COLOR,
    logoMargin: 2,
    logoBorderRadius: 0,
    ecl: 'M',
    onError: undefined,
    gradientDirection:[170,0,0,0],
    linearGradient:['rgb(255,0,0)','rgb(0,255,255)'],
    enableLinearGradient:false,
  };

  constructor(props) {
    super(props);
    this.state = calculateMatrix(props);
  }

  static getDerivedStateFromProps(props, state) {
    // if value has changed, re-calculateMatrix
    if (props.value !== state.value || props.size !== state.size) {
      return calculateMatrix(props);
    }
    return null;
  }

  render() {
    const {
      getRef,
      size,
      color,
      backgroundColor,
      logo,
      logoSize,
      logoMargin,
      logoBackgroundColor,
      logoBorderRadius,
      enableLinearGradient,
    } = this.props;

    const logoPosition = size / 2 - logoSize / 2 - logoMargin;
    const logoWrapperSize = logoSize + logoMargin * 2;
    const logoWrapperBorderRadius =
      logoBorderRadius + (logoBorderRadius && logoMargin);
    const {cellSize, path} = this.state;

    return (
      <Svg ref={getRef} width={size} height={size}>
        <Defs>
          <ClipPath id="clip-wrapper">
            <Rect
              width={logoWrapperSize}
              height={logoWrapperSize}
              rx={logoWrapperBorderRadius}
              ry={logoWrapperBorderRadius}
            />
          </ClipPath>
          <ClipPath id="clip-logo">
            <Rect
              width={logoSize}
              height={logoSize}
              rx={logoBorderRadius}
              ry={logoBorderRadius}
            />
          </ClipPath>
          <LinearGradient id="grad" x1={this.props.gradientDirection[0]} y1={this.props.gradientDirection[1]} x2={this.props.gradientDirection[2]} y2={this.props.gradientDirection[3]}>
            <Stop offset="0" stopColor={this.props.linearGradient[0]} stopOpacity="1" />
            <Stop offset="1" stopColor={this.props.linearGradient[1]} stopOpacity="1" />
          </LinearGradient>

        </Defs>
        <Rect width={size} height={size} fill={backgroundColor} />
          {path && cellSize && (
              <Path d={path} stroke={enableLinearGradient ? "url(#grad)" : color} strokeWidth={cellSize} />
          )}
        {logo && (
          <G x={logoPosition} y={logoPosition}>
            <Rect
              width={logoWrapperSize}
              height={logoWrapperSize}
              fill={logoBackgroundColor}
              clipPath="url(#clip-wrapper)"
            />
            <G x={logoMargin} y={logoMargin}>
              <Image
                width={logoSize}
                height={logoSize}
                preserveAspectRatio="xMidYMid slice"
                href={logo}
                clipPath="url(#clip-logo)"
              />
            </G>
          </G>
        )}
      </Svg>
    );
  }
}
<commit_msg>Update `linearGradient`<commit_after>import React, { PureComponent } from 'react'
import { Image as RNImage } from 'react-native'
import PropTypes from 'prop-types'
import Svg, {
  Defs,
  G,
  Rect,
  Path,
  Image,
  ClipPath,
  LinearGradient,
  Stop
} from 'react-native-svg'
import genMatrix from './genMatrix'

const DEFAULT_SIZE = 100
const DEFAULT_BG_COLOR = 'white'

/* calculate the size of the cell and draw the path */
function calculateMatrix (props) {
  const { value, size, ecl, onError } = props
  try {
    const matrix = genMatrix(value, ecl)
    const cellSize = size / matrix.length
    return {
      value,
      size,
      cellSize,
      path: transformMatrixIntoPath(cellSize, matrix)
    }
  } catch (error) {
    if (onError && typeof onError === 'function') {
      onError(error)
    } else {
      // Pass the error when no handler presented
      throw error
    }
  }
  return {}
}

/* project the matrix into path draw */
function transformMatrixIntoPath (cellSize, matrix) {
  // adjust origin
  let d = ''
  matrix.forEach((row, i) => {
    let needDraw = false
    row.forEach((column, j) => {
      if (column) {
        if (!needDraw) {
          d += `M${cellSize * j} ${cellSize / 2 + cellSize * i} `
          needDraw = true
        }
        if (needDraw && j === matrix.length - 1) {
          d += `L${cellSize * (j + 1)} ${cellSize / 2 + cellSize * i} `
        }
      } else {
        if (needDraw) {
          d += `L${cellSize * j} ${cellSize / 2 + cellSize * i} `
          needDraw = false
        }
      }
    })
  })
  return d
}

/**
 * A simple component for displaying QR Code using svg
 */
export default class QRCode extends PureComponent {
  static propTypes = {
    /* what the qr code stands for */
    value: PropTypes.string,
    /* the whole component size */
    size: PropTypes.number,
    /* the color of the cell */
    color: PropTypes.string,
    /* the color of the background */
    backgroundColor: PropTypes.string,
    /* an image source object. example {uri: 'base64string'} or {require('pathToImage')} */
    logo: RNImage.propTypes.source,
    /* logo size in pixels */
    logoSize: PropTypes.number,
    /* the logo gets a filled rectangular background with this color. Use 'transparent'
         if your logo already has its own backdrop. Default = same as backgroundColor */
    logoBackgroundColor: PropTypes.string,
    /* logo's distance to its wrapper */
    logoMargin: PropTypes.number,
    /* the border-radius of logo image */
    logoBorderRadius: PropTypes.number,
    /* get svg ref for further usage */
    getRef: PropTypes.func,
    /* error correction level */
    ecl: PropTypes.oneOf(['L', 'M', 'Q', 'H']),
    /* Callback function that's called in case if any errors
     * appeared during the process of code generating.
     * Error object is passed to the callback.
     */
    onError: PropTypes.func
  }

  static defaultProps = {
    value: 'This is a QR Code.',
    size: DEFAULT_SIZE,
    color: 'black',
    backgroundColor: DEFAULT_BG_COLOR,
    logoSize: DEFAULT_SIZE * 0.2,
    logoBackgroundColor: DEFAULT_BG_COLOR,
    logoMargin: 2,
    logoBorderRadius: 0,
    ecl: 'M',
    onError: undefined,
    gradientDirection: ['0%', '0%', '100%', '100%'],
    linearGradient: ['rgb(255,0,0)', 'rgb(0,255,255)'],
    enableLinearGradient: false
  }

  constructor (props) {
    super(props)
    this.state = calculateMatrix(props)
  }

  static getDerivedStateFromProps (props, state) {
    // if value has changed, re-calculateMatrix
    if (props.value !== state.value || props.size !== state.size) {
      return calculateMatrix(props)
    }
    return null
  }

  render () {
    const {
      getRef,
      size,
      color,
      backgroundColor,
      logo,
      logoSize,
      logoMargin,
      logoBackgroundColor,
      logoBorderRadius,
      gradientDirection,
      linearGradient,
      enableLinearGradient
    } = this.props

    const logoPosition = size / 2 - logoSize / 2 - logoMargin
    const logoWrapperSize = logoSize + logoMargin * 2
    const logoWrapperBorderRadius =
      logoBorderRadius + (logoBorderRadius && logoMargin)
    const { cellSize, path } = this.state

    return (
      <Svg ref={getRef} width={size} height={size}>
        <Defs>
          <ClipPath id='clip-wrapper'>
            <Rect
              width={logoWrapperSize}
              height={logoWrapperSize}
              rx={logoWrapperBorderRadius}
              ry={logoWrapperBorderRadius}
            />
          </ClipPath>
          <ClipPath id='clip-logo'>
            <Rect
              width={logoSize}
              height={logoSize}
              rx={logoBorderRadius}
              ry={logoBorderRadius}
            />
          </ClipPath>
          <LinearGradient
            id='grad'
            x1={gradientDirection[0]}
            y1={gradientDirection[1]}
            x2={gradientDirection[2]}
            y2={gradientDirection[3]}
          >
            <Stop offset='0' stopColor={linearGradient[0]} stopOpacity='1' />
            <Stop offset='1' stopColor={linearGradient[1]} stopOpacity='1' />
          </LinearGradient>
        </Defs>
        <Rect width={size} height={size} fill={backgroundColor} />
        {path && cellSize && (
          <Path
            d={path}
            stroke={enableLinearGradient ? 'url(#grad)' : color}
            strokeWidth={cellSize}
          />
        )}
        {logo && (
          <G x={logoPosition} y={logoPosition}>
            <Rect
              width={logoWrapperSize}
              height={logoWrapperSize}
              fill={logoBackgroundColor}
              clipPath='url(#clip-wrapper)'
            />
            <G x={logoMargin} y={logoMargin}>
              <Image
                width={logoSize}
                height={logoSize}
                preserveAspectRatio='xMidYMid slice'
                href={logo}
                clipPath='url(#clip-logo)'
              />
            </G>
          </G>
        )}
      </Svg>
    )
  }
}
<|endoftext|>


<commit_before>/**
 * Created by isc on 12/05/15.
 */
angular.module('myApp.controllers')
	.controller('EvidenceCtrl', ['$document', '$sce', '$scope', '$http',
		'defaults', '$controller', 'Session', '$rootScope', 'camomileService',

		function ($document, $sce, $scope, $http, defaults, $controller, Session, $rootScope, camomileService) {

			/*import MissPlete from './MissPlete.js';

        	new MissPlete({
            	input: document.querySelector('input[name="entry_input"]'),

            	options: [["Barcelona", "BCN"], ["San Francisco", "SF"]]
        	});*/

			$controller('CommonCtrl', {
				$scope: $scope,
				$http: $http,
				defaults: defaults,
				Session: Session
			});

			$scope.model.incomingQueue = $rootScope.queues.evidenceIn;
			$scope.model.outgoingQueue = $rootScope.queues.evidenceOut;

			$scope.model.q = {};

			$scope.model.user_input = {};

			$scope.model.updateIsDisplayedVideo = function (activate) {
				$scope.model.isDisplayedVideo = activate;
			};

			// initialize page state
			$scope.model.updateIsDisplayedVideo(false);

			var _getVideo = function (id_medium, callback) {

				if ($scope.model.useDefaultVideoPath) {
					callback(null, $sce.trustAsResourceUrl(camomileService.getMediumURL(id_medium, 'webm')));
				} else {
					camomileService.getMedium(id_medium, function (err, medium) {
						callback(err, $sce.trustAsResourceUrl($scope.model.videoPath + '/' + medium.url + '.mp4'));
					});
				}
			};

			// Initializes the data from the queue
			// rename from "initQueueData" to "popQueueElement"
			$scope.model.popQueueElement = function () {

				// Get queue first element and pop it from the queue
				camomileService.dequeue($scope.model.incomingQueue, function (err, item) {

					if (err) {
						alert(item.error);
						$scope.$apply(function () {
							$scope.model.video = undefined;
							$scope.model.isDisplayedVideo = false;
							$scope.model.updateIsDisplayedVideo(false);
						});

						return;
					}

					//$scope.model.resetTransparentPlan();
					$scope.model.updateIsDisplayedVideo(true);

					if (item.modality === "pronounced") {
						document.getElementById("message").innerHTML = "WARNING: The person name might be pronounced !";
					}

					$scope.model.q = item;
					$scope.model.user_input.person_name = $scope.model.q.person_name;
					$scope.model.initialData = $scope.model.q.person_name;

					// Update the add entry button's status
					$scope.model.updateIsDisplayedVideo($scope.model.user_input.person_name != "");

					async.parallel({
							video: function (callback) {
								_getVideo($scope.model.q.medium_id, callback);
							},
							serverDate: function (callback) {
								camomileService.getDate(function (err, data) {
									callback(null, data.date);
								});
							}
						},
						function (err, results) {
							$scope.model.video = results.video;
							$scope.model.serverDate = results.serverDate;
							$scope.model.clientDate = Date.now();

							$scope.model.restrict_toggle = 2;
							$scope.model.current_time_temp = $scope.model.q.t;
							$scope.model.infbndsec = parseFloat($scope.model.q.t || 0);
							$scope.model.infbndsec-=5.0;
							if ($scope.model.infbndsec < 0) {
								$scope.model.infbndsec = 0;
							}
							$scope.model.supbndsec = parseFloat($scope.model.q.t || 0);
							$scope.model.supbndsec+=5.0;
							if ($scope.model.supbndsec > $scope.model.fullDuration) {
								$scope.model.supbndsec = $scope.model.fullDuration;
							}
							$scope.model.duration = $scope.model.supbndsec - $scope.model.infbndsec;

							$scope.$apply(function () {
								$scope.model.current_time = $scope.model.q.t;
							});

						});
				});
			};

			// Event launched when click on the save button.
			$scope.model.saveQueueElement = function (isEvidence) {

				if (isEvidence == "" && document.getElementById('evidence').src === "") {
					document.getElementById("message").innerHTML = "Please draw a bounding box around the face.";
				}

				var item = {};

				item.log = {};
				item.log.user = Session.username;
				item.log.date = $scope.model.serverDate;
				item.log.duration = Date.now() - $scope.model.clientDate;
				/*camomileService.me(function(callback){
					item.log.user_id = _id;
				});*/

				item.input = {};
				item.input.corpus_id = $scope.model.q.corpus_id;
				item.input.medium_id = $scope.model.q.medium_id;
				item.input.modality = $scope.model.q.modality;
				item.input.person_name = $scope.model.initialData;
				item.input.t = $scope.model.q.t;

				var b_box = {};
				b_box.w = parseFloat(document.getElementById("Wbox").value);
				b_box.h = parseFloat(document.getElementById("Hbox").value);
				b_box.x = parseFloat(document.getElementById("Xbox").value);
				b_box.y = parseFloat(document.getElementById("Ybox").value);

				item.output = {};
				item.output.status = isEvidence;
				if (isEvidence == "yes") {
					item.output.person_name = $scope.model.user_input.person_name;
					item.output.t = $scope.model.current_time;
					item.output.image = document.getElementById('evidence').src;
					item.output.bounding_box = b_box;
				}

				document.getElementById('evidenceImages').style.display = "none";
				document.getElementById('evidence').src = "";
				document.getElementById('draw').children[0].width = document.getElementById('draw').children[0].width;
				document.getElementById("Wbox").value = "";
				document.getElementById("Hbox").value = "";
				document.getElementById("Xbox").value = "";
				document.getElementById("Ybox").value = "";
				document.getElementById("message").innerHTML = "";

				camomileService.enqueue($scope.model.outgoingQueue, item, function (err, data) {

					if (err) {
						console.log("Something went wrong");
					} else {
						$scope.model.popQueueElement();
					}

				});
			};

			$document.on(
				"keydown",
				function (event) {
					var targetID = event.target.id;
					var button_checked = false;
					if (targetID == 'confirm' || targetID == 'cancel') {
						button_checked = true;
					}
					//enter
					if (event.keyCode == 13 && targetID != 'localServerInput') {
						//If the focus is on the check buttons, blur the focus first
						if (button_checked) {
							event.target.blur();
						}
						$scope.$apply(function () {
							$scope.model.saveQueueElement(true);
						});
					}
					//space
					if (event.keyCode == 32 && targetID != "entry_input") {
						if (button_checked) {
							event.target.blur();
						}
						$scope.$apply(function () {
							$scope.model.toggle_play();
						});
					}
					//esc-> skip
					if (event.keyCode == 27) {
						$scope.$apply(function () {
							//skip
							$scope.model.saveQueueElement(false);
						});
					}
					//Left
					if (event.keyCode == 37) {
						$scope.$apply(function () {
							if ($scope.model.current_time - 0.04 > $scope.model.infbndsec) {
								$scope.model.current_time = $scope.model.current_time - 0.04;
							} else {
								$scope.model.current_time = $scope.model.infbndsec;
							}
						});
					}
					//Right
					if (event.keyCode == 39) {
						$scope.$apply(function () {
							if ($scope.model.current_time + 0.04 < $scope.model.supbndsec) {
								$scope.model.current_time = $scope.model.current_time + 0.04;
							} else {
								$scope.model.current_time = $scope.model.supbndsec;
							}
						});
					}
					//Up
					if (event.keyCode == 38) {
						$scope.$apply(function () {
							if ($scope.model.current_time - 1 > $scope.model.infbndsec) {
								$scope.model.current_time = $scope.model.current_time - 1;
							} else {
								$scope.model.current_time = $scope.model.infbndsec;
							}
						});

					} //Down
					if (event.keyCode == 40) {
						$scope.$apply(function () {

							if ($scope.model.current_time + 1 < $scope.model.supbndsec) {
								$scope.model.current_time = $scope.model.current_time + 1;
							} else {
								$scope.model.current_time = $scope.model.supbndsec;
							}
						});
					}
				}
			);

		}
	]);

angular.module('myApp.controllers').directive('drawing', function(){
  return {
    restrict: 'E',
    scope: { localRectangles: '=rectangleList' },
    template: '<canvas class="drawing"></canvas>',
    link: function(scope, element){
    	// There are 3 canvas, one used to determine the zone to copy
    	// another one to extract the image and clip it, the last one to resize the image
      var canvasElement = element.children()[0];
      var ctx = canvasElement.getContext('2d');
      var canvasB = document.getElementById("recup");
      var ctxb = canvasB.getContext('2d');
      var canvasE = document.getElementById("evid");
      var ctxe = canvasE.getContext('2d');

      // The first canvas can be sized at the beginning
      canvasElement.width = document.getElementById("video-container").offsetWidth;
      canvasElement.height = document.getElementById("video-container").offsetHeight;

      // Are we drawing?
      var drawing = false;

      // the last coordinates before the current move
      var centerX;
      var centerY;

      element.children()[0].addEventListener('mousedown', function(event){
        reset();
        startX = event.offsetX;
        startY = event.offsetY;
        document.getElementById("player").pause();

        // begins new line
        ctx.beginPath();

        drawing = true;
      },false);

	  element.children()[0].addEventListener('mousemove', function(event){

        if(drawing){

        //document.getElementById('evid').style.display = "none";
        document.getElementById('evidenceImages').style.display = "none";

          // get current mouse position
          currentX = event.offsetX;
          currentY = event.offsetY;

          if((startX<currentX && startY<currentY) || (startX>currentX && startY>currentY)){
          	if(Math.abs(currentY-startY)<Math.abs(currentX-startX)) currentX = currentY-startY+startX;
          	else currentY = currentX-startX+startY;
          }
          else{
          	if(Math.abs(currentY-startY)<Math.abs(currentX-startX)) currentX = startY-currentY+startX;
          	else currentY = startX-currentX+startY;
    	  }

          // limit all the rectangle within the canvas and draw
          if(currentX >= 0 && currentX <= 360*document.getElementById('player').videoWidth/document.getElementById('player').videoHeight && currentY >= 0 && currentY <= 360){
            draw(startX, startY, currentX, currentY);
          }
        }

      },false);

      // canvas reset
      function reset(){
      	// This simple operation reset the canvas
       canvasElement.width = canvasElement.width;
       canvasB.width = canvasB.width;
       canvasE.width = canvasE.width;
      }

      element.children()[0].addEventListener('mouseup', function(event){
        // stop drawing
        drawing = false;
        //document.getElementById('evid').style.display = "";
        document.getElementById('evidenceImages').style.display = "inline-block";
      },false);

      function draw(startX, startY,
                    currentX, currentY, rotate){

        reset();
        var sizeX = currentX - startX;
        var sizeY = currentY - startY;

        ctx.rect(Math.min(startX,currentX),
                 Math.min(startY,currentY),
                 Math.abs(sizeX), Math.abs(sizeY));
        ctx.lineWidth = 3;
        // color gradient
        /*var gradient=ctx.createLinearGradient(Math.min(oppositeX,currentX),Math.min(oppositeY,currentY),Math.max(oppositeX,currentX),Math.max(oppositeY,currentY));
        gradient.addColorStop("0.05","red");
        gradient.addColorStop("0.15","blue");
        gradient.addColorStop("0.25","red");
        gradient.addColorStop("0.35","blue");
        gradient.addColorStop("0.45","red");
        gradient.addColorStop("0.55","blue");
        gradient.addColorStop("0.65","red");
        gradient.addColorStop("0.75","blue");
        gradient.addColorStop("0.85","red");
        gradient.addColorStop("0.95","blue");
        ctx.strokeStyle = gradient;*/
        // color
        ctx.strokeStyle = 'red';
        // draw it
        ctx.stroke();
        // Launch the copy process
        copy(Math.min(startX,currentX),Math.min(startY,currentY),Math.abs(sizeX),Math.abs(sizeY));
        document.getElementById("Xbox").value = Math.min(startX,currentX)/(360*document.getElementById('player').videoWidth/document.getElementById('player').videoHeight);
        document.getElementById("Ybox").value = Math.min(startY,currentY)/360;
        document.getElementById("Wbox").value = Math.abs(sizeX)/(360*document.getElementById('player').videoWidth/document.getElementById('player').videoHeight);
        document.getElementById("Hbox").value = Math.abs(sizeY)/360;
      }

      function copy(X, Y, sizeX, sizeY){

      	// Get the video source and size the second canvas according to the dimension (16:9 or 4:3)
        var src = document.getElementById('player');
        canvasB.width = 360*src.videoWidth/src.videoHeight;
        canvasB.height = 360;
        // Copy the image
        ctxb.drawImage(src,0,0,canvasB.width,canvasB.height);
        // Clip the image
        var btmp = ctxb.getImageData(X, Y, sizeX, sizeY);
        // Clear the second canvas to put the part of the image we want
        ctxb.clearRect(0,0,canvasB.width,canvasB.height);
        ctxb.putImageData(btmp,0,0);
        // Size of the last canvas
        canvasE.width = sizeX;
        canvasE.height = sizeY;
        // Copy from the second canvas to the third
        ctxe.putImageData(btmp,0,0);
        //dataURI JPEG output
        document.getElementById('evidence').src = canvasE.toDataURL("image/png", 1.0);
      }

    }
  };
});<commit_msg>remove default path of the video<commit_after>/**
 * Created by isc on 12/05/15.
 */
angular.module('myApp.controllers')
	.controller('EvidenceCtrl', ['$document', '$sce', '$scope', '$http',
		'defaults', '$controller', 'Session', '$rootScope', 'camomileService',

		function ($document, $sce, $scope, $http, defaults, $controller, Session, $rootScope, camomileService) {

			/*import MissPlete from './MissPlete.js';

        	new MissPlete({
            	input: document.querySelector('input[name="entry_input"]'),

            	options: [["Barcelona", "BCN"], ["San Francisco", "SF"]]
        	});*/

			$controller('CommonCtrl', {
				$scope: $scope,
				$http: $http,
				defaults: defaults,
				Session: Session
			});

			$scope.model.incomingQueue = $rootScope.queues.evidenceIn;
			$scope.model.outgoingQueue = $rootScope.queues.evidenceOut;

			$scope.model.q = {};

			$scope.model.user_input = {};

			$scope.model.updateIsDisplayedVideo = function (activate) {
				$scope.model.isDisplayedVideo = activate;
			};

			// initialize page state
			$scope.model.updateIsDisplayedVideo(false);

			var _getVideo = function (id_medium, callback) {

				camomileService.getMedium(id_medium, function (err, medium) {
					callback(err, $sce.trustAsResourceUrl($scope.model.videoPath + '/' + medium.url + '.mp4'));
				});
			};

			// Initializes the data from the queue
			// rename from "initQueueData" to "popQueueElement"
			$scope.model.popQueueElement = function () {

				// Get queue first element and pop it from the queue
				camomileService.dequeue($scope.model.incomingQueue, function (err, item) {

					if (err) {
						alert(item.error);
						$scope.$apply(function () {
							$scope.model.video = undefined;
							$scope.model.isDisplayedVideo = false;
							$scope.model.updateIsDisplayedVideo(false);
						});

						return;
					}

					//$scope.model.resetTransparentPlan();
					$scope.model.updateIsDisplayedVideo(true);

					if (item.modality === "pronounced") {
						document.getElementById("message").innerHTML = "WARNING: The person name might be pronounced !";
					}

					$scope.model.q = item;
					$scope.model.user_input.person_name = $scope.model.q.person_name;
					$scope.model.initialData = $scope.model.q.person_name;

					// Update the add entry button's status
					$scope.model.updateIsDisplayedVideo($scope.model.user_input.person_name != "");

					async.parallel({
							video: function (callback) {
								_getVideo($scope.model.q.medium_id, callback);
							},
							serverDate: function (callback) {
								camomileService.getDate(function (err, data) {
									callback(null, data.date);
								});
							}
						},
						function (err, results) {
							$scope.model.video = results.video;
							$scope.model.serverDate = results.serverDate;
							$scope.model.clientDate = Date.now();

							$scope.model.restrict_toggle = 2;
							$scope.model.current_time_temp = $scope.model.q.t;
							$scope.model.infbndsec = parseFloat($scope.model.q.t || 0);
							$scope.model.infbndsec-=5.0;
							if ($scope.model.infbndsec < 0) {
								$scope.model.infbndsec = 0;
							}
							$scope.model.supbndsec = parseFloat($scope.model.q.t || 0);
							$scope.model.supbndsec+=5.0;
							if ($scope.model.supbndsec > $scope.model.fullDuration) {
								$scope.model.supbndsec = $scope.model.fullDuration;
							}
							$scope.model.duration = $scope.model.supbndsec - $scope.model.infbndsec;

							$scope.$apply(function () {
								$scope.model.current_time = $scope.model.q.t;
							});

						});
				});
			};

			// Event launched when click on the save button.
			$scope.model.saveQueueElement = function (isEvidence) {

				if (isEvidence == "" && document.getElementById('evidence').src === "") {
					document.getElementById("message").innerHTML = "Please draw a bounding box around the face.";
				}

				var item = {};

				item.log = {};
				item.log.user = Session.username;
				item.log.date = $scope.model.serverDate;
				item.log.duration = Date.now() - $scope.model.clientDate;
				/*camomileService.me(function(callback){
					item.log.user_id = _id;
				});*/

				item.input = {};
				item.input.corpus_id = $scope.model.q.corpus_id;
				item.input.medium_id = $scope.model.q.medium_id;
				item.input.modality = $scope.model.q.modality;
				item.input.person_name = $scope.model.initialData;
				item.input.t = $scope.model.q.t;

				var b_box = {};
				b_box.w = parseFloat(document.getElementById("Wbox").value);
				b_box.h = parseFloat(document.getElementById("Hbox").value);
				b_box.x = parseFloat(document.getElementById("Xbox").value);
				b_box.y = parseFloat(document.getElementById("Ybox").value);

				item.output = {};
				item.output.status = isEvidence;
				if (isEvidence == "yes") {
					item.output.person_name = $scope.model.user_input.person_name;
					item.output.t = $scope.model.current_time;
					item.output.image = document.getElementById('evidence').src;
					item.output.bounding_box = b_box;
				}

				document.getElementById('evidenceImages').style.display = "none";
				document.getElementById('evidence').src = "";
				document.getElementById('draw').children[0].width = document.getElementById('draw').children[0].width;
				document.getElementById("Wbox").value = "";
				document.getElementById("Hbox").value = "";
				document.getElementById("Xbox").value = "";
				document.getElementById("Ybox").value = "";
				document.getElementById("message").innerHTML = "";

				camomileService.enqueue($scope.model.outgoingQueue, item, function (err, data) {

					if (err) {
						console.log("Something went wrong");
					} else {
						$scope.model.popQueueElement();
					}

				});
			};

			$document.on(
				"keydown",
				function (event) {
					var targetID = event.target.id;
					var button_checked = false;
					if (targetID == 'confirm' || targetID == 'cancel') {
						button_checked = true;
					}
					//enter
					if (event.keyCode == 13 && targetID != 'localServerInput') {
						//If the focus is on the check buttons, blur the focus first
						if (button_checked) {
							event.target.blur();
						}
						$scope.$apply(function () {
							$scope.model.saveQueueElement(true);
						});
					}
					//space
					if (event.keyCode == 32 && targetID != "entry_input") {
						if (button_checked) {
							event.target.blur();
						}
						$scope.$apply(function () {
							$scope.model.toggle_play();
						});
					}
					//esc-> skip
					if (event.keyCode == 27) {
						$scope.$apply(function () {
							//skip
							$scope.model.saveQueueElement(false);
						});
					}
					//Left
					if (event.keyCode == 37) {
						$scope.$apply(function () {
							if ($scope.model.current_time - 0.04 > $scope.model.infbndsec) {
								$scope.model.current_time = $scope.model.current_time - 0.04;
							} else {
								$scope.model.current_time = $scope.model.infbndsec;
							}
						});
					}
					//Right
					if (event.keyCode == 39) {
						$scope.$apply(function () {
							if ($scope.model.current_time + 0.04 < $scope.model.supbndsec) {
								$scope.model.current_time = $scope.model.current_time + 0.04;
							} else {
								$scope.model.current_time = $scope.model.supbndsec;
							}
						});
					}
					//Up
					if (event.keyCode == 38) {
						$scope.$apply(function () {
							if ($scope.model.current_time - 1 > $scope.model.infbndsec) {
								$scope.model.current_time = $scope.model.current_time - 1;
							} else {
								$scope.model.current_time = $scope.model.infbndsec;
							}
						});

					} //Down
					if (event.keyCode == 40) {
						$scope.$apply(function () {

							if ($scope.model.current_time + 1 < $scope.model.supbndsec) {
								$scope.model.current_time = $scope.model.current_time + 1;
							} else {
								$scope.model.current_time = $scope.model.supbndsec;
							}
						});
					}
				}
			);

		}
	]);

angular.module('myApp.controllers').directive('drawing', function(){
  return {
    restrict: 'E',
    scope: { localRectangles: '=rectangleList' },
    template: '<canvas class="drawing"></canvas>',
    link: function(scope, element){
    	// There are 3 canvas, one used to determine the zone to copy
    	// another one to extract the image and clip it, the last one to resize the image
      var canvasElement = element.children()[0];
      var ctx = canvasElement.getContext('2d');
      var canvasB = document.getElementById("recup");
      var ctxb = canvasB.getContext('2d');
      var canvasE = document.getElementById("evid");
      var ctxe = canvasE.getContext('2d');

      // The first canvas can be sized at the beginning
      canvasElement.width = document.getElementById("video-container").offsetWidth;
      canvasElement.height = document.getElementById("video-container").offsetHeight;

      // Are we drawing?
      var drawing = false;

      // the last coordinates before the current move
      var centerX;
      var centerY;

      element.children()[0].addEventListener('mousedown', function(event){
        reset();
        startX = event.offsetX;
        startY = event.offsetY;
        document.getElementById("player").pause();

        // begins new line
        ctx.beginPath();

        drawing = true;
      },false);

	  element.children()[0].addEventListener('mousemove', function(event){

        if(drawing){

        //document.getElementById('evid').style.display = "none";
        document.getElementById('evidenceImages').style.display = "none";

          // get current mouse position
          currentX = event.offsetX;
          currentY = event.offsetY;

          if((startX<currentX && startY<currentY) || (startX>currentX && startY>currentY)){
          	if(Math.abs(currentY-startY)<Math.abs(currentX-startX)) currentX = currentY-startY+startX;
          	else currentY = currentX-startX+startY;
          }
          else{
          	if(Math.abs(currentY-startY)<Math.abs(currentX-startX)) currentX = startY-currentY+startX;
          	else currentY = startX-currentX+startY;
    	  }

          // limit all the rectangle within the canvas and draw
          if(currentX >= 0 && currentX <= 360*document.getElementById('player').videoWidth/document.getElementById('player').videoHeight && currentY >= 0 && currentY <= 360){
            draw(startX, startY, currentX, currentY);
          }
        }

      },false);

      // canvas reset
      function reset(){
      	// This simple operation reset the canvas
       canvasElement.width = canvasElement.width;
       canvasB.width = canvasB.width;
       canvasE.width = canvasE.width;
      }

      element.children()[0].addEventListener('mouseup', function(event){
        // stop drawing
        drawing = false;
        //document.getElementById('evid').style.display = "";
        document.getElementById('evidenceImages').style.display = "inline-block";
      },false);

      function draw(startX, startY,
                    currentX, currentY, rotate){

        reset();
        var sizeX = currentX - startX;
        var sizeY = currentY - startY;

        ctx.rect(Math.min(startX,currentX),
                 Math.min(startY,currentY),
                 Math.abs(sizeX), Math.abs(sizeY));
        ctx.lineWidth = 3;
        // color gradient
        /*var gradient=ctx.createLinearGradient(Math.min(oppositeX,currentX),Math.min(oppositeY,currentY),Math.max(oppositeX,currentX),Math.max(oppositeY,currentY));
        gradient.addColorStop("0.05","red");
        gradient.addColorStop("0.15","blue");
        gradient.addColorStop("0.25","red");
        gradient.addColorStop("0.35","blue");
        gradient.addColorStop("0.45","red");
        gradient.addColorStop("0.55","blue");
        gradient.addColorStop("0.65","red");
        gradient.addColorStop("0.75","blue");
        gradient.addColorStop("0.85","red");
        gradient.addColorStop("0.95","blue");
        ctx.strokeStyle = gradient;*/
        // color
        ctx.strokeStyle = 'red';
        // draw it
        ctx.stroke();
        // Launch the copy process
        copy(Math.min(startX,currentX),Math.min(startY,currentY),Math.abs(sizeX),Math.abs(sizeY));
        document.getElementById("Xbox").value = Math.min(startX,currentX)/(360*document.getElementById('player').videoWidth/document.getElementById('player').videoHeight);
        document.getElementById("Ybox").value = Math.min(startY,currentY)/360;
        document.getElementById("Wbox").value = Math.abs(sizeX)/(360*document.getElementById('player').videoWidth/document.getElementById('player').videoHeight);
        document.getElementById("Hbox").value = Math.abs(sizeY)/360;
      }

      function copy(X, Y, sizeX, sizeY){

      	// Get the video source and size the second canvas according to the dimension (16:9 or 4:3)
        var src = document.getElementById('player');
        canvasB.width = 360*src.videoWidth/src.videoHeight;
        canvasB.height = 360;
        // Copy the image
        ctxb.drawImage(src,0,0,canvasB.width,canvasB.height);
        // Clip the image
        var btmp = ctxb.getImageData(X, Y, sizeX, sizeY);
        // Clear the second canvas to put the part of the image we want
        ctxb.clearRect(0,0,canvasB.width,canvasB.height);
        ctxb.putImageData(btmp,0,0);
        // Size of the last canvas
        canvasE.width = sizeX;
        canvasE.height = sizeY;
        // Copy from the second canvas to the third
        ctxe.putImageData(btmp,0,0);
        //dataURI JPEG output
        document.getElementById('evidence').src = canvasE.toDataURL("image/png", 1.0);
      }

    }
  };
});<|endoftext|>


<commit_before>#!/usr/bin/env ringo
/**
 * @fileoverview Script to create static JsDoc documentation.
 *      Use -h or --help to get a list of available options.
 *
 * @see http://code.google.com/p/jsdoc-toolkit/
 */

// stdlib
var files = require('ringo/utils/files');
var {makeTree, write, copyTree, join, Path} = require('fs');
var {render} = require('ringo/skin');
var {Parser} = require('ringo/args');
var {isFile, isDirectory} = require('fs-base');
var {ScriptRepository} = require('ringo/jsdoc');
var strings = require('ringo/utils/strings');
var objects = require('ringo/utils/objects');

// custom
var {repositoryList, moduleDoc, moduleList, structureModuleDoc, getRepositoryName} = require('./jsdocserializer');
var config = require('./config.js');

// need config.macros in context for skin rendering
var defaultContext = {};

// let skins now we are in static mode
defaultContext.isStaticRenderer = true;

/**
 * @param {Object} repostitory
 * @param {String} exportDirectory
 * @param {Boolean} quiet
 */
var renderRepository = exports.renderRepository = function (repository, exportDirectory, quiet) {
    // need apps/jsdoc on path for skin extend to work
    if (require.paths.indexOf(module.directory)) {
        require.paths.unshift(module.directory);
    }
    config.macros.forEach(function(moduleId) {
        defaultContext = objects.merge(defaultContext,
            require(files.resolveId(module.directory, moduleId))
        );
    });

    if (!quiet) print ('Writing to ' + exportDirectory + '...');
    copyStaticFiles(exportDirectory);
    if (!quiet) print(repository.path);
    writeModuleList(exportDirectory, repository);
    moduleList(repository.path).forEach(function(module) {
        if (!quiet) print('\t' + module.id);
        writeModuleDoc(exportDirectory, repository, module.id);
    });

    if (!quiet) print('Finished writing to ' + exportDirectory);
    return;
}

/**
 * Copy static files of this webapp to target directory
 *
 * @param {String} target
 */
function copyStaticFiles(target) {
    makeTree(join(target, 'static'));
    copyTree(join(module.directory, 'static'), join(target, 'static'));
    return;
};

/**
 * Write the module list to directory. Corresponds to actions:repository
 *
 * @param {String} target directory of file to be written
 * @param {String} repository path
 */
function writeModuleList(target, repository) {
    var repositoryHtml = render('skins/repository.html',
        objects.merge(defaultContext, {
            repositoryName: repository.name,
            modules: moduleList(repository.path, true),
            rootPath: './',
        })
    );
    write(join(target, 'index.html'), repositoryHtml);
};

/**
 * Write documentation page for a module to directory. corresponds to actions:module
 *
 * @param {String} directory
 * @param {String} repository path
 * @param {String} moduleId
 */
function writeModuleDoc(target, repository, moduleId){

    var moduleDirectory = target;
    var modules = [];
    moduleDirectory = join(target, moduleId);
    makeTree(moduleDirectory);
    modules = moduleList(repository.path);

    var docs = moduleDoc(repository.path, moduleId);
    if (docs == null) {
        throw new Error('Could not parse JsDoc for ' + repository.path + moduleId);
    }

    var slashCount = strings.count(moduleId, '/');
    var relativeRoot = '../' + strings.repeat('../', slashCount);

    var moduleHtml = render('skins/module.html',
        objects.merge(defaultContext, {
            rootPath: relativeRoot,
            repositoryName: repository.name,
            moduleId: moduleId,
            modules: modules,
            module: structureModuleDoc(docs),
        })
    );

    var moduleFile = join(moduleDirectory, 'index.html');
    write(moduleFile, moduleHtml);
    return;
};

/**
 * Create static documentation for a Repository.
 *
 *   ringo doc.js -s /home/foo/ringojs/modules/
 *
 * You can specify a human readable name for the module which will
 * be display in the documentation:
 *
 *   ringo doc.js -s /home/foo/ringojs/modules -n "Ringojs Modules"
 *
 * @param args
 */
function main(args) {

    /**
     * Print script help
     */
    function help() {
        print('Create JsDoc documentation for CommonJs modules.');
        print('Usage:');
        print('  ringo ' + script + ' -s [sourcepath]');
        print('Options:');
        print(parser.help());
        return;
    };

    var script = args.shift();
    var parser = new Parser();
    parser.addOption('s', 'source', 'repository', 'Path to repository');
    parser.addOption('d', 'directory', 'directory', 'Directory for output files (default: "out")');
    parser.addOption('n', 'name', 'name', 'Name of the Repository (default: auto generated from path)');
    parser.addOption('q', 'quiet', null, 'Do not output any messages.');
    parser.addOption('h', 'help', null, 'Print help message and exit');
    var opts = parser.parse(args);
    if (opts.help) {
        help();
        return;
    }
    if (!opts.source) {
        throw new Error('No source specified.');
    }

    var exportDirectory = join(opts.directory || './out/');
    var repository = {
        path: opts.source,
        name: opts.name || getRepositoryName(opts.source)
    };
    var quiet = opts.quiet || false;

    // check if export dir exists & is empty
    var dest = new Path(exportDirectory);
    if (dest.exists() && !dest.isDirectory()) {
        throw new Error(dest + ' exists but is not a directory.');
    } else if (dest.isDirectory() && dest.list().length > 0) {
        throw new Error('Directory ' + dest + ' exists but is not empty');
    }

    // figure out what type of doc we write, single module, multi repos
    // or single repo
    if (!isDirectory(repository.path)) {
        throw new Error('Invalid source specified. Must be directory.');
        return;
    }

    renderRepository(repository, exportDirectory, quiet);
    return;
};

if (require.main == module) {
    try {
        main(system.args);
    } catch (error) {
        print(error);
        print('Use -h or --help to get a list of available options.');
    }
}
<commit_msg>fix jsdoc messing with require.paths<commit_after>#!/usr/bin/env ringo
/**
 * @fileoverview Script to create static JsDoc documentation.
 *      Use -h or --help to get a list of available options.
 *
 * @see http://code.google.com/p/jsdoc-toolkit/
 */

// stdlib
var files = require('ringo/utils/files');
var {makeTree, write, copyTree, join, Path} = require('fs');
var {render} = require('ringo/skin');
var {Parser} = require('ringo/args');
var {isFile, isDirectory} = require('fs-base');
var {ScriptRepository} = require('ringo/jsdoc');
var strings = require('ringo/utils/strings');
var objects = require('ringo/utils/objects');

// custom
var {repositoryList, moduleDoc, moduleList, structureModuleDoc, getRepositoryName} = require('./jsdocserializer');
var config = require('./config.js');

// need config.macros in context for skin rendering
var defaultContext = {};

// let skins now we are in static mode
defaultContext.isStaticRenderer = true;

/**
 * @param {Object} repostitory
 * @param {String} exportDirectory
 * @param {Boolean} quiet
 */
var renderRepository = exports.renderRepository = function (repository, exportDirectory, quiet) {
    // need apps/jsdoc on path for skin extend to work
    if (require.paths.indexOf(module.directory) != -1) {
        require.paths.push(module.directory);
    }
    config.macros.forEach(function(moduleId) {
        defaultContext = objects.merge(defaultContext,
            require(files.resolveId(module.directory, moduleId))
        );
    });

    if (!quiet) print ('Writing to ' + exportDirectory + '...');
    copyStaticFiles(exportDirectory);
    if (!quiet) print(repository.path);
    writeModuleList(exportDirectory, repository);
    moduleList(repository.path).forEach(function(module) {
        if (!quiet) print('\t' + module.id);
        writeModuleDoc(exportDirectory, repository, module.id);
    });

    if (!quiet) print('Finished writing to ' + exportDirectory);
    return;
}

/**
 * Copy static files of this webapp to target directory
 *
 * @param {String} target
 */
function copyStaticFiles(target) {
    makeTree(join(target, 'static'));
    copyTree(join(module.directory, 'static'), join(target, 'static'));
    return;
};

/**
 * Write the module list to directory. Corresponds to actions:repository
 *
 * @param {String} target directory of file to be written
 * @param {String} repository path
 */
function writeModuleList(target, repository) {
    var repositoryHtml = render('skins/repository.html',
        objects.merge(defaultContext, {
            repositoryName: repository.name,
            modules: moduleList(repository.path, true),
            rootPath: './',
        })
    );
    write(join(target, 'index.html'), repositoryHtml);
};

/**
 * Write documentation page for a module to directory. corresponds to actions:module
 *
 * @param {String} directory
 * @param {String} repository path
 * @param {String} moduleId
 */
function writeModuleDoc(target, repository, moduleId){

    var moduleDirectory = target;
    var modules = [];
    moduleDirectory = join(target, moduleId);
    makeTree(moduleDirectory);
    modules = moduleList(repository.path);

    var docs = moduleDoc(repository.path, moduleId);
    if (docs == null) {
        throw new Error('Could not parse JsDoc for ' + repository.path + moduleId);
    }

    var slashCount = strings.count(moduleId, '/');
    var relativeRoot = '../' + strings.repeat('../', slashCount);

    var moduleHtml = render('skins/module.html',
        objects.merge(defaultContext, {
            rootPath: relativeRoot,
            repositoryName: repository.name,
            moduleId: moduleId,
            modules: modules,
            module: structureModuleDoc(docs),
        })
    );

    var moduleFile = join(moduleDirectory, 'index.html');
    write(moduleFile, moduleHtml);
    return;
};

/**
 * Create static documentation for a Repository.
 *
 *   ringo doc.js -s /home/foo/ringojs/modules/
 *
 * You can specify a human readable name for the module which will
 * be display in the documentation:
 *
 *   ringo doc.js -s /home/foo/ringojs/modules -n "Ringojs Modules"
 *
 * @param args
 */
function main(args) {

    /**
     * Print script help
     */
    function help() {
        print('Create JsDoc documentation for CommonJs modules.');
        print('Usage:');
        print('  ringo ' + script + ' -s [sourcepath]');
        print('Options:');
        print(parser.help());
        return;
    };

    var script = args.shift();
    var parser = new Parser();
    parser.addOption('s', 'source', 'repository', 'Path to repository');
    parser.addOption('d', 'directory', 'directory', 'Directory for output files (default: "out")');
    parser.addOption('n', 'name', 'name', 'Name of the Repository (default: auto generated from path)');
    parser.addOption('q', 'quiet', null, 'Do not output any messages.');
    parser.addOption('h', 'help', null, 'Print help message and exit');
    var opts = parser.parse(args);
    if (opts.help) {
        help();
        return;
    }
    if (!opts.source) {
        throw new Error('No source specified.');
    }

    var exportDirectory = join(opts.directory || './out/');
    var repository = {
        path: opts.source,
        name: opts.name || getRepositoryName(opts.source)
    };
    var quiet = opts.quiet || false;

    // check if export dir exists & is empty
    var dest = new Path(exportDirectory);
    if (dest.exists() && !dest.isDirectory()) {
        throw new Error(dest + ' exists but is not a directory.');
    } else if (dest.isDirectory() && dest.list().length > 0) {
        throw new Error('Directory ' + dest + ' exists but is not empty');
    }

    // figure out what type of doc we write, single module, multi repos
    // or single repo
    if (!isDirectory(repository.path)) {
        throw new Error('Invalid source specified. Must be directory.');
        return;
    }

    renderRepository(repository, exportDirectory, quiet);
    return;
};

if (require.main == module) {
    try {
        main(system.args);
    } catch (error) {
        print(error);
        print('Use -h or --help to get a list of available options.');
    }
}
<|endoftext|>


<commit_before>import { h, Component } from 'preact';

const DOM = typeof document!=='undefined' && !!document.createElement;

let updateMode = false;

if (DOM) {
	/** Hook into document.createElement() to slap a namespace on manually namespaced nodes (yup)
	 *	@private
	 */
	let oldCreate = document.createElement;
	document.createElement = (name) => {
		if (updateMode || name==='svg') {
			return document.createElementNS('http://www.w3.org/2000/svg', name);
		}
		return oldCreate.call(document, name);
	};
}

/** A list of SVG properties that are read-only, requiring `setAttribute()` to mutate.
 *	@private
 */
const ATTRS = DOM ? ['width', 'height', 'viewBox', 'preserveAspectRatio'] : [];

/** Wrapper around <svg> that provides Preact support.
 *	@public
 */
class SVG extends Component {
	componentWillUpdate() {
		updateMode = true;
	}

	// after any update, manually apply exempted readOnly SVG properties as attributes:
	componentDidUpdate() {
		updateMode = false;
		let { base, props } = this;
		for (let i in props) {
			if (props.hasOwnProperty(i) && ~ATTRS.indexOf(i) && base.getAttribute(i)!==props[i]) {
				base.setAttribute(i, props[i]);
			}
		}
	}

	render({ children, ...props }) {
		// componentWillUpdate() is not called on first render, so we have to shim that here.
		// thankfully, first render() does synchronous DOM generation so it works fine.
		if (!this.hasRendered) {
			this.hasRendered = updateMode = true;
		}

		let attrs = {
			xmlns: 'http://www.w3.org/2000/svg',
			version: '1.1'
		};
		for (let i in props) if (props.hasOwnProperty(i) && ATTRS.indexOf(i)<0) {
			attrs[i] = props[i];
		}
		return <svg {...attrs}>{ children }</svg>;
	}
}
<commit_msg>Fix regression (missing export)<commit_after>import { h, Component } from 'preact';

const DOM = typeof document!=='undefined' && !!document.createElement;

let updateMode = false;

if (DOM) {
	/** Hook into document.createElement() to slap a namespace on manually namespaced nodes (yup)
	 *	@private
	 */
	let oldCreate = document.createElement;
	document.createElement = (name) => {
		if (updateMode || name==='svg') {
			return document.createElementNS('http://www.w3.org/2000/svg', name);
		}
		return oldCreate.call(document, name);
	};
}

/** A list of SVG properties that are read-only, requiring `setAttribute()` to mutate.
 *	@private
 */
const ATTRS = DOM ? ['width', 'height', 'viewBox', 'preserveAspectRatio'] : [];

/** Wrapper around <svg> that provides Preact support.
 *	@public
 */
export default class SVG extends Component {
	componentWillUpdate() {
		updateMode = true;
	}

	// after any update, manually apply exempted readOnly SVG properties as attributes:
	componentDidUpdate() {
		updateMode = false;
		let { base, props } = this;
		for (let i in props) {
			if (props.hasOwnProperty(i) && ~ATTRS.indexOf(i) && base.getAttribute(i)!==props[i]) {
				base.setAttribute(i, props[i]);
			}
		}
	}

	render({ children, ...props }) {
		// componentWillUpdate() is not called on first render, so we have to shim that here.
		// thankfully, first render() does synchronous DOM generation so it works fine.
		if (!this.hasRendered) {
			this.hasRendered = updateMode = true;
		}

		let attrs = {
			xmlns: 'http://www.w3.org/2000/svg',
			version: '1.1'
		};
		for (let i in props) if (props.hasOwnProperty(i) && ATTRS.indexOf(i)<0) {
			attrs[i] = props[i];
		}
		return <svg {...attrs}>{ children }</svg>;
	}
}
<|endoftext|>