<commit_before>/**
 * Given a DOM subtree, wraps it in a list, and puts each line into its own
 * list item.
 *
 * @param {Node} node modified in place.  Its content is pulled into an
 *     HTMLOListElement, and each line is moved into a separate list item.
 *     This requires cloning elements, so the input might not have unique
 *     IDs after numbering.
 */
function numberLines(node, opt_startLineNum) {
  var nocode = /(?:^|\s)nocode(?:\s|$)/;
  var lineBreak = /\r\n?|\n/;

  var document = node.ownerDocument;

  var whitespace;
  if (node.currentStyle) {
    whitespace = node.currentStyle.whiteSpace;
  } else if (window.getComputedStyle) {
    whitespace = document.defaultView.getComputedStyle(node, null)
        .getPropertyValue('white-space');
  }
  // If it's preformatted, then we need to split lines on line breaks
  // in addition to
s.
  var isPreformatted = whitespace && 'pre' === whitespace.substring(0, 3);

  var li = document.createElement('LI');
  while (node.firstChild) {
    li.appendChild(node.firstChild);
  }
  // An array of lines.  We split below, so this is initialized to one
  // un-split line.
  var listItems = [li];

  function walk(node) {
    switch (node.nodeType) {
      case 1:  // Element
        if (nocode.test(node.className)) { break; }
        if ('BR' === node.nodeName) {
          breakAfter(node);
          // Discard the
 since it is now flush against a
.
          if (node.parentNode) {
            node.parentNode.removeChild(node);
          }
        } else {
          for (var child = node.firstChild; child; child = child.nextSibling) {
            walk(child);
          }
        }
        break;
      case 3: case 4:  // Text
        if (isPreformatted) {
          var text = node.nodeValue;
          var match = text.match(lineBreak);
          if (match) {
            var firstLine = text.substring(0, match.index);
            node.nodeValue = firstLine;
            var tail = text.substring(match.index + match[0].length);
console.log('split "' + text.replace(/\r\n?|\n/g, '\\n') + '" into "' + firstLine + '" and "' + tail.replace(/\r\n?|\n/g, '\\n') + '"');
            if (tail) {
              var parent = node.parentNode;
              parent.insertBefore(
                  document.createTextNode(tail), node.nextSibling);
            }
            breakAfter(node);
            if (!firstLine) {
              // Don't leave blank text nodes in the DOM.
              node.parentNode.removeChild(node);
            }
          }
        }
        break;
    }
  }

  // Split a line after the given node.
  function breakAfter(lineEndNode) {
    // If there's nothing to the right, then we can skip ending the line
    // here, and move root-wards since splitting just before an end-tag
    // would require us to create a bunch of empty copies.
    while (!lineEndNode.nextSibling) {
      lineEndNode = lineEndNode.parentNode;
      if (!lineEndNode) { return; }
    }

    function breakLeftOf(limit, copy) {
      // Clone shallowly if this node needs to be on both sides of the break.
      var rightSide = copy ? limit.cloneNode(false) : limit;
      var parent = limit.parentNode;
      if (parent) {
        // We clone the parent chain.
        // This helps us resurrect important styling elements that cross lines.
        // E.g. in Foo
Bar
        // should be rewritten to
Foo

Bar
.
        var parentClone = breakLeftOf(parent, 1);
        // Move the clone and everything to the right of the original
        // onto the cloned parent.
        var next = limit.nextSibling;
        parentClone.appendChild(rightSide);
        for (var sibling = next; sibling; sibling = next) {
          next = sibling.nextSibling;
          parentClone.appendChild(sibling);
        }
      }
      return rightSide;
    }

    var split = breakLeftOf(lineEndNode.nextSibling, 0);

    // Walk the parent chain until we reach an unattached LI.
    for (var parent; (parent = split.parentNode);) { split = parent; }
    // Put it on the list of lines for later processing.
    listItems.push(split);
console.log('pushing listItem length=' + listItems.length);
  }

  // Split lines while there are lines left to split.
  for (var i = 0;  // Number of lines that have been split so far.
       i < listItems.length;  // length updated by breakAfter calls.
       ++i) {
console.log('walking list item ' + i);
    walk(listItems[i]);
  }

  // Make sure numeric indices show correctly.
  if (opt_startLineNum === (opt_startLineNum|0)) {
    listItems[0].setAttribute('value', opt_startLineNum);
  }

  var ol = document.createElement('OL');
  ol.className = 'linenums';
  var offset = Math.max(0, ((opt_startLineNum - 1 /* zero index */)) | 0) || 0;
  for (var i = 0, n = listItems.length; i < n; ++i) {
    li = listItems[i];
    // Stick a class on the LIs so that stylesheets can
    // color odd/even rows, or any other row pattern that
    // is co-prime with 10.
    li.className = 'L' + ((i + offset) % 10);
    if (!li.firstChild) {
      li.appendChild(document.createTextNode('\xA0'));
    }
    ol.appendChild(li);
  }

  node.appendChild(ol);
}<commit_msg>logging for IE<commit_after>/**
 * Given a DOM subtree, wraps it in a list, and puts each line into its own
 * list item.
 *
 * @param {Node} node modified in place.  Its content is pulled into an
 *     HTMLOListElement, and each line is moved into a separate list item.
 *     This requires cloning elements, so the input might not have unique
 *     IDs after numbering.
 */
function numberLines(node, opt_startLineNum) {
  var nocode = /(?:^|\s)nocode(?:\s|$)/;
  var lineBreak = /\r\n?|\n/;

  var document = node.ownerDocument;

  var whitespace;
  if (node.currentStyle) {
    whitespace = node.currentStyle.whiteSpace;
  } else if (window.getComputedStyle) {
    whitespace = document.defaultView.getComputedStyle(node, null)
        .getPropertyValue('white-space');
  }
  // If it's preformatted, then we need to split lines on line breaks
  // in addition to
s.
  var isPreformatted = whitespace && 'pre' === whitespace.substring(0, 3);

  var li = document.createElement('LI');
  while (node.firstChild) {
    li.appendChild(node.firstChild);
  }
  // An array of lines.  We split below, so this is initialized to one
  // un-split line.
  var listItems = [li];

  function walk(node) {
    switch (node.nodeType) {
      case 1:  // Element
        if (nocode.test(node.className)) { break; }
        if ('BR' === node.nodeName) {
          breakAfter(node);
          // Discard the
 since it is now flush against a
.
          if (node.parentNode) {
            node.parentNode.removeChild(node);
          }
        } else {
          for (var child = node.firstChild; child; child = child.nextSibling) {
            walk(child);
          }
        }
        break;
      case 3: case 4:  // Text
console.log('saw text node, isPreformatted=' + isPreformatted);
        if (isPreformatted) {
          var text = node.nodeValue;
          var match = text.match(lineBreak);
          if (match) {
            var firstLine = text.substring(0, match.index);
            node.nodeValue = firstLine;
            var tail = text.substring(match.index + match[0].length);
console.log('split "' + text.replace(/\r\n?|\n/g, '\\n') + '" into "' + firstLine + '" and "' + tail.replace(/\r\n?|\n/g, '\\n') + '"');
            if (tail) {
              var parent = node.parentNode;
              parent.insertBefore(
                  document.createTextNode(tail), node.nextSibling);
            }
            breakAfter(node);
            if (!firstLine) {
              // Don't leave blank text nodes in the DOM.
              node.parentNode.removeChild(node);
            }
          }
        }
        break;
    }
  }

  // Split a line after the given node.
  function breakAfter(lineEndNode) {
    // If there's nothing to the right, then we can skip ending the line
    // here, and move root-wards since splitting just before an end-tag
    // would require us to create a bunch of empty copies.
    while (!lineEndNode.nextSibling) {
      lineEndNode = lineEndNode.parentNode;
      if (!lineEndNode) { return; }
    }

    function breakLeftOf(limit, copy) {
      // Clone shallowly if this node needs to be on both sides of the break.
      var rightSide = copy ? limit.cloneNode(false) : limit;
      var parent = limit.parentNode;
      if (parent) {
        // We clone the parent chain.
        // This helps us resurrect important styling elements that cross lines.
        // E.g. in Foo
Bar
        // should be rewritten to
Foo

Bar
.
        var parentClone = breakLeftOf(parent, 1);
        // Move the clone and everything to the right of the original
        // onto the cloned parent.
        var next = limit.nextSibling;
        parentClone.appendChild(rightSide);
        for (var sibling = next; sibling; sibling = next) {
          next = sibling.nextSibling;
          parentClone.appendChild(sibling);
        }
      }
      return rightSide;
    }

    var split = breakLeftOf(lineEndNode.nextSibling, 0);

    // Walk the parent chain until we reach an unattached LI.
    for (var parent; (parent = split.parentNode);) { split = parent; }
    // Put it on the list of lines for later processing.
    listItems.push(split);
console.log('pushing listItem length=' + listItems.length);
  }

  // Split lines while there are lines left to split.
  for (var i = 0;  // Number of lines that have been split so far.
       i < listItems.length;  // length updated by breakAfter calls.
       ++i) {
console.log('walking list item ' + i);
    walk(listItems[i]);
  }

  // Make sure numeric indices show correctly.
  if (opt_startLineNum === (opt_startLineNum|0)) {
    listItems[0].setAttribute('value', opt_startLineNum);
  }

  var ol = document.createElement('OL');
  ol.className = 'linenums';
  var offset = Math.max(0, ((opt_startLineNum - 1 /* zero index */)) | 0) || 0;
  for (var i = 0, n = listItems.length; i < n; ++i) {
    li = listItems[i];
    // Stick a class on the LIs so that stylesheets can
    // color odd/even rows, or any other row pattern that
    // is co-prime with 10.
    li.className = 'L' + ((i + offset) % 10);
    if (!li.firstChild) {
      li.appendChild(document.createTextNode('\xA0'));
    }
    ol.appendChild(li);
  }

  node.appendChild(ol);
}<|endoftext|>


<commit_before>var gulp = require('gulp-param')(require('gulp'), process.argv);
var zip = require('gulp-zip');
var run = require('gulp-run');
var del = require('del');
var install = require('gulp-install');
var runSequence = require('run-sequence');
var awsLambda = require("node-aws-lambda");

