<commit_before>document.addEventListener('DOMContentLoaded', function() {
  var testTimeout = 5000;
  var common = parent.__common;
  var frameId = window.__frameId;
  var frameReady = common[frameId + 'Ready'] || { onNext() {} };
  var Rx = document.Rx;
  var helpers = Rx.helpers;
  var chai = parent.chai;
  var source = document.__source;
  var __getUserInput = document.__getUserInput || (x => x);
  var checkChallengePayload = document.__checkChallengePayload;

  document.__getJsOutput = function getJsOutput() {
    if (window.__err || !common.shouldRun()) {
      return window.__err || 'source disabled';
    }
    let output;
    try {
      /* eslint-disable no-eval */
      output = eval(source);
      /* eslint-enable no-eval */
    } catch (e) {
      output = e.message + '\n' + e.stack;
      window.__err = e;
    }
    return output;
  };

  document.__runTests = function runTests(tests = []) {
    /* eslint-disable no-unused-vars */
    const editor = { getValue() { return source; } };
    const code = source;
    /* eslint-enable no-unused-vars */
    if (window.__err) {
      return Rx.Observable.from(tests)
        .map(test => {
          return {
            ...test,
            err: window.__err.message + '\n' + window.__err.stack,
            message: window.__err.message,
            stack: window.__err.stack
          };
        })
        .toArray()
        .do(() => { window.__err = null; });
    }

    // Iterate through the test one at a time
    // on new stacks
    return Rx.Observable.from(tests, null, null, Rx.Scheduler.default)
      // add delay here for firefox to catch up
      .delay(200)
      /* eslint-disable no-unused-vars */
      .flatMap(({ text, testString }) => {
        const assert = chai.assert;
        const getUserInput = __getUserInput;
        /* eslint-enable no-unused-vars */
        const newTest = { text, testString };
        let test;
        let __result;

        // uncomment the following line to inspect
        // the framerunner as it runs tests
        // make sure the dev tools console is open
        // debugger;
        try {
          /* eslint-disable no-eval */
          // eval test string to actual JavaScript
          // This return can be a function
          // i.e. function() { assert(true, 'happy coding'); }
          test = eval(testString);
          /* eslint-enable no-eval */
          if (typeof test === 'function') {

            // we know that the test eval'ed to a function
            // the function could expect a callback
            // or it could return a promise/observable
            // or it could still be sync
            if (test.length === 1) {
              // a function with length 0 means it expects 0 args
              // We call it and store the result
              // This result may be a promise or an observable or undefined
              __result = test(getUserInput);
            } else {
              // if function takes arguments
              // we expect it to be of the form
              // function(cb) { /* ... */ }
              // and callback has the following signature
              // function(err) { /* ... */ }
              __result = Rx.Observable.fromNodeCallback(test)(getUserInput);
            }

            if (helpers.isPromise(__result)) {
              // turn promise into an observable
              __result = Rx.Observable.fromPromise(__result);
            }
          } else {
            // test is not a function
            // fill result with for compatibility
            __result = Rx.Observable.of(null);
          }
        } catch (e) {
          // something threw an uncaught error
          // we catch here and wrap it in an observable
          __result = Rx.Observable.throw(e);
        }
        return __result
          .timeout(testTimeout)
          .map(() => {
            // we don't need the result of a promise/observable/cb here
            // all data asserts should happen further up the chain
            // mark test as passing
            newTest.pass = true;
            return newTest;
          })
          .catch(err => {
            // we catch the error here to prevent the error from bubbling up
            // and collapsing the pipe
            let message = (err.message || '');
            const assertIndex = message.indexOf(': expected');
            if (assertIndex !== -1) {
              message = message.slice(0, assertIndex);
            }
            message = message.replace(/<code>(.*)<\/code>/, '$1');
            newTest.err = err.message + '\n' + err.stack;
            newTest.stack = err.stack;
            newTest.message = message;
            // RxJS catch expects an observable as a return
            return Rx.Observable.of(newTest);
          });
      })
      // gather tests back into an array
      .toArray();
  };

  // notify that the window methods are ready to run
  frameReady.onNext({ checkChallengePayload });
});
<commit_msg>Code tags removed from output<commit_after>document.addEventListener('DOMContentLoaded', function() {
  var testTimeout = 5000;
  var common = parent.__common;
  var frameId = window.__frameId;
  var frameReady = common[frameId + 'Ready'] || { onNext() {} };
  var Rx = document.Rx;
  var helpers = Rx.helpers;
  var chai = parent.chai;
  var source = document.__source;
  var __getUserInput = document.__getUserInput || (x => x);
  var checkChallengePayload = document.__checkChallengePayload;

  document.__getJsOutput = function getJsOutput() {
    if (window.__err || !common.shouldRun()) {
      return window.__err || 'source disabled';
    }
    let output;
    try {
      /* eslint-disable no-eval */
      output = eval(source);
      /* eslint-enable no-eval */
    } catch (e) {
      output = e.message + '\n' + e.stack;
      window.__err = e;
    }
    return output;
  };

  document.__runTests = function runTests(tests = []) {
    /* eslint-disable no-unused-vars */
    const editor = { getValue() { return source; } };
    const code = source;
    /* eslint-enable no-unused-vars */
    if (window.__err) {
      return Rx.Observable.from(tests)
        .map(test => {
          return {
            ...test,
            err: window.__err.message + '\n' + window.__err.stack,
            message: window.__err.message,
            stack: window.__err.stack
          };
        })
        .toArray()
        .do(() => { window.__err = null; });
    }

    // Iterate through the test one at a time
    // on new stacks
    return Rx.Observable.from(tests, null, null, Rx.Scheduler.default)
      // add delay here for firefox to catch up
      .delay(200)
      /* eslint-disable no-unused-vars */
      .flatMap(({ text, testString }) => {
        const assert = chai.assert;
        const getUserInput = __getUserInput;
        /* eslint-enable no-unused-vars */
        const newTest = { text, testString };
        let test;
        let __result;

        // uncomment the following line to inspect
        // the framerunner as it runs tests
        // make sure the dev tools console is open
        // debugger;
        try {
          /* eslint-disable no-eval */
          // eval test string to actual JavaScript
          // This return can be a function
          // i.e. function() { assert(true, 'happy coding'); }
          test = eval(testString);
          /* eslint-enable no-eval */
          if (typeof test === 'function') {

            // we know that the test eval'ed to a function
            // the function could expect a callback
            // or it could return a promise/observable
            // or it could still be sync
            if (test.length === 1) {
              // a function with length 0 means it expects 0 args
              // We call it and store the result
              // This result may be a promise or an observable or undefined
              __result = test(getUserInput);
            } else {
              // if function takes arguments
              // we expect it to be of the form
              // function(cb) { /* ... */ }
              // and callback has the following signature
              // function(err) { /* ... */ }
              __result = Rx.Observable.fromNodeCallback(test)(getUserInput);
            }

            if (helpers.isPromise(__result)) {
              // turn promise into an observable
              __result = Rx.Observable.fromPromise(__result);
            }
          } else {
            // test is not a function
            // fill result with for compatibility
            __result = Rx.Observable.of(null);
          }
        } catch (e) {
          // something threw an uncaught error
          // we catch here and wrap it in an observable
          __result = Rx.Observable.throw(e);
        }
        return __result
          .timeout(testTimeout)
          .map(() => {
            // we don't need the result of a promise/observable/cb here
            // all data asserts should happen further up the chain
            // mark test as passing
            newTest.pass = true;
            return newTest;
          })
          .catch(err => {
            // we catch the error here to prevent the error from bubbling up
            // and collapsing the pipe
            let message = (err.message || '');
            const assertIndex = message.indexOf(': expected');
            if (assertIndex !== -1) {
              message = message.slice(0, assertIndex);
            }
            message = message.replace(/<code>(.*?)<\/code>/g, '$1');
            newTest.err = err.message + '\n' + err.stack;
            newTest.stack = err.stack;
            newTest.message = message;
            // RxJS catch expects an observable as a return
            return Rx.Observable.of(newTest);
          });
      })
      // gather tests back into an array
      .toArray();
  };

  // notify that the window methods are ready to run
  frameReady.onNext({ checkChallengePayload });
});
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2015-present, Joshua Hollenbeck
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree.
 */
const RefraxTools = require('RefraxTools');
const RefraxConfig = require('RefraxConfig');
const RefraxStore = require('RefraxStore');
const RefraxTreeNode = require('RefraxTreeNode');
const RefraxParameters = require('RefraxParameters');
const RefraxQueryParameters = require('RefraxQueryParameters');
const RefraxPath = require('RefraxPath');
const RefraxOptions = require('RefraxOptions');
const RefraxConstants = require('RefraxConstants');
const ACTION_GET = RefraxConstants.action.get;
const ACTION_CREATE = RefraxConstants.action.create;
const FRAGMENT_DEFAULT = RefraxConstants.defaultFragment;
const STRATEGY_MERGE = RefraxConstants.strategy.merge;
const STRATEGY_REPLACE = RefraxConstants.strategy.replace;
const CLASSIFY_RESOURCE = RefraxConstants.classify.resource;

// simple-depth serialize to avoid circular references for error debugging
function serializer() {
  var stack = [];

  return function(key, value) {
    if (stack.length > 0) {
      if (stack.indexOf(this) === -1 && typeof(value) === 'object') {
        return '...';
      }
    }
    else {
      stack.push(value);
    }

    return value;
  };
}

function fillURI(uri, params, paramMap) {
  var vars = uri.match(/:(\w+)/g) || []
    , lastParamKey = null
    , i, v, value;

  for (i = 0; i < vars.length; i++) {
    v = vars[i];

    lastParamKey = v.substr(1);
    if (paramMap && paramMap[lastParamKey]) {
      lastParamKey = paramMap[lastParamKey];
    }

    if ((value = params[lastParamKey])) {
      uri = uri.replace(v, value);
    }
    else {
      throw new TypeError('Failed to map path component `' + lastParamKey + '` from `' + uri + '`' +
      ' while using params: ' + JSON.stringify(params, serializer()));
    }
  }

  return {
    lastParamKey: lastParamKey,
    uri: uri
  };
}

function encodeURIValue(value) {
  if (RefraxTools.isPlainObject(value)) {
    value = JSON.stringify(value);
  }

  return global.encodeURIComponent(value);
}

function encodeURIData(data) {
  var result = [];

  RefraxTools.each(data || [], function(value, key) {
    if (RefraxTools.isArray(value)) {
      RefraxTools.each(value, function(v) {
        result.push(key + '[]=' + encodeURIValue(v));
      });
    }
    else {
      result.push(key + '=' + encodeURIValue(value));
    }
  });

  return result.length > 0
    ? '?' + result.join('&')
    : '';
}

/**
 * Given a stack representing a path in our Schema tree and options affecting it, we
 * reduce and resolve it down to a descriptor describing a resource.
 */
