<commit_before>/*
 * Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
 *
 * @APPPLANT_LICENSE_HEADER_START@
 *
 * This file contains Original Code and/or Modifications of Original Code
 * as defined in and that are subject to the Apache License
 * Version 2.0 (the 'License'). You may not use this file except in
 * compliance with the License. Please obtain a copy of the License at
 * http://opensource.org/licenses/Apache-2.0/ and read it before using this
 * file.
 *
 * The Original Code and all software distributed under the License are
 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
 * Please see the License for the specific language governing rights and
 * limitations under the License.
 *
 * @APPPLANT_LICENSE_HEADER_END@
 */

/*************
 * INTERFACE *
 *************/

/**
 * Returns the default settings.
 *
 * @return {Object}
 */
exports.getDefaults = function () {
    return this.core.getDefaults();
};

/**
 * Overwrite default settings.
 *
 * @param {Object} defaults
 */
exports.setDefaults = function (defaults) {
    this.core.setDefaults(defaults);
};

/**
 * Schedule a new local notification.
 *
 * @param {Object} notifications
 *      The notification properties
 * @param {Function} callback
 *      A function to be called after the notification has been canceled
 * @param {Object?} scope
 *      The scope for the callback function
 * @param {Object?} args
 *      skipPermission:true schedules the notifications immediatly without
 *                          registering or checking for permission
 */
exports.schedule = function (notifications, callback, scope, args) {
    this.core.schedule(notifications, callback, scope, args);
};

/**
 * Update existing notifications specified by IDs in options.
 *
 * @param {Object} notifications
 *      The notification properties to update
 * @param {Function} callback
 *      A function to be called after the notification has been updated
 * @param {Object?} scope
 *      The scope for the callback function
 * @param {Object?} args
 *      skipPermission:true schedules the notifications immediatly without
 *                          registering or checking for permission
 */
exports.update = function (notifications, callback, scope, args) {
    this.core.update(notifications, callback, scope, args);
};

/**
 * Clear the specified notification.
 *
 * @param {String} id
 *      The ID of the notification
 * @param {Function} callback
 *      A function to be called after the notification has been cleared
 * @param {Object?} scope
 *      The scope for the callback function
 */
exports.clear = function (ids, callback, scope) {
    this.core.clear(ids, callback, scope);
};

/**
 * Clear all previously sheduled notifications.
 *
 * @param {Function} callback
 *      A function to be called after all notifications have been cleared
 * @param {Object?} scope
 *      The scope for the callback function
 */
exports.clearAll = function (callback, scope) {
    this.core.clearAll(callback, scope);
};

/**
 * Cancel the specified notifications.
 *
 * @param {String[]} ids
 *      The IDs of the notifications
 * @param {Function} callback
 *      A function to be called after the notifications has been canceled
 * @param {Object?} scope
 *      The scope for the callback function
 */
exports.cancel = function (ids, callback, scope) {
    this.core.cancel(ids, callback, scope);
};

/**
 * Remove all previously registered notifications.
 *
 * @param {Function} callback
 *      A function to be called after all notifications have been canceled
 * @param {Object?} scope
 *      The scope for the callback function
 */
exports.cancelAll = function (callback, scope) {
    this.core.cancelAll(callback, scope);
};

/**
 * Check if a notification with an ID is present.
 *
 * @param {String} id
 *      The ID of the notification
 * @param {Function} callback
 *      A callback function to be called with the list
 * @param {Object?} scope
 *      The scope for the callback function
 */
exports.isPresent = function (id, callback, scope) {
    this.core.isPresent(id, callback, scope);
};

/**
 * Check if a notification with an ID is scheduled.
 *
 * @param {String} id
 *      The ID of the notification
 * @param {Function} callback
 *      A callback function to be called with the list
 * @param {Object?} scope
 *      The scope for the callback function
 */
exports.isScheduled = function (id, callback, scope) {
    this.core.isScheduled(id, callback, scope);
};

/**
 * Check if a notification with an ID was triggered.
 *
 * @param {String} id
 *      The ID of the notification
 * @param {Function} callback
 *      A callback function to be called with the list
 * @param {Object?} scope
 *      The scope for the callback function
 */
exports.isTriggered = function (id, callback, scope) {
    this.core.isTriggered(id, callback, scope);
};

/**
 * List all local notification IDs.
 *
 * @param {Function} callback
 *      A callback function to be called with the list
 * @param {Object?} scope
 *      The scope for the callback function
 */
exports.getAllIds = function (callback, scope) {
    this.core.getAllIds(callback, scope);
};

/**
 * Alias for `getAllIds`.
 */
exports.getIds = function () {
    this.getAllIds.apply(this, arguments);
};

/**
 * List all scheduled notification IDs.
 *
 * @param {Function} callback
 *      A callback function to be called with the list
 * @param {Object?} scope
 *      The scope for the callback function
 */
exports.getScheduledIds = function (callback, scope) {
    this.core.getScheduledIds(callback, scope);
};

/**
 * List all triggered notification IDs.
 *
 * @param {Function} callback
 *      A callback function to be called with the list
 * @param {Object?} scope
 *      The scope for the callback function
 */
exports.getTriggeredIds = function (callback, scope) {
    this.core.getTriggeredIds(callback, scope);
};

/**
 * Property list for given local notifications.
 * If called without IDs, all notification will be returned.
 *
 * @param {Number[]?} ids
 *      Set of notification IDs
 * @param {Function} callback
 *      A callback function to be called with the list
 * @param {Object?} scope
 *      The scope for the callback function
 */
exports.get = function () {
    this.core.get.apply(this.core, arguments);
};

/**
 * Property list for all local notifications.
 *
 * @param {Function} callback
 *      A callback function to be called with the list
 * @param {Object?} scope
 *      The scope for the callback function
 */
exports.getAll = function (callback, scope) {
    this.core.getAll(callback, scope);
};

/**
 * Property list for given scheduled notifications.
 * If called without IDs, all notification will be returned.
 *
 * @param {Number[]?} ids
 *      Set of notification IDs
 * @param {Function} callback
 *      A callback function to be called with the list
 * @param {Object?} scope
 *      The scope for the callback function
 */
exports.getScheduled = function () {
    this.core.getScheduled.apply(this.core, arguments);
};

/**
 * Property list for all scheduled notifications.
 *
 * @param {Function} callback
 *      A callback function to be called with the list
 * @param {Object?} scope
 *      The scope for the callback function
 */
exports.getAllScheduled = function (callback, scope) {
    this.core.getAllScheduled(callback, scope);
};

/**
 * Property list for given triggered notifications.
 * If called without IDs, all notification will be returned.
 *
 * @param {Number[]?} ids
 *      Set of notification IDs
 * @param {Function} callback
 *      A callback function to be called with the list
 * @param {Object?} scope
 *      The scope for the callback function
 */
exports.getTriggered = function () {
    this.core.getTriggered.apply(this.core, arguments);
};

/**
 * Property list for all triggered notifications.
 *
 * @param {Function} callback
 *      A callback function to be called with the list
 * @param {Object?} scope
 *      The scope for the callback function
 */
exports.getAllTriggered = function (callback, scope) {
    this.core.getAllTriggered(callback, scope);
};

/**
 * Informs if the app has the permission to show notifications.
 *
 * @param {Function} callback
 *      The function to be exec as the callback
 * @param {Object?} scope
 *      The callback function's scope
 */
exports.hasPermission = function (callback, scope) {
    this.core.hasPermission(callback, scope);
};

/**
 * Register permission to show notifications if not already granted.
 *
 * @param {Function} callback
 *      The function to be exec as the callback
 * @param {Object?} scope
 *      The callback function's scope
 */
exports.registerPermission = function (callback, scope) {
    this.core.registerPermission(callback, scope);
};

/****************
 * DEPRECATIONS *
 ****************/

/**
 * Schedule a new local notification.
 */
exports.add = function () {
    console.warn('Depreated: Please use `notification.local.schedule` instead.');

    this.schedule.apply(this, arguments);
};

/**
 * Register permission to show notifications
 * if not already granted.
 */
exports.promptForPermission = function () {
    console.warn('Depreated: Please use `notification.local.registerPermission` instead.');

    this.registerPermission.apply(this, arguments);
};

/**********
 * EVENTS *
 **********/

/**
 * Register callback for given event.
 *
 * @param {String} event
 *      The event's name
 * @param {Function} callback
 *      The function to be exec as callback
 * @param {Object?} scope
 *      The callback function's scope
 */
exports.on = function (event, callback, scope) {
    this.core.on(event, callback, scope);
};

/**
 * Unregister callback for given event.
 *
 * @param {String} event
 *      The event's name
 * @param {Function} callback
 *      The function to be exec as callback
 */
exports.un = function (event, callback) {
    this.core.un(event, callback);
};
<commit_msg>Forgot to add summary functions to js<commit_after>/*
 * Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
 *
 * @APPPLANT_LICENSE_HEADER_START@
 *
 * This file contains Original Code and/or Modifications of Original Code
 * as defined in and that are subject to the Apache License
 * Version 2.0 (the 'License'). You may not use this file except in
 * compliance with the License. Please obtain a copy of the License at
 * http://opensource.org/licenses/Apache-2.0/ and read it before using this
 * file.
 *
 * The Original Code and all software distributed under the License are
 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
 * Please see the License for the specific language governing rights and
 * limitations under the License.
 *
 * @APPPLANT_LICENSE_HEADER_END@
 */

/*************
 * INTERFACE *
 *************/

/**
 * Returns the default settings.
 *
 * @return {Object}
 */
exports.getDefaults = function () {
    return this.core.getDefaults();
};

/**
 * Overwrite default settings.
 *
 * @param {Object} defaults
 */
exports.setDefaults = function (defaults) {
    this.core.setDefaults(defaults);
};

/**
 * Set summary options for a summary local notification.
 *
 * @param {Object} notifications
 *      The notification properties
 * @param {Function} callback
 *      A function to be called after the notification has been canceled
 * @param {Object?} scope
 *      The scope for the callback function
 * @param {Object?} args
 *      skipPermission:true schedules the notifications immediatly without
 *                          registering or checking for permission
 */
exports.setSummary = function (notifications, callback, scope, args) {
    this.core.setSummary(notifications, callback, scope, args);
};

/**
 * Schedule a new local notification.
 *
 * @param {Object} notifications
 *      The notification properties
 * @param {Function} callback
 *      A function to be called after the notification has been canceled
 * @param {Object?} scope
 *      The scope for the callback function
 * @param {Object?} args
 *      skipPermission:true schedules the notifications immediatly without
 *                          registering or checking for permission
 */
exports.schedule = function (notifications, callback, scope, args) {
    this.core.schedule(notifications, callback, scope, args);
};

/**
 * Update existing notifications specified by IDs in options.
 *
 * @param {Object} notifications
 *      The notification properties to update
 * @param {Function} callback
 *      A function to be called after the notification has been updated
 * @param {Object?} scope
 *      The scope for the callback function
 * @param {Object?} args
 *      skipPermission:true schedules the notifications immediatly without
 *                          registering or checking for permission
 */
exports.update = function (notifications, callback, scope, args) {
    this.core.update(notifications, callback, scope, args);
};

/**
 * Clear the specified notification.
 *
 * @param {String} id
 *      The ID of the notification
 * @param {Function} callback
 *      A function to be called after the notification has been cleared
 * @param {Object?} scope
 *      The scope for the callback function
 */
exports.clear = function (ids, callback, scope) {
    this.core.clear(ids, callback, scope);
};

/**
 * Clear all previously sheduled notifications.
 *
 * @param {Function} callback
 *      A function to be called after all notifications have been cleared
 * @param {Object?} scope
 *      The scope for the callback function
 */