gulp.task('default', function() {
  console.log('test');
});

gulp.task('install', function() {
  gulp.src(['./package.json'])
    .pipe(install());
});

gulp.task('lambda', function(event) {
  run('node_modules/lambda-local/bin/lambda-local -l index.js -t 60 -e ' + event)
    .exec();
});

gulp.task('clean', function() {
  return del(['./dist', './dist.zip']);
});

gulp.task('js', function() {
  return gulp.src(['index.js', 'lib/**/*'], {
    base: '.'
  }).pipe(gulp.dest('dist/'));
});

gulp.task('node-mods', function() {
  return gulp.src('./package.json')
    .pipe(gulp.dest('dist/'))
    .pipe(install({
      production: true
    }));
});

gulp.task('zip', function() {
  return gulp.src(['dist/**/*', '!dist/package.json'])
    .pipe(zip('dist.zip'))
    .pipe(gulp.dest('./'));
});

gulp.task('package', function() {
  return runSequence(
    ['clean'],
    ['js'],
    ['node-mods'],
    ['zip']
  );
});
<commit_msg>Fix target.<commit_after>var gulp = require('gulp-param')(require('gulp'), process.argv);
var zip = require('gulp-zip');
var run = require('gulp-run');
var del = require('del');
var install = require('gulp-install');
var runSequence = require('run-sequence');
var awsLambda = require("node-aws-lambda");

gulp.task('default', function() {
  return runSequence(
    ['clean'],
    ['js'],
    ['node-mods'],
    ['zip']
  );
});

gulp.task('install', function() {
  gulp.src(['./package.json'])
    .pipe(install());
});

gulp.task('lambda', function(event) {
  run('node_modules/lambda-local/bin/lambda-local -l index.js -t 60 -e ' + event)
    .exec();
});

gulp.task('clean', function() {
  return del(['./dist', './dist.zip']);
});

gulp.task('js', function() {
  return gulp.src(['index.js', 'lib/**/*'], {
    base: '.'
  }).pipe(gulp.dest('dist/'));
});

gulp.task('node-mods', function() {
  return gulp.src('./package.json')
    .pipe(gulp.dest('dist/'))
    .pipe(install({
      production: true
    }));
});

gulp.task('zip', function() {
  return gulp.src(['dist/**/*', '!dist/package.json'])
    .pipe(zip('dist.zip'))
    .pipe(gulp.dest('./'));
});
<|endoftext|>


<commit_before>/**
 * Copyright 2015-present 650 Industries. All rights reserved.
 *
 * @providesModule ExManifests
 */
'use strict';

import {
  NativeModules,
  Platform,
} from 'react-native';

import ExUrls from 'ExUrls';
import url from 'url';

const {
  ExponentKernel,
} = NativeModules;

let ExManifests = {
  async manifestUrlToBundleUrlAndManifestAsync(manifestUrl) {
    if (Platform.OS !== 'ios') {
      throw new Error('This method is only supported on iOS');
    }
    let httpManifestUrl = ExUrls.toHttp(manifestUrl);
    let httpManifestUrlComponents = url.parse(httpManifestUrl);
    // Append index.exp to path
    if (!httpManifestUrlComponents.pathname) {
      httpManifestUrlComponents.pathname = '';
    }
    let indexOfDeepLink = httpManifestUrlComponents.pathname.indexOf('+');
    if (indexOfDeepLink !== -1) {
      httpManifestUrlComponents.pathname = httpManifestUrlComponents.pathname.substring(0, indexOfDeepLink);
    }
    if (!httpManifestUrlComponents.pathname.endsWith('/')) {
      httpManifestUrlComponents.pathname += '/';
    }
    httpManifestUrlComponents.pathname += 'index.exp';
    httpManifestUrl = url.format(httpManifestUrlComponents);

    // Fetch manifest
    let manifestString;
    try {
      manifestString = await ExponentKernel.getManifestAsync(httpManifestUrl, manifestUrl);
    } catch (e) {
      e.message = `Error while loading: ${e.message}.`;
      throw e;
    }

    // Parse JSON
    let manifest;
    try {
      manifest = JSON.parse(manifestString);
    } catch (error) {
      // manifestUrl didn't return a manifest. Try using manifestUrl as the bundleUrl.
      return {
        bundleUrl: manifestUrl,
        manifest: {},
      };
    }

    // Build bundleUrl
    if (!manifest.bundleUrl) {
      throw new Error('No bundleUrl in manifest.');
    }

    return {
      // TODO: remove url.resolve and only use manifest.bundleUrl
      bundleUrl: url.resolve(httpManifestUrl, manifest.bundleUrl),
      manifest,
    };
  },

  getFramePropsFromManifest(manifest, bundleUrl) {
    let source = ExUrls.toHttp(bundleUrl);
    let { query } = url.parse(source, true);
    let appKey = manifest.appKey || query.app || 'main';

    let debuggerHost = manifest.debuggerHost;
    let debuggerHostname = debuggerHost ? ExUrls.getHostnameForHost(debuggerHost) :
      null;
    let debuggerPort = debuggerHost ? Number(ExUrls.getPortForHost(debuggerHost)) :
      -1;

    return { source, appKey, debuggerHostname, debuggerPort };
  },

  isManifestSdkVersionSupported(manifest) {
    let sdkVersion = manifest.sdkVersion;
    if (sdkVersion === 'UNVERSIONED') {
      return true; // you're on your own, buddy!
    }

    let supportedVersions = ExponentKernel.sdkVersions;
    let sdkVersionComponents;
    let isManifestSdkVersionSupported = false;

    try {
      sdkVersionComponents = sdkVersion.split('.').map(component => parseInt(component, 10));
    } catch (_) {}

    supportedVersions.forEach(supportedVersion => {
      if (supportedVersion === sdkVersion) {
        isManifestSdkVersionSupported = true;
      }
      try {
        let supportedVersionComponents = supportedVersion.split('.').map(component => parseInt(component, 10));
        if (sdkVersionComponents[0] === supportedVersionComponents[0] && sdkVersionComponents[1] === supportedVersionComponents[1]) {
          isManifestSdkVersionSupported = true;
        }
      } catch (_) {}
    });
    return isManifestSdkVersionSupported;
  },
};

export default ExManifests;
<commit_msg>Throw loading error if manifest verification fails<commit_after>/**
 * Copyright 2015-present 650 Industries. All rights reserved.
 *
 * @providesModule ExManifests
 */
'use strict';

import {
  NativeModules,
  Platform,
} from 'react-native';

import ExUrls from 'ExUrls';
import url from 'url';

const {
  ExponentKernel,
} = NativeModules;

let ExManifests = {
  async manifestUrlToBundleUrlAndManifestAsync(manifestUrl) {
    if (Platform.OS !== 'ios') {
      throw new Error('This method is only supported on iOS');
    }
    let httpManifestUrl = ExUrls.toHttp(manifestUrl);
    let httpManifestUrlComponents = url.parse(httpManifestUrl);
    // Append index.exp to path
    if (!httpManifestUrlComponents.pathname) {
      httpManifestUrlComponents.pathname = '';
    }
    let indexOfDeepLink = httpManifestUrlComponents.pathname.indexOf('+');
    if (indexOfDeepLink !== -1) {
      httpManifestUrlComponents.pathname = httpManifestUrlComponents.pathname.substring(0, indexOfDeepLink);
    }
    if (!httpManifestUrlComponents.pathname.endsWith('/')) {
      httpManifestUrlComponents.pathname += '/';
    }
    httpManifestUrlComponents.pathname += 'index.exp';
    httpManifestUrl = url.format(httpManifestUrlComponents);

    // Fetch manifest
    let manifestString;
    try {
      manifestString = await ExponentKernel.getManifestAsync(httpManifestUrl, manifestUrl);
    } catch (e) {
      e.message = `Error while loading: ${e.message}.`;
      throw e;
    }

    // Parse JSON
    let manifest;
    try {
      manifest = JSON.parse(manifestString);
    } catch (error) {
      // manifestUrl didn't return a manifest. Try using manifestUrl as the bundleUrl.
      return {
        bundleUrl: manifestUrl,
        manifest: {},
      };
    }

    if (!manifest.isVerified) {
      throw new Error('This experience could not be verified.');
    }
    if (!manifest.bundleUrl) {
      throw new Error('No bundleUrl in manifest.');
    }

    return {
      // TODO: remove url.resolve and only use manifest.bundleUrl
      bundleUrl: url.resolve(httpManifestUrl, manifest.bundleUrl),
      manifest,
    };
  },

  getFramePropsFromManifest(manifest, bundleUrl) {
    let source = ExUrls.toHttp(bundleUrl);
    let { query } = url.parse(source, true);
    let appKey = manifest.appKey || query.app || 'main';

    let debuggerHost = manifest.debuggerHost;
    let debuggerHostname = debuggerHost ? ExUrls.getHostnameForHost(debuggerHost) :
      null;
    let debuggerPort = debuggerHost ? Number(ExUrls.getPortForHost(debuggerHost)) :
      -1;

    return { source, appKey, debuggerHostname, debuggerPort };
  },

  isManifestSdkVersionSupported(manifest) {
    let sdkVersion = manifest.sdkVersion;
    if (sdkVersion === 'UNVERSIONED') {
      return true; // you're on your own, buddy!
    }

    let supportedVersions = ExponentKernel.sdkVersions;
    let sdkVersionComponents;
    let isManifestSdkVersionSupported = false;

    try {
      sdkVersionComponents = sdkVersion.split('.').map(component => parseInt(component, 10));
    } catch (_) {}

    supportedVersions.forEach(supportedVersion => {
      if (supportedVersion === sdkVersion) {
        isManifestSdkVersionSupported = true;
      }
      try {
        let supportedVersionComponents = supportedVersion.split('.').map(component => parseInt(component, 10));
        if (sdkVersionComponents[0] === supportedVersionComponents[0] && sdkVersionComponents[1] === supportedVersionComponents[1]) {
          isManifestSdkVersionSupported = true;
        }
      } catch (_) {}
    });
    return isManifestSdkVersionSupported;
  },
};

export default ExManifests;
<|endoftext|>


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