function processStack(resourceDescriptor, stack) {
  var action = resourceDescriptor.action
    , canResolveParams = action !== 'inspect'
    , resolvedParamMap = {}
    , resolvedPath = []
    , resolvedParamId = null
    , resolvedQueryParams = {}
    , resolvedAppendPaths = []
    , i, item, definition
    , lastURIParamId = null
    , key, result;

  if (!stack) {
    throw new TypeError('generateDescriptor: expected non-null stack');
  }

  // Pass 1
  for (i = 0; i < stack.length; i++) {
    item = stack[i];
    if (!item) {
      throw new TypeError('generateDescriptor: Found null stack element at index ' + i + ' from stack ' + JSON.stringify(stack));
    }

    definition = item.definition;

    if (item instanceof RefraxStore) {
      // every store encounter is considered a hard scope change
      resourceDescriptor.store = item;
      resolvedParamId = definition.paramId || null;
      resourceDescriptor.type = definition.type;
      resourceDescriptor.classify = CLASSIFY_RESOURCE;
      resourceDescriptor.partial = FRAGMENT_DEFAULT;
      resourceDescriptor.fragments = [];
    }
    else if (item instanceof RefraxTreeNode) {
      if (definition.paramMap) {
        resolvedParamMap = RefraxTools.extend(resolvedParamMap, definition.paramMap);
      }

      if (definition.paramId) {
        resolvedParamId = resolvedParamId;
      }

      resourceDescriptor.partial = definition.partial || FRAGMENT_DEFAULT;
      resourceDescriptor.fragments = definition.fragments || [];
      if (definition.classify) {
        resourceDescriptor.classify = definition.classify;
      }
    }
    else if (item instanceof RefraxOptions) {
      if (item.cacheStrategy) {
        resourceDescriptor.cacheStrategy = item.cacheStrategy;
      }

      if (item.collectionStrategy) {
        resourceDescriptor.collectionStrategy = item.collectionStrategy;
      }
    }
    else if (item instanceof RefraxParameters) {
      RefraxTools.extend(resourceDescriptor.params, item);
    }
    else if (item instanceof RefraxQueryParameters) {
      resolvedQueryParams = RefraxTools.extend(resolvedQueryParams, item);
    }
    else if (item instanceof RefraxPath) {
      resolvedAppendPaths.push(item);
    }
    else if (RefraxTools.isPlainObject(item)) {
      RefraxTools.extend(resourceDescriptor.payload, item);
    }
  }

  // Pass 2 - Since URI uses resolved params we need to do it separately
  for (i = 0; i < stack.length; i++) {
    item = stack[i];
    definition = item.definition;

    if (item instanceof RefraxTreeNode) {
      if (definition.uri) {
        result = canResolveParams ? fillURI(definition.uri,
                                            resourceDescriptor.params,
                                            resolvedParamMap)
                                  : {uri: definition.uri};
        resolvedPath.push(result.uri);
        lastURIParamId = result.lastParamKey;
      }
      else if (definition.paramId) {
        result = canResolveParams ? fillURI(':'+definition.paramId,
                                            resourceDescriptor.params,
                                            resolvedParamMap)
                                  : {uri: ':'+definition.paramId};
        resolvedPath.push(result.uri);
        lastURIParamId = result.lastParamKey;
      }
    }
  }

  resolvedAppendPaths = RefraxTools.map(RefraxTools.select(resolvedAppendPaths, function(rPath) {
    return rPath.isModifier || resolvedPath.push(rPath.path);
  }), function(rPath) {
    return rPath.path;
  });

  // If we have no base path's ignore pathing all together
  if (resolvedPath.length > 0) {
    resourceDescriptor.basePath =
      resourceDescriptor.path = RefraxConfig.hostname + '/' + resolvedPath.join('/');

    if (resolvedAppendPaths.length > 0) {
      resourceDescriptor.path+= '/' + resolvedAppendPaths.join('/');
    }

    if (action === ACTION_GET) {
      // NOTE: we append QueryParams to both basePath & path since basePath is typically used
      //  for cache query reference and path is used as the actual request path
      resolvedQueryParams = encodeURIData(resolvedQueryParams);
      resourceDescriptor.basePath+= resolvedQueryParams;
      resourceDescriptor.path+= resolvedQueryParams;
    }
  }

  key = resolvedParamId || lastURIParamId || 'id';
  if (resolvedParamMap[key]) {
    key = resolvedParamMap[key];
  }
  resolvedParamId = (resolvedParamId = resourceDescriptor.params[key]) &&
                    ('' + resolvedParamId);

  resourceDescriptor.event = ['change'].concat(resolvedParamId || []).join(':');
  resourceDescriptor.id = resolvedParamId;
  resourceDescriptor.fragments = resourceDescriptor.fragments.reverse();
}

class RefraxResourceDescriptor {
  constructor(action = ACTION_GET, stack = []) {
    this.action = action;
    this.event = ['change'];
    this.classify = CLASSIFY_RESOURCE;
    this.partial = FRAGMENT_DEFAULT;
    this.id = null;
    this.params = {};
    this.fragments = [];
    this.payload = {};
    this.store = null;
    this.type = null;
    this.cacheStrategy = STRATEGY_REPLACE;
    this.collectionStrategy = action === ACTION_CREATE ? STRATEGY_MERGE : STRATEGY_REPLACE;

    if (!RefraxTools.isArray(stack)) {
      stack = [stack];
    }

    processStack(this, stack);
  }

  // Using our own descriptor's rules, grab an id from an object
  idFrom(target) {
    // TODO: id map?
    return target && target.id && ('' + target.id);
  }
}

export default RefraxResourceDescriptor;
<commit_msg>Add valdity property on ResourceDescriptor and allow bypass<commit_after>/**
 * Copyright (c) 2015-present, Joshua Hollenbeck
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree.
 */
const RefraxTools = require('RefraxTools');
const RefraxConfig = require('RefraxConfig');
const RefraxStore = require('RefraxStore');
const RefraxTreeNode = require('RefraxTreeNode');
const RefraxParameters = require('RefraxParameters');
const RefraxQueryParameters = require('RefraxQueryParameters');
const RefraxPath = require('RefraxPath');
const RefraxOptions = require('RefraxOptions');
const RefraxConstants = require('RefraxConstants');
const ACTION_GET = RefraxConstants.action.get;
const ACTION_CREATE = RefraxConstants.action.create;
const FRAGMENT_DEFAULT = RefraxConstants.defaultFragment;
const STRATEGY_MERGE = RefraxConstants.strategy.merge;
const STRATEGY_REPLACE = RefraxConstants.strategy.replace;
const CLASSIFY_RESOURCE = RefraxConstants.classify.resource;
const CLASSIFY_INVALID = RefraxConstants.classify.invalid;

// simple-depth serialize to avoid circular references for error debugging
function serializer() {
  var stack = [];

  return function(key, value) {
    if (stack.length > 0) {
      if (stack.indexOf(this) === -1 && typeof(value) === 'object') {
        return '...';
      }
    }
    else {
      stack.push(value);
    }

    return value;
  };
}

function fillURI(uri, params, paramMap) {
  var vars = uri.match(/:(\w+)/g) || []
    , lastParamKey = null
    , i, v, value
    , errors = [];

  for (i = 0; i < vars.length; i++) {
    v = vars[i];

    lastParamKey = v.substr(1);
    if (paramMap && paramMap[lastParamKey]) {
      lastParamKey = paramMap[lastParamKey];
    }

    if ((value = params[lastParamKey])) {
      uri = uri.replace(v, value);
    }
    else {
      errors.push(lastParamKey);
      uri = uri.replace(v, ':' + lastParamKey);
    }
  }

  return {
    lastParamKey: lastParamKey,
    uri: uri,
    errors: errors
  };
}

function encodeURIValue(value) {
  if (RefraxTools.isPlainObject(value)) {
    value = JSON.stringify(value);
  }

  return global.encodeURIComponent(value);
}

function encodeURIData(data) {
  var result = [];

  RefraxTools.each(data || [], function(value, key) {
    if (RefraxTools.isArray(value)) {
      RefraxTools.each(value, function(v) {
        result.push(key + '[]=' + encodeURIValue(v));
      });
    }
    else {
      result.push(key + '=' + encodeURIValue(value));
    }
  });

  return result.length > 0
    ? '?' + result.join('&')
    : '';
}

/**
 * Given a stack representing a path in our Schema tree and options affecting it, we
 * reduce and resolve it down to a descriptor describing a resource.
 */
function processStack(resourceDescriptor, stack) {
  var action = resourceDescriptor.action
    , errorOnInvalid = action !== 'inspect'
    , resolvedParamMap = {}
    , resolvedPath = []
    , resolvedParamId = null
    , resolvedQueryParams = {}
    , resolvedAppendPaths = []
    , pathErrors = []
    , i, item, definition
    , lastURIParamId = null
    , key, result;

  if (!stack) {
    throw new TypeError('generateDescriptor: expected non-null stack');
  }

  // Pass 1
  for (i = 0; i < stack.length; i++) {
    item = stack[i];
    if (!item) {
      throw new TypeError('generateDescriptor: Found null stack element at index ' + i + ' from stack ' + JSON.stringify(stack));
    }

    definition = item.definition;

    if (item instanceof RefraxStore) {
      // every store encounter is considered a hard scope change
      resourceDescriptor.store = item;
      resolvedParamId = definition.paramId || null;
      resourceDescriptor.type = definition.type;
      resourceDescriptor.classify = CLASSIFY_RESOURCE;
      resourceDescriptor.partial = FRAGMENT_DEFAULT;
      resourceDescriptor.fragments = [];
    }
    else if (item instanceof RefraxTreeNode) {
      if (definition.paramMap) {
        resolvedParamMap = RefraxTools.extend(resolvedParamMap, definition.paramMap);
      }

      if (definition.paramId) {
        resolvedParamId = resolvedParamId;
      }

      resourceDescriptor.partial = definition.partial || FRAGMENT_DEFAULT;
      resourceDescriptor.fragments = definition.fragments || [];
      if (definition.classify) {
        resourceDescriptor.classify = definition.classify;
      }
    }
    else if (item instanceof RefraxOptions) {
      if (item.cacheStrategy) {
        resourceDescriptor.cacheStrategy = item.cacheStrategy;
      }

      if (item.collectionStrategy) {
        resourceDescriptor.collectionStrategy = item.collectionStrategy;
      }

      if (typeof(item.errorOnInvalid) === 'boolean') {
        errorOnInvalid = item.errorOnInvalid;
      }
    }
    else if (item instanceof RefraxParameters) {
      RefraxTools.extend(resourceDescriptor.params, item);
    }
    else if (item instanceof RefraxQueryParameters) {
      resolvedQueryParams = RefraxTools.extend(resolvedQueryParams, item);
    }
    else if (item instanceof RefraxPath) {
      resolvedAppendPaths.push(item);
    }
    else if (RefraxTools.isPlainObject(item)) {
      RefraxTools.extend(resourceDescriptor.payload, item);
    }
  }

  // Pass 2 - Since URI uses resolved params we need to do it separately
  for (i = 0; i < stack.length; i++) {
    item = stack[i];
    definition = item.definition;

    if (item instanceof RefraxTreeNode) {
      result = null;

      if (definition.uri) {
        result = fillURI(definition.uri, resourceDescriptor.params, resolvedParamMap);
      }
      else if (definition.paramId) {
        result = fillURI(':'+definition.paramId, resourceDescriptor.params, resolvedParamMap);
      }

      if (result) {
        pathErrors = pathErrors.concat(result.errors);
        resolvedPath.push(result.uri);
        lastURIParamId = result.lastParamKey;
      }
    }
  }

  resolvedAppendPaths = RefraxTools.map(RefraxTools.select(resolvedAppendPaths, function(rPath) {
    return rPath.isModifier || resolvedPath.push(rPath.path);
  }), function(rPath) {
    return rPath.path;
  });

  // If we have no base path's ignore pathing all together
  if (resolvedPath.length > 0) {
    resourceDescriptor.basePath =
      resourceDescriptor.path = RefraxConfig.hostname + '/' + resolvedPath.join('/');

    if (resolvedAppendPaths.length > 0) {
      resourceDescriptor.path+= '/' + resolvedAppendPaths.join('/');
    }

    if (action === ACTION_GET) {
      // NOTE: we append QueryParams to both basePath & path since basePath is typically used
      //  for cache query reference and path is used as the actual request path
      resolvedQueryParams = encodeURIData(resolvedQueryParams);
      resourceDescriptor.basePath+= resolvedQueryParams;
      resourceDescriptor.path+= resolvedQueryParams;
    }
  }

  key = resolvedParamId || lastURIParamId || 'id';
  if (resolvedParamMap[key]) {
    key = resolvedParamMap[key];
  }
  resolvedParamId = (resolvedParamId = resourceDescriptor.params[key]) &&
                    ('' + resolvedParamId);

  resourceDescriptor.event = ['change'].concat(resolvedParamId || []).join(':');
  resourceDescriptor.id = resolvedParamId;
  resourceDescriptor.fragments = resourceDescriptor.fragments.reverse();

  if (pathErrors.length > 0) {
    resourceDescriptor.valid = false;

    if (errorOnInvalid) {
      throw new TypeError(
        'Failed to map path: `' + resourceDescriptor.path + '` using params: ' +
        JSON.stringify(resourceDescriptor.params, serializer())
      );
    }
  }
}