exports.clearAll = function (callback, scope) {
    this.core.clearAll(callback, scope);
};

/**
 * Cancel the specified notifications.
 *
 * @param {String[]} ids
 *      The IDs of the notifications
 * @param {Function} callback
 *      A function to be called after the notifications has been canceled
 * @param {Object?} scope
 *      The scope for the callback function
 */
exports.cancel = function (ids, callback, scope) {
    this.core.cancel(ids, callback, scope);
};

/**
 * Remove all previously registered notifications.
 *
 * @param {Function} callback
 *      A function to be called after all notifications have been canceled
 * @param {Object?} scope
 *      The scope for the callback function
 */
exports.cancelAll = function (callback, scope) {
    this.core.cancelAll(callback, scope);
};

/**
 * Check if a notification with an ID is present.
 *
 * @param {String} id
 *      The ID of the notification
 * @param {Function} callback
 *      A callback function to be called with the list
 * @param {Object?} scope
 *      The scope for the callback function
 */
exports.isPresent = function (id, callback, scope) {
    this.core.isPresent(id, callback, scope);
};

/**
 * Check if a notification with an ID is scheduled.
 *
 * @param {String} id
 *      The ID of the notification
 * @param {Function} callback
 *      A callback function to be called with the list
 * @param {Object?} scope
 *      The scope for the callback function
 */
exports.isScheduled = function (id, callback, scope) {
    this.core.isScheduled(id, callback, scope);
};

/**
 * Check if a notification with an ID was triggered.
 *
 * @param {String} id
 *      The ID of the notification
 * @param {Function} callback
 *      A callback function to be called with the list
 * @param {Object?} scope
 *      The scope for the callback function
 */
exports.isTriggered = function (id, callback, scope) {
    this.core.isTriggered(id, callback, scope);
};

/**
 * List all local notification IDs.
 *
 * @param {Function} callback
 *      A callback function to be called with the list
 * @param {Object?} scope
 *      The scope for the callback function
 */
exports.getAllIds = function (callback, scope) {
    this.core.getAllIds(callback, scope);
};

/**
 * Alias for `getAllIds`.
 */
exports.getIds = function () {
    this.getAllIds.apply(this, arguments);
};

/**
 * List all scheduled notification IDs.
 *
 * @param {Function} callback
 *      A callback function to be called with the list
 * @param {Object?} scope
 *      The scope for the callback function
 */
exports.getScheduledIds = function (callback, scope) {
    this.core.getScheduledIds(callback, scope);
};

/**
 * List all triggered notification IDs.
 *
 * @param {Function} callback
 *      A callback function to be called with the list
 * @param {Object?} scope
 *      The scope for the callback function
 */
exports.getTriggeredIds = function (callback, scope) {
    this.core.getTriggeredIds(callback, scope);
};

/**
 * Property list for given local notifications.
 * If called without IDs, all notification will be returned.
 *
 * @param {Number[]?} ids
 *      Set of notification IDs
 * @param {Function} callback
 *      A callback function to be called with the list
 * @param {Object?} scope
 *      The scope for the callback function
 */
exports.get = function () {
    this.core.get.apply(this.core, arguments);
};

/**
 * Property list for all local notifications.
 *
 * @param {Function} callback
 *      A callback function to be called with the list
 * @param {Object?} scope
 *      The scope for the callback function
 */
exports.getAll = function (callback, scope) {
    this.core.getAll(callback, scope);
};

/**
 * Property list for given scheduled notifications.
 * If called without IDs, all notification will be returned.
 *
 * @param {Number[]?} ids
 *      Set of notification IDs
 * @param {Function} callback
 *      A callback function to be called with the list
 * @param {Object?} scope
 *      The scope for the callback function
 */
exports.getScheduled = function () {
    this.core.getScheduled.apply(this.core, arguments);
};

/**
 * Property list for all scheduled notifications.
 *
 * @param {Function} callback
 *      A callback function to be called with the list
 * @param {Object?} scope
 *      The scope for the callback function
 */
exports.getAllScheduled = function (callback, scope) {
    this.core.getAllScheduled(callback, scope);
};

/**
 * Property list for given triggered notifications.
 * If called without IDs, all notification will be returned.
 *
 * @param {Number[]?} ids
 *      Set of notification IDs
 * @param {Function} callback
 *      A callback function to be called with the list
 * @param {Object?} scope
 *      The scope for the callback function
 */
exports.getTriggered = function () {
    this.core.getTriggered.apply(this.core, arguments);
};

/**
 * Property list for all triggered notifications.
 *
 * @param {Function} callback
 *      A callback function to be called with the list
 * @param {Object?} scope
 *      The scope for the callback function
 */
exports.getAllTriggered = function (callback, scope) {
    this.core.getAllTriggered(callback, scope);
};

/**
 * Informs if the app has the permission to show notifications.
 *
 * @param {Function} callback
 *      The function to be exec as the callback
 * @param {Object?} scope
 *      The callback function's scope
 */
exports.hasPermission = function (callback, scope) {
    this.core.hasPermission(callback, scope);
};

/**
 * Register permission to show notifications if not already granted.
 *
 * @param {Function} callback
 *      The function to be exec as the callback
 * @param {Object?} scope
 *      The callback function's scope
 */
exports.registerPermission = function (callback, scope) {
    this.core.registerPermission(callback, scope);
};

/****************
 * DEPRECATIONS *
 ****************/

/**
 * Schedule a new local notification.
 */
exports.add = function () {
    console.warn('Depreated: Please use `notification.local.schedule` instead.');

    this.schedule.apply(this, arguments);
};

/**
 * Register permission to show notifications
 * if not already granted.
 */
exports.promptForPermission = function () {
    console.warn('Depreated: Please use `notification.local.registerPermission` instead.');

    this.registerPermission.apply(this, arguments);
};

/**
 * Increment the number in the notifications file
 *
 * @param {Function} callback
 *      The function to be exec as the callback
 * @param {Object?} scope
 *      The callback function's scope
 */
exports.incrementSummaryCount = function (callback, scope) {
    this.core.incrementSummaryCount(callback, scope);
};

/**
 * decrement the number in the notifications file
 *
 * @param {Function} callback
 *      The function to be exec as the callback
 * @param {Object?} scope
 *      The callback function's scope
 */
exports.decrementSummaryCount = function (callback, scope) {
    this.core.decrementSummaryCount(callback, scope);
};

/**
 * sets the number in the notification summary file
 *
 * @param {Function} callback
 *      The function to be exec as the callback
 * @param {Object?} scope
 *      The callback function's scope
 */
exports.setSummaryCount = function (count, callback, scope) {
    this.core.setSummaryCount(count, callback, scope);
};

/**********
 * EVENTS *
 **********/

/**
 * Register callback for given event.
 *
 * @param {String} event
 *      The event's name
 * @param {Function} callback
 *      The function to be exec as callback
 * @param {Object?} scope
 *      The callback function's scope
 */
exports.on = function (event, callback, scope) {
    this.core.on(event, callback, scope);
};

/**
 * Unregister callback for given event.
 *
 * @param {String} event
 *      The event's name
 * @param {Function} callback
 *      The function to be exec as callback
 */
exports.un = function (event, callback) {
    this.core.un(event, callback);
};
<|endoftext|>


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

var defaultIndent = '  ';
var input = document.getElementById('input');
var output = document.getElementById('output');
var select = document.getElementById('select');
var download = document.getElementById('download');
var downloadLink = document.getElementById('downloadLink');
var binaryBlobUrl = null;

function debounce(f, wait) {
  var lastTime = 0;
  var timeoutId = -1;
  var wrapped = function() {
    var time = +new Date();
    if (time - lastTime < wait) {
      if (timeoutId == -1)
        timeoutId = setTimeout(wrapped, (lastTime + wait) - time);
      return;
    }
    if (timeoutId != -1)
      clearTimeout(timeoutId);
    timeoutId = -1;
    lastTime = time;
    f.apply(null, arguments);
  };
  return wrapped;
}

function insertTextAtSelection(input, src) {
  var selectionStart = input.selectionStart;
  var selectionEnd = input.selectionEnd;
  var oldValue = input.value;
  input.value = oldValue.slice(0, selectionStart) + src +
                oldValue.slice(selectionEnd);
  input.selectionStart = input.selectionEnd = selectionStart + src.length;
}

function onInputKeyDown(e) {
  if (e.keyCode == 9) {  // tab
    insertTextAtSelection(this, defaultIndent);
    e.preventDefault();
  } else if (e.keyCode == 13) {  // newline
    // count nesting depth
    var parens = 0;
    var lastOpen = -1;
    var indent = '';
    for (var i = this.selectionStart - 1; i >= 0; --i) {
      var c = this.value[i];
      if (c == '(') {
        if (--parens < 0) {
          if (lastOpen != -1)
            i = lastOpen;
          else
            indent = defaultIndent;
          break;
        // find first sibling "(", if any
        } else if (parens == 0 && lastOpen == -1) {
          lastOpen = i;
        }
      } else if (c == ')') {
        parens++;
      }
    }
    // get column of current nesting
    var col = 0;
    for (; i > 0; --i) {
      var c = this.value[i];
      if (c == '\n') {
        col--;  // went back too far
        break;
      } else {
        col++;
      }
    }
    // write newline, plus indentation
    insertTextAtSelection(this, '\n' + ' '.repeat(col) + indent);
    e.preventDefault();
  }
}

function compile(text) {
  wasm.ready.then(function() {
    output.textContent = '';
    try {
      var stackAllocator = new wasm.StackAllocator(wasm.LibcAllocator);
      var script = wasm.parseAst(stackAllocator.allocator, 'test.wast', text);
      script.check();
      var binaryOutput = script.toBinary({log: true});
      output.textContent = binaryOutput.log;
      var blob = new Blob([binaryOutput.buffer]);
      if (binaryBlobUrl) {
        URL.revokeObjectURL(binaryBlobUrl);
      }
      binaryBlobUrl = URL.createObjectURL(blob);
      downloadLink.setAttribute('href', binaryBlobUrl);
      download.classList.remove('disabled');
    } catch (e) {
      output.textContent += e.toString();
      download.classList.add('disabled');
    } finally {
      if (script) script.$destroy();
      if (stackAllocator) stackAllocator.$destroy();
    }
  });
}

var compileInput = debounce(function() { compile(input.value); }, 100);

function onInputInput(e) {
  compileInput();
}

var examples = [
  {
    name: 'empty',
    contents: '(module)'
  },

  {
    name: 'simple',
    contents:
      '(module\n' +
      '  (func $addTwo (param i32 i32) (result i32)\n' +
      '    (i32.add\n' +
      '      (get_local 0)\n' +
      '      (get_local 1)))\n' +
      '  (export "addTwo" (func $addTwo)))\n'
  },

  {
    name: 'factorial',
    contents:
      '(module\n' +
      '  (func $fac (param i64) (result i64)\n' +
      '    (if i64\n' +
      '      (i64.lt_s (get_local 0) (i64.const 1))\n' +
      '      (then (i64.const 1))\n' +
      '      (else\n' +
      '        (i64.mul\n' +
      '          (get_local 0)\n' +
      '          (call $fac\n' +
      '            (i64.sub\n' +
      '              (get_local 0)\n' +
      '              (i64.const 1)))))))\n' +
      '  (export "fac" (func $fac)))\n'
  },

  {
    name: 'stuff',
    contents:
      '(module\n' +
      '  (import "foo" "bar" (func (param f32)))\n' +
      '  (memory (data "hi"))\n' +
      '  (type (func (param i32) (result i32)))\n' +
      '  (start 1)\n' +
      '  (table 0 1 anyfunc)\n' +
      '  (func)\n' +
      '  (func (type 0) (drop (i32.const 42)))\n' +
      '  (export "e" (func 1)))\n'
  }
];