/**
 * A Scenery input listener that is able to find the closest in a list of nodes to a "down" event and trigger a drag
 * on the closest (assuming it has a SimpleDragHandler).
 *
 * Handles items of the form:
 * {
 *   startDrag: function( event ),
 *   computeDistance: function( globalPoint ) : number
 * }
 *
 * @author Jonathan Olson (PhET Interactive Simulations)
 */
define( function( require ) {
  'use strict';

  // modules
  var inherit = require( 'PHET_CORE/inherit' );
  var sun = require( 'SUN/sun' );
  var Tandem = require( 'TANDEM/Tandem' );

  /**
   * @constructor
   *
   * @param {number} touchThreshold - The distance
   */
  function ClosestDragListener( touchThreshold, mouseThreshold ) {
    // @private
    this.touchThreshold = touchThreshold;
    this.mouseThreshold = mouseThreshold;

    // @private
    this.items = [];

    Tandem.indicateUninstrumentedCode();
  }

  sun.register( 'ClosestDragListener', ClosestDragListener );

  inherit( Object, ClosestDragListener, {
    /**
     * Adds an item that can be dragged.
     * @public
     *
     * @param {item} item
     */
    addDraggableItem: function( item ) {
      assert && assert( !!item.startDrag && !!item.computeDistance, 'Added an invalid item for ClosestDragListener' );
      this.items.push( item );
    },

    /**
     * Removes a previously-added item.
     * @public
     *
     * @param {item} item
     */
    removeDraggableItem: function( item ) {
      var index = _.indexOf( this.items, item );
      assert && assert( index >= 0 );
      this.items.splice( index, 1 );
    },

    down: function( event ) {
      // If there was nothing else in the way
      if ( event.target === event.currentTarget ) {
        var threshold = 0;
        if ( event.pointer.isTouch ) {
          threshold = this.touchThreshold;
        }
        if ( event.pointer.isMouse ) {
          threshold = this.mouseThreshold;
        }
        if ( threshold ) {
          // search for the closest item
          var currentItem = null;
          var currentDistance = Number.POSITIVE_INFINITY;
          var globalPoint = event.pointer.point;
          var numItems = this.items.length;
          for ( var i = 0; i < numItems; i++ ) {
            var item = this.items[ i ];

            var distance = item.computeDistance( globalPoint );
            if ( distance < currentDistance ) {
              currentDistance = distance;
              currentItem = item;
            }
          }

          // if we have a closest item under the threshold, attempt to start a drag on it
          if ( currentItem && currentDistance < threshold ) {
            currentItem.startDrag( event );
          }
        }
      }
    }
  } );

  return ClosestDragListener;
} );<commit_msg>Removing pointer type shortcuts, see https://github.com/phetsims/scenery/issues/724<commit_after>// Copyright 2016-2017, University of Colorado Boulder

/**
 * A Scenery input listener that is able to find the closest in a list of nodes to a "down" event and trigger a drag
 * on the closest (assuming it has a SimpleDragHandler).
 *
 * Handles items of the form:
 * {
 *   startDrag: function( event ),
 *   computeDistance: function( globalPoint ) : number
 * }
 *
 * @author Jonathan Olson (PhET Interactive Simulations)
 */
define( function( require ) {
  'use strict';

  // modules
  var inherit = require( 'PHET_CORE/inherit' );
  var Mouse = require( 'SCENERY/input/Mouse' );
  var sun = require( 'SUN/sun' );
  var Tandem = require( 'TANDEM/Tandem' );
  var Touch = require( 'SCENERY/input/Touch' );

  /**
   * @constructor
   *
   * @param {number} touchThreshold - The distance
   */
  function ClosestDragListener( touchThreshold, mouseThreshold ) {
    // @private
    this.touchThreshold = touchThreshold;
    this.mouseThreshold = mouseThreshold;

    // @private
    this.items = [];

    Tandem.indicateUninstrumentedCode();
  }

  sun.register( 'ClosestDragListener', ClosestDragListener );

  inherit( Object, ClosestDragListener, {
    /**
     * Adds an item that can be dragged.
     * @public
     *
     * @param {item} item
     */
    addDraggableItem: function( item ) {
      assert && assert( !!item.startDrag && !!item.computeDistance, 'Added an invalid item for ClosestDragListener' );
      this.items.push( item );
    },

    /**
     * Removes a previously-added item.
     * @public
     *
     * @param {item} item
     */
    removeDraggableItem: function( item ) {
      var index = _.indexOf( this.items, item );
      assert && assert( index >= 0 );
      this.items.splice( index, 1 );
    },

    down: function( event ) {
      // If there was nothing else in the way
      if ( event.target === event.currentTarget ) {
        var threshold = 0;
        if ( event.pointer instanceof Touch ) {
          threshold = this.touchThreshold;
        }
        if ( event.pointer instanceof Mouse ) {
          threshold = this.mouseThreshold;
        }
        if ( threshold ) {
          // search for the closest item
          var currentItem = null;
          var currentDistance = Number.POSITIVE_INFINITY;
          var globalPoint = event.pointer.point;
          var numItems = this.items.length;
          for ( var i = 0; i < numItems; i++ ) {
            var item = this.items[ i ];

            var distance = item.computeDistance( globalPoint );
            if ( distance < currentDistance ) {
              currentDistance = distance;
              currentItem = item;
            }
          }

          // if we have a closest item under the threshold, attempt to start a drag on it
          if ( currentItem && currentDistance < threshold ) {
            currentItem.startDrag( event );
          }
        }
      }
    }
  } );

  return ClosestDragListener;
} );<|endoftext|>


<commit_before>import axios from 'axios';
import * as JSONAccess from './JSONAccess';

// Re-export stuff from JSONAccess into the MonarchAccess namespace
export const { loadJSONXHR, loadJSONAxios } = JSONAccess;

const biolink = global.serviceUrls.BIOLINK;
// const scigraphData = global.serviceUrls.SCIGRAPH_DATA;
// const scigraphOntology = global.serviceUrls.SCIGRAPH_ONTOLOGY;

// TIP: Example of a domain-specific (as opposed to a generic loadJSON)
// service function. This set of domain-specific services will pretty much
// correspond to the set of needed services for the Monarch UI application, and may
// not necessarily be the same set of functions needed by a generic client
// of Monarch's services/data. In other words, we can add convenience/aggregation
// services here that may not make sense for general-purpose use. Our goal
// with MonarchAccess is to isolate the UI from the service layer, and only secondarily,
// to create a general-purpose service layer, which is more what BioLink promises
// to be.
//

export function getNodeSummary(nodeId, nodeType) {
  const url = `/node/${nodeType}/${nodeId}.json`;

  const returnedPromise = new Promise((resolve, reject) => {
    axios.get(url)
      .then(resp => {
        const responseData = resp.data
        // const { responseURL } = resp.request;
        // console.log('...getNodeSummary', resp, responseData, responseURL);
        if (typeof responseData !== 'object') {
          reject(responseData);
        }
        else {
          resolve(responseData);
        }
      })
      .catch(err => {
        reject(err);
      });
  });

  return returnedPromise;
}

export function getSearchTermSuggestions(term, selected) {
  const baseUrl = `${biolink}search/entity/autocomplete/`;
  const urlExtension = `${baseUrl}${term}`;
  const params = new URLSearchParams();
  params.append('rows', 10);
  params.append('start', 0);
  params.append('highlight_class', 'hilite');
  params.append('boost_q', 'category:genotype^-10');
  if (selected.toString() === 'gene') {
    params.append('boost_fx', 'pow(edges,0.334)');
  }
  if (selected.length > 0) {
    selected.forEach(elem => {
      params.append('category', elem);
    });
  }
  else {
    ['gene', 'variant locus', 'phenotype', 'genotype', 'disease']
      .forEach(elem => (params.append('category', elem)));
  }
  params.append('prefix', '-OMIA');
  const returnedPromise = new Promise((resolve, reject) => {
    axios.get(urlExtension, { params })
      .then(resp => {
        const responseData = resp.data;
        if (typeof responseData !== 'object') {
          reject(responseData);
        }
        else {
          resolve(responseData);
        }
      })
      .catch(err => {
        reject(err);
      });
  });

  return returnedPromise;
}

export function getNodeAssociations(nodeType, identifier, biolinkAnnotationSuffix, params) {
  const baseUrl = `${biolink}bioentity/`;
  const urlExtension = `${nodeType}/${identifier}/${biolinkAnnotationSuffix}`;
  const returnedPromise = new Promise((resolve, reject) => {
    axios.get(`${baseUrl}${urlExtension}`, { params })
      .then(resp => {
        const responseData = resp;
        if (typeof responseData !== 'object') {
          reject(responseData);
        }
        else {
          resolve(responseData);
        }
      })
      .catch(err => {
        reject(err);
      });
  });
  return returnedPromise;
}

export function getNodeLabelByCurie(curie) {
  const baseUrl = `${biolink}bioentity/${curie}`;
  const params = {
    fetch_objects: true,
    rows: 100,
  };
  const returnedPromise = new Promise((resolve, reject) => {
    axios.get(baseUrl, { params })
      .then(resp => {
        const responseData = resp;
        if (typeof responseData !== 'object') {
          reject(responseData);
        }
        else {
          resolve(responseData);
        }
      })
      .catch(err => {
        reject(err);
      });
  });
  return returnedPromise;
}

export function comparePhenotypes(phenotypesList, geneList, species = 'all', mode = 'search') {
  const baseUrl = 'https://beta.monarchinitiative.org/analyze/phenotypes.json?';
  const params = new URLSearchParams();
  const phenoCuries = phenotypesList.map(elem => {
    return elem.curie;
  });
  params.append('input_items', phenoCuries);
  params.append('gene_items', geneList);
  params.append('target_species', species);
  params.append('mode', mode);
  const returnedPromise = new Promise((resolve, reject) => {
    axios.get(baseUrl, { params })
      .then(resp => {
        const responseData = resp;
        if (typeof responseData !== 'object') {
          reject(responseData);
        }
        else {
          resolve(responseData);
        }
      })
      .catch(err => {
        reject(err);
      });
  });
  return returnedPromise;
}