class RefraxResourceDescriptor {
  constructor(action = ACTION_GET, stack = []) {
    this.action = action;
    this.event = ['change'];
    this.classify = CLASSIFY_RESOURCE;
    this.partial = FRAGMENT_DEFAULT;
    this.id = null;
    this.params = {};
    this.fragments = [];
    this.payload = {};
    this.store = null;
    this.type = null;
    this.cacheStrategy = STRATEGY_REPLACE;
    this.collectionStrategy = action === ACTION_CREATE ? STRATEGY_MERGE : STRATEGY_REPLACE;
    this.valid = true;

    if (!RefraxTools.isArray(stack)) {
      stack = [stack];
    }

    processStack(this, stack);
  }

  // Using our own descriptor's rules, grab an id from an object
  idFrom(target) {
    // TODO: id map?
    return target && target.id && ('' + target.id);
  }
}

export default RefraxResourceDescriptor;
<|endoftext|>


<commit_before>'use strict';

var MEDIA_URL = '/staticuploads/';

/**
 * Handle login with facebook button.
 */
$('.loginBtn--facebook').click(function(){
  event.preventDefault();

  // Check if the "share" button was clicked.
  if($(this).hasClass('fb-share')) {
    shareThisPost();
  } else {
    checkLoginState();
  }
});

/**
 * Share a post to facebook.
 */
function shareThisPost(){
  // var href = $(location).attr('href');
  // console.log(href);
  // var name = href.split("/")[4];
  // var description = $('#description').text();
  // var caption = $('#description').text();
  // var baseHref = href.split("/")[0] + '//' + href.split("/")[2];
  // var image = baseHref + $('#FB-image-game').attr('src');
  // console.log(image);

  // FB.ui({
  //   app_id: '1063610257017045',
  //   method: 'share',
  //   redirect_uri: href,
  //   href: 'https://developers.facebook.com/docs/',
  // }, function(response){});

  FB.ui({
    method: 'feed',
    // redirect_uri: 'YOUR URL HERE',
    link: 'https://developers.facebook.com/docs/reference/dialogs/',
    // picture: 'http://fbrell.com/f8.jpg',
    name: 'Facebook Dialogs',
    // caption: 'Reference Documentation',
    // description: 'Using Dialogs to interact with people.'
  }, function(response){});

  // FB.ui({
  //   // method: 'share',
  //   // name: 'Something',
  //   // picture: image,
  //   // href: url.toString(),
  //   hashtag: '#WhatsBuzz'
  //   // link: url,
  //   // description: captionText,
  //   // caption: 'http://www.whatsbuzz.co.il'
  //
  // }, function(response){
  //   if (response && response.post_id) {
  //     console.log('share success');
  //   } else {
  //     console.log('share error');
  //   }
  // });
}

/**
 * Handle the quizzes button, when displayed.
 */
$('#quizzes-game').click(function(){
  $('#facebooklogin').hide();
  showSpinner();

  // Show the quiz and hide the play button
  setTimeout(function(){
    $('#quizzes').show();
  }, 5250);
});

/**
 * Handle "show more" button in the nav pages.
 * Get posts, by type, from server and display them on the page.
 */
$('#show-more-in-page').click(function(event){
  event.preventDefault();
  var type = $('.show-more').data('posts-type');
  var start = $('.posts').length;
  $.get("/get-more-posts/" + type + "/" + start, function(data){
    // Convert the data to array of js objects.
    var data = JSON.parse(data[0].posts);

    // Create a post for each of them.
    data.forEach(function(postObject){
      // The title.
      var postTitle = $('<h2>').text(postObject.fields.title);
      // The image banner.
      var postImage = $('<img>').addClass('banner-image').attr('src', MEDIA_URL + postObject.fields.image_banner).attr('alt', postObject.fields.image_banner);
      // The button link.
      var postSlog = $('<a>').attr('href', "/posts/" + postObject.fields.slug).append($('<div>').addClass('row link').append($('<p>').text("התחל משחק")));

      // The whole post card.
      var postObj = $('<div>').addClass('col-sm-6 posts').append($('<div>').addClass('post').append(postTitle).append(postImage).append(postSlog));

      $('#main-posts').append(postObj);
    });
  });
});<commit_msg>fb share.<commit_after>'use strict';

var MEDIA_URL = '/staticuploads/';

/**
 * Handle login with facebook button.
 */
$('.loginBtn--facebook').click(function(){
  event.preventDefault();

  // Check if the "share" button was clicked.
  if($(this).hasClass('fb-share')) {
    shareThisPost();
  } else {
    checkLoginState();
  }
});

/**
 * Share a post to facebook.
 */
function shareThisPost(){
  // var href = $(location).attr('href');
  // console.log(href);
  // var name = href.split("/")[4];
  // var description = $('#description').text();
  // var caption = $('#description').text();
  // var baseHref = href.split("/")[0] + '//' + href.split("/")[2];
  // var image = baseHref + $('#FB-image-game').attr('src');
  // console.log(image);

  FB.ui({
    method: 'share',
    href: 'https://developers.facebook.com/docs/',
  }, function(response){});

  // FB.ui({
  //   // method: 'share',
  //   // name: 'Something',
  //   // picture: image,
  //   // href: url.toString(),
  //   hashtag: '#WhatsBuzz'
  //   // link: url,
  //   // description: captionText,
  //   // caption: 'http://www.whatsbuzz.co.il'
  //
  // }, function(response){
  //   if (response && response.post_id) {
  //     console.log('share success');
  //   } else {
  //     console.log('share error');
  //   }
  // });
}

/**
 * Handle the quizzes button, when displayed.
 */
$('#quizzes-game').click(function(){
  $('#facebooklogin').hide();
  showSpinner();

  // Show the quiz and hide the play button
  setTimeout(function(){
    $('#quizzes').show();
  }, 5250);
});

/**
 * Handle "show more" button in the nav pages.
 * Get posts, by type, from server and display them on the page.
 */
$('#show-more-in-page').click(function(event){
  event.preventDefault();
  var type = $('.show-more').data('posts-type');
  var start = $('.posts').length;
  $.get("/get-more-posts/" + type + "/" + start, function(data){
    // Convert the data to array of js objects.
    var data = JSON.parse(data[0].posts);

    // Create a post for each of them.
    data.forEach(function(postObject){
      // The title.
      var postTitle = $('<h2>').text(postObject.fields.title);
      // The image banner.
      var postImage = $('<img>').addClass('banner-image').attr('src', MEDIA_URL + postObject.fields.image_banner).attr('alt', postObject.fields.image_banner);
      // The button link.
      var postSlog = $('<a>').attr('href', "/posts/" + postObject.fields.slug).append($('<div>').addClass('row link').append($('<p>').text("התחל משחק")));

      // The whole post card.
      var postObj = $('<div>').addClass('col-sm-6 posts').append($('<div>').addClass('post').append(postTitle).append(postImage).append(postSlog));

      $('#main-posts').append(postObj);
    });
  });
});<|endoftext|>