function setExample(index) {
  var contents = examples[index].contents;
  input.value = contents;
  compileInput();
}

function onSelectChanged(e) {
  setExample(this.selectedIndex);
}

function onDownloadClicked(e) {
  // See https://developer.mozilla.com/en-US/docs/Web/API/MouseEvent
  var event = new MouseEvent('click', {
    view: window,
    bubbles: true,
    cancelable: true,
  });
  downloadLink.dispatchEvent(event);
}

input.addEventListener('keydown', onInputKeyDown);
input.addEventListener('input', onInputInput);
select.addEventListener('change', onSelectChanged);
download.addEventListener('click', onDownloadClicked);

for (var i = 0; i < examples.length; ++i) {
  var example = examples[i];
  var option = document.createElement('option');
  option.textContent = example.name;
  select.appendChild(option);
}
select.selectedIndex = 1;
setExample(select.selectedIndex);
<commit_msg>Update demo examples to linear format<commit_after>/*
 * Copyright 2016 WebAssembly Community Group participants
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var defaultIndent = '  ';
var input = document.getElementById('input');
var output = document.getElementById('output');
var select = document.getElementById('select');
var download = document.getElementById('download');
var downloadLink = document.getElementById('downloadLink');
var binaryBlobUrl = null;

function debounce(f, wait) {
  var lastTime = 0;
  var timeoutId = -1;
  var wrapped = function() {
    var time = +new Date();
    if (time - lastTime < wait) {
      if (timeoutId == -1)
        timeoutId = setTimeout(wrapped, (lastTime + wait) - time);
      return;
    }
    if (timeoutId != -1)
      clearTimeout(timeoutId);
    timeoutId = -1;
    lastTime = time;
    f.apply(null, arguments);
  };
  return wrapped;
}

function insertTextAtSelection(input, src) {
  var selectionStart = input.selectionStart;
  var selectionEnd = input.selectionEnd;
  var oldValue = input.value;
  input.value = oldValue.slice(0, selectionStart) + src +
                oldValue.slice(selectionEnd);
  input.selectionStart = input.selectionEnd = selectionStart + src.length;
}

function onInputKeyDown(e) {
  if (e.keyCode == 9) {  // tab
    insertTextAtSelection(this, defaultIndent);
    e.preventDefault();
  } else if (e.keyCode == 13) {  // newline
    // count nesting depth
    var parens = 0;
    var lastOpen = -1;
    var indent = '';
    for (var i = this.selectionStart - 1; i >= 0; --i) {
      var c = this.value[i];
      if (c == '(') {
        if (--parens < 0) {
          if (lastOpen != -1)
            i = lastOpen;
          else
            indent = defaultIndent;
          break;
        // find first sibling "(", if any
        } else if (parens == 0 && lastOpen == -1) {
          lastOpen = i;
        }
      } else if (c == ')') {
        parens++;
      }
    }
    // get column of current nesting
    var col = 0;
    for (; i > 0; --i) {
      var c = this.value[i];
      if (c == '\n') {
        col--;  // went back too far
        break;
      } else {
        col++;
      }
    }
    // write newline, plus indentation
    insertTextAtSelection(this, '\n' + ' '.repeat(col) + indent);
    e.preventDefault();
  }
}

function compile(text) {
  wasm.ready.then(function() {
    output.textContent = '';
    try {
      var stackAllocator = new wasm.StackAllocator(wasm.LibcAllocator);
      var script = wasm.parseAst(stackAllocator.allocator, 'test.wast', text);
      script.check();
      var binaryOutput = script.toBinary({log: true});
      output.textContent = binaryOutput.log;
      var blob = new Blob([binaryOutput.buffer]);
      if (binaryBlobUrl) {
        URL.revokeObjectURL(binaryBlobUrl);
      }
      binaryBlobUrl = URL.createObjectURL(blob);
      downloadLink.setAttribute('href', binaryBlobUrl);
      download.classList.remove('disabled');
    } catch (e) {
      output.textContent += e.toString();
      download.classList.add('disabled');
    } finally {
      if (script) script.$destroy();
      if (stackAllocator) stackAllocator.$destroy();
    }
  });
}

var compileInput = debounce(function() { compile(input.value); }, 100);

function onInputInput(e) {
  compileInput();
}

var examples = [
  {
    name: 'empty',
    contents: '(module)'
  },

  {
    name: 'simple',
    contents:
      '(module\n' +
      '  (func $addTwo (param i32 i32) (result i32)\n' +
      '    get_local 0\n' +
      '    get_local 1\n' +
      '    i32.add)\n' +
      '  (export "addTwo" (func $addTwo)))\n'
  },

  {
    name: 'factorial',
    contents:
      '(module\n' +
      '  (func $fac (param i64) (result i64)\n' +
      '    get_local 0\n' +
      '    i64.const 1\n' +
      '    i64.lt_s\n' +
      '    if i64\n' +
      '      i64.const 1\n' +
      '    else\n' +
      '      get_local 0\n' +
      '      get_local 0\n' +
      '      i64.const 1\n' +
      '      i64.sub\n' +
      '      call $fac\n' +
      '      i64.mul\n' +
      '    end)\n' +
      '  (export "fac" (func $fac)))\n'
  },

  {
    name: 'stuff',
    contents:
      '(module\n' +
      '  (import "foo" "bar" (func (param f32)))\n' +
      '  (memory (data "hi"))\n' +
      '  (type (func (param i32) (result i32)))\n' +
      '  (start 1)\n' +
      '  (table 0 1 anyfunc)\n' +
      '  (func)\n' +
      '  (func (type 0)\n' +
      '    i32.const 42\n' +
      '    drop)\n' +
      '  (export "e" (func 1)))\n'
  }
];

function setExample(index) {
  var contents = examples[index].contents;
  input.value = contents;
  compileInput();
}

function onSelectChanged(e) {
  setExample(this.selectedIndex);
}

function onDownloadClicked(e) {
  // See https://developer.mozilla.com/en-US/docs/Web/API/MouseEvent
  var event = new MouseEvent('click', {
    view: window,
    bubbles: true,
    cancelable: true,
  });
  downloadLink.dispatchEvent(event);
}

input.addEventListener('keydown', onInputKeyDown);
input.addEventListener('input', onInputInput);
select.addEventListener('change', onSelectChanged);
download.addEventListener('click', onDownloadClicked);

for (var i = 0; i < examples.length; ++i) {
  var example = examples[i];
  var option = document.createElement('option');
  option.textContent = example.name;
  select.appendChild(option);
}
select.selectedIndex = 1;
setExample(select.selectedIndex);
<|endoftext|>


<commit_before>CKEDITOR.editorConfig = function( config ) {
  config.allowedContent = true;
  config.removeFormatTags = "";
  config.protectedSource.push(/<r:([\S]+).*<\/r:\1>/g);
  config.protectedSource.push(/<r:[^>/]*\/>/g);

  config.forcePasteAsPlainText = true;
  // if you want to remove clipboard, you have to remove all of these:
  // clipboard, pastetext, pastefromword
  config.removePlugins = "save, newpage, preview, print, templates, forms, flash, smiley, language, pagebreak, iframe, bidi";

  var startupMode = $.cookie('ckeditor.startupMode');
  if (startupMode == 'source' || startupMode == 'wysiwyg' ) {
    config.startupMode = startupMode;
  }

  this.on('mode', function(){
    $.cookie('ckeditor.startupMode', this.mode);
  })

};
<commit_msg>Comment out paste plain text line and give the option to paste with formatting.<commit_after>CKEDITOR.editorConfig = function( config ) {
  config.allowedContent = true;
  config.removeFormatTags = "";
  config.protectedSource.push(/<r:([\S]+).*<\/r:\1>/g);
  config.protectedSource.push(/<r:[^>/]*\/>/g);
  //let paste from word be available
  // config.forcePasteAsPlainText = false;
  // if you want to remove clipboard, you have to remove all of these:
  // clipboard, pastetext, pastefromword
  config.removePlugins = "save, newpage, preview, print, templates, forms, flash, smiley, language, pagebreak, iframe, bidi";

  var startupMode = $.cookie('ckeditor.startupMode');
  if (startupMode == 'source' || startupMode == 'wysiwyg' ) {
    config.startupMode = startupMode;
  }

  this.on('mode', function(){
    $.cookie('ckeditor.startupMode', this.mode);
  })

};
<|endoftext|>


<commit_before>import {
  BaseModel, identifiedBy, identifier, session, field, hasMany, computed, action,
} from '../model';
import { reduce, map, filter, find, inRange, merge } from 'lodash';
import invariant from 'invariant';
import Attachment from './exercise/attachment';
import Author from './exercise/author';
import Question from './exercise/question';
import Tag from './exercise/tag';

export { Attachment, Author, Question, Tag };

@identifiedBy('exercise')
export default class Exercise extends BaseModel {

  static build(attrs) {
    return new this(merge(attrs, {
      questions: [{
        formats: ['free-response'],
      }],
    }));
  }

  @identifier uuid;
  @field id;
  @field uid;
  @field version;
  @field nickname;
  @field({ type: 'array' }) versions;

  @field is_vocab;
  @field number;
  @field stimulus_html;
  @session wrapper;

  @hasMany({ model: Attachment }) attachments;
  @hasMany({ model: Author }) authors;
  @hasMany({ model: Author })  copyright_holders;
  @hasMany({ model: Question, inverseOf: 'exercise' }) questions;
  @hasMany({
    model: Tag,
    extend: {
      withType(type, { multiple = false } = {}) {
        return multiple ? filter(this, { type }) : find(this, { type });
      },
      findOrAddWithType(type) {
        return this.withType(type) || this.get(this.push(`${type}:`) - 1);
      },
    },
  }) tags;

  @computed get pool_types() {
    return [];
  }

  @computed get cnxModuleUUIDs() {
    return map(filter(this.tags, { type: 'context-cnxmod' }), 'value');
  }

  @computed get validity() {
    return reduce(this.questios, (memo, question) => ({
      valid: memo.valid && question.validity.valid,
      part: memo.part || question.validity.part,
    }) , { valid: true });
  }

  @action toggleMultiPart() {
    if (this.isMultiPart) {
      this.questions.slice(1);
    } else {
      this.questions.push({});
    }
  }

  @action moveQuestion(question, offset) {
    const index = this.questions.indexOf(question);
    invariant((index !== -1) && inRange(index+offset, 0, this.questions.length),
      'question not found or cannot move past bounds');
    this.questions.splice(index+offset, 0, this.questions.splice(index, 1)[0]);
  }

  @computed get isMultiPart() {
    return this.questions.length > 1;
  }

  @computed get isPublishable() {
    return Boolean(!this.isNew && this.validity.valid);
  }
}
<commit_msg>exercise can only be published if published_at is null<commit_after>import {
  BaseModel, identifiedBy, identifier, session, field, hasMany, computed, action,
} from '../model';
import { reduce, map, filter, find, inRange, merge } from 'lodash';
import invariant from 'invariant';
import Attachment from './exercise/attachment';
import Author from './exercise/author';
import Question from './exercise/question';
import Tag from './exercise/tag';

export { Attachment, Author, Question, Tag };

@identifiedBy('exercise')
export default class Exercise extends BaseModel {

  static build(attrs) {
    return new this(merge(attrs, {
      questions: [{
        formats: ['free-response'],
      }],
    }));
  }

  @identifier uuid;
  @field id;
  @field uid;
  @field version;
  @field nickname;
  @field({ type: 'array' }) versions;

  @field is_vocab;
  @field number;
  @field stimulus_html;
  @session published_at;
  @session wrapper;

  @hasMany({ model: Attachment }) attachments;
  @hasMany({ model: Author }) authors;
  @hasMany({ model: Author })  copyright_holders;
  @hasMany({ model: Question, inverseOf: 'exercise' }) questions;
  @hasMany({
    model: Tag,
    extend: {
      withType(type, { multiple = false } = {}) {
        return multiple ? filter(this, { type }) : find(this, { type });
      },
      findOrAddWithType(type) {
        return this.withType(type) || this.get(this.push(`${type}:`) - 1);
      },
    },
  }) tags;

  @computed get pool_types() {
    return [];
  }

  @computed get cnxModuleUUIDs() {
    return map(filter(this.tags, { type: 'context-cnxmod' }), 'value');
  }

  @computed get validity() {
    return reduce(this.questios, (memo, question) => ({
      valid: memo.valid && question.validity.valid,
      part: memo.part || question.validity.part,
    }) , { valid: true });
  }

  @action toggleMultiPart() {
    if (this.isMultiPart) {
      this.questions.slice(1);
    } else {
      this.questions.push({});
    }
  }

  @action moveQuestion(question, offset) {
    const index = this.questions.indexOf(question);
    invariant((index !== -1) && inRange(index+offset, 0, this.questions.length),
      'question not found or cannot move past bounds');
    this.questions.splice(index+offset, 0, this.questions.splice(index, 1)[0]);
  }

  @computed get isMultiPart() {
    return this.questions.length > 1;
  }

  @computed get isPublishable() {
    return Boolean(!this.isNew && this.validity.valid && !this.published_at);
  }
}
<|endoftext|>


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

const info = require('../package');
const opts = require('nomnom')
  .option('version', {
    abbr: 'v',
    flag: true,
    callback: () => {
      console.log(info.version);
      process.exit();
    },
    help: 'Print program version.'
  })
  .option('url', {
    position: 0,
    required: true,
    help: 'URL to the video.'
  })
  .option('quality', {
    abbr: 'q',
    metavar: 'ITAG',
    help: 'Video quality to download, default: highest'
  })
  .option('range', {
    abbr: 'r',
    metavar: 'INT-INT',
    help: 'Byte range to download, ie 10355705-12452856'
  })
  .option('begin', {
    abbr: 'b',
    metavar: 'INT',
    help: 'Time to begin video, format by 1:30.123 and 1m30s'
  })
  .option('output', {
    abbr: 'o',
    metavar: 'FILE',
    help: 'Save to file, template by {prop}, default: stdout'
  })
  .option('filter', {
    full: 'filter',
    metavar: 'STR',
    help: 'Can be video, videoonly, audio, audioonly'
  })
  .option('filterContainer', {
    full: 'filter-container',
    metavar: 'REGEXP',
    help: 'Filter in format container'
  })
  .option('unfilterContainer', {
    full: 'unfilter-container',
    metavar: 'REGEXP',
    help: 'Filter out format container'
  })
  .option('filterResolution', {
    full: 'filter-resolution',
    metavar: 'REGEXP',
    help: 'Filter in format resolution'
  })
  .option('unfilterResolution', {
    full: 'unfilter-resolution',
    metavar: 'REGEXP',
    help: 'Filter out format resolution'
  })
  .option('filterEncoding', {
    full: 'filter-encoding',
    metavar: 'REGEXP',
    help: 'Filter in format encoding'
  })
  .option('unfilterEncoding', {
    full: 'unfilter-encoding',
    metavar: 'REGEXP',
    help: 'Filter out format encoding'
  })
  .option('info', {
    abbr: 'i',
    flag: true,
    help: 'Print video info without downloading'
  })
  .option('infoJson', {
    full: 'info-json',
    abbr: 'j',
    flag: true,
    help: 'Print video info as JSON without downloading'
  })
  .option('printUrl', {
    full: 'print-url',
    flag: true,
    help: 'Print direct download URL'
  })
  .option('noCache', {
    full: 'no-cache',
    flat: true,
    help: 'Skip file cache for html5player'
  })
  .option('debug', {
    flag: true,
    help: 'Print debug information'
  })
  .script('ytdl')
  .colors()
  .parse()
  ;

const path    = require('path');
const fs      = require('fs');
const ytdl    = require('ytdl-core');
const homedir = require('homedir');
const util    = require('../lib/util');

const chalk = require('chalk');
const label = chalk.bold.gray;

if (opts.cache !== false) {
  // Keep cache in file.
  var cachefile = path.resolve(homedir(), '.ytdl-cache.json');
  fs.readFile(cachefile, (err, contents) => {
    if (err) return;
    try {
      ytdl.cache.store = JSON.parse(contents);
    } catch (err) {
      console.error(err.message);
    }
  });

  ytdl.cache.set = (key, value) => {
    ytdl.cache.store[key] = value;
    fs.writeFile(cachefile,
      JSON.stringify(ytdl.cache.store, null, 2), () => {});
  };
}

/**
 * Prints basic video information.
 *
 * @param {Object} info
 */