/*
  might be useful, probably should be deleted and reinvented.
  Basically calls scigraph directly instead of using the webapp response.
  Not currently displayed.
  probably should delete this.
    xloadPathContentAsync(path, done) {
      console.log('xloadPathContentAsync', path);
      const oReq = new XMLHttpRequest();
      oReq.addEventListener('load', function load() {
        // console.log('xloadPathContentAsync', path, this);
        var responseJSON = this.responseText;
        var response = JSON.parse(responseJSON);
        done(response, this.responseURL, path);
      });

      let refinedPath = path;

      // const hashIndex = refinedPath.indexOf('#');
      // if (hashIndex >= 0) {
      //   refinedPath = refinedPath.slice(0, hashIndex) + '?stripme' + refinedPath.slice(hashIndex);
      // }
      // else {
      //   refinedPath += '?stripme';
      // }
      oReq.open('GET', refinedPath);
      oReq.send();
    },

    getHierarchy() {
      console.log('qurl', this.node);
      //Determine if ID is clique leader
      var qurl = this.node.global_scigraph_data_url + "dynamic/cliqueLeader/" + this.nodeId + ".json";
      this.xloadPathContentAsync(qurl,
        function(response, responseURL, path) {
          console.log('xpathLoadedAsync', response, responseURL, path);

          var graph = new bbop.model.graph();
          graph.load_json(response);
          var nodeList = graph.all_nodes();
          console.log('nodeList', nodeList);
          if (nodeList.length !== 1) {
            console.log('nodeList ERROR too many entries', nodeList);
          }
          else {
            var leaderId = nodeList[0].id();
            console.log('leaderId', leaderId);
          }
        });
    }
*/

// url1 = 'https://beta.monarchinitiative.org/analyze/phenotypes.json' +
//   '?input_items=' +
//   'HP%3A0000316+HP%3A0000322+HP%3A0000272' +
//   '&' +
//   'mode=compare' +
//   '&' +
//   'target_species=all' +
//   '&' +
//   'limit=100' +
//   '&' +
//   'gene_list=' +
//   'NCBIGene%3A7157%2CNCBIGene%3A5290%2CNCBIGene%3A5728%2CNCBIGene%3A324%2CNCBIGene%3A7428'

// target_species=<taxids>
// input_items=<phenotypes>
// gene_items=<genes>
// mode=search, ?
// limit=<integer>

<commit_msg>removed commented out call<commit_after>import axios from 'axios';
import * as JSONAccess from './JSONAccess';

// Re-export stuff from JSONAccess into the MonarchAccess namespace
export const { loadJSONXHR, loadJSONAxios } = JSONAccess;

const biolink = global.serviceUrls.BIOLINK;
// const scigraphData = global.serviceUrls.SCIGRAPH_DATA;
// const scigraphOntology = global.serviceUrls.SCIGRAPH_ONTOLOGY;

// TIP: Example of a domain-specific (as opposed to a generic loadJSON)
// service function. This set of domain-specific services will pretty much
// correspond to the set of needed services for the Monarch UI application, and may
// not necessarily be the same set of functions needed by a generic client
// of Monarch's services/data. In other words, we can add convenience/aggregation
// services here that may not make sense for general-purpose use. Our goal
// with MonarchAccess is to isolate the UI from the service layer, and only secondarily,
// to create a general-purpose service layer, which is more what BioLink promises
// to be.
//

export function getNodeSummary(nodeId, nodeType) {
  const url = `/node/${nodeType}/${nodeId}.json`;

  const returnedPromise = new Promise((resolve, reject) => {
    axios.get(url)
      .then(resp => {
        const responseData = resp.data
        // const { responseURL } = resp.request;
        // console.log('...getNodeSummary', resp, responseData, responseURL);
        if (typeof responseData !== 'object') {
          reject(responseData);
        }
        else {
          resolve(responseData);
        }
      })
      .catch(err => {
        reject(err);
      });
  });

  return returnedPromise;
}

export function getSearchTermSuggestions(term, selected) {
  const baseUrl = `${biolink}search/entity/autocomplete/`;
  const urlExtension = `${baseUrl}${term}`;
  const params = new URLSearchParams();
  params.append('rows', 10);
  params.append('start', 0);
  params.append('highlight_class', 'hilite');
  params.append('boost_q', 'category:genotype^-10');
  if (selected.toString() === 'gene') {
    params.append('boost_fx', 'pow(edges,0.334)');
  }
  if (selected.length > 0) {
    selected.forEach(elem => {
      params.append('category', elem);
    });
  }
  else {
    ['gene', 'variant locus', 'phenotype', 'genotype', 'disease']
      .forEach(elem => (params.append('category', elem)));
  }
  params.append('prefix', '-OMIA');
  const returnedPromise = new Promise((resolve, reject) => {
    axios.get(urlExtension, { params })
      .then(resp => {
        const responseData = resp.data;
        if (typeof responseData !== 'object') {
          reject(responseData);
        }
        else {
          resolve(responseData);
        }
      })
      .catch(err => {
        reject(err);
      });
  });

  return returnedPromise;
}

export function getNodeAssociations(nodeType, identifier, biolinkAnnotationSuffix, params) {
  const baseUrl = `${biolink}bioentity/`;
  const urlExtension = `${nodeType}/${identifier}/${biolinkAnnotationSuffix}`;
  const returnedPromise = new Promise((resolve, reject) => {
    axios.get(`${baseUrl}${urlExtension}`, { params })
      .then(resp => {
        const responseData = resp;
        if (typeof responseData !== 'object') {
          reject(responseData);
        }
        else {
          resolve(responseData);
        }
      })
      .catch(err => {
        reject(err);
      });
  });
  return returnedPromise;
}

export function getNodeLabelByCurie(curie) {
  const baseUrl = `${biolink}bioentity/${curie}`;
  const params = {
    fetch_objects: true,
    rows: 100,
  };
  const returnedPromise = new Promise((resolve, reject) => {
    axios.get(baseUrl, { params })
      .then(resp => {
        const responseData = resp;
        if (typeof responseData !== 'object') {
          reject(responseData);
        }
        else {
          resolve(responseData);
        }
      })
      .catch(err => {
        reject(err);
      });
  });
  return returnedPromise;
}

export function comparePhenotypes(phenotypesList, geneList, species = 'all', mode = 'search') {
  const baseUrl = 'https://beta.monarchinitiative.org/analyze/phenotypes.json?';
  const params = new URLSearchParams();
  const phenoCuries = phenotypesList.map(elem => {
    return elem.curie;
  });
  params.append('input_items', phenoCuries);
  params.append('gene_items', geneList);
  params.append('target_species', species);
  params.append('mode', mode);
  const returnedPromise = new Promise((resolve, reject) => {
    axios.get(baseUrl, { params })
      .then(resp => {
        const responseData = resp;
        if (typeof responseData !== 'object') {
          reject(responseData);
        }
        else {
          resolve(responseData);
        }
      })
      .catch(err => {
        reject(err);
      });
  });
  return returnedPromise;
}

/*
  might be useful, probably should be deleted and reinvented.
  Basically calls scigraph directly instead of using the webapp response.
  Not currently displayed.
  probably should delete this.
    xloadPathContentAsync(path, done) {
      console.log('xloadPathContentAsync', path);
      const oReq = new XMLHttpRequest();
      oReq.addEventListener('load', function load() {
        // console.log('xloadPathContentAsync', path, this);
        var responseJSON = this.responseText;
        var response = JSON.parse(responseJSON);
        done(response, this.responseURL, path);
      });

      let refinedPath = path;

      // const hashIndex = refinedPath.indexOf('#');
      // if (hashIndex >= 0) {
      //   refinedPath = refinedPath.slice(0, hashIndex) + '?stripme' + refinedPath.slice(hashIndex);
      // }
      // else {
      //   refinedPath += '?stripme';
      // }
      oReq.open('GET', refinedPath);
      oReq.send();
    },

    getHierarchy() {
      console.log('qurl', this.node);
      //Determine if ID is clique leader
      var qurl = this.node.global_scigraph_data_url + "dynamic/cliqueLeader/" + this.nodeId + ".json";
      this.xloadPathContentAsync(qurl,
        function(response, responseURL, path) {
          console.log('xpathLoadedAsync', response, responseURL, path);

          var graph = new bbop.model.graph();
          graph.load_json(response);
          var nodeList = graph.all_nodes();
          console.log('nodeList', nodeList);
          if (nodeList.length !== 1) {
            console.log('nodeList ERROR too many entries', nodeList);
          }
          else {
            var leaderId = nodeList[0].id();
            console.log('leaderId', leaderId);
          }
        });
    }
*/

<|endoftext|>


<commit_before>var Backbone            = require('backbone'),
    $                   = require('jquery'),
    _                   = require('underscore'),
    Service             = require('cloud/models/service'),
    gmaps               = require('google-maps'),
    editServiceTemplate = require('templates/edit_service');

function modelSaveFailCallback(args) {
  this.$("#facilitySaveError").show().focus();
  console.log("failed.");
  console.log(args);
}

function modelSaveSuccessCallback(args) {
  this.$("#facilitySaved").show().focus();
  this.$("#facilitySaved").delay(5000).fadeOut();

  console.log("saved.");
  console.log(args);
}

function saveFacility(model, services, successCallback, failCallback) {
  // var self = this;
  model.save().then(function(foo) {
    // var services = self.$('#facilityForm').serializeObject().services || [];
    _.each(model.get("services"), function(service) {
      service.destroy();
    });

    var serviceObjects = _.map(services, function(serviceData) {
      var service = new Service();
      service.set("facility", model);
      service.set(serviceData);
      return service;
    });

    Service.saveAll(serviceObjects, function(services, error) {
      if (services) {
        _.each(services, function(s) {
          var sObj = new Service();
          sObj.id = s.id;
          model.add("services", sObj);
        });

        model.save()
          .then(function(fac) {
            successCallback(fac);
          }, function(error) {
            failCallback(error);
          });

      } else {
        failCallback(error);
      }
    });
  },
  failCallback());
}