<commit_before>minerva.views.MapPanel = minerva.views.Panel.extend({

    events: {
        'click .m-save-current-baselayer': function () {
            this.session.metadata().map.center = this.map.center();
            this.session.metadata().map.zoom = this.map.zoom();
            this.session.saveSession();
        }
    },

    changeLayerOpacity: function (dataset) {
        // TODO ideally move opacity from the Dataset to the Layer.

        var layerRepr = this.datasetLayerReprs[dataset.get('_id')];

        if (dataset.get('visible')) {
            layerRepr.setOpacity(dataset.get('opacity'));
        } else {
            layerRepr.setOpacity(0.0);
        }
    },

    changeLayerZIndex: function (dataset) {
        var baseMapZIndex = 1;
        if (dataset.get('order')) {
            this.datasetLayerReprs[dataset.id][dataset.get('order')]();
        }
        // TODO: HACK MoveToBottom method will set the layer's index to 0 and put it under the base map.
        // Calling moveUp(1) to place it on top of base map
        if (dataset.get('order') === 'moveToBottom') {
            this.datasetLayerReprs[dataset.id].moveUp(baseMapZIndex);
        }
        this.map.draw();
    },

    // MapContainer Interface >>
    // These functions are an interface for a MapContainer that may be
    // separable in the future from this MapPanel, and can be called
    // by an Adapter.

    /**
     * Deletes the passed in layer from the map.
     *
     * @param {geo.layer} geoLayer - GeoJs layer assumed to be included
     * in the current GeoJs map owned by this MapContainer.
     */
    deleteLayer: function (geoLayer) {
        this.map.deleteLayer(geoLayer);
    },

    /**
     * Creates a new GeoJs layer from the current GeoJs map owned by this
     * MapContainer, of the requested type, passing in the properties object.
     *
     * @param {string} geoLayerType - type of GeoJs layer to be created
     * @param {Object} [properties] - GeoJs layer properties to be passed upon
     * construction of the GeoJs layer
     * @returns {geo.layer}
     */
    createLayer: function (geoLayerType, properties) {
        return this.map.createLayer(geoLayerType, properties || {});
    },

    /**
     * Accessor for the MapContainer's Backbone view.
     *
     * @returns {Backbone.View}
     */
    getMapView: function () {
        return this;
    },

    /**
     * Adds the passed in GeoJs layer as a layer of interest for the
     * FeatureInfoWidget owned by this MapContainer.
     *
     * @param {geo.layer} layer - The GeoJs layer to have info displayed about
     * it in by the FeatureInfoWidget.
     */
    addFeatureInfoLayer: function (layer) {
        if (this.map && this.map.featureInfoWidget) {
            this.map.featureInfoWidget.layers.push(layer);
        } else {
            console.error('Attempting to addFeatureInfoLayer, but widget uninitialized');
        }
    },

    /**
     * Render the GeoJs map owned by this MapContainer, which will render all of the
     * map's layers.
     */
    renderMap: function () {
        if (!this.map) {
            var mapSettings = this.session.metadata().map;
            this.map = geo.map({
                node: '.m-map-panel-map',
                center: mapSettings.center,
                zoom: mapSettings.zoom,
                interactor: geo.mapInteractor({
                    map: this.map,
                    click: {
                        enabled: true,
                        cancelOnMove: true
                    }
                })
            });
            this.map.createLayer(mapSettings.basemap,
                                 _.has(mapSettings, 'basemap_args')
                                 ? mapSettings.basemap_args : {});
            this.uiLayer = this.map.createLayer('ui');
            this.mapCreated = true;
            _.each(this.collection.models, function (dataset) {
                if (dataset.get('displayed')) {
                    this.addDataset(dataset);
                }
            }, this);
            this.map.featureInfoWidget =
                new minerva.views.WmsFeatureInfoWidget({
                    map: this.map,
                    version: '1.1.1',
                    layers: [],
                    callback: 'getLayerFeatures',
                    session: this.session,
                    parentView: this
                });
            this.map.featureInfoWidget.setElement($('#m-map-panel')).render();
            this.map.geoOn(geo.event.mouseclick, function (evt) {
                this.featureInfoWidget.content = '';
                this.featureInfoWidget.callInfo(0, evt.geo);
            });
        }
        this.map.draw();
    },

    // << MapContainer Interface

    /**
     * Async function to add the passed in dataset to the current map as a rendered layer,
     * will set the 'geoError' property to be true if there is a rendering error.
     *
     * @param {minerva.models.DatasetModel} dataset - The dataset to be rendered
     * @param {string} layerType - The type of map visualization used to render the dataset
     * @param {Object} visProperties - Properties used to render the dataset as a layerType
     */
    addDataset: function (dataset, layerType, visProperties) {
        if (!dataset.metadata()) {
            return;
        }
        var datasetId = dataset.get('_id');

        if (!_.contains(this.datasetLayerReprs, datasetId)) {
            // For now, get the layerType directly from the dataset,
            // but we should really allow the user to specify the desired
            // layerType.
            layerType = dataset.getGeoRenderType();

            // If visProperties is not provided, check for properties stored in the metadata.
            if (!visProperties) {
                visProperties = (dataset.getMinervaMetadata() || {}).visProperties || {};
            }

            minerva.core.AdapterRegistry.once('m:map_adapter_layerCreated', function (repr) {
                this.datasetLayerReprs[datasetId] = repr;
                repr.render(this);
            }, this).once('m:map_adapter_error', function (dataset, layerType) {
                dataset.set('geoError', true);
            }, this).once('m:map_adapter_layerError', function (repr) {
                if (repr) {
                    repr.delete(this);
                    dataset.set('geoError', true);
                }
            }, this)._createRepresentation(this, dataset, layerType, visProperties);
        }
    },

    /**
     * Remove a rendered dataset from the current map.
     */
    removeDataset: function (dataset) {
        var datasetId = dataset.get('_id');
        var layerRepr = this.datasetLayerReprs[datasetId];
        if (layerRepr) {
            if (this.map.featureInfoWidget) {
                var layerIndex = $.inArray(layerRepr.geoJsLayer,
                    this.map.featureInfoWidget.layers);
                if (layerIndex > -1) {
                    this.map.featureInfoWidget.layers.splice(layerIndex, 1);
                }
            }
            layerRepr.delete(this);
            this.map.draw();
        }
        delete this.datasetLayerReprs[datasetId];
    },

    initialize: function (settings) {
        this.session = settings.session.model;
        this.listenTo(this.session, 'm:mapUpdated', function () {
            // TODO for now only dealing with center
            if (this.map) {
                // TODO could better separate geojs needs from session storage
                this.map.center(this.session.metadata().map.center);
            }
        });
        this.datasetLayerReprs = {};
        this.legendWidget = {};

        this.collection = settings.session.datasetsCollection;
        this.listenTo(this.collection, 'change:displayed', function (dataset) {
            // There is a slight danger of a user trying to add a dataset
            // to a session while the map is not yet created.  If the map isn't
            // created, we don't need to add/remove the datasets here because
            // they will be taken care of in the renderMap initialization block.
            if (this.mapCreated) {
                if (dataset.get('displayed')) {
                    this.addDataset(dataset);
                } else {
                    this.removeDataset(dataset);
                }
            }
        }, this);

        /* TODO: add an event handler like this:

            this.listenTo(this.collection, 'change:visProperties', function (dataset) {
                // rerender the layer
            });

          For now, it is unnecessary because the only way to change the visProperties
          for a dataset in the UI is through the configuration menu present when the
          dataset is *not* rendered.
        */

        this.listenTo(this.collection, 'change:opacity', function (dataset) {
            if (this.mapCreated) {
                this.changeLayerOpacity(dataset);
            }
        }, this);

        this.listenTo(this.collection, 'change:visible', function (dataset) {
            if (this.mapCreated) {
                this.changeLayerOpacity(dataset);
            }
        }, this);

        this.listenTo(this.collection, 'change:order', function (dataset) {
            if (this.mapCreated) {
                this.changeLayerZIndex(dataset);
            }
        }, this);

        minerva.views.Panel.prototype.initialize.apply(this);
    },

    render: function () {
        this.$el.html(minerva.templates.mapPanel({}));
        this.renderMap();
        var tooltipProperties = {
            placement: 'left',
            delay: 400,
            container: this.$el,
            trigger: 'hover'
        };
        this.$('.m-save-current-baselayer').tooltip(tooltipProperties);
        return this;
    }
});
<commit_msg>Allow overriding of adapter through metadata<commit_after>minerva.views.MapPanel = minerva.views.Panel.extend({

    events: {
        'click .m-save-current-baselayer': function () {
            this.session.metadata().map.center = this.map.center();
            this.session.metadata().map.zoom = this.map.zoom();
            this.session.saveSession();
        }
    },

    changeLayerOpacity: function (dataset) {
        // TODO ideally move opacity from the Dataset to the Layer.

        var layerRepr = this.datasetLayerReprs[dataset.get('_id')];

        if (dataset.get('visible')) {
            layerRepr.setOpacity(dataset.get('opacity'));
        } else {
            layerRepr.setOpacity(0.0);
        }
    },

    changeLayerZIndex: function (dataset) {
        var baseMapZIndex = 1;
        if (dataset.get('order')) {
            this.datasetLayerReprs[dataset.id][dataset.get('order')]();
        }
        // TODO: HACK MoveToBottom method will set the layer's index to 0 and put it under the base map.
        // Calling moveUp(1) to place it on top of base map
        if (dataset.get('order') === 'moveToBottom') {
            this.datasetLayerReprs[dataset.id].moveUp(baseMapZIndex);
        }
        this.map.draw();
    },

    // MapContainer Interface >>
    // These functions are an interface for a MapContainer that may be
    // separable in the future from this MapPanel, and can be called
    // by an Adapter.

    /**
     * Deletes the passed in layer from the map.
     *
     * @param {geo.layer} geoLayer - GeoJs layer assumed to be included
     * in the current GeoJs map owned by this MapContainer.
     */
    deleteLayer: function (geoLayer) {
        this.map.deleteLayer(geoLayer);
    },

    /**
     * Creates a new GeoJs layer from the current GeoJs map owned by this
     * MapContainer, of the requested type, passing in the properties object.
     *
     * @param {string} geoLayerType - type of GeoJs layer to be created
     * @param {Object} [properties] - GeoJs layer properties to be passed upon
     * construction of the GeoJs layer
     * @returns {geo.layer}
     */
    createLayer: function (geoLayerType, properties) {
        return this.map.createLayer(geoLayerType, properties || {});
    },

    /**
     * Accessor for the MapContainer's Backbone view.
     *
     * @returns {Backbone.View}
     */
    getMapView: function () {
        return this;
    },

    /**
     * Adds the passed in GeoJs layer as a layer of interest for the
     * FeatureInfoWidget owned by this MapContainer.
     *
     * @param {geo.layer} layer - The GeoJs layer to have info displayed about
     * it in by the FeatureInfoWidget.
     */
    addFeatureInfoLayer: function (layer) {
        if (this.map && this.map.featureInfoWidget) {
            this.map.featureInfoWidget.layers.push(layer);
        } else {
            console.error('Attempting to addFeatureInfoLayer, but widget uninitialized');
        }
    },

    /**
     * Render the GeoJs map owned by this MapContainer, which will render all of the
     * map's layers.
     */
    renderMap: function () {
        if (!this.map) {
            var mapSettings = this.session.metadata().map;
            this.map = geo.map({
                node: '.m-map-panel-map',
                center: mapSettings.center,
                zoom: mapSettings.zoom,
                interactor: geo.mapInteractor({
                    map: this.map,
                    click: {
                        enabled: true,
                        cancelOnMove: true
                    }
                })
            });
            this.map.createLayer(mapSettings.basemap,
                                 _.has(mapSettings, 'basemap_args')
                                 ? mapSettings.basemap_args : {});
            this.uiLayer = this.map.createLayer('ui');
            this.mapCreated = true;
            _.each(this.collection.models, function (dataset) {
                if (dataset.get('displayed')) {
                    this.addDataset(dataset);
                }
            }, this);
            this.map.featureInfoWidget =
                new minerva.views.WmsFeatureInfoWidget({
                    map: this.map,
                    version: '1.1.1',
                    layers: [],
                    callback: 'getLayerFeatures',
                    session: this.session,
                    parentView: this
                });
            this.map.featureInfoWidget.setElement($('#m-map-panel')).render();
            this.map.geoOn(geo.event.mouseclick, function (evt) {
                this.featureInfoWidget.content = '';
                this.featureInfoWidget.callInfo(0, evt.geo);
            });
        }
        this.map.draw();
    },

    // << MapContainer Interface

    /**
     * Async function to add the passed in dataset to the current map as a rendered layer,
     * will set the 'geoError' property to be true if there is a rendering error.
     *
     * @param {minerva.models.DatasetModel} dataset - The dataset to be rendered
     * @param {string} layerType - The type of map visualization used to render the dataset
     * @param {Object} visProperties - Properties used to render the dataset as a layerType
     */
    addDataset: function (dataset, layerType, visProperties) {
        if (!dataset.metadata()) {
            return;
        }
        var datasetId = dataset.get('_id');

        if (!_.contains(this.datasetLayerReprs, datasetId)) {
            // For now, get the layerType directly from the dataset,
            // but we should really allow the user to specify the desired
            // layerType.
            layerType = dataset.getMinervaMetadata().adapter || dataset.getGeoRenderType();

            // If visProperties is not provided, check for properties stored in the metadata.
            if (!visProperties) {
                visProperties = (dataset.getMinervaMetadata() || {}).visProperties || {};
            }

            minerva.core.AdapterRegistry.once('m:map_adapter_layerCreated', function (repr) {
                this.datasetLayerReprs[datasetId] = repr;
                repr.render(this);
            }, this).once('m:map_adapter_error', function (dataset, layerType) {
                dataset.set('geoError', true);
            }, this).once('m:map_adapter_layerError', function (repr) {
                if (repr) {
                    repr.delete(this);
                    dataset.set('geoError', true);
                }
            }, this)._createRepresentation(this, dataset, layerType, visProperties);
        }
    },

    /**
     * Remove a rendered dataset from the current map.
     */
    removeDataset: function (dataset) {
        var datasetId = dataset.get('_id');
        var layerRepr = this.datasetLayerReprs[datasetId];
        if (layerRepr) {
            if (this.map.featureInfoWidget) {
                var layerIndex = $.inArray(layerRepr.geoJsLayer,
                    this.map.featureInfoWidget.layers);
                if (layerIndex > -1) {
                    this.map.featureInfoWidget.layers.splice(layerIndex, 1);
                }
            }
            layerRepr.delete(this);
            this.map.draw();
        }
        delete this.datasetLayerReprs[datasetId];
    },

    initialize: function (settings) {
        this.session = settings.session.model;
        this.listenTo(this.session, 'm:mapUpdated', function () {
            // TODO for now only dealing with center
            if (this.map) {
                // TODO could better separate geojs needs from session storage
                this.map.center(this.session.metadata().map.center);
            }
        });
        this.datasetLayerReprs = {};
        this.legendWidget = {};

        this.collection = settings.session.datasetsCollection;
        this.listenTo(this.collection, 'change:displayed', function (dataset) {
            // There is a slight danger of a user trying to add a dataset
            // to a session while the map is not yet created.  If the map isn't
            // created, we don't need to add/remove the datasets here because
            // they will be taken care of in the renderMap initialization block.
            if (this.mapCreated) {
                if (dataset.get('displayed')) {
                    this.addDataset(dataset);
                } else {
                    this.removeDataset(dataset);
                }
            }
        }, this);

        /* TODO: add an event handler like this:

            this.listenTo(this.collection, 'change:visProperties', function (dataset) {
                // rerender the layer
            });

          For now, it is unnecessary because the only way to change the visProperties
          for a dataset in the UI is through the configuration menu present when the
          dataset is *not* rendered.
        */

        this.listenTo(this.collection, 'change:opacity', function (dataset) {
            if (this.mapCreated) {
                this.changeLayerOpacity(dataset);
            }
        }, this);

        this.listenTo(this.collection, 'change:visible', function (dataset) {
            if (this.mapCreated) {
                this.changeLayerOpacity(dataset);
            }
        }, this);

        this.listenTo(this.collection, 'change:order', function (dataset) {
            if (this.mapCreated) {
                this.changeLayerZIndex(dataset);
            }
        }, this);

        minerva.views.Panel.prototype.initialize.apply(this);
    },

    render: function () {
        this.$el.html(minerva.templates.mapPanel({}));
        this.renderMap();
        var tooltipProperties = {
            placement: 'left',
            delay: 400,
            container: this.$el,
            trigger: 'hover'
        };
        this.$('.m-save-current-baselayer').tooltip(tooltipProperties);
        return this;
    }
});
<|endoftext|>