function printVideoInfo(info) {
  console.log();
  console.log(label('title: ') + info.title);
  console.log(label('author: ') + info.author.name);
  console.log(label('average rating: ') + info.avg_rating);
  console.log(label('view count: ') + info.view_count);
  console.log(label('length: ') + util.toHumanTime(info.length_seconds));
}

if (opts.infoJson) {
  ytdl.getInfo(opts.url, { debug: opts.debug }, (err, info) => {
    if (err) {
      console.error(err.message);
      process.exit(1);
      return;
    }
    console.log(JSON.stringify(info));
  });
} else if (opts.info) {
  const cliff = require('cliff');
  ytdl.getInfo(opts.url, { debug: opts.debug }, (err, info) => {
    if (err) {
      console.error(err.message);
      process.exit(1);
      return;
    }

    printVideoInfo(info);

    var cols = [
      'itag',
      'container',
      'resolution',
      'video enc',
      'audio bitrate',
      'audio enc'
    ];
    info.formats.forEach((format) => {
      format['video enc']     = format.encoding;
      format['audio bitrate'] = format.audioBitrate;
      format['audio enc']     = format.audioEncoding;
      cols.forEach((col) => {
        format[col] = format[col] || '';
      });
    });
    console.log(label('formats:'));
    var colors = ['green', 'blue', 'green', 'blue', 'green', 'blue'];
    console.log(cliff.stringifyObjectRows(info.formats, cols, colors));
  });

} else {
  var output = opts.output;
  var ext = (output || '').match(/(\.\w+)?$/)[1];

  if (output) {
    if (ext && !opts.quality && !opts.filterContainer) {
      opts.filterContainer = '^' + ext.slice(1) + '$';
    }
  }

  var ytdlOptions = {};
  ytdlOptions.quality = /,/.test(opts.quality) ?
    opts.quality.split(',') : opts.quality;
  if (opts.range) {
    var s = opts.range.split('-');
    ytdlOptions.range = { start: s[0], end: s[1] };
  }
  ytdlOptions.begin = opts.begin;

  // Create filters.
  var filters = [];

  /**
   * @param {String} field
   * @param {String} regexpStr
   * @param {Boolean|null} negated
   */
  var createFilter = (field, regexpStr, negated) => {
    try {
      var regexp = new RegExp(regexpStr, 'i');
    } catch (err) {
      console.error(err.message);
      process.exit(1);
    }

    filters.push(format => negated !== regexp.test(format[field]));
  };

  ['container', 'resolution', 'encoding'].forEach((field) => {
    var key = 'filter' + field[0].toUpperCase() + field.slice(1);
    if (opts[key]) {
      createFilter(field, opts[key], false);
    }

    key = 'un' + key;
    if (opts[key]) {
      createFilter(field, opts[key], true);
    }
  });

  // Support basic ytdl-core filters manually, so that other
  // cli filters are supported when used together.
  switch (opts.filter) {
    case 'video':
      filters.push(format => format.bitrate);
      break;

    case 'videoonly':
      filters.push(format => format.bitrate && !format.audioBitrate);
      break;

    case 'audio':
      filters.push(format => format.audioBitrate);
      break;

    case 'audioonly':
      filters.push(format => !format.bitrate && format.audioBitrate);
      break;
  }

  ytdlOptions.filter = (format) => {
    return filters.every(filter => filter(format));
  };

  if (opts.printUrl) {
    ytdl.getInfo(opts.url, { debug: opts.debug }, (err, info) => {
      if (err) {
        console.error(err.message);
        process.exit(1);
        return;
      }
      var format = ytdl.chooseFormat(info.formats, ytdlOptions);
      if (format instanceof Error) {
        console.error(format.message);
        process.exit(1);
        return;
      }
      console.log(format.url);
    });

  } else {
    var readStream = ytdl(opts.url, ytdlOptions);
    var liveBroadcast = false;

    readStream.on('info', (info, format) => {
      if (!output) {
        readStream.pipe(process.stdout).on('error', (err) => {
          console.error(err.message);
          process.exit(1);
        });
        return;
      }

      output = util.tmpl(output, [info, format]);
      if (!ext && format.container) {
        output += '.' + format.container;
      }
      readStream.pipe(fs.createWriteStream(output))
        .on('error', (err) => {
          console.error(err.message);
          process.exit(1);
        });

      // Print information about the video if not streaming to stdout.
      printVideoInfo(info);

      console.log(label('container: ') + format.container);
      console.log(label('resolution: ') + format.resolution);
      console.log(label('encoding: ') + format.encoding);

      liveBroadcast = format.live;
      if (!liveBroadcast) { return; }

      const throttle = require('lodash.throttle');
      var dataRead = 0;
      var updateProgress = throttle(() => {
        process.stdout.cursorTo(0);
        process.stdout.clearLine(1);
        process.stdout.write(label('size: ') + util.toHumanSize(dataRead) +
                             ' (' + dataRead +' bytes)');
      }, 500);

      readStream.on('data', (data) => {
        dataRead += data.length;
        updateProgress();
      });
    });

    readStream.on('response', (res) => {
      if (!output || liveBroadcast) { return; }

      // Print information about the format we're downloading.
      var size = parseInt(res.headers['content-length'], 10);
      console.log(label('size: ') + util.toHumanSize(size) +
                  ' (' + size +' bytes)');
      console.log(label('output: ') + output);
      console.log();

      // Create progress bar.
      const bar = require('progress-bar').create(process.stdout, 50);
      const throttle = require('lodash.throttle');
      bar.format = '$bar; $percentage;%';

      var lastPercent = null;
      var updateBar = () => {
        var percent = dataRead / size;
        var newPercent = Math.floor(percent * 100);
        if (newPercent != lastPercent) {
          lastPercent = newPercent;
          bar.update(percent);
        }
      };
      var updateBarThrottled = throttle(updateBar, 100, { trailing: false });

      // Keep track of progress.
      var dataRead = 0;
      readStream.on('data', (data) => {
        dataRead += data.length;
        if (dataRead === size) {
          updateBar();
        } else {
          updateBarThrottled();
        }
      });
    });

    readStream.on('error', (err) => {
      console.error(err.message);
      process.exit(1);
    });

    readStream.on('end', () => {
      console.log();
    });

    process.on('SIGINT', () => {
      console.log();
      process.exit();
    });
  }
}
<commit_msg>update to use map cache (fixes #67)<commit_after>#!/usr/bin/env node

const info = require('../package');
const opts = require('nomnom')
  .option('version', {
    abbr: 'v',
    flag: true,
    callback: () => {
      console.log(info.version);
      process.exit();
    },
    help: 'Print program version.'
  })
  .option('url', {
    position: 0,
    required: true,
    help: 'URL to the video.'
  })
  .option('quality', {
    abbr: 'q',
    metavar: 'ITAG',
    help: 'Video quality to download, default: highest'
  })
  .option('range', {
    abbr: 'r',
    metavar: 'INT-INT',
    help: 'Byte range to download, ie 10355705-12452856'
  })
  .option('begin', {
    abbr: 'b',
    metavar: 'INT',
    help: 'Time to begin video, format by 1:30.123 and 1m30s'
  })
  .option('output', {
    abbr: 'o',
    metavar: 'FILE',
    help: 'Save to file, template by {prop}, default: stdout'
  })
  .option('filter', {
    full: 'filter',
    metavar: 'STR',
    help: 'Can be video, videoonly, audio, audioonly'
  })
  .option('filterContainer', {
    full: 'filter-container',
    metavar: 'REGEXP',
    help: 'Filter in format container'
  })
  .option('unfilterContainer', {
    full: 'unfilter-container',
    metavar: 'REGEXP',
    help: 'Filter out format container'
  })
  .option('filterResolution', {
    full: 'filter-resolution',
    metavar: 'REGEXP',
    help: 'Filter in format resolution'
  })
  .option('unfilterResolution', {
    full: 'unfilter-resolution',
    metavar: 'REGEXP',
    help: 'Filter out format resolution'
  })
  .option('filterEncoding', {
    full: 'filter-encoding',
    metavar: 'REGEXP',
    help: 'Filter in format encoding'
  })
  .option('unfilterEncoding', {
    full: 'unfilter-encoding',
    metavar: 'REGEXP',
    help: 'Filter out format encoding'
  })
  .option('info', {
    abbr: 'i',
    flag: true,
    help: 'Print video info without downloading'
  })
  .option('infoJson', {
    full: 'info-json',
    abbr: 'j',
    flag: true,
    help: 'Print video info as JSON without downloading'
  })
  .option('printUrl', {
    full: 'print-url',
    flag: true,
    help: 'Print direct download URL'
  })
  .option('noCache', {
    full: 'no-cache',
    flat: true,
    help: 'Skip file cache for html5player'
  })
  .option('debug', {
    flag: true,
    help: 'Print debug information'
  })
  .script('ytdl')
  .colors()
  .parse()
  ;

const path    = require('path');
const fs      = require('fs');
const ytdl    = require('ytdl-core');
const homedir = require('homedir');
const util    = require('../lib/util');

const chalk = require('chalk');
const label = chalk.bold.gray;

if (opts.cache !== false) {
  // Keep cache in file.
  var cachefile = path.resolve(homedir(), '.ytdl-cache.json');
  var cache = {};
  fs.readFile(cachefile, (err, contents) => {
    if (err) return;
    try {
      cache = JSON.parse(contents);
    } catch (err) {
      console.error(`Badly formatted cachefile (${cachefile}): ${err.message}`);
    }
  });

  ytdl.cache.get = key => cache[key];
  ytdl.cache.set = (key, value) => {
    cache[key] = value;
    fs.writeFile(cachefile,
      JSON.stringify(cache, null, 2), () => {});
  };
}

/**
 * Prints basic video information.
 *
 * @param {Object} info
 */
function printVideoInfo(info) {
  console.log();
  console.log(label('title: ') + info.title);
  console.log(label('author: ') + info.author.name);
  console.log(label('average rating: ') + info.avg_rating);
  console.log(label('view count: ') + info.view_count);
  console.log(label('length: ') + util.toHumanTime(info.length_seconds));
}

if (opts.infoJson) {
  ytdl.getInfo(opts.url, { debug: opts.debug }, (err, info) => {
    if (err) {
      console.error(err.message);
      process.exit(1);
      return;
    }
    console.log(JSON.stringify(info));
  });
} else if (opts.info) {
  const cliff = require('cliff');
  ytdl.getInfo(opts.url, { debug: opts.debug }, (err, info) => {
    if (err) {
      console.error(err.message);
      process.exit(1);
      return;
    }

    printVideoInfo(info);

    var cols = [
      'itag',
      'container',
      'resolution',
      'video enc',
      'audio bitrate',
      'audio enc'
    ];
    info.formats.forEach((format) => {
      format['video enc']     = format.encoding;
      format['audio bitrate'] = format.audioBitrate;
      format['audio enc']     = format.audioEncoding;
      cols.forEach((col) => {
        format[col] = format[col] || '';
      });
    });
    console.log(label('formats:'));
    var colors = ['green', 'blue', 'green', 'blue', 'green', 'blue'];
    console.log(cliff.stringifyObjectRows(info.formats, cols, colors));
  });

} else {
  var output = opts.output;
  var ext = (output || '').match(/(\.\w+)?$/)[1];

  if (output) {
    if (ext && !opts.quality && !opts.filterContainer) {
      opts.filterContainer = '^' + ext.slice(1) + '$';
    }
  }

  var ytdlOptions = {};
  ytdlOptions.quality = /,/.test(opts.quality) ?
    opts.quality.split(',') : opts.quality;
  if (opts.range) {
    var s = opts.range.split('-');
    ytdlOptions.range = { start: s[0], end: s[1] };
  }
  ytdlOptions.begin = opts.begin;

  // Create filters.
  var filters = [];

  /**
   * @param {String} field
   * @param {String} regexpStr
   * @param {Boolean|null} negated
   */
  var createFilter = (field, regexpStr, negated) => {
    try {
      var regexp = new RegExp(regexpStr, 'i');
    } catch (err) {
      console.error(err.message);
      process.exit(1);
    }

    filters.push(format => negated !== regexp.test(format[field]));
  };

  ['container', 'resolution', 'encoding'].forEach((field) => {
    var key = 'filter' + field[0].toUpperCase() + field.slice(1);
    if (opts[key]) {
      createFilter(field, opts[key], false);
    }

    key = 'un' + key;
    if (opts[key]) {
      createFilter(field, opts[key], true);
    }
  });

  // Support basic ytdl-core filters manually, so that other
  // cli filters are supported when used together.
  switch (opts.filter) {
    case 'video':
      filters.push(format => format.bitrate);
      break;

    case 'videoonly':
      filters.push(format => format.bitrate && !format.audioBitrate);
      break;

    case 'audio':
      filters.push(format => format.audioBitrate);
      break;

    case 'audioonly':
      filters.push(format => !format.bitrate && format.audioBitrate);
      break;
  }

  ytdlOptions.filter = (format) => {
    return filters.every(filter => filter(format));
  };

  if (opts.printUrl) {
    ytdl.getInfo(opts.url, { debug: opts.debug }, (err, info) => {
      if (err) {
        console.error(err.message);
        process.exit(1);
        return;
      }
      var format = ytdl.chooseFormat(info.formats, ytdlOptions);
      if (format instanceof Error) {
        console.error(format.message);
        process.exit(1);
        return;
      }
      console.log(format.url);
    });

  } else {
    var readStream = ytdl(opts.url, ytdlOptions);
    var liveBroadcast = false;

    readStream.on('info', (info, format) => {
      if (!output) {
        readStream.pipe(process.stdout).on('error', (err) => {
          console.error(err.message);
          process.exit(1);
        });
        return;
      }

      output = util.tmpl(output, [info, format]);
      if (!ext && format.container) {
        output += '.' + format.container;
      }
      readStream.pipe(fs.createWriteStream(output))
        .on('error', (err) => {
          console.error(err.message);
          process.exit(1);
        });

      // Print information about the video if not streaming to stdout.
      printVideoInfo(info);

      console.log(label('container: ') + format.container);
      console.log(label('resolution: ') + format.resolution);
      console.log(label('encoding: ') + format.encoding);

      liveBroadcast = format.live;
      if (!liveBroadcast) { return; }

      const throttle = require('lodash.throttle');
      var dataRead = 0;
      var updateProgress = throttle(() => {
        process.stdout.cursorTo(0);
        process.stdout.clearLine(1);
        process.stdout.write(label('size: ') + util.toHumanSize(dataRead) +
                             ' (' + dataRead +' bytes)');
      }, 500);

      readStream.on('data', (data) => {
        dataRead += data.length;
        updateProgress();
      });
    });

    readStream.on('response', (res) => {
      if (!output || liveBroadcast) { return; }

      // Print information about the format we're downloading.
      var size = parseInt(res.headers['content-length'], 10);
      console.log(label('size: ') + util.toHumanSize(size) +
                  ' (' + size +' bytes)');
      console.log(label('output: ') + output);
      console.log();

      // Create progress bar.
      const bar = require('progress-bar').create(process.stdout, 50);
      const throttle = require('lodash.throttle');
      bar.format = '$bar; $percentage;%';

      var lastPercent = null;
      var updateBar = () => {
        var percent = dataRead / size;
        var newPercent = Math.floor(percent * 100);
        if (newPercent != lastPercent) {
          lastPercent = newPercent;
          bar.update(percent);
        }
      };
      var updateBarThrottled = throttle(updateBar, 100, { trailing: false });

      // Keep track of progress.
      var dataRead = 0;
      readStream.on('data', (data) => {
        dataRead += data.length;
        if (dataRead === size) {
          updateBar();
        } else {
          updateBarThrottled();
        }
      });
    });

    readStream.on('error', (err) => {
      console.error(err.message);
      process.exit(1);
    });

    readStream.on('end', () => {
      console.log();
    });

    process.on('SIGINT', () => {
      console.log();
      process.exit();
    });
  }
}
<|endoftext|>


<commit_before>"use strict";

var neo4j = require("neo4j");
var q = require("q");
var util = require("util");

//var server = new neo4j.GraphDatabase("http://localhost:7474");

/**
 * Directory
 */

var Directory = function (server) {
	this.server = server;
}

Directory.prototype.root_area = function () {
	var dir = this;

	return promise_query(this.server,
		[
			"MATCH (root:Area)",
			"WHERE NOT ()-[:PARENT_OF]->(root)",
			"RETURN root"
		],
		{},
		function (results) {
			var node = results[0]["root"]; // should only be one result
			return new Area(dir, node.id, node.data);
		}
	);
}

Directory.prototype.area = function (area_id) {
	var dir = this;
	var deferred = q.defer();
	this.server.getNodeById(area_id, function (err, node) {
		if (err) {
			deferred.reject(err);
			throw err;
		}
		var data = node.data;
		var area = new Area(dir, node.id, data);
		deferred.resolve(area);
		return;
	});
	return deferred.promise;
}

exports.Directory = Directory;

/**
 * Area
 */

var Area = function (dir, area_id, area_info) {
	this.directory = dir;
	this.area_id = area_id;
	this.name = area_info.name;
	if (area_info.note !== undefined) this.note = area_info.note;
}

Area.prototype.descend_along_path = function (path) {
	var area = this;

	// construct query
	var query = ["START n=node({root_area_id}) MATCH (n)"];
	path.forEach(function (area_name, depth) {
		query.push(util.format(
			"-[:PARENT_OF]->(x%d:Area { name: \"%s\"})",
			depth, area_name
		));
	});
	var result_node_name = util.format("x%d", path.length - 1);
	query.push(util.format("RETURN %s", result_node_name));

	return promise_query(this.directory.server,
		query, {"root_area_id" : this.get_area_id()},
		function (target_node) {
			var target = target_node[0][result_node_name];
			return new Area(
				area.directory, target.id, target.data
			);
		}
	);
}

Area.prototype.parent = function () {
	var area = this;

	return promise_query(
		this.directory.server,
		[
			"START n=node({area_id})",
			"MATCH (parent:Area)-[:PARENT_OF]->(n)",
			"RETURN parent"
		],
		{"area_id" : this.area_id},
		function (parents) {
			if (!parents.length) return null;
			var parent = parents[0]["parent"];
			return new Area(area.directory, parent.id, parent.data);
		}
	);
}

Area.prototype.children = function () {
	var area = this;

	return promise_query(this.directory.server,
		[
			"START n=node({area_id})",
			"MATCH (n)-[:PARENT_OF]->(child:Area)",
			"RETURN child"
		],
		{"area_id" : this.area_id},
		function (child_nodes) {
			return child_nodes.map(function (child_node) {
				var child_area = child_node["child"];
				return new Area(
					area.directory, child_area.id, child_area.data
				);
			});
		}
	);
}

Area.prototype.descendents = function () {
	var area = this;

	return promise_query(this.directory.server,
		[
			"START n=node({area_id})",
			"MATCH (n)-[depth:PARENT_OF*]->(dp:Area)",
			"OPTIONAL MATCH (dp)-[:PARENT_OF]->(d:Area)",
			"RETURN d, depth, dp"
		],
		{"area_id" : this.area_id},
		function (descendents) {
			var tree_dict = {};
			tree_dict[area.area_id] = [];
			var area_dict = {};
			area_dict[area.area_id] = area;

			descendents.forEach(function (d) {
				var depth = d.depth.length;
				if (!d.d) {
					if (depth == 1) {
						tree_dict[area.area_id].push(d.dp.id);
						area_dict[d.dp.id] = new Area(area.directory, d.dp.id, d.dp.data);
					}
				} else {
					var depth = d.depth.length;

					if (depth == 1 && tree_dict[area.area_id].indexOf(d.dp.id) == -1) {
						tree_dict[area.area_id].push(d.dp.id);
						area_dict[d.dp.id] = new Area(area.directory, d.dp.id, d.dp.data);
					}

					if (!(d.dp.id in tree_dict)) {
						tree_dict[d.dp.id] = [];
					}
					tree_dict[d.dp.id].push(d.d.id);
					area_dict[d.d.id] = new Area(area.directory, d.d.id, d.d.data);
				}
			});
			var queue = [];
			var attach_descendents = function (node) {
				node.children = [];
				if (node.area.area_id in tree_dict) {
					tree_dict[node.area.area_id].forEach(function (child) {
						var new_area = {area: area_dict[child]};
						attach_descendents(new_area);
						node.children.push(new_area);
					});
				}
			}

			var root_node = {"area" : area};
			attach_descendents(root_node);

			return root_node;
		}
	);
}

Area.prototype.path = function (base_area_id) {
	var area = this;

	if (base_area_id) base_area_id = parseInt(base_area_id);

	return promise_query(this.directory.server,
		[
			"START n=node({area_id})",
			base_area_id ? ", base=node({base_area})" : "",
			"MATCH (m:Area)-[link:PARENT_OF*]->(n)",
			base_area_id
				? "WHERE (base)-[:PARENT_OF*]->(m) OR (base) = (m)"
				: ""
			,
			"RETURN link, m, n"
		],
		{"area_id" : this.area_id, "base_area" : base_area_id},
		function (results) {
			var path = [];
			if (results.length) {
				path[0] = new Area(area.directory, results[0].n.id, results[0].n.data);
				results.forEach(function (result) {
					var pos = result.link.length;
					path[pos] = new Area(area.directory, result.m.id, result.m.data);
				});
			}
			return path.reverse().slice(1);
		}
	);
}

Area.prototype.search = function (search_str) {
	var area = this;
	var search_regex = util.format("(%s)", search_str.replace(/ /g, "|"));
	console.log(search_regex);

	return promise_query(this.directory.server,
		[
			"START n=node({area_id})",
			"MATCH (m:Area)-[link:PARENT_OF*]->(target)",
			util.format("WHERE target.name =~ \"(?i).*%s.*\"", search_regex),
			"AND ((n)-[:PARENT_OF*]->(m:Area) OR (n) = (m))",
			"RETURN target, link, m"
		],
		{"area_id" : this.area_id},
		function (results) {
			var paths = {};
			results.forEach(function (result) {
				var a = result.target;
				paths[a.id] =[];
				paths[a.id][0] = new Area(area.directory, a.id, a.data);
			});
			results.forEach(function (result) {
				var distance = result.link.length;
				var target = result.target;
				var m = result.m;

				// delete if part of path
				if (m.id in paths) {
					console.log(m.id);
					delete paths[m.id];
				}

				if (target.id in paths) {
					paths[target.id][distance] = new Area(
						area.directory, m.id, m.data
					);
				}
			});
			var result_list = [];
			Object.keys(paths).forEach(function (target_id) {
				result_list.push(paths[target_id].reverse().slice(1));
			});
			return result_list;
		}
	);
}

Area.prototype.collections = function () {
	var area = this;

	return promise_query(this.directory.server,
		[
			"START n=node({area_id})",
			"MATCH (collection:Collection)-[:RESPONSIBLE_FOR*]->(n)",
			"WHERE NOT ()-[:COMES_BEFORE]->(collection)",
			"RETURN collection"
		],
		{"area_id" : this.area_id},
		function (results) {
			return results.map(function (result) {
				var collection = result["collection"];
				return new Collection(
					area.directory, collection.id
				);
			});
		}
	);
}

Area.prototype.all_contacts = function () {
	var area = this;

	return promise_query(this.directory.server,
		[
			"START n=node({area_id})",
			"MATCH (n)<-[:RESPONSIBLE_FOR]-(c:Collection)",
			"MATCH (contact:Contact)-[:IN_COLLECTION]->(c)",
			"OPTIONAL MATCH (c)-[succ:COMES_BEFORE]->(c2:Collection)",
			"RETURN contact,c,succ,c2"
		],
		{"area_id" : this.area_id},
		function (results) {

			var contacts = [];
			var all_contacts = {};
			var parent = {};
			results.forEach(function (result) {
				var coll_id = result["c"].id;
				if (!(coll_id in all_contacts)) {
					all_contacts[coll_id] = {
						contacts : [],
						successors : []
					};

					if (result["c2"] != null) {
						parent[result["c2"].id] = {
							"parent" : result["c"].id,
							"note" : result["succ"].data.note
						};
					}
				}
				all_contacts[coll_id].contacts.push(
					new Contact(
						area.directory,
						result["contact"].id,
						result["contact"].data
					)
				);

			});

			Object.keys(all_contacts).forEach(function (coll) {
				if (!(coll in parent)) {
					contacts.push(all_contacts[coll]);
				} else {
					all_contacts[parent[coll].parent].successors.push({
						"collection" : all_contacts[coll],
						"note" : parent[coll].note
					});
				}
			});

			return contacts;
		}
	);
}

Area.prototype.descendent_contact_count = function () {
	var area = this;

	return promise_query(this.directory.server,
		[
			"START n=node({area_id})",
			"MATCH (n)-[:PARENT_OF*]->()<-[*]-(a:Contact)",
			"RETURN COUNT(a)"
		],
		{area_id : this.area_id},
		function (results) {
			return {"contacts" : results[0]["COUNT(a)"]};
		}
	);
}

Area.prototype.get_area_id = function () {
	return this.area_id;
}

Area.prototype.get_name = function () {
	return this.name;
}

Area.prototype.get_notes = function () {
	return this.notes;
}

exports.Area = Area;

/**
 * Collection
 */

var Collection = function (directory, collection_id) {
	this.directory = directory;
	this.collection_id = collection_id;
}

Collection.prototype.contacts = function () {
	var collection = this;

	return promise_query(this.directory.server,
		[
			"START n=node({collection_id})",
			"MATCH (contact:Contact)-[:IN_COLLECTION]->(n)",
			"RETURN contact",
			"ORDER BY contact.last_name, contact.first_name"
		],
		{"collection_id" : this.collection_id},
		function (results) {
			return results.map(function (result) {
				var contact = result["contact"];
				return new Contact(
					collection.directory, contact.id, contact.data
				);
			});
		}
	);
}

Collection.prototype.successors = function () {
	var collection = this;

	return promise_query(this.directory.server,
		[
			"START n=node({collection_id})",
			"MATCH (n)-[link:COMES_BEFORE]->(succ:Collection)",
			"RETURN succ, link"
		],
		{"collection_id" : this.collection_id},
		function (results) {
			return results.map(function (result) {
				return new Collection(
					collection.directory, result["succ"].id
				);
			})
		}
	);
}

exports.Collection = Collection;

/**
 * Contact
 */

var Contact = function (directory, contact_id, contact_info) {

	this.directory = directory;
	this.contact_id = contact_id;
	this.contact_info = contact_info;
}

Contact.prototype.refresh = function () {
	var contact = this;
	return promise_query(this.directory.server,
		[
			"START n=node({contact_id})",
			"MATCH (n)-[:HAS_URL]->(url:Url)",
			"RETURN url"
		],
		{"contact_id" : this.contact_id},
		function (results) {
			if (results.length) {
				var url = results[0]["url"];
				contact.url = url.data;
			}
			return contact;
		}
	);
}

/*(Contact.prototype.working_times = function () {

}*/

Contact.prototype.get_contact_id = function () {
	return this.contact_id;
}

Contact.prototype.get_info = function () {
	return this.contact_info;
}

exports.Contact = Contact;

/**
 * Patterns
 */

var promise_query = function (server, query, params, process_results) {
	var query_str = query.join(" ");
	var deferred = q.defer();
	server.query(query_str, params, function (err, results) {
		if (err) {
			deferred.reject(err);
		}
		var processed_results = process_results(results);
		deferred.resolve(processed_results);
	});
	return deferred.promise;
}<commit_msg>Added URLs to contact details.<commit_after>"use strict";

var neo4j = require("neo4j");
var q = require("q");
var util = require("util");

//var server = new neo4j.GraphDatabase("http://localhost:7474");

/**
 * Directory
 */

var Directory = function (server) {
	this.server = server;
}

Directory.prototype.root_area = function () {
	var dir = this;

	return promise_query(this.server,
		[
			"MATCH (root:Area)",
			"WHERE NOT ()-[:PARENT_OF]->(root)",
			"RETURN root"
		],
		{},
		function (results) {
			var node = results[0]["root"]; // should only be one result
			return new Area(dir, node.id, node.data);
		}
	);
}

Directory.prototype.area = function (area_id) {
	var dir = this;
	var deferred = q.defer();
	this.server.getNodeById(area_id, function (err, node) {
		if (err) {
			deferred.reject(err);
			throw err;
		}
		var data = node.data;
		var area = new Area(dir, node.id, data);
		deferred.resolve(area);
		return;
	});
	return deferred.promise;
}

exports.Directory = Directory;

/**
 * Area
 */

var Area = function (dir, area_id, area_info) {
	this.directory = dir;
	this.area_id = area_id;
	this.name = area_info.name;
	if (area_info.note !== undefined) this.note = area_info.note;
}

Area.prototype.descend_along_path = function (path) {
	var area = this;

	// construct query
	var query = ["START n=node({root_area_id}) MATCH (n)"];
	path.forEach(function (area_name, depth) {
		query.push(util.format(
			"-[:PARENT_OF]->(x%d:Area { name: \"%s\"})",
			depth, area_name
		));
	});
	var result_node_name = util.format("x%d", path.length - 1);
	query.push(util.format("RETURN %s", result_node_name));

	return promise_query(this.directory.server,
		query, {"root_area_id" : this.get_area_id()},
		function (target_node) {
			var target = target_node[0][result_node_name];
			return new Area(
				area.directory, target.id, target.data
			);
		}
	);
}

Area.prototype.parent = function () {
	var area = this;

	return promise_query(
		this.directory.server,
		[
			"START n=node({area_id})",
			"MATCH (parent:Area)-[:PARENT_OF]->(n)",
			"RETURN parent"
		],
		{"area_id" : this.area_id},
		function (parents) {
			if (!parents.length) return null;
			var parent = parents[0]["parent"];
			return new Area(area.directory, parent.id, parent.data);
		}
	);
}

Area.prototype.children = function () {
	var area = this;

	return promise_query(this.directory.server,
		[
			"START n=node({area_id})",
			"MATCH (n)-[:PARENT_OF]->(child:Area)",
			"RETURN child"
		],
		{"area_id" : this.area_id},
		function (child_nodes) {
			return child_nodes.map(function (child_node) {
				var child_area = child_node["child"];
				return new Area(
					area.directory, child_area.id, child_area.data
				);
			});
		}
	);
}

Area.prototype.descendents = function () {
	var area = this;

	return promise_query(this.directory.server,
		[
			"START n=node({area_id})",
			"MATCH (n)-[depth:PARENT_OF*]->(dp:Area)",
			"OPTIONAL MATCH (dp)-[:PARENT_OF]->(d:Area)",
			"RETURN d, depth, dp"
		],
		{"area_id" : this.area_id},
		function (descendents) {
			var tree_dict = {};
			tree_dict[area.area_id] = [];
			var area_dict = {};
			area_dict[area.area_id] = area;

			descendents.forEach(function (d) {
				var depth = d.depth.length;
				if (!d.d) {
					if (depth == 1) {
						tree_dict[area.area_id].push(d.dp.id);
						area_dict[d.dp.id] = new Area(area.directory, d.dp.id, d.dp.data);
					}
				} else {
					var depth = d.depth.length;

					if (depth == 1 && tree_dict[area.area_id].indexOf(d.dp.id) == -1) {
						tree_dict[area.area_id].push(d.dp.id);
						area_dict[d.dp.id] = new Area(area.directory, d.dp.id, d.dp.data);
					}

					if (!(d.dp.id in tree_dict)) {
						tree_dict[d.dp.id] = [];
					}
					tree_dict[d.dp.id].push(d.d.id);
					area_dict[d.d.id] = new Area(area.directory, d.d.id, d.d.data);
				}
			});
			var queue = [];
			var attach_descendents = function (node) {
				node.children = [];
				if (node.area.area_id in tree_dict) {
					tree_dict[node.area.area_id].forEach(function (child) {
						var new_area = {area: area_dict[child]};
						attach_descendents(new_area);
						node.children.push(new_area);
					});
				}
			}

			var root_node = {"area" : area};
			attach_descendents(root_node);

			return root_node;
		}
	);
}

Area.prototype.path = function (base_area_id) {
	var area = this;

	if (base_area_id) base_area_id = parseInt(base_area_id);

	return promise_query(this.directory.server,
		[
			"START n=node({area_id})",
			base_area_id ? ", base=node({base_area})" : "",
			"MATCH (m:Area)-[link:PARENT_OF*]->(n)",
			base_area_id
				? "WHERE (base)-[:PARENT_OF*]->(m) OR (base) = (m)"
				: ""
			,
			"RETURN link, m, n"
		],
		{"area_id" : this.area_id, "base_area" : base_area_id},
		function (results) {
			var path = [];
			if (results.length) {
				path[0] = new Area(area.directory, results[0].n.id, results[0].n.data);
				results.forEach(function (result) {
					var pos = result.link.length;
					path[pos] = new Area(area.directory, result.m.id, result.m.data);
				});
			}
			return path.reverse().slice(1);
		}
	);
}

Area.prototype.search = function (search_str) {
	var area = this;
	var search_regex = util.format("(%s)", search_str.replace(/ /g, "|"));
	console.log(search_regex);

	return promise_query(this.directory.server,
		[
			"START n=node({area_id})",
			"MATCH (m:Area)-[link:PARENT_OF*]->(target)",
			util.format("WHERE target.name =~ \"(?i).*%s.*\"", search_regex),
			"AND ((n)-[:PARENT_OF*]->(m:Area) OR (n) = (m))",
			"RETURN target, link, m"
		],
		{"area_id" : this.area_id},
		function (results) {
			var paths = {};
			results.forEach(function (result) {
				var a = result.target;
				paths[a.id] =[];
				paths[a.id][0] = new Area(area.directory, a.id, a.data);
			});
			results.forEach(function (result) {
				var distance = result.link.length;
				var target = result.target;
				var m = result.m;

				// delete if part of path
				if (m.id in paths) {
					console.log(m.id);
					delete paths[m.id];
				}

				if (target.id in paths) {
					paths[target.id][distance] = new Area(
						area.directory, m.id, m.data
					);
				}
			});
			var result_list = [];
			Object.keys(paths).forEach(function (target_id) {
				result_list.push(paths[target_id].reverse().slice(1));
			});
			return result_list;
		}
	);
}

Area.prototype.collections = function () {
	var area = this;

	return promise_query(this.directory.server,
		[
			"START n=node({area_id})",
			"MATCH (collection:Collection)-[:RESPONSIBLE_FOR*]->(n)",
			"WHERE NOT ()-[:COMES_BEFORE]->(collection)",
			"RETURN collection"
		],
		{"area_id" : this.area_id},
		function (results) {
			return results.map(function (result) {
				var collection = result["collection"];
				return new Collection(
					area.directory, collection.id
				);
			});
		}
	);
}

Area.prototype.all_contacts = function () {
	var area = this;

	return promise_query(this.directory.server,
		[
			"START n=node({area_id})",
			"MATCH (n)<-[:RESPONSIBLE_FOR]-(c:Collection)",
			"MATCH (contact:Contact)-[:IN_COLLECTION]->(c)",
			"OPTIONAL MATCH (contact)-[:HAS_URL]->(url:Url)",
			"OPTIONAL MATCH (c)-[succ:COMES_BEFORE]->(c2:Collection)",
			"RETURN contact,url,c,succ,c2"
		],
		{"area_id" : this.area_id},
		function (results) {

			var contacts = [];
			var all_contacts = {};
			var parent = {};
			results.forEach(function (result) {
				var coll_id = result["c"].id;
				if (!(coll_id in all_contacts)) {
					all_contacts[coll_id] = {
						contacts : [],
						successors : []
					};

					if (result["c2"] != null) {
						parent[result["c2"].id] = {
							"parent" : result["c"].id,
							"note" : result["succ"].data.note
						};
					}
				}
				all_contacts[coll_id].contacts.push(
					new Contact(
						area.directory,
						result["contact"].id,
						result["contact"].data,
						result["url"] ? result["url"].data : null
					)
				);

			});

			Object.keys(all_contacts).forEach(function (coll) {
				if (!(coll in parent)) {
					contacts.push(all_contacts[coll]);
				} else {
					all_contacts[parent[coll].parent].successors.push({
						"collection" : all_contacts[coll],
						"note" : parent[coll].note
					});
				}
			});

			return contacts;
		}
	);
}

Area.prototype.descendent_contact_count = function () {
	var area = this;

	return promise_query(this.directory.server,
		[
			"START n=node({area_id})",
			"MATCH (n)-[:PARENT_OF*]->()<-[*]-(a:Contact)",
			"RETURN COUNT(a)"
		],
		{area_id : this.area_id},
		function (results) {
			return {"contacts" : results[0]["COUNT(a)"]};
		}
	);
}

Area.prototype.get_area_id = function () {
	return this.area_id;
}

Area.prototype.get_name = function () {
	return this.name;
}

Area.prototype.get_notes = function () {
	return this.notes;
}

exports.Area = Area;

/**
 * Collection
 */

var Collection = function (directory, collection_id) {
	this.directory = directory;
	this.collection_id = collection_id;
}

Collection.prototype.contacts = function () {
	var collection = this;

	return promise_query(this.directory.server,
		[
			"START n=node({collection_id})",
			"MATCH (contact:Contact)-[:IN_COLLECTION]->(n)",
			"OPTIONAL MATCH (contact)-[:HAS_URL]->(url:Url)",
			"RETURN contact, url",
			"ORDER BY contact.last_name, contact.first_name"
		],
		{"collection_id" : this.collection_id},
		function (results) {
			return results.map(function (result) {
				var contact = result["contact"];
				var url = result["url"];
				console.log("urL");
				console.log(url);
				return new Contact(
					collection.directory, contact.id, contact.data, url ? url.data : null
				);
			});
		}
	);
}

Collection.prototype.successors = function () {
	var collection = this;

	return promise_query(this.directory.server,
		[
			"START n=node({collection_id})",
			"MATCH (n)-[link:COMES_BEFORE]->(succ:Collection)",
			"RETURN succ, link"
		],
		{"collection_id" : this.collection_id},
		function (results) {
			return results.map(function (result) {
				return new Collection(
					collection.directory, result["succ"].id
				);
			})
		}
	);
}

exports.Collection = Collection;

/**
 * Contact
 */

var Contact = function (directory, contact_id, contact_info, url) {

	this.directory = directory;
	this.contact_id = contact_id;
	this.contact_info = contact_info;
	if (url) this.url = url;
}

/*(Contact.prototype.working_times = function () {

}*/

Contact.prototype.get_contact_id = function () {
	return this.contact_id;
}

Contact.prototype.get_info = function () {
	return this.contact_info;
}

exports.Contact = Contact;

/**
 * Patterns
 */

var promise_query = function (server, query, params, process_results) {
	var query_str = query.join(" ");
	var deferred = q.defer();
	server.query(query_str, params, function (err, results) {
		if (err) {
			deferred.reject(err);
		}
		var processed_results = process_results(results);
		deferred.resolve(processed_results);
	});
	return deferred.promise;
}<|endoftext|>


<commit_before>import mapConstants from './mapConstants';

const lerp = (minVal, maxVal, pos_r) => pos_r * (maxVal - minVal) + minVal;

const reverseLerp = (minVal, maxVal, pos) => (pos - minVal) / (maxVal - minVal);

const latLonToWorld = coordinate => {
    const x_r = lerp(mapConstants.map_x_boundaries[0], mapConstants.map_x_boundaries[1], coordinate[0] / mapConstants.map_w),
        y_r = lerp(mapConstants.map_y_boundaries[0], mapConstants.map_y_boundaries[1], (mapConstants.map_h - coordinate[1]) / mapConstants.map_h);
    return [x_r, y_r];
}

const worldToLatLon = coordinate => {
    const x = reverseLerp(mapConstants.map_x_boundaries[0], mapConstants.map_x_boundaries[1], coordinate[0]) * mapConstants.map_w,
        y = mapConstants.map_h - reverseLerp(mapConstants.map_y_boundaries[0], mapConstants.map_y_boundaries[1], coordinate[1]) * mapConstants.map_h;
    return [x, y];
}

const getTileRadius = r => parseInt(Math.floor(r / 64));

const getScaledRadius = r => r / (mapConstants.map_x_boundaries[1] - mapConstants.map_x_boundaries[0]) * mapConstants.map_w;

const calculateDistance = (order, units, measure) => {
    if (order == 1) {
        if (units == "km") {
            return measure * mapConstants.scale * 1000;
        }
        return measure * mapConstants.scale;
    }
    return measure * mapConstants.scale;
}

export {
    lerp,
    reverseLerp,
    latLonToWorld,
    worldToLatLon,
    getTileRadius,
    getScaledRadius,
    calculateDistance
}<commit_msg>refactor: use named exports<commit_after>import mapConstants from './mapConstants';

export const lerp = (minVal, maxVal, pos_r) => pos_r * (maxVal - minVal) + minVal;

export const reverseLerp = (minVal, maxVal, pos) => (pos - minVal) / (maxVal - minVal);

export const latLonToWorld = coordinate => {
    const x_r = lerp(mapConstants.map_x_boundaries[0], mapConstants.map_x_boundaries[1], coordinate[0] / mapConstants.map_w),
        y_r = lerp(mapConstants.map_y_boundaries[0], mapConstants.map_y_boundaries[1], (mapConstants.map_h - coordinate[1]) / mapConstants.map_h);
    return [x_r, y_r];
}

export const worldToLatLon = coordinate => {
    const x = reverseLerp(mapConstants.map_x_boundaries[0], mapConstants.map_x_boundaries[1], coordinate[0]) * mapConstants.map_w,
        y = mapConstants.map_h - reverseLerp(mapConstants.map_y_boundaries[0], mapConstants.map_y_boundaries[1], coordinate[1]) * mapConstants.map_h;
    return [x, y];
}

export const getTileRadius = r => parseInt(Math.floor(r / 64));

export const getScaledRadius = r => r / (mapConstants.map_x_boundaries[1] - mapConstants.map_x_boundaries[0]) * mapConstants.map_w;

export const calculateDistance = (order, units, measure) => {
    if (order == 1) {
        if (units == "km") {
            return measure * mapConstants.scale * 1000;
        }
        return measure * mapConstants.scale;
    }
    return measure * mapConstants.scale;
}<|endoftext|>


<commit_before>/*!
Filterize, a jQuery Plugin to filter select list
by Eduard Deza at Hiringo Team, http://hiringo.com

Version 1.0.0
Full source at https://github.com/edezacas/Filterize
*/

;(function ($, window, document, undefined) {

    var pluginName = 'filterize';

    function Plugin (element, options) {
        this.element = element;
        this._name = pluginName;
        this._defaults = $.fn[pluginName].defaults;
        this.options = $.extend( {}, this._defaults, options );

        this.init();
    }

    $.extend(Plugin.prototype, {

        // Initialization logic
        init: function () {
	        this.buildWrapper();
            this.buildSelect();
            this.buildCache();
            this.bindEvents();
        },
		//Build Wrapper for Select List
		buildWrapper: function(){
			var select = $(this.element);

			select
			.wrap('

')
			.append('<option class="filterize-no_results" value="no-results">'+this.options.noresultsText+'</option>');

			var parent = select.parent();
			parent.prepend('
'+this.options.titleText+'

');
		},
		//Build Select Custom List
		buildSelect: function(){
			var select = $(this.element),
				parent = select.parent(),
				boxList = parent.find('.filterize-list'),
				list = parent.find('ul'),
				title = parent.find('.filterize-title');

			title.css('min-width',title.outerWidth());

			for(var i = 0,len = select.children('option').length;i < len;i++){
				var option = select.children('option').eq(i),
					clase = option.attr("class");

				if(typeof clase == "undefined"){
					clase = "";
				}

				list.append('

'+option.text()+'

')
			}

			boxList.prepend('
<input type="text" autocomplete="off" tabindex="1">
');

			select.hide();

			// open list
			title.on('click', function(){
				boxList.slideToggle();
				$(this).toggleClass('active');
			});

			this.fireSearch();
		},
        // Cache DOM nodes for performance
        buildCache: function () {
            this.$element = $(this.element);
        },

        // Bind events that trigger methods
        bindEvents: function() {
            var plugin = this;

            plugin.$element.on('filterize:update'+'.'+plugin._name, function() {
                plugin.update.call(plugin);
            });
        },
        //Search input value on list
        fireSearch: function(){

			var select = $(this.element),
				parent = select.parent(),
				boxList = parent.find('.filterize-list'),
				list = parent.find('ul'),
				title = parent.find('.filterize-title');

			// selected option

			list.on('click','li',function(){

				var val = $(this).data("value"),
					texto = $(this).find("p").text();

				title.text(texto);
				boxList.slideUp();

				select.val(val);

				//Trigger change event to notify
				select.trigger("change");

				title.toggleClass('active');

			});

			$('.filterize-list-search input').on('change', function(){
			    var filter = $(this).val(),
			    	list = 	parent.find('ul')
			    	elNoRes = $(list).find(".filterize-no_results");

			    if(filter) {
			      // this finds all links in a list that contain the input,
			      // and hide the ones not containing the input while showing the ones that do
			      $(list).find("p:not(:Contains(" + filter + "))").parent().stop(true, false).hide();
			      $(list).find("p:Contains(" + filter + ")").parent().stop(true, false).show();
			      elNoRes.stop(true, false).hide();

			      //No results
			      if(!$(list).find("p:Contains(" + filter + ")").length){
				      elNoRes.stop(true, false).show();
			      }

			    } else {
					elNoRes.stop(true, false).hide();
					$(list).find("li:not(.filterize-no_results)").show();
			    }

			    return false;
			  })
			.keyup( function () {
			    // fire the above change event after every letter
			    $(this).change();
			});

			// custom css expression for a case-insensitive contains()
			jQuery.expr[':'].Contains = function(a,i,m){
			    return (a.textContent || a.innerText || "").toUpperCase().indexOf(m[3].toUpperCase())>=0;
			};

        }

    });

    $.fn[pluginName] = function (options) {
        this.each(function() {
            if ( !$.data( this, "plugin_" + pluginName ) ) {
                $.data( this, "plugin_" + pluginName, new Plugin( this, options ) );
            }
        });
        return this;
    };

    $.fn[pluginName].defaults = {
        titleText: 'Select an option',
	    noresultsText: 'No results matched'
    };

})( jQuery, window, document );
<commit_msg>Minor fix<commit_after>/*!
Filterize, a jQuery Plugin to filter select list
by Eduard Deza at Hiringo Team, http://hiringo.com

Version 1.0.0
Full source at https://github.com/edezacas/Filterize
*/

;(function ($, window, document, undefined) {

    var pluginName = 'filterize';

    function Plugin (element, options) {
        this.element = element;
        this._name = pluginName;
        this._defaults = $.fn[pluginName].defaults;
        this.options = $.extend( {}, this._defaults, options );

        this.init();
    }

    $.extend(Plugin.prototype, {

        // Initialization logic
        init: function () {
	        this.buildWrapper();
            this.buildSelect();
            this.buildCache();
            this.bindEvents();
        },
		//Build Wrapper for Select List
		buildWrapper: function(){
			var select = $(this.element);

			select
			.wrap('

')
			.append('<option class="filterize-no_results" value="no-results">'+this.options.noresultsText+'</option>');

			var parent = select.parent();
			parent.prepend('
'+this.options.titleText+'

');
		},
		//Build Select Custom List
		buildSelect: function(){
			var select = $(this.element),
				parent = select.parent(),
				boxList = parent.find('.filterize-list'),
				list = parent.find('ul'),
				title = parent.find('.filterize-title');

			title.css('min-width',title.outerWidth());

			for(var i = 0,len = select.children('option').length;i < len;i++){
				var option = select.children('option').eq(i),
					clase = option.attr("class");

				if(typeof clase == "undefined"){
					clase = "";
				}

				list.append('

'+option.text()+'

')
			}

			boxList.prepend('
<input type="text" autocomplete="off" tabindex="1">
');

			select.hide();

			// open list
			title.on('click', function(){
				boxList.stop(true, true).slideToggle();
				$(this).toggleClass('active');
			});

			this.fireSearch();
		},
        // Cache DOM nodes for performance
        buildCache: function () {
            this.$element = $(this.element);
        },

        // Bind events that trigger methods
        bindEvents: function() {
            var plugin = this;

            plugin.$element.on('filterize:update'+'.'+plugin._name, function() {
                plugin.update.call(plugin);
            });
        },
        //Search input value on list
        fireSearch: function(){

			var select = $(this.element),
				parent = select.parent(),
				boxList = parent.find('.filterize-list'),
				list = parent.find('ul'),
				title = parent.find('.filterize-title');

			// selected option

			list.on('click','li',function(){

				var val = $(this).data("value"),
					texto = $(this).find("p").text();

				title.text(texto);
				boxList.slideUp();

				select.val(val);

				//Trigger change event to notify
				select.trigger("change");

				title.toggleClass('active');

			});

			$('.filterize-list-search input').on('change', function(){
			    var filter = $(this).val(),
			    	list = 	parent.find('ul')
			    	elNoRes = $(list).find(".filterize-no_results");

			    if(filter) {
			      // this finds all links in a list that contain the input,
			      // and hide the ones not containing the input while showing the ones that do
			      $(list).find("p:not(:Contains(" + filter + "))").parent().stop(true, false).hide();
			      $(list).find("p:Contains(" + filter + ")").parent().stop(true, false).show();
			      elNoRes.stop(true, false).hide();

			      //No results
			      if(!$(list).find("p:Contains(" + filter + ")").length){
				      elNoRes.stop(true, false).show();
			      }

			    } else {
					elNoRes.stop(true, false).hide();
					$(list).find("li:not(.filterize-no_results)").show();
			    }

			    return false;
			  })
			.keyup( function () {
			    // fire the above change event after every letter
			    $(this).change();
			});

			// custom css expression for a case-insensitive contains()
			jQuery.expr[':'].Contains = function(a,i,m){
			    return (a.textContent || a.innerText || "").toUpperCase().indexOf(m[3].toUpperCase())>=0;
			};

        }

    });

    $.fn[pluginName] = function (options) {
        this.each(function() {
            if ( !$.data( this, "plugin_" + pluginName ) ) {
                $.data( this, "plugin_" + pluginName, new Plugin( this, options ) );
            }
        });
        return this;
    };

    $.fn[pluginName].defaults = {
        titleText: 'Select an option',
	    noresultsText: 'No results matched'
    };

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


<commit_before>import React, { Component } from 'react';
import PropTypes from 'prop-types';

class SunMedia extends Component {
  componentDidMount() {
    const script = document.createElement('script');
    script.async = true;
    script.type = 'application/javascript';
    script.src = this.props.src;
    this.ref.appendChild(script);
  }

  render() {
    return this.props.active ? (
      <div
        id="sunmedia-contaier"
        ref={node => {
          this.ref = node;
        }}
      />
    ) : null;
  }
}

SunMedia.propTypes = {
  src: PropTypes.string.isRequired,
  active: PropTypes.bool.isRequired,
};

export default SunMedia;
<commit_msg>Adds support for amp (even if we can't use it)<commit_after>import React, { Component, Fragment } from 'react';
import PropTypes from 'prop-types';
import { Helmet } from 'react-helmet';

class SunMedia extends Component {
  static propTypes = {
    src: PropTypes.string.isRequired,
    active: PropTypes.bool.isRequired,
    isAmp: PropTypes.bool.isRequired,
    cid: PropTypes.string,
  };

  static defaultProps = {
    cid: null,
  };

  componentDidMount() {
    if (this.props.isAmp) return;

    const script = document.createElement('script');
    script.async = true;
    script.type = 'application/javascript';
    script.src = this.props.src;
    this.ref.appendChild(script);
  }

  render() {
    const { active, isAmp, cid } = this.props;

    // This won't work for now, as we are filtering out sunmedia ads on AMP,
    // but we can try again later if we have some way to get the `data-cid`.
    if (isAmp) {
      return (
        <Fragment>
          <Helmet>
            <script
              async=""
              custom-element="amp-ad"
              src="https://cdn.ampproject.org/v0/amp-ad-0.1.js"
            />
          </Helmet>
          <amp-ad type="sunmedia" layout="fill" data-cid={cid} data-cskp={1} data-crst={1} />
        </Fragment>
      );
    }

    return active ? (
      <div
        ref={node => {
          this.ref = node;
        }}
      />
    ) : null;
  }
}

export default SunMedia;
<|endoftext|>