var EditView = Backbone.View.extend({
  template: require('templates/edit'),

  events: {
    'click #add_category':    'addCategory',
    'click #remove_category': 'removeCategory'
  },

  addCategory: function(argument) {
    var context = { category: this.$('#categories').val() };
    this.$('#services').prepend(editServiceTemplate(context));
    return false;
  },

  removeCategory: function(event) {
    var parent = this.$(event.target).closest('.service-edit-row');
    parent.remove();
    return false;
  },

  setupForm: function() {
    var g = this.model.get('gender');
    var el;

    el = this.$('#gender_' + (g ? g : ''));
    el.prop('checked', true);

    this.$("#age_everyone").click(function() {
      this.$('[name="age"]').prop('checked', $(this).prop('checked'));
    }.bind(this));

    if ( this.model.get("age") ) {
      _(this.model.get("age")).each(function(age) {
        this.$("#age_" + age.toUpperCase()).prop('checked', true);
      }.bind(this));
    } else {
      this.$("#age_everyone").click();
    }

    this.$('#submit').click(function() {
      this.saveForm();
    }.bind(this));
  },

  saveForm: function() {
    // var self = this;
    var servicePromises = [];
    var formValues = this.$('#facilityForm').serializeObject();
    if ( formValues.gender === "" ) {
      formValues.gender = null;
    }

    if ( this.$("#age_everyone").prop('checked') ) {
      formValues.age = null;
    } else {
      var ages = _.map(this.$("[name=age]input:checked"), function(cb) {
        return $(cb).attr('value');
      });

      ages = _(ages).compact();
      formValues.age = ages;
    }

    var oldServices = _.clone(formValues.services);

    // _.each(formValues.services, function(service, i) {
    //   self.model.get("services")[i].set(service);
    // });

    delete formValues.services;
    this.model.set(formValues);

    var save = _.bind(saveFacility, this);
    // save(this.model, oldServices, _.bind(modelSaveSuccessCallback, this), _.bind(modelSaveFailCallback, this));

    // self.model.save().then(function(foo) {
    //   var services = self.$('#facilityForm').serializeObject().services || [];
    //   console.log(Service);
    //   debugger;

    //   _.each(services, function(service) {
    //     servicePromises.push(service.save());
    //   });

    //   Parse.Promise.when(servicePromises).then(
    //     function(args) {
    //       self.$("#facilitySaved").show().focus();
    //       self.$("#facilitySaved").delay(5000).fadeOut();

    //       console.log("saved.");
    //       console.log(args);
    //     },
    //     function(args) {
    //       self.$("#facilitySaveError").show().focus();
    //       console.log("failed.");
    //       console.log(args);
    //     }
    //   );
    // },
    // _.bind(modelSaveFailCallback, self)
    // );
  },

  render: function() {
    var hours = [];

    for(var idx = 0; idx <= 23; idx++) {
      if (idx < 10) { idx = '0' + idx; }
      hours.push(idx + ':00');
      hours.push(idx + ':30');
    }

    var templateData = this.model.presentJSON();
    templateData.services.forEach(function(service) {
      service.allHours = hours;
    });
    $(this.el).html(this.template({facility: templateData}));
    this.setupForm();
    return this;
  }
});

module.exports = EditView;
<commit_msg>get multi-service working.<commit_after>var Backbone            = require('backbone'),
    $                   = require('jquery'),
    _                   = require('underscore'),
    Service             = require('cloud/models/service'),
    gmaps               = require('google-maps'),
    editServiceTemplate = require('templates/edit_service');

function modelSaveFailCallback(args) {
  this.$("#facilitySaveError").show().focus();
  console.log("failed.");
  console.log(args);
}

function modelSaveSuccessCallback(args) {
  this.$("#facilitySaved").show().focus();
  this.$("#facilitySaved").delay(5000).fadeOut();

  console.log("saved.");
  console.log(args);
}

function saveFacility(model, services, successCallback, failCallback) {
  model.save().then(function(foo) {
    _.each(model.get("services"), function(service) {
      service.destroy();
    });

    var serviceObjects = _.map(services, function(serviceData) {
      var service = new Service();
      service.set("facility", model);

      delete serviceData.id;
      service.set(serviceData);

      return service;
    });

    Service.saveAll(serviceObjects, function(services, error) {
      if (services) {
        model.set("services", _.map(services, function(s) {
          var sObj = new Service();
          sObj.id = s.id;
          return sObj;
        }));

        model.save()
          .then(function(fac) {
            successCallback(fac);
          }, function(error) {
            failCallback(error);
          });

      } else {
        failCallback(error);
      }
    });
  },
  failCallback);
}

var EditView = Backbone.View.extend({
  template: require('templates/edit'),

  events: {
    'click #add_category':    'addCategory',
    'click #remove_category': 'removeCategory'
  },

  addCategory: function(argument) {
    var context = { category: this.$('#categories').val() };
    this.$('#services').prepend(editServiceTemplate(context));
    return false;
  },

  removeCategory: function(event) {
    var parent = this.$(event.target).closest('.service-edit-row');
    parent.remove();
    return false;
  },

  setupForm: function() {
    var g = this.model.get('gender');
    var el;

    el = this.$('#gender_' + (g ? g : ''));
    el.prop('checked', true);

    this.$("#age_everyone").click(function() {
      this.$('[name="age"]').prop('checked', $(this).prop('checked'));
    }.bind(this));

    if ( this.model.get("age") ) {
      _(this.model.get("age")).each(function(age) {
        this.$("#age_" + age.toUpperCase()).prop('checked', true);
      }.bind(this));
    } else {
      this.$("#age_everyone").click();
    }

    this.$('#submit').click(function() {
      this.saveForm();
    }.bind(this));
  },

  saveForm: function() {
    // var self = this;
    var servicePromises = [];
    var formValues = this.$('#facilityForm').serializeObject();
    if ( formValues.gender === "" ) {
      formValues.gender = null;
    }

    if ( this.$("#age_everyone").prop('checked') ) {
      formValues.age = null;
    } else {
      var ages = _.map(this.$("[name=age]input:checked"), function(cb) {
        return $(cb).attr('value');
      });

      ages = _(ages).compact();
      formValues.age = ages;
    }

    var oldServices = _.clone(formValues.services);

    // _.each(formValues.services, function(service, i) {
    //   self.model.get("services")[i].set(service);
    // });

    delete formValues.services;
    this.model.set(formValues);

    var save = _.bind(saveFacility, this);
    save(this.model, oldServices, _.bind(modelSaveSuccessCallback, this), _.bind(modelSaveFailCallback, this));

  },

  render: function() {
    var hours = [];

    for(var idx = 0; idx <= 23; idx++) {
      if (idx < 10) { idx = '0' + idx; }
      hours.push(idx + ':00');
      hours.push(idx + ':30');
    }

    var templateData = this.model.presentJSON();
    templateData.services.forEach(function(service) {
      service.allHours = hours;
    });
    $(this.el).html(this.template({facility: templateData}));
    this.setupForm();
    return this;
  }
});

module.exports = EditView;
<|endoftext|>


<commit_before>import { isStandalone } from "../app/codeCharta/util/envDetector"

const HtmlWebpackPlugin = require("html-webpack-plugin")
const path = require("path")
const { CleanWebpackPlugin } = require("clean-webpack-plugin")

const dist = path.resolve(__dirname, "../dist/webpack")

const target = isStandalone() ? "node" : "web"

module.exports = {
	mode: "development",
	target,
	entry: "./app/app.ts",
	output: {
		filename: "bundle.js",
		path: dist
	},
	devServer: {
		contentBase: dist,
		compress: true, // enable gzip compression
		hot: true, // hot module replacement. Depends on HotModuleReplacementPlugin
		port: 3000,
		clientLogLevel: "error"
	},
	module: require("./webpack.loaders.js"),
	plugins: [
		new CleanWebpackPlugin(),
		new HtmlWebpackPlugin({
			template: "./app/index.html"
		})
	],
	devtool: "source-map",
	resolve: {
		extensions: [".ts", ".tsx", ".js"]
	}
}
<commit_msg>Refactor target usage in module exports directly #815<commit_after>import { isStandalone } from "../app/codeCharta/util/envDetector"

const HtmlWebpackPlugin = require("html-webpack-plugin")
const path = require("path")
const { CleanWebpackPlugin } = require("clean-webpack-plugin")

const dist = path.resolve(__dirname, "../dist/webpack")

module.exports = {
	mode: "development",
	target: isStandalone() ? "node" : "web",
	entry: "./app/app.ts",
	output: {
		filename: "bundle.js",
		path: dist
	},
	devServer: {
		contentBase: dist,
		compress: true, // enable gzip compression
		hot: true, // hot module replacement. Depends on HotModuleReplacementPlugin
		port: 3000,
		clientLogLevel: "error"
	},
	module: require("./webpack.loaders.js"),
	plugins: [
		new CleanWebpackPlugin(),
		new HtmlWebpackPlugin({
			template: "./app/index.html"
		})
	],
	devtool: "source-map",
	resolve: {
		extensions: [".ts", ".tsx", ".js"]
	}
}
<|endoftext|>


<commit_before>define('utility', ['jquery'], function ($) {
  var Utility = {
    DOM:{
      serializeObject:function (el) {
        var o = {};
        var a = $(el).serializeArray();
        $.each(a, function () {
          if (o[this.name] !== undefined) {
            if (!o[this.name].push) {
              o[this.name] = [o[this.name]];
            }
            o[this.name].push(this.value || '');
          } else {
            o[this.name] = this.value || '';
          }
        });
        return o;
      }
    }
  };

  return Utility;
});<commit_msg>Oops, typo in dependency name<commit_after>define(['jquery'], function ($) {
  var Utility = {
    DOM:{
      serializeObject:function (el) {
        var o = {};
        var a = $(el).serializeArray();
        $.each(a, function () {
          if (o[this.name] !== undefined) {
            if (!o[this.name].push) {
              o[this.name] = [o[this.name]];
            }
            o[this.name].push(this.value || '');
          } else {
            o[this.name] = this.value || '';
          }
        });
        return o;
      }
    }
  };

  return Utility;
});<|endoftext|>


<commit_before>import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import Box from '../box';
import cx from 'classnames';
import theme from './theme.css';

const SIZES = {
  medium: {
    paddingHorizontal: 2,
    paddingVertical: 1,
  },
  small: {
    paddingHorizontal: 2,
  },
};