<commit_before>import { Link } from "react-router";

const Back = () => {
  if (Meteor.isCordova) return null;

  return (
    <Link to="/profile/settings" className="locked-top locked-left soft-double@lap-and-up soft h7 text-dark-secondary plain" style={{ zIndex: 10 }}>

      Back
    </Link>
  );
};

export default Back;
<commit_msg>lint profile settings back<commit_after>import { Link } from "react-router";

const Back = () => {
  if (Meteor.isCordova) return null;

  return (
    <Link
      to="/profile/settings"
      className="locked-top locked-left soft-double@lap-and-up soft h7 text-dark-secondary plain"
      style={{ zIndex: 10 }}
    >

        Back

    </Link>
  );
};

export default Back;
<|endoftext|>


<commit_before>const User = require('../../models/User');
const Elo = require('arpad');

function findUsersOfLeague(req, res) {
  User.findAll({ where: { league: req.params.league } }).then((data) => {
    console.log(data);
    res.json(data)
  });
}

function findUser(req, res) {
  User.find({ where: { username: req.params.username } }).then((data) => {
    console.log(data);
    res.json(data)
  });
}

function getNewElo(req, res) {
  let user1;
  let user2;
  const elo = new Elo();
  const user1Promise = User.findOne({ where: { username: req.params.username1 } }).then(data => { user1 = data; })
  const user2Promise = User.findOne({ where: { username: req.params.username2 } }).then(data => { user2 = data; })
  Promise.all([user1Promise, user2Promise]).then((fullfill, reject) => {
      const newUser1Elo = elo.newRatingIfWon(user1.elo, user2.elo);
      const newUser2Elo = elo.newRatingIfLost(user2.elo, user1.elo);
      console.log({ yourNewElo: newUser1Elo, theirNewElo: newUser2Elo })
      res.json({ yourNewElo: newUser1Elo, theirNewElo: newUser2Elo });
    })
}

module.exports = { findUsersOfLeague, getNewElo };
<commit_msg>Update elo in database on click<commit_after>const User = require('../../models/User');
const Elo = require('arpad');

function findUsersOfLeague(req, res) {
  User.findAll({ where: { league: req.params.league } }).then((data) => {
    console.log(data);
    res.json(data)
  });
}

function findUser(req, res) {
  User.find({ where: { username: req.params.username } }).then((data) => {
    console.log(data);
    res.json(data)
  });
}

function getNewElo(req, res) {
  let user1;
  let user2;
  const elo = new Elo();
  const user1Promise = User.findOne({ where: { username: req.params.username1 } }).then(data => { user1 = data; })
  const user2Promise = User.findOne({ where: { username: req.params.username2 } }).then(data => { user2 = data; })
  Promise.all([user1Promise, user2Promise]).then(() => {
      user1.update({'elo': elo.newRatingIfWon(user1.elo, user2.elo)})
      .then(user2.update({'elo': elo.newRatingIfLost(user2.elo, user1.elo)}))
      .then(res.json('updated elo in postgres'));
    })
}

module.exports = { findUsersOfLeague, getNewElo };
<|endoftext|>


<commit_before>import { busy, scheduleRetry } from './actions';
import { JS_ERROR } from './constants';
import type { Config, OfflineAction, ResultAction } from './types';

const complete = (
  action: ResultAction,
  success: boolean,
  payload: {}
): ResultAction => ({
  ...action,
  payload,
  meta: { ...action.meta, success, completed: true }
});

const send = (action: OfflineAction, dispatch, config: Config, retries = 0) => {
  const metadata = action.meta.offline;
  dispatch(busy(true));
  return config
    .effect(metadata.effect, action)
    .then(result => {
      const commitAction = metadata.commit || {
        ...config.defaultCommit,
        meta: { ...config.defaultCommit.meta, offlineAction: action }
      };
      try {
        dispatch(complete(commitAction, true, result));
      } catch (e) {
        dispatch(complete({ type: JS_ERROR, payload: e }, false));
      }
    })
    .catch(error => {
      const rollbackAction = metadata.rollback || {
        ...config.defaultRollback,
        meta: { ...config.defaultRollback.meta, offlineAction: action }
      };

      // discard
      if (config.discard(error, action, retries)) {
        dispatch(complete(rollbackAction, false, error));
        return;
      }
      const delay = config.retry(action, retries);
      if (delay != null) {
        dispatch(scheduleRetry(delay));
        return;
      }
      dispatch(complete(rollbackAction, false, error));
    });
};

export default send;
<commit_msg>Allow to use Promises on `discard` function<commit_after>import { busy, scheduleRetry } from './actions';
import { JS_ERROR } from './constants';
import type { Config, OfflineAction, ResultAction } from './types';

const complete = (
  action: ResultAction,
  success: boolean,
  payload: {}
): ResultAction => ({
  ...action,
  payload,
  meta: { ...action.meta, success, completed: true }
});

const send = (action: OfflineAction, dispatch, config: Config, retries = 0) => {
  const metadata = action.meta.offline;
  dispatch(busy(true));
  return config
    .effect(metadata.effect, action)
    .then(result => {
      const commitAction = metadata.commit || {
        ...config.defaultCommit,
        meta: { ...config.defaultCommit.meta, offlineAction: action }
      };
      try {
        dispatch(complete(commitAction, true, result));
      } catch (e) {
        dispatch(complete({ type: JS_ERROR, payload: e }, false));
      }
    })
    .catch(async error => {
      const rollbackAction = metadata.rollback || {
        ...config.defaultRollback,
        meta: { ...config.defaultRollback.meta, offlineAction: action }
      };

      // discard
      let mustDiscard = true
      try {
        mustDiscard = await config.discard(error, action, retries)
      } catch(e) {
        console.warn(e)
      }

      if (!mustDiscard) {
        const delay = config.retry(action, retries);
        if (delay != null) {
          dispatch(scheduleRetry(delay));
          return;
        }
      }

      dispatch(complete(rollbackAction, false, error));
    });
};

export default send;
<|endoftext|>


<commit_before>/*jslint node: true, white: true */

/*
 * PhotoBoothRunner
 * https://github.com/brandonmartinez/MM.Photography.PhotoBoothRunner
 *
 * Copyright (c) 2015 Martinez Media, LLC
 * Licensed under the MIT license.
 */

'use strict';

exports.start = function (options) {
	// Function-scoped Variables and requires
	////////////////////////////////////////////////////
	var Q = require('q'),
		gpio = require('rpi-gpio'),
		debug = require('debug')('photoboothrunner'),
		configuration;

	// Configure Q
	Q.longStackSupport = true;

	// Private Functions
	////////////////////////////////////////////////////
	function shutterPressed(config) {
		if(!config.Status.TakingPhotos){
			config.Status.TakingPhotos = true;
			debug('Shutter button pressed!');

			// Simulating a delay
			setTimeout(function(){
				config.Status.TakingPhotos = false;
			}, 5000);
		}
		else {
			debug('Shutter button pressed, but currently taking photos.');
		}
	}

	function configureInputPin(pin) {
		return gpio.setup(pin, gpio.DIR_IN);
	}

	function configureOutputPin(pin, initialValue) {
		return gpio.setup(pin, gpio.DIR_OUT)
			.then(function () {
				return gpio.write(pin, initialValue);
			});
	}

	function setup(config) {
		debug('Setting up GPIO');

		// Set Mode to BCM and Export Utility to gpio-admin
		gpio.setMode(gpio.MODE_BCM);

		// Configure Inputs
		return Q.fcall(function() {
				return configureInputPin(config.ShutterButtonPin);
			})
			.then(function () {
				return configureInputPin(config.QuitButtonPin);
			})
			// Configure Outputs
			.then(function () {
				return configureOutputPin(config.ProcessingLedPin, false);
			})
			.then(function () {
				return configureOutputPin(config.PosingLedPin, true);
			})
			.then(function () {
				return configureOutputPin(config.ShutterButtonLedPin, true);
			})
			// Complete promise chain with our config
			.then(function () {
				return config;
			});
	}

	function run(config) {
		var deferred = Q.defer();

		debug('Application Loop Starting');

		console.log('Press the shutter button to begin!');

		gpio.on('change', function (channel, value) {
		    debug('Channel ' + channel + ' value is now ' + value);

		    switch(channel) {
		    	case config.ShutterButtonPin:
		    		if(value){
		    			shutterPressed(config);
		    		}
		    		break;
		    	case config.QuitButtonPin:
		    		// If asked to quit, we'll resolve our promise
		    		if(value) {
		    			deferred.resolve(config);
		    		}
		    		break;
		    	default:
		    		debug('No action available for channel' + channel + '.');
		    }
		});

		return deferred.promise;
	}

	// Options and Configuration
	////////////////////////////////////////////////////
	if(!options || (typeof options !== 'object')) {
		options = {};
	}

	configuration = {
		ShutterButtonPin: options.ShutterButtonPin || 24,
		ShutterButtonLedPin: options.ShutterButtonLedPin || 23,
		QuitButtonPin: options.QuitButtonPin || 26,
		ProcessingLedPin: options.ProcessingLedPin || 22,
		PosingLedPin: options.PosingLedPin || 18,
		// fswebcam -r 1280x720 --no-banner "/home/pi/Pictures/Photobooth/%Y%m%d%H%M%S.jpg"
		TakePhotoCommandText: options.TakePhotoCommandText || 'gphoto2 --capture-image-and-download --filename "/home/pi/Pictures/Photobooth/%Y%m%d%H%M%S.jpg"',
		ProcessPhotosCommandText: options.ProcessPhotosCommandText || 'sudo /home/pi/scripts/photobooth/assemble_and_print',
		Status: {
			TakingPhotos: false,
		}
	};

	// Safety Nets
	////////////////////////////////////////////////////
	process.on('SIGINT', gpio.destroy);

	// Run the App!
	////////////////////////////////////////////////////
	return Q.fcall(function() {
			// While we could just do Q(configuration), jslint doesn't like it
			return configuration;
		})
		.then(gpio.destroy)
		.then(setup)
		.then(run)
		.catch(function(error) {
			debug(error.stack);
		})
		.then(gpio.destroy, function(error){
			debug(error.stack);
		})
		.done();
};<commit_msg>Minor tweaks to process<commit_after>/*jslint node: true, white: true */

/*
 * PhotoBoothRunner
 * https://github.com/brandonmartinez/MM.Photography.PhotoBoothRunner
 *
 * Copyright (c) 2015 Martinez Media, LLC
 * Licensed under the MIT license.
 */

'use strict';

exports.start = function (options) {
	// Function-scoped Variables and requires
	////////////////////////////////////////////////////
	var Q = require('q'),
		gpio = require('rpi-gpio'),
		debug = require('debug')('photoboothrunner'),
		configuration,
		lock = false;

	// Configure Q
	Q.longStackSupport = true;

	// Private Functions
	////////////////////////////////////////////////////
	function shutterPressed(config) {
		if(!lock){
			lock = true;
			debug('Shutter button pressed!');

			return gpio.write({
				channel: config.PosingLedPin,
				value: true
			})
			.delay(500)
			.then(function(){
				return gpio.write({
					channel: config.PosingLedPin,
					value: false
				});
			})
			.delay(500)
			.then(function(){
				return gpio.write({
					channel: config.PosingLedPin,
					value: true
				});
			})
			.delay(500)
			.then(function(){
				return gpio.write({
					channel: config.PosingLedPin,
					value: false
				});
			})
			.delay(500)
			.then(function(){
				return gpio.write({
					channel: config.PosingLedPin,
					value: true
				});
			})
			.delay(500)
			.then(function(){
				return gpio.write({
					channel: config.PosingLedPin,
					value: false
				});
			}).done(function() {
				lock = false;
			});
		}

		debug('Shutter button pressed, but currently taking photos.');
	}

	function setup(config) {
		debug('Setting up GPIO');

		// Set Mode to BCM and Export Utility to gpio-admin
		gpio.setMode(gpio.MODE_BCM);

		// Pins to setup
		var channelConfigs = [
			{
				channel: config.ShutterButtonPin,
				direction: gpio.DIR_IN
			},
			{
				channel: config.QuitButtonPin,
				direction: gpio.DIR_IN
			},
			{
				channel: config.ProcessingLedPin,
				direction: gpio.DIR_OUT
			},
			{
				channel: config.PosingLedPin,
				direction: gpio.DIR_OUT
			},
			// {
			// 	channel: config.ShutterButtonLedPin,
			// 	direction: gpio.DIR_OUT
			// },
			{
				channel: config.HeartbeatLedPin,
				direction: gpio.DIR_OUT
			}
		];

		return channelConfigs
			.reduce(function (chain, channelConfig) {
				return chain
					.then(function(){ return channelConfig; })
					.then(gpio.setup);
			}, new Q())
		    .then(function(){
				return config;
			});
	}

	function setDefaultValues(config) {
		return gpio.write({
			channel: config.HeartbeatLedPin,
			value: true
		})
		// .then(function(){
		// 	return gpio.write({
		// 		channel: config.ShutterButtonLedPin,
		// 		value: true
		// 	});
		// })
		.then(function(){
			return gpio.write({
				channel: config.PosingLedPin,
				value: false
			});
		})
		.then(function(){
			return gpio.write({
				channel: config.ProcessingLedPin,
				value: false
			});
		})
		.then(function(){
			return config;
		});
	}

	function run(config) {
		var deferred = Q.defer();

		debug('Application Loop Starting');

		console.log('Press the shutter button to begin!');

		gpio.on('change', function (channel, value) {
		    debug('Channel ' + channel + ' value is now ' + value);

		    switch(channel) {
		    	case config.ShutterButtonPin:
		    		if(value){
		    			shutterPressed(config);
		    		}
		    		break;
		    	case config.QuitButtonPin:
		    		// If asked to quit, we'll resolve our promise
		    		if(value) {
		    			deferred.resolve(config);
		    		}
		    		break;
		    	default:
		    		debug('No action available for channel' + channel + '.');
		    }
		});

		return deferred.promise;
	}

	// Options and Configuration
	////////////////////////////////////////////////////
	if(!options || (typeof options !== 'object')) {
		options = {};
	}

	configuration = {
		ShutterButtonPin: options.ShutterButtonPin || 17,
		//ShutterButtonLedPin: options.ShutterButtonLedPin || 23,
		QuitButtonPin: options.QuitButtonPin || 27,
		ProcessingLedPin: options.ProcessingLedPin || 16,
		PosingLedPin: options.PosingLedPin || 20,
		HeartbeatLedPin: options.HeartbeatLedPin || 21,
		// fswebcam -r 1280x720 --no-banner "/home/pi/Pictures/Photobooth/%Y%m%d%H%M%S.jpg"
		TakePhotoCommandText: options.TakePhotoCommandText || 'gphoto2 --capture-image-and-download --filename "/home/pi/Pictures/Photobooth/%Y%m%d%H%M%S.jpg"',
		ProcessPhotosCommandText: options.ProcessPhotosCommandText || 'sudo /home/pi/scripts/photobooth/assemble_and_print',
		Status: {
			TakingPhotos: false,
		}
	};

	// Safety Nets
	////////////////////////////////////////////////////
	process.on('SIGINT', gpio.destroy);

	// Run the App!
	////////////////////////////////////////////////////
	return Q.fcall(function() {
			// While we could just do Q(configuration), jslint doesn't like it
			return configuration;
		})
		.then(setup)
		.then(setDefaultValues)
		.then(run)
		.catch(function(error) {
			debug(error.stack);
		})
		.then(gpio.destroy, function(error){
			debug(error.stack);
		})
		.done();
};<|endoftext|>


<commit_before>import escape from 'lodash.escape';

/* Browser and window tools */

export function isiOS() {
  return /iPad|iPhone|iPod/.test(navigator.userAgent);
}

export function forceScroll(x, y, maxAttempts=100) {
  /*
  Sometimes, after navigating somewhere with .pushState, Chrome
  decides to restore scroll position from the previous state after loading.
  No idea what for. No idea why. It just does.
  This function works around that behavior.
  */

  window.scrollTo(x, y);
  let attemptsMade = 0;
  const interval = window.setInterval(() => {
    if (window.scrollX == x && window.scrollY == y) {
      attemptsMade += 1;
      if (attemptsMade >= maxAttempts) {
        window.clearInterval(interval);
      }
    } else {
      window.scrollTo(x, y);
      window.clearInterval(interval);
    }
  }, 1);
}

/* HTML snippets */

export function bigLoader(progress=0.25) {
  return `<div class="big-loader-container">${loader(progress)}</div>`;
}

export function loader(progress=0.25) {
  const dashOffset = 565.48 * (1 - progress);
  return `
    <svg class="loader" viewBox="0 0 200 200" preserveAspectRatio="xMinYMin">
      <circle r="90" cx="100" cy="100" fill="transparent"
              stroke-dasharray="565.48" stroke-dashoffset="0"
              style="stroke-dashoffset: ${dashOffset}px;">
      </circle>
    </svg>
  `
}

/* Element manipulations */

export function clear(element) {
  element.innerHTML = '';
}

export function toggleClass(element, className, condition) {
  /* This shim is used because older Safari and IE don't support
     the second arg to classList.toggle */
  if (condition === undefined) {
    condition = element.classList.contains(className);
  }

  if (condition) {
    element.classList.add(className);
  } else {
    element.classList.remove(className);
  }
}

export function toggle(element, condition) {
  if (condition) {
    show(element);
  } else {
    hide(element);
  }
}

export function show(element) {
  element.removeAttribute('hidden');
}

export function hide(element) {
  element.setAttribute('hidden', 'hidden');
}

/* Generic */

export function restrictBreaks(string, separator=', ') {
  return string
    .split(separator)
    .map(part => `<nobr>${escape(part)}</nobr>`)
    .join(separator);
}

export function niceURL(s) {
  if (s.endsWith('/')) s = s.substr(0, s.length - 1);
  if (s.startsWith('http://')) s = s.substr(7, s.length - 7);
  if (s.startsWith('https://')) s = s.substr(8, s.length - 8);
  return s;
}

export function capfirst(s) {
  return s.slice(0, 1).toUpperCase() + s.slice(1);
}

export function range(bound) {
  const range = [];
  for (let n = 0; n <= bound; n++) {
    range.push(n);
  }
  return range;
}

export function groupArray(array, name, callback, equal=(a, b) => a == b) {
  const groups = [];
  let lastGroup = null;
  array.forEach(item => {
    const groupValue = callback(item);
    if (lastGroup && equal(lastGroup[name], groupValue)) {
      lastGroup.items.push(item);
    } else {
      lastGroup = {items: [item]};
      lastGroup[name] = groupValue;
      groups.push(lastGroup);
    }
  });
  return groups;
}

export function regexpEscape(s) {
  return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
}

export function zipIntoObject(keys, values) {
  const obj = {}
  for (let x = 0; x < values.length; x++) {
    obj[keys[x]] = values[x];
  }
  return obj;
}

export function uuid() {
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
    const r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
    return v.toString(16);
  });
}
<commit_msg>Add a default condition to toggle function<commit_after>import escape from 'lodash.escape';

/* Browser and window tools */

export function isiOS() {
  return /iPad|iPhone|iPod/.test(navigator.userAgent);
}

export function forceScroll(x, y, maxAttempts=100) {
  /*
  Sometimes, after navigating somewhere with .pushState, Chrome
  decides to restore scroll position from the previous state after loading.
  No idea what for. No idea why. It just does.
  This function works around that behavior.
  */

  window.scrollTo(x, y);
  let attemptsMade = 0;
  const interval = window.setInterval(() => {
    if (window.scrollX == x && window.scrollY == y) {
      attemptsMade += 1;
      if (attemptsMade >= maxAttempts) {
        window.clearInterval(interval);
      }
    } else {
      window.scrollTo(x, y);
      window.clearInterval(interval);
    }
  }, 1);
}

/* HTML snippets */

export function bigLoader(progress=0.25) {
  return `<div class="big-loader-container">${loader(progress)}</div>`;
}

export function loader(progress=0.25) {
  const dashOffset = 565.48 * (1 - progress);
  return `
    <svg class="loader" viewBox="0 0 200 200" preserveAspectRatio="xMinYMin">
      <circle r="90" cx="100" cy="100" fill="transparent"
              stroke-dasharray="565.48" stroke-dashoffset="0"
              style="stroke-dashoffset: ${dashOffset}px;">
      </circle>
    </svg>
  `
}

/* Element manipulations */