class StatusLabel extends PureComponent {
  render() {
    const { children, className, color, size, ...others } = this.props;

    const classNames = cx(theme['label'], theme[color], theme[size], className);

    return (
      <Box className={classNames} element="span" {...SIZES[size]} {...others} data-teamleader-ui="status-label">
        {children}
      </Box>
    );
  }
}

StatusLabel.propTypes = {
  children: PropTypes.any.isRequired,
  className: PropTypes.string,
  color: PropTypes.oneOf(['neutral', 'mint', 'violet', 'ruby', 'gold', 'aqua']),
  size: PropTypes.oneOf(Object.keys(SIZES)),
};

StatusLabel.defaultProps = {
  color: 'neutral',
  size: 'medium',
};

export default StatusLabel;
<commit_msg>add descriptions to the status label proptypes<commit_after>import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import Box from '../box';
import cx from 'classnames';
import theme from './theme.css';

const SIZES = {
  medium: {
    paddingHorizontal: 2,
    paddingVertical: 1,
  },
  small: {
    paddingHorizontal: 2,
  },
};

class StatusLabel extends PureComponent {
  render() {
    const { children, className, color, size, ...others } = this.props;

    const classNames = cx(theme['label'], theme[color], theme[size], className);

    return (
      <Box className={classNames} element="span" {...SIZES[size]} {...others} data-teamleader-ui="status-label">
        {children}
      </Box>
    );
  }
}

StatusLabel.propTypes = {
  /** The content to display inside the status label */
  children: PropTypes.any.isRequired,
  /** A classname to add to the status label to give custom styles */
  className: PropTypes.string,
  /** The name of the color them you want to give to the status label */
  color: PropTypes.oneOf(['neutral', 'mint', 'violet', 'ruby', 'gold', 'aqua']),
  /** Size of the button */
  size: PropTypes.oneOf(Object.keys(SIZES)),
};

StatusLabel.defaultProps = {
  color: 'neutral',
  size: 'medium',
};

export default StatusLabel;
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2015 Google Inc. All Rights Reserved.
 *
 * 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.
 */