export function clear(element) {
  element.innerHTML = '';
}

export function toggleClass(element, className, condition) {
  /* This shim is used because older Safari and IE don't support
     the second arg to classList.toggle */
  if (condition === undefined) {
    condition = element.classList.contains(className);
  }

  if (condition) {
    element.classList.add(className);
  } else {
    element.classList.remove(className);
  }
}

export function toggle(element, condition=undefined) {
  if (condition === undefined) {
    condition = element.hasAttribute('hidden');
  }

  if (condition) {
    show(element);
  } else {
    hide(element);
  }
}

export function show(element) {
  element.removeAttribute('hidden');
}

export function hide(element) {
  element.setAttribute('hidden', 'hidden');
}

/* Generic */

export function restrictBreaks(string, separator=', ') {
  return string
    .split(separator)
    .map(part => `<nobr>${escape(part)}</nobr>`)
    .join(separator);
}

export function niceURL(s) {
  if (s.endsWith('/')) s = s.substr(0, s.length - 1);
  if (s.startsWith('http://')) s = s.substr(7, s.length - 7);
  if (s.startsWith('https://')) s = s.substr(8, s.length - 8);
  return s;
}

export function capfirst(s) {
  return s.slice(0, 1).toUpperCase() + s.slice(1);
}

export function range(bound) {
  const range = [];
  for (let n = 0; n <= bound; n++) {
    range.push(n);
  }
  return range;
}

export function groupArray(array, name, callback, equal=(a, b) => a == b) {
  const groups = [];
  let lastGroup = null;
  array.forEach(item => {
    const groupValue = callback(item);
    if (lastGroup && equal(lastGroup[name], groupValue)) {
      lastGroup.items.push(item);
    } else {
      lastGroup = {items: [item]};
      lastGroup[name] = groupValue;
      groups.push(lastGroup);
    }
  });
  return groups;
}

export function regexpEscape(s) {
  return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
}

export function zipIntoObject(keys, values) {
  const obj = {}
  for (let x = 0; x < values.length; x++) {
    obj[keys[x]] = values[x];
  }
  return obj;
}

export function uuid() {
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
    const r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
    return v.toString(16);
  });
}
<|endoftext|>


<commit_before>var fs = require('fs');
var path = require('path');
var marked = require('marked');
var utils = require('./utils');
var normalizeNewline = require('normalize-newline');

var validFileRegex = /\.[\w]+$/;
var firstLineRegex = /^[\n\r]?([^\n\r]+)/;
var trailingNewline = /\s+$/;

var forwardReferenceSections = {};

var tags = {

  /**
   * Add a new section to the style guide.
   *
   * The @section tag can define the section name, otherwise the first line of the
   * description will be used as the section name.
   *
   * @example
      /**
       * My Section
       *
       * A description of the section and how to use it.
       *
       * @section
       *\/

       /**
       * A description of the section and how to use it.
       *
       * @section My Section
       *\/
   */
  section: function () {
    var name, description;

    if (!this.tag.description && !this.comment.description) {
      throw new SyntaxError('unnamed section (' + this.file + ':' +
        (this.tag.line+1) + ')');
    }

    // @section did not define the name so use the first line of the comment
    // description as the section name and use the rest as the section description
    if (!this.tag.description) {
      var normDescription = normalizeNewline(this.comment.description);
      name = normDescription.match(firstLineRegex)[1];
      description = normDescription.substr(name.length + 1);
    }

    // @section defined the name so use the comment description as the section
    // description
    else {
      name = this.tag.description;
      description = this.comment.description;
    }

    this.block.name = name;
    this.block.description = marked(description).replace(trailingNewline, '');
    this.block.id = utils.getId(name);
    this.block.depth = 1;  // start sections as H1 until sectionof is encountered
    this.block.isSection = true;

    // we're going to cheat and make an array have object like indices so we
    // have quick access to sections by their name and still have an ordered list
    // that we can use in the template
    this.sections.push(this.block);

    // add any children from forward referenced sectionof
    if (forwardReferenceSections[name]) {
      this.block.children = [];

      forwardReferenceSections[name].forEach(function(section) {
        this.block.children.push(section.block);
      }.bind(this));

      delete forwardReferenceSections[name];
    }

    // look to see if this section defines a sectionof so we can create a named
    // hierarchy. Can define multiple sectionof tags on one block. Unfortunately
    // this means we have to loop over the tags twice
    var sectionofTag, sectionofName;
    this.comment.tags.forEach(function(tag) {
      if (tag.tag === 'sectionof') {
        sectionofTag = tag;
        sectionofName = tag.description + '.' + name;

        if (this.sections[sectionofName]) {
          throw new SyntaxError('section \'' + this.block.name +
            '\' has already been declared within the section \'' +
            sectionofTag.description + '\' (' + this.file + ':' +
            (sectionofTag.line+1) + ')');
        }

        this.sections[sectionofName] = this.block;

        // also add the normalized name for case insensitivity
        this.sections[ utils.normalizeName(sectionofName) ] = this.block;
      }
    }.bind(this));

    if (!sectionofTag) {
      this.sections[name] = this.block;

      // also add the normalized name for case insensitivity
      this.sections[ utils.normalizeName(name) ] = this.block;
    }
  },

  /**
   * Add a section as a child of another section.
   *
   * @example
      /**
       * A description of the parent section.
       *
       * @section Parent Section
       *\/

      /**
       * A description of the child section.
       *
       * @section Child Section
       * @sectionof Parent Section
       *\/
   */
  sectionof: function() {
    if (!this.tag.description) {
      throw new SyntaxError('@sectionof must reference a section (' +
        this.file + ':' + (this.tag.line+1) + ')');
    }

    var section = this.sections[this.tag.description];
    this.block.depth = this.tag.description.split('.').length + 1;

    // cap heading levels at 6
    if (this.block.depth > 6) {
      this.block.depth = 6;
    }

    var id = utils.getId(this.tag.description.replace('.', ' '));
    this.block.id = id + '-' + this.block.id;
    this.block.parent = this.tag.description;

    if (section) {
      section.children = section.children || [];
      section.children.push(this.block);
    }

    // forward referenced section
    else {
      forwardReferenceSections[this.tag.description] = forwardReferenceSections[this.tag.description] || [];
      forwardReferenceSections[this.tag.description].push({
        block: this.block,

        // save error so we have line number, file, and correct location
        error: new ReferenceError('section \'' + this.tag.description +
          '\' is not defined (' + this.file + ':' + (this.tag.line+1) + ')')
      });
    }
  },

  /**
   * Assign the section to a page. Each page will be written to a file. Only the
   * root section needs to specify the page as all children will inherit from it.
   * @example
      /**
       * Section belonging to a page.
       *
       * @section Section Name
       * @page Page Name
       *\/
   */
   page: function() {
    this.block.page = this.tag.description;

    if (this.pages[this.tag.description]) {
      this.pages[this.tag.description].sections.push(this.block);
    }
    else {
      var page = {
        name: this.block.page,
        id: utils.getId(this.block.page),
        sections: [this.block]
      };

      this.pages[this.block.page] = page;

      // also add the normalized name for case insensitivity
      this.pages[ utils.normalizeName(this.block.page) ] = page;

      this.pages.push(page);
    }
   },

  /**
   * Provide an example that will be displayed in the style guide. Can provide a
   * type to change the language for code highlighting. Can also provide a
   * filename to be used as the example.
   * @see http://prismjs.com/#languages-list
   *
   * @example
      /**
       * A simple example.
       *
       * @example
       *
foo

       *\/

      /**
       * An example with a language type.
       *
       * @example {javascript}
       * console.log('foo');
       *\/

      /**
       * An example from a file
       *
       * @example
       * path/to/file.html
       *\/
   */
  example: function() {
    var description = this.tag.description.trimRight();

    if (validFileRegex.test(description)) {
      var resolvedPath = path.resolve(path.dirname(this.file), description);

      try {
        description = fs.readFileSync(resolvedPath, 'utf-8');
      } catch (e) {
        throw new ReferenceError('File not found \'' + resolvedPath + '\' (' +
          this.file + ':' + (this.tag.line+1) + ')');
      }
    }

    this.block[this.tag.tag] = {
      description: description,
      type: this.tag.type || 'markup'
    };

    // default code to use the example only if hideCode hasn't been set
    if (this.tag.tag === 'example' && !this.block.code && !this.block.hideCode) {

      // don't make them the same object so you can edit one later in preprocess
      this.block.code = JSON.parse(JSON.stringify(this.block.example));
    }

    // replace html encoded at symbol with the actual @ symbol
    // this allows the use of the @ symbol in code examples without the parser
    // trying to parse it as a tag
    // @code
    // .example {
    //   @extend %placeholder-selector;
    // }
    if (this.block.code) {
      this.block.code.description = this.block.code.description.replace('@', '@');
    }
  },

  /**
   * Hide the code output of an example.
   *
   * @example
      /**
       * A simple example.
       *
       * @example
       *
foo

       * @hideCode
       *\/
   */
  hideCode: function() {
    this.block.hideCode = true;

    if (this.block.code) {
      delete this.block.code;
    }
  },

  /**
   * Use a markdown file as the documentation. The first heading of the .md file
   * will be used as the name of the section if @section does not define one.
   * Because the @section doesn't have a name, the @doc must precede the @section.
   * Only @code and @example can be used inside of the doc file.
   *
   * @example
      /**
       * @section
       * @doc path/to/file.md
       *\/
   */
  doc: function() {
    var file = this.tag.description.trimRight();
    var resolvedPath = path.resolve(path.dirname(this.file), file);
    var lexer = new marked.Lexer();
    var headingSet = false;
    var description = '';
    var result, parsedResult, isCode, isHeading, tag;

    try {
      file = normalizeNewline(fs.readFileSync(resolvedPath, 'utf-8'));
    } catch (e) {
      throw new ReferenceError('File not found \'' + resolvedPath + '\' (' +
        this.file + ':' + (this.tag.line+1) + ')');
    }

    // loop through the file by removing one line at a time and use the marked
    // rules to look for heading and code blocks
    //
    // modified from the marked token parser
    // @see https://github.com/chjj/marked/blob/master/lib/marked.js#L150
    while (file.indexOf('\n') !== -1) {
      isCode = false;
      isHeading = false;

      // code
      if (result = lexer.rules.code.exec(file)) {
        file = file.substring(result[0].length);
        parsedResult = result[0].replace(/^ {4}/gm, '').replace(/\n+$/, '');
        isCode = true;
      }

      // fences (gfm)
      else if (result = lexer.rules.fences.exec(file)) {
        file = file.substring(result[0].length);
        parsedResult = result[3];
        isCode = true;
      }

      // heading
      else if (result = lexer.rules.heading.exec(file)) {
        file = file.substring(result[0].length);
        parsedResult = result[2];
        isHeading = true;
      }

      // lheading
      else if (result = lexer.rules.lheading.exec(file)) {
        file = file.substring(result[0].length);
        parsedResult = result[1];
        isHeading = true;
      }

      // go to next line
      else if (file.indexOf('\n') !== -1) {
        description += file.substring(0, file.indexOf('\n')+1);
        file = file.substring(file.indexOf('\n')+1);
      }

      // handle code being able to create example or code tags
      if (isCode) {
        if (parsedResult.indexOf('@example') === 0) {
          tag = 'example';
        }
        else if (parsedResult.indexOf('@code') === 0) {
          tag = 'code';
        }

        // any code block that is not @example or @code will be added to the
        // description
        else {
          description += result[0];
          continue;
        }

        this.comment.tags.push({
          tag: tag,
          type: (result[2] ? result[2] : ''),
          description: parsedResult.replace('@' + tag, '').trimLeft()
        });
      }

      // handle heading setting the section name
      else if (isHeading) {

        // if section name is already set then just add this heading to the
        // description
        if (headingSet) {
          description += result[0];
        }

        else {
          // look at the @section tag and set its name if it's not defined
          for (var i = 0; (tag = this.comment.tags[i]); i++) {
            if (tag.tag === 'section') {
              if (!tag.description) {
                tag.description = parsedResult;
              }

              // if section name is already set then just add this heading to the
              // description
              else {
                description += result[0];
              }

              break;
            }
          }

          headingSet = true;
        }
      }
    }

    // add last line to description
    description += file;

    this.comment.description += description.trimRight();
  }
};
tags.code = tags.example;  // @code and @example generate the same structure