CLASS({
  package: 'foam.build',
  name: 'BuildApp',

  imports: [
    'log',
    'error'
  ],
  requires: [
    'foam.dao.NodeFileDAO as FileDAO',
    'foam.dao.File',
    'foam.core.dao.OrDAO',
    'node.dao.ModelFileDAO',
    'foam.build.WebApplication'
  ],
  properties: [
    {
      name: 'appDefinition'
    },
    {
      name: 'controller',
      help: 'Name of the main controller/model to create',
    },
    {
      model_: 'StringArrayProperty',
      name: 'coreFiles',
      adapt: function(_, s) { if ( typeof s === 'string' ) return s.split(','); return s; }
    },
    {
      name: 'defaultView',
      help: "Default view of the controller to use.  If not set, the controller will be used as view (if it is one), or DetailView will be used"
    },
    {
      name: 'targetPath',
      help: "Directory to write output files to.  Will be created if it doesn't exist.",
      required: true
    },
    {
      model_: 'BooleanProperty',
      name: 'precompileTemplates',
      help: 'True to precompile templates of models loaded from the ModelDAO.',
      defaultValue: false
    },
    {
      model_: 'BooleanProperty',
      name: 'includeFoamCSS',
      defaultValue: false
    },
    {
      model_: 'StringProperty',
      name: 'icon'
    },
    {
      model_: 'StringProperty',
      name: 'version'
    },
    {
      model_: 'StringArrayProperty',
      name: 'resources'
    },
    {
      model_: 'BooleanProperty',
      name: 'appcacheManifest',
      defaultValue: false
    },
    {
      model_: 'StringArrayProperty',
      name: 'extraFiles',
      help: 'Extra files to both load during the build process, and include in the built image.',
      adapt: function(_, s) { if ( typeof s === 'string' ) return s.split(','); return s; }
    },
    {
      model_: 'StringArrayProperty',
      name: 'extraBuildFiles',
      help: 'Extra files to load during the build process, but NOT include in the built image.',
      adapt: function(_, s) { if ( typeof s === 'string' ) return s.split(','); return s; }
    },
    {
      model_: 'StringArrayProperty',
      name: 'extraModels',
      help: 'Extra models to include in the image regardless of if they were arequired or not.',
      adapt: function(_, s) { if ( typeof s === 'string' ) return s.split(','); return s; },
      factory: function() { return ['foam.ui.FoamTagView']; }
    },
    {
      model_: 'StringArrayProperty',
      name: 'blacklistModels',
      help: 'Models to unconditionally exclude from the image, even if they are listed as required.',
      adapt: function(_, s) { if ( typeof s === 'string' ) return s.split(','); return s; }
    },
    {
      model_: 'BooleanProperty',
      name: 'outputManifest',
      defaultValue: false,
      help: 'Set to true to write out a MANIFEST file listing all included models.'
    },
    {
      name: 'htmlFileName',
      help: 'Name of the main html file to produce.',
      defaultValue: 'main.html'
    },
    {
      model_: 'StringArrayProperty',
      name: 'htmlHeaders'
    },
    {
      name: 'formatter',
      factory: function() {
        return {
          __proto__: JSONUtil.compact,
          formatFunction: function(f) {
            var s = f.code.toString();
            if ( s.startsWith('function ' + f.name + '(') ) return s;
            return s.replace(/function ([^\(]*)\(/, 'function ' + f.name + '(')
          },
          keys_: {},
          keyify: JSONUtil.prettyModel.keyify,
          outputObject_: function(out, obj, opt_defaultModel) {
            var first = true;

            out('{');
            if ( obj.model_.id !== opt_defaultModel ) {
              this.outputModel_(out, obj);
              first = false;
            }

            if ( Template.isInstance(obj) ) var isTemplate = true;

            var properties = obj.model_.getRuntimeProperties();
            for ( var key in properties ) {
              var prop = properties[key];

              if ( ! this.p(prop) && ( ! isTemplate || prop.name !== 'code' ) ) continue;

              if ( prop.name === 'documentation' ) continue;

              if ( prop.name in obj.instance_ ) {
                var val = obj[prop.name];
                if ( Array.isArray(val) && ! val.length ) continue;
                if ( ! first ) out(',');
                out(this.keyify(prop.name), ': ');

                if ( prop.name === 'methods' ) {
                  out('[');
                  var ff = true;
                  for ( var i = 0 ; i < val.length ; i++ ) {
                    if ( ! ff ) out(',');

                    out(this.formatFunction(val[i]));
                    ff = false;
                  }
                  out(']');
                } else {
                  if ( Array.isArray(val) && prop.subType ) {
                    this.outputArray_(out, val, prop.subType);
                  } else {
                    this.output(out, val);
                  }
                }
                first = false;
              }
            }

            out('}');
          }
        };
      }
    },
    {
      name: 'path',
      factory: function() { return require('path'); }
    },
    {
      name: 'fileDAO',
      factory: function() { return this.FileDAO.create(); }
    },
    {
      model_: 'StringArrayProperty',
      name: 'extraClassPaths',
      help: 'List of extra .js hierarchies to load models from.  Paths will be checked in the order given, finally falling back to the main FOAM js/ hierarchy.',
      adapt: function(_, s) { if ( typeof s === 'string' ) return s.split(','); return s; }
    },
    {
      model_: 'StringProperty',
      name: 'locale'
    },
    // TODO(markdittmer): Remove "i18nMessagesPath" when all build processes
    // no longer require it.
    {
      model_: 'StringProperty',
      name: 'i18nMessagesPath'
    },
    {
      model_: 'StringProperty',
      name: 'i18nTranslationsPath'
    },
    {
      model_: 'StringArrayProperty',
      name: 'i18nMessages',
      adapt: function(_, s) {
        if (typeof s === 'string') return s.split(',');
        return s;
      }
    },
    {
      model_: 'StringArrayProperty',
      name: 'i18nTranslations',
      adapt: function(_, s) {
        if (typeof s === 'string') return s.split(',');
        return s;
      }
    },
    {
      model_: 'StringProperty',
      name: 'jsFileName',
      getter: function() {
        return 'foam' + (this.locale ? '_' + this.locale : '') + '.js';
      }
    },
    {
      model_: 'StringProperty',
      name: 'manifestFileName',
      getter: function() {
        return 'app' + (this.locale ? '_' + this.locale : '') + '.manifest';
      }
    },
    {
      name: 'localizedHTMLFileName_',
      getter: function() {
        var match = this.htmlFileName.match(/[.][^.]*$/g);
        var ext = match ? match[0] : '';
        var baseName = this.htmlFileName.slice(0,
            this.htmlFileName.length - ext.length);
        return baseName + (this.locale ? '_' + this.locale : '') + ext;
      }
    },
    {
      model_: 'StringProperty',
      name: 'delegate'
    }
  ],
  methods: {
    execute: function() {
      for ( var i = 0; i < this.extraClassPaths.length ; i++ ) {
        this.X.ModelDAO = this.OrDAO.create({
          delegate: this.ModelFileDAO.create({
            classpath: this.extraClassPaths[i]
          }),
          primary: this.X.ModelDAO
        });
      }

      if ( this.appDefinition ) {
        this.X.ModelDAO.find(this.appDefinition, {
          put: function(d) {
            this.copyFrom(d);
            this.execute_();
          }.bind(this),
          error: function() {
            console.log("App definition failed");
            this.execute_();
          }.bind(this)
        });
      } else {
        this.execute_();
      }
    },
    execute_: function() {
      if ( this.delegate ) {
        arequire(this.delegate)(function(DelegateModel) {
          DelegateModel.create({ builder: this }).buildApp();
        }.bind(this));
      } else {
        this.buildApp();
      }
    },
    buildApp: function() {
      if ( ! this.targetPath ) {
        this.error("targetPath is required");
        process.exit(1);
      }
      if ( ! this.controller ) {
        this.error("controller is required");
        process.exit(1);
      }

      var extraBuildFiles = this.extraBuildFiles.concat(this.extraFiles);
      for ( var i = 0 ; i < extraBuildFiles.length ; i++ ) {
        var path = this.getFilePath(extraBuildFiles[i]);
        require(path);
      }

      var view = this.defaultView ? arequire(this.defaultView) : anop;

      var seq = [view];
      for ( var i = 0; i < this.extraModels.length ; i++ ) {
        seq.push(arequire(this.extraModels[i]));
      }

      aseq(
        aseq.apply(null, seq),
        arequire(this.controller))(this.buildModel.bind(this));
    },
    buildCoreJS_: function(ret) {
      var i = 0;
      var self = this;
      var corejs = '';
      var file;
      if ( this.coreFiles.length ) var myfiles = this.coreFiles;
      else myfiles = files;
      myfiles = myfiles.concat(this.extraFiles);
      awhile(
        function() { return i < myfiles.length; },
        aif(
          function() {
            file = myfiles[i++];
            if ( Array.isArray(file) ) {
              if ( file[1] == IN_NODEJS )
                return false;
              file = file[0];
            }
            return true;
          },
          aseq(
            function(ret) {
              var path = this.getFilePath(file);
              this.fileDAO.find(path, {
                put: ret,
                error: function() {
                  self.error.apply(["Error reading file: ", path].concat(arguments));
                }
              });
            }.bind(this),
            function(ret, file) {
              corejs += '\n';
              corejs += file.contents;
              ret();
            })))(function() { ret(corejs); });
    },
    buildAppJS_: function(ret) {
      var models = {};
      var visited = {};
      var error = this.error;
      var self = this;

      function add(require) {
        if ( visited[require] ) return;
        visited[require] = true;

        var model = X.lookup(require);
        if ( ! model ) {
          error("Could not load model: ", require);
        }
        if ( model.package &&
             self.blacklistModels.indexOf(model.id) == -1 ) {
          models[model.id] = model;
        }

        model.getAllRequires().forEach(add);
      };
      add(this.controller);
      if ( this.defaultView ) add(this.defaultView);

      for ( var i = 0; i < this.extraModels.length ; i++ ) {
        add(this.extraModels[i]);
      }

      var contents = '';

      var ids = Object.keys(models);
      if ( this.outputManifest ) {
        this.fileDAO.put(this.File.create({
          path: this.targetPath + this.path.sep + 'MANIFEST',
          contents: ids.join('\n')
        }));
      }

      for ( var i = 0; i < ids.length; i++ ) {
        var model = models[ids[i]];
        if ( this.precompileTemplates ) {
          for ( var j = 0 ; j < model.templates.length ; j++ ) {
            var t = model.templates[j];
            // It's safe to remove leading and trailing whitespace from CSS.
            if ( t.name === 'CSS' ) t.template = t.template.split('\n').map(function(s) { return s.trim(); }).join('\n');
            t.code = TemplateUtil.compile(t);
            t.clearProperty('template');
          }
        }
        contents += 'CLASS(';
        var formatter = this.precompileTemplates ? this.formatter : JSONUtil.compact;
        contents += formatter.where(NOT_TRANSIENT).stringifyObject(models[ids[i]], 'Model');
        contents += ')\n';
      }

      ret(contents);
    },
    buildModel: function(model) {
      if ( ! model ) {
        this.error('Could not find model: ', this.controller);
      }
      this.log('Building   ', model.id);
      this.log('Target is: ', this.targetPath);
      this.log(this.precompileTemplates ? '' : 'NOT ', 'pre-compiling templates.');

      var self = this;
      aseq(
        function(ret) {
          var file = this.File.create({
            path: this.targetPath + this.path.sep + this.localizedHTMLFileName_,
            contents: this.HTML()
          });

          console.log('Writing: ', file.path);
          this.fileDAO.put(file, {
            put: ret,
            error: function() {
              self.error('ERROR writing file: ', file.path);
              process.exit(1);
            }
          });
        }.bind(this),
        aif(this.appcacheManifest,
            function(ret) {
              var file = this.File.create({
                path: this.targetPath + this.path.sep + this.manifestFileName,
                contents: this.MANIFEST()
              });
              console.log('Writing: ', file.path);
              this.fileDAO.put(file, {
                put: ret,
                error: function() {
                  this.error("ERROR writing file: ", file.path);
                  process.exit(1);
                }
              });
            }.bind(this)),
        apar(
          function(ret) { this.buildCoreJS_(ret); }.bind(this),
          function(ret) { this.buildAppJS_(ret); }.bind(this)),
          function(ret, corejs, appjs) {
            var file = this.File.create({
              path: this.targetPath + this.path.sep + this.jsFileName,
              contents: corejs + appjs
            });
            console.log('Writing: ', file.path);
            this.fileDAO.put(file, {
              put: ret,
              error: function() {
                self.error('ERROR writing file: ', file.path);
                process.exit(1);
              }
            });
          }.bind(this)
          )(
        function(){
          process.exit(0);
        });
    },
    getFilePath: function(file) {
      var path = file;
      if ( path.slice(-3) !== '.js' ) path += '.js';
      if ( path.charAt(0) !== this.path.sep )
        path = FOAM_BOOT_DIR + this.path.sep + path;
      return path;
    }
  },
  templates: [
    function HTML() {/*<html<% if ( this.appcacheManifest ) { %> manifest="%%getManifestFileName"<% } %>><meta charset="utf-8"><%= this.htmlHeaders.join('') %><% if ( this.includeFoamCSS ) { %><link rel="stylesheet" type="text/css" href="foam.css"/><% } %><% if ( this.icon ) { %><link rel="icon" sizes="128x128" href="<%= this.icon %>"/><% } %><foam model="<%= this.controller %>"<% if ( this.defaultView ) { %> view="<%= this.defaultView %>"<% } %>></foam>*/},
    function MANIFEST() {/*CACHE MANIFEST
# version <%= this.version %>
<% if ( this.appDefinition ) { %># hash: <%= this.appDefinition.hashCode() %><% } %>

CACHE:
%%jsFileName
%%localizedHTMLFileName_
<% if ( this.includeFoamCSS ) { %>foam.css<% } %>
<% for ( var i = 0 ; i < this.resources.length ; i++ ) { %><%= this.resources[i] %>
<% } %>

NETWORK:
*
*/}
  ]
});
<commit_msg>Cleanup.<commit_after>/**
 * @license
 * Copyright 2015 Google Inc. All Rights Reserved.
 *
 * 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.
 */

CLASS({
  package: 'foam.build',
  name: 'BuildApp',

  imports: [
    'log',
    'error'
  ],
  requires: [
    'foam.dao.NodeFileDAO as FileDAO',
    'foam.dao.File',
    'foam.core.dao.OrDAO',
    'node.dao.ModelFileDAO',
    'foam.build.WebApplication'
  ],
  properties: [
    {
      name: 'appDefinition'
    },
    {
      name: 'controller',
      help: 'Name of the main controller/model to create',
    },
    {
      model_: 'StringArrayProperty',
      name: 'coreFiles',
      adapt: function(_, s) { if ( typeof s === 'string' ) return s.split(','); return s; }
    },
    {
      name: 'defaultView',
      help: "Default view of the controller to use.  If not set, the controller will be used as view (if it is one), or DetailView will be used"
    },
    {
      name: 'targetPath',
      help: "Directory to write output files to.  Will be created if it doesn't exist.",
      required: true
    },
    {
      model_: 'BooleanProperty',
      name: 'precompileTemplates',
      help: 'True to precompile templates of models loaded from the ModelDAO.',
      defaultValue: false
    },
    {
      model_: 'BooleanProperty',
      name: 'includeFoamCSS',
      defaultValue: false
    },
    {
      model_: 'StringProperty',
      name: 'icon'
    },
    {
      model_: 'StringProperty',
      name: 'version'
    },
    {
      model_: 'StringArrayProperty',
      name: 'resources'
    },
    {
      model_: 'BooleanProperty',
      name: 'appcacheManifest',
      defaultValue: false
    },
    {
      model_: 'StringArrayProperty',
      name: 'extraFiles',
      help: 'Extra files to both load during the build process, and include in the built image.',
      adapt: function(_, s) { if ( typeof s === 'string' ) return s.split(','); return s; }
    },
    {
      model_: 'StringArrayProperty',
      name: 'extraBuildFiles',
      help: 'Extra files to load during the build process, but NOT include in the built image.',
      adapt: function(_, s) { if ( typeof s === 'string' ) return s.split(','); return s; }
    },
    {
      model_: 'StringArrayProperty',
      name: 'extraModels',
      help: 'Extra models to include in the image regardless of if they were arequired or not.',
      adapt: function(_, s) { if ( typeof s === 'string' ) return s.split(','); return s; },
      factory: function() { return ['foam.ui.FoamTagView']; }
    },
    {
      model_: 'StringArrayProperty',
      name: 'blacklistModels',
      help: 'Models to unconditionally exclude from the image, even if they are listed as required.',
      adapt: function(_, s) { if ( typeof s === 'string' ) return s.split(','); return s; }
    },
    {
      model_: 'BooleanProperty',
      name: 'outputManifest',
      defaultValue: false,
      help: 'Set to true to write out a MANIFEST file listing all included models.'
    },
    {
      name: 'htmlFileName',
      help: 'Name of the main html file to produce.',
      defaultValue: 'main.html'
    },
    {
      model_: 'StringArrayProperty',
      name: 'htmlHeaders'
    },
    {
      name: 'formatter',
      factory: function() {
        return {
          __proto__: JSONUtil.compact,
          formatFunction: function(f) {
            var s = f.code.toString();
            if ( s.startsWith('function ' + f.name + '(') ) return s;
            return s.replace(/function ([^\(]*)\(/, 'function ' + f.name + '(')
          },
          keys_: {},
          keyify: JSONUtil.prettyModel.keyify,
          outputObject_: function(out, obj, opt_defaultModel) {
            var first = true;

            out('{');
            if ( obj.model_.id !== opt_defaultModel ) {
              this.outputModel_(out, obj);
              first = false;
            }

            if ( Template.isInstance(obj) ) var isTemplate = true;

            var properties = obj.model_.getRuntimeProperties();
            for ( var key in properties ) {
              var prop = properties[key];

              if ( ! this.p(prop) && ( ! isTemplate || prop.name !== 'code' ) ) continue;

              if ( prop.name === 'documentation' ) continue;

              if ( prop.name in obj.instance_ ) {
                var val = obj[prop.name];
                if ( Array.isArray(val) && ! val.length ) continue;
                if ( ! first ) out(',');
                out(this.keyify(prop.name), ': ');

                if ( prop.name === 'methods' ) {
                  out('[');
                  var ff = true;
                  for ( var i = 0 ; i < val.length ; i++ ) {
                    if ( ! ff ) out(',');

                    out(this.formatFunction(val[i]));
                    ff = false;
                  }
                  out(']');
                } else {
                  if ( Array.isArray(val) && prop.subType ) {
                    this.outputArray_(out, val, prop.subType);
                  } else {
                    this.output(out, val);
                  }
                }
                first = false;
              }
            }

            out('}');
          }
        };
      }
    },
    {
      name: 'path',
      factory: function() { return require('path'); }
    },
    {
      name: 'fileDAO',
      factory: function() { return this.FileDAO.create(); }
    },
    {
      model_: 'StringArrayProperty',
      name: 'extraClassPaths',
      help: 'List of extra .js hierarchies to load models from.  Paths will be checked in the order given, finally falling back to the main FOAM js/ hierarchy.',
      adapt: function(_, s) { if ( typeof s === 'string' ) return s.split(','); return s; }
    },
    {
      model_: 'StringProperty',
      name: 'locale'
    },
    // TODO(markdittmer): Remove "i18nMessagesPath" when all build processes
    // no longer require it.
    {
      model_: 'StringProperty',
      name: 'i18nMessagesPath'
    },
    {
      model_: 'StringProperty',
      name: 'i18nTranslationsPath'
    },
    {
      model_: 'StringArrayProperty',
      name: 'i18nMessages',
      adapt: function(_, s) {
        if (typeof s === 'string') return s.split(',');
        return s;
      }
    },
    {
      model_: 'StringArrayProperty',
      name: 'i18nTranslations',
      adapt: function(_, s) {
        if (typeof s === 'string') return s.split(',');
        return s;
      }
    },
    {
      model_: 'StringProperty',
      name: 'jsFileName',
      getter: function() {
        return 'foam' + (this.locale ? '_' + this.locale : '') + '.js';
      }
    },
    {
      model_: 'StringProperty',
      name: 'manifestFileName',
      getter: function() {
        return 'app' + (this.locale ? '_' + this.locale : '') + '.manifest';
      }
    },
    {
      name: 'localizedHTMLFileName_',
      getter: function() {
        var match = this.htmlFileName.match(/[.][^.]*$/g);
        var ext = match ? match[0] : '';
        var baseName = this.htmlFileName.slice(0,
            this.htmlFileName.length - ext.length);
        return baseName + (this.locale ? '_' + this.locale : '') + ext;
      }
    },
    {
      model_: 'StringProperty',
      name: 'delegate'
    }
  ],
  methods: {
    execute: function() {
      for ( var i = 0; i < this.extraClassPaths.length ; i++ ) {
        this.X.ModelDAO = this.OrDAO.create({
          delegate: this.ModelFileDAO.create({
            classpath: this.extraClassPaths[i]
          }),
          primary: this.X.ModelDAO
        });
      }

      if ( this.appDefinition ) {
        this.X.ModelDAO.find(this.appDefinition, {
          put: function(d) {
            this.copyFrom(d);
            this.execute_();
          }.bind(this),
          error: function() {
            console.log("App definition failed");
            this.execute_();
          }.bind(this)
        });
      } else {
        this.execute_();
      }
    },
    execute_: function() {
      if ( this.delegate ) {
        arequire(this.delegate)(function(DelegateModel) {
          DelegateModel.create({ builder: this }).buildApp();
        }.bind(this));
      } else {
        this.buildApp();
      }
    },
    buildApp: function() {
      if ( ! this.targetPath ) {
        this.error("targetPath is required");
        process.exit(1);
      }
      if ( ! this.controller ) {
        this.error("controller is required");
        process.exit(1);
      }

      var extraBuildFiles = this.extraBuildFiles.concat(this.extraFiles);
      for ( var i = 0 ; i < extraBuildFiles.length ; i++ ) {
        var path = this.getFilePath(extraBuildFiles[i]);
        require(path);
      }

      var view = this.defaultView ? arequire(this.defaultView) : anop;

      var seq = [view];
      for ( var i = 0; i < this.extraModels.length ; i++ ) {
        seq.push(arequire(this.extraModels[i]));
      }

      aseq(
        aseq.apply(null, seq),
        arequire(this.controller))(this.buildModel.bind(this));
    },
    buildCoreJS_: function(ret) {
      var i = 0;
      var self = this;
      var corejs = '';
      var file;
      var myfiles = this.coreFiles.length ? this.coreFiles : files ;
      myfiles = myfiles.concat(this.extraFiles);
      awhile(
        function() { return i < myfiles.length; },
        aif(
          function() {
            file = myfiles[i++];
            if ( Array.isArray(file) ) {
              if ( file[1] == IN_NODEJS )
                return false;
              file = file[0];
            }
            return true;
          },
          aseq(
            function(ret) {
              var path = this.getFilePath(file);
              this.fileDAO.find(path, {
                put: ret,
                error: function() {
                  self.error.apply(["Error reading file: ", path].concat(arguments));
                }
              });
            }.bind(this),
            function(ret, file) {
              corejs += '\n';
              corejs += file.contents;
              ret();
            })))(function() { ret(corejs); });
    },
    buildAppJS_: function(ret) {
      var models = {};
      var visited = {};
      var error = this.error;
      var self = this;

      function add(require) {
        if ( visited[require] ) return;
        visited[require] = true;

        var model = X.lookup(require);
        if ( ! model ) {
          error("Could not load model: ", require);
        }
        if ( model.package &&
             self.blacklistModels.indexOf(model.id) == -1 ) {
          models[model.id] = model;
        }

        model.getAllRequires().forEach(add);
      };
      add(this.controller);
      if ( this.defaultView ) add(this.defaultView);

      for ( var i = 0; i < this.extraModels.length ; i++ ) {
        add(this.extraModels[i]);
      }

      var contents = '';

      var ids = Object.keys(models);
      if ( this.outputManifest ) {
        this.fileDAO.put(this.File.create({
          path: this.targetPath + this.path.sep + 'MANIFEST',
          contents: ids.join('\n')
        }));
      }

      for ( var i = 0; i < ids.length; i++ ) {
        var model = models[ids[i]];
        if ( this.precompileTemplates ) {
          for ( var j = 0 ; j < model.templates.length ; j++ ) {
            var t = model.templates[j];
            // It's safe to remove leading and trailing whitespace from CSS.
            if ( t.name === 'CSS' ) t.template = t.template.split('\n').map(function(s) { return s.trim(); }).join('\n');
            t.code = TemplateUtil.compile(t);
            t.clearProperty('template');
          }
        }
        contents += 'CLASS(';
        var formatter = this.precompileTemplates ? this.formatter : JSONUtil.compact;
        contents += formatter.where(NOT_TRANSIENT).stringifyObject(models[ids[i]], 'Model');
        contents += ')\n';
      }

      ret(contents);
    },
    buildModel: function(model) {
      if ( ! model ) {
        this.error('Could not find model: ', this.controller);
      }
      this.log('Building   ', model.id);
      this.log('Target is: ', this.targetPath);
      this.log(this.precompileTemplates ? '' : 'NOT ', 'pre-compiling templates.');

      var self = this;
      aseq(
        function(ret) {
          var file = this.File.create({
            path: this.targetPath + this.path.sep + this.localizedHTMLFileName_,
            contents: this.HTML()
          });

          console.log('Writing: ', file.path);
          this.fileDAO.put(file, {
            put: ret,
            error: function() {
              self.error('ERROR writing file: ', file.path);
              process.exit(1);
            }
          });
        }.bind(this),
        aif(this.appcacheManifest,
            function(ret) {
              var file = this.File.create({
                path: this.targetPath + this.path.sep + this.manifestFileName,
                contents: this.MANIFEST()
              });
              console.log('Writing: ', file.path);
              this.fileDAO.put(file, {
                put: ret,
                error: function() {
                  this.error("ERROR writing file: ", file.path);
                  process.exit(1);
                }
              });
            }.bind(this)),
        apar(
          function(ret) { this.buildCoreJS_(ret); }.bind(this),
          function(ret) { this.buildAppJS_(ret); }.bind(this)),
          function(ret, corejs, appjs) {
            var file = this.File.create({
              path: this.targetPath + this.path.sep + this.jsFileName,
              contents: corejs + appjs
            });
            console.log('Writing: ', file.path);
            this.fileDAO.put(file, {
              put: ret,
              error: function() {
                self.error('ERROR writing file: ', file.path);
                process.exit(1);
              }
            });
          }.bind(this)
          )(
        function(){
          process.exit(0);
        });
    },
    getFilePath: function(file) {
      var path = file;
      if ( path.slice(-3) !== '.js' ) path += '.js';
      if ( path.charAt(0) !== this.path.sep )
        path = FOAM_BOOT_DIR + this.path.sep + path;
      return path;
    }
  },
  templates: [
    function HTML() {/*<html<% if ( this.appcacheManifest ) { %> manifest="%%getManifestFileName"<% } %>><meta charset="utf-8"><%= this.htmlHeaders.join('') %><% if ( this.includeFoamCSS ) { %><link rel="stylesheet" type="text/css" href="foam.css"/><% } %><% if ( this.icon ) { %><link rel="icon" sizes="128x128" href="<%= this.icon %>"/><% } %><foam model="<%= this.controller %>"<% if ( this.defaultView ) { %> view="<%= this.defaultView %>"<% } %>></foam>*/},
    function MANIFEST() {/*CACHE MANIFEST
# version <%= this.version %>
<% if ( this.appDefinition ) { %># hash: <%= this.appDefinition.hashCode() %><% } %>

CACHE:
%%jsFileName
%%localizedHTMLFileName_
<% if ( this.includeFoamCSS ) { %>foam.css<% } %>
<% for ( var i = 0 ; i < this.resources.length ; i++ ) { %><%= this.resources[i] %>
<% } %>

NETWORK:
*
*/}
  ]
});
<|endoftext|>