module.exports = tags;
module.exports.forwardReferenceSections = forwardReferenceSections;<commit_msg>added trim() to normalize strings<commit_after>var fs = require('fs');
var path = require('path');
var marked = require('marked');
var utils = require('./utils');
var normalizeNewline = require('normalize-newline');

var validFileRegex = /\.[\w]+$/;
var firstLineRegex = /^[\n\r]?([^\n\r]+)/;
var trailingNewline = /\s+$/;

var forwardReferenceSections = {};

var tags = {

  /**
   * Add a new section to the style guide.
   *
   * The @section tag can define the section name, otherwise the first line of the
   * description will be used as the section name.
   *
   * @example
      /**
       * My Section
       *
       * A description of the section and how to use it.
       *
       * @section
       *\/

       /**
       * A description of the section and how to use it.
       *
       * @section My Section
       *\/
   */
  section: function () {
    var name, description;

    //added trim() to normalize returns on different OSs
    if (!this.tag.description && !this.comment.description.trim() ) {
      throw new SyntaxError('unnamed section (' + this.file + ':' +
        (this.tag.line+1) + ')');
    }

    // @section did not define the name so use the first line of the comment
    // description as the section name and use the rest as the section description
    if (!this.tag.description) {
      var normDescription = normalizeNewline(this.comment.description);
      name = normDescription.match(firstLineRegex)[1];
      description = normDescription.substr(name.length + 1);
    }

    // @section defined the name so use the comment description as the section
    // description
    else {
      name = this.tag.description;
      description = this.comment.description;
    }

    this.block.name = name;
    this.block.description = marked(description).replace(trailingNewline, '');
    this.block.id = utils.getId(name);
    this.block.depth = 1;  // start sections as H1 until sectionof is encountered
    this.block.isSection = true;

    // we're going to cheat and make an array have object like indices so we
    // have quick access to sections by their name and still have an ordered list
    // that we can use in the template
    this.sections.push(this.block);

    // add any children from forward referenced sectionof
    if (forwardReferenceSections[name]) {
      this.block.children = [];

      forwardReferenceSections[name].forEach(function(section) {
        this.block.children.push(section.block);
      }.bind(this));

      delete forwardReferenceSections[name];
    }

    // look to see if this section defines a sectionof so we can create a named
    // hierarchy. Can define multiple sectionof tags on one block. Unfortunately
    // this means we have to loop over the tags twice
    var sectionofTag, sectionofName;
    this.comment.tags.forEach(function(tag) {
      if (tag.tag === 'sectionof') {
        sectionofTag = tag;
        sectionofName = tag.description + '.' + name;

        if (this.sections[sectionofName]) {
          throw new SyntaxError('section \'' + this.block.name +
            '\' has already been declared within the section \'' +
            sectionofTag.description + '\' (' + this.file + ':' +
            (sectionofTag.line+1) + ')');
        }

        this.sections[sectionofName] = this.block;

        // also add the normalized name for case insensitivity
        this.sections[ utils.normalizeName(sectionofName) ] = this.block;
      }
    }.bind(this));

    if (!sectionofTag) {
      this.sections[name] = this.block;

      // also add the normalized name for case insensitivity
      this.sections[ utils.normalizeName(name) ] = this.block;
    }
  },

  /**
   * Add a section as a child of another section.
   *
   * @example
      /**
       * A description of the parent section.
       *
       * @section Parent Section
       *\/

      /**
       * A description of the child section.
       *
       * @section Child Section
       * @sectionof Parent Section
       *\/
   */
  sectionof: function() {
    if (!this.tag.description) {
      throw new SyntaxError('@sectionof must reference a section (' +
        this.file + ':' + (this.tag.line+1) + ')');
    }

    var section = this.sections[this.tag.description];
    this.block.depth = this.tag.description.split('.').length + 1;

    // cap heading levels at 6
    if (this.block.depth > 6) {
      this.block.depth = 6;
    }

    var id = utils.getId(this.tag.description.replace('.', ' '));
    this.block.id = id + '-' + this.block.id;
    this.block.parent = this.tag.description;

    if (section) {
      section.children = section.children || [];
      section.children.push(this.block);
    }

    // forward referenced section
    else {
      forwardReferenceSections[this.tag.description] = forwardReferenceSections[this.tag.description] || [];
      forwardReferenceSections[this.tag.description].push({
        block: this.block,

        // save error so we have line number, file, and correct location
        error: new ReferenceError('section \'' + this.tag.description +
          '\' is not defined (' + this.file + ':' + (this.tag.line+1) + ')')
      });
    }
  },

  /**
   * Assign the section to a page. Each page will be written to a file. Only the
   * root section needs to specify the page as all children will inherit from it.
   * @example
      /**
       * Section belonging to a page.
       *
       * @section Section Name
       * @page Page Name
       *\/
   */
   page: function() {
    this.block.page = this.tag.description;

    if (this.pages[this.tag.description]) {
      this.pages[this.tag.description].sections.push(this.block);
    }
    else {
      var page = {
        name: this.block.page,
        id: utils.getId(this.block.page),
        sections: [this.block]
      };

      this.pages[this.block.page] = page;

      // also add the normalized name for case insensitivity
      this.pages[ utils.normalizeName(this.block.page) ] = page;

      this.pages.push(page);
    }
   },

  /**
   * Provide an example that will be displayed in the style guide. Can provide a
   * type to change the language for code highlighting. Can also provide a
   * filename to be used as the example.
   * @see http://prismjs.com/#languages-list
   *
   * @example
      /**
       * A simple example.
       *
       * @example
       *
foo

       *\/

      /**
       * An example with a language type.
       *
       * @example {javascript}
       * console.log('foo');
       *\/

      /**
       * An example from a file
       *
       * @example
       * path/to/file.html
       *\/
   */
  example: function() {
    var description = this.tag.description.trimRight();

    if (validFileRegex.test(description)) {
      var resolvedPath = path.resolve(path.dirname(this.file), description);

      try {
        description = fs.readFileSync(resolvedPath, 'utf-8');
      } catch (e) {
        throw new ReferenceError('File not found \'' + resolvedPath + '\' (' +
          this.file + ':' + (this.tag.line+1) + ')');
      }
    }

    this.block[this.tag.tag] = {
      description: description,
      type: this.tag.type || 'markup'
    };

    // default code to use the example only if hideCode hasn't been set
    if (this.tag.tag === 'example' && !this.block.code && !this.block.hideCode) {

      // don't make them the same object so you can edit one later in preprocess
      this.block.code = JSON.parse(JSON.stringify(this.block.example));
    }

    // replace html encoded at symbol with the actual @ symbol
    // this allows the use of the @ symbol in code examples without the parser
    // trying to parse it as a tag
    // @code
    // .example {
    //   @extend %placeholder-selector;
    // }
    if (this.block.code) {
      this.block.code.description = this.block.code.description.replace('@', '@');
    }
  },

  /**
   * Hide the code output of an example.
   *
   * @example
      /**
       * A simple example.
       *
       * @example
       *
foo

       * @hideCode
       *\/
   */
  hideCode: function() {
    this.block.hideCode = true;

    if (this.block.code) {
      delete this.block.code;
    }
  },

  /**
   * Use a markdown file as the documentation. The first heading of the .md file
   * will be used as the name of the section if @section does not define one.
   * Because the @section doesn't have a name, the @doc must precede the @section.
   * Only @code and @example can be used inside of the doc file.
   *
   * @example
      /**
       * @section
       * @doc path/to/file.md
       *\/
   */
  doc: function() {
    var file = this.tag.description.trimRight();
    var resolvedPath = path.resolve(path.dirname(this.file), file);
    var lexer = new marked.Lexer();
    var headingSet = false;
    var description = '';
    var result, parsedResult, isCode, isHeading, tag;

    try {
      file = normalizeNewline(fs.readFileSync(resolvedPath, 'utf-8'));
    } catch (e) {
      throw new ReferenceError('File not found \'' + resolvedPath + '\' (' +
        this.file + ':' + (this.tag.line+1) + ')');
    }

    // loop through the file by removing one line at a time and use the marked
    // rules to look for heading and code blocks
    //
    // modified from the marked token parser
    // @see https://github.com/chjj/marked/blob/master/lib/marked.js#L150
    while (file.indexOf('\n') !== -1) {
      isCode = false;
      isHeading = false;

      // code
      if (result = lexer.rules.code.exec(file)) {
        file = file.substring(result[0].length);
        parsedResult = result[0].replace(/^ {4}/gm, '').replace(/\n+$/, '');
        isCode = true;
      }

      // fences (gfm)
      else if (result = lexer.rules.fences.exec(file)) {
        file = file.substring(result[0].length);
        parsedResult = result[3];
        isCode = true;
      }

      // heading
      else if (result = lexer.rules.heading.exec(file)) {
        file = file.substring(result[0].length);
        parsedResult = result[2];
        isHeading = true;
      }

      // lheading
      else if (result = lexer.rules.lheading.exec(file)) {
        file = file.substring(result[0].length);
        parsedResult = result[1];
        isHeading = true;
      }

      // go to next line
      else if (file.indexOf('\n') !== -1) {
        description += file.substring(0, file.indexOf('\n')+1);
        file = file.substring(file.indexOf('\n')+1);
      }

      // handle code being able to create example or code tags
      if (isCode) {
        if (parsedResult.indexOf('@example') === 0) {
          tag = 'example';
        }
        else if (parsedResult.indexOf('@code') === 0) {
          tag = 'code';
        }

        // any code block that is not @example or @code will be added to the
        // description
        else {
          description += result[0];
          continue;
        }

        this.comment.tags.push({
          tag: tag,
          type: (result[2] ? result[2] : ''),
          description: parsedResult.replace('@' + tag, '').trimLeft()
        });
      }

      // handle heading setting the section name
      else if (isHeading) {

        // if section name is already set then just add this heading to the
        // description
        if (headingSet) {
          description += result[0];
        }

        else {
          // look at the @section tag and set its name if it's not defined
          for (var i = 0; (tag = this.comment.tags[i]); i++) {
            if (tag.tag === 'section') {
              if (!tag.description) {
                tag.description = parsedResult;
              }

              // if section name is already set then just add this heading to the
              // description
              else {
                description += result[0];
              }

              break;
            }
          }

          headingSet = true;
        }
      }
    }

    // add last line to description
    description += file;

    this.comment.description += description.trimRight();
  }
};
tags.code = tags.example;  // @code and @example generate the same structure

module.exports = tags;
module.exports.forwardReferenceSections = forwardReferenceSections;<|endoftext|>