<commit_before>'use strict';

modules.exports = {
  'env': {
    'browser': false,
    'node': true,
    'commonjs': true,
    'es6': false
  },
  'rules': {
    'strict': [
      2,
      'never'
    ],
    'indent': [
      2,
      2
    ],
    'quotes': [
      2,
      'single',
      'avoid-escape'
    ],
    'no-shadow': 2,
    'no-shadow-restricted-names': 2,
    'no-undef': 2,
    'no-unused-vars': [
      2,
      {
        'vars': 'all',
        'args': 'after-used'
      }
    ],
    'no-use-before-define': 2,
    'comma-dangle': [
      2,
      'never'
    ],
    'no-cond-assign': [
      2,
      'always'
    ],
    'no-console': 1,
    'no-debugger': 1,
    'no-alert': 1,
    'no-constant-condition': 1,
    'no-dupe-keys': 2,
    'no-duplicate-case': 2,
    'no-empty': 2,
    'no-ex-assign': 2,
    'no-extra-boolean-cast': 0,
    'no-extra-semi': 2,
    'no-func-assign': 2,
    'no-inner-declarations': 2,
    'no-invalid-regexp': 2,
    'no-irregular-whitespace': 2,
    'no-obj-calls': 2,
    'no-sparse-arrays': 2,
    'no-unreachable': 2,
    'use-isnan': 2,
    'block-scoped-var': 2,
    'consistent-return': 2,
    'curly': [
      2,
      'multi-line'
    ],
    'default-case': 2,
    'dot-notation': [
      2,
      {
        'allowKeywords': true
      }
    ],
    'eqeqeq': 2,
    'guard-for-in': 2,
    'no-caller': 2,
    'no-else-return': 2,
    'no-eq-null': 2,
    'no-eval': 2,
    'no-extend-native': 2,
    'no-extra-bind': 2,
    'no-fallthrough': 2,
    'no-floating-decimal': 2,
    'no-implied-eval': 2,
    'no-lone-blocks': 2,
    'no-loop-func': 2,
    'no-multi-str': 2,
    'no-native-reassign': 2,
    'no-new': 2,
    'no-new-func': 2,
    'no-new-wrappers': 2,
    'no-octal': 2,
    'no-octal-escape': 2,
    'no-param-reassign': 2,
    'no-proto': 2,
    'no-redeclare': 2,
    'no-return-assign': 2,
    'no-script-url': 2,
    'no-self-compare': 2,
    'no-sequences': 2,
    'no-throw-literal': 2,
    'no-with': 2,
    'radix': 2,
    'vars-on-top': 0,
    'wrap-iife': [
      2,
      'any'
    ],
    'yoda': 2,
    'brace-style': [
      2,
      '1tbs',
      {
        'allowSingleLine': true
      }
    ],
    'camelcase': [
      2,
      {
        'properties': 'never'
      }
    ],
    'comma-spacing': [
      2,
      {
        'before': false,
        'after': true
      }
    ],
    'comma-style': [
      2,
      'last'
    ],
    'eol-last': 2,
    'func-names': 0,
    'key-spacing': [
      2,
      {
        'beforeColon': false,
        'afterColon': true
      }
    ],
    'new-cap': [
      2,
      {
        'newIsCap': true
      }
    ],
    'no-multiple-empty-lines': [
      2,
      {
        'max': 2
      }
    ],
    'no-nested-ternary': 2,
    'no-new-object': 2,
    'no-spaced-func': 2,
    'no-trailing-spaces': 2,
    'no-extra-parens': [
      2,
      'functions'
    ],
    'no-underscore-dangle': 0,
    'one-var': [
      2,
      'never'
    ],
    'padded-blocks': 0,
    'semi': [
      2,
      'always'
    ],
    'semi-spacing': [
      2,
      {
        'before': false,
        'after': true
      }
    ],
    'space-after-keywords': 2,
    'space-before-blocks': 2,
    'space-before-function-paren': [
      2,
      'never'
    ],
    'space-infix-ops': 2,
    'space-return-throw-case': 2,
    'spaced-comment': [
      2,
      'always',
      {
        'exceptions': [
          '-',
          '+'
        ],
        'markers': [
          '=',
          '!'
        ]
      }
    ]
  }
}<commit_msg>no-cond-assign => except-parens<commit_after>'use strict';

module.exports = {
  'env': {
    'browser': false,
    'node': true,
    'commonjs': true,
    'es6': false
  },
  'rules': {
    'strict': [
      2,
      'never'
    ],
    'indent': [
      2,
      2
    ],
    'quotes': [
      2,
      'single',
      'avoid-escape'
    ],
    'no-shadow': 2,
    'no-shadow-restricted-names': 2,
    'no-undef': 2,
    'no-unused-vars': [
      2,
      {
        'vars': 'all',
        'args': 'after-used'
      }
    ],
    'no-use-before-define': 2,
    'comma-dangle': [
      2,
      'never'
    ],
    'no-cond-assign': [
      2,
      'except-parens'
    ],
    'no-console': 1,
    'no-debugger': 1,
    'no-alert': 1,
    'no-constant-condition': 1,
    'no-dupe-keys': 2,
    'no-duplicate-case': 2,
    'no-empty': 2,
    'no-ex-assign': 2,
    'no-extra-boolean-cast': 0,
    'no-extra-semi': 2,
    'no-func-assign': 2,
    'no-inner-declarations': 2,
    'no-invalid-regexp': 2,
    'no-irregular-whitespace': 2,
    'no-obj-calls': 2,
    'no-sparse-arrays': 2,
    'no-unreachable': 2,
    'use-isnan': 2,
    'block-scoped-var': 2,
    'consistent-return': 2,
    'curly': [
      2,
      'multi-line'
    ],
    'default-case': 2,
    'dot-notation': [
      2,
      {
        'allowKeywords': true
      }
    ],
    'eqeqeq': 2,
    'guard-for-in': 2,
    'no-caller': 2,
    'no-else-return': 2,
    'no-eq-null': 2,
    'no-eval': 2,
    'no-extend-native': 2,
    'no-extra-bind': 2,
    'no-fallthrough': 2,
    'no-floating-decimal': 2,
    'no-implied-eval': 2,
    'no-lone-blocks': 2,
    'no-loop-func': 2,
    'no-multi-str': 2,
    'no-native-reassign': 2,
    'no-new': 2,
    'no-new-func': 2,
    'no-new-wrappers': 2,
    'no-octal': 2,
    'no-octal-escape': 2,
    'no-param-reassign': 2,
    'no-proto': 2,
    'no-redeclare': 2,
    'no-return-assign': 2,
    'no-script-url': 2,
    'no-self-compare': 2,
    'no-sequences': 2,
    'no-throw-literal': 2,
    'no-with': 2,
    'radix': 2,
    'vars-on-top': 0,
    'wrap-iife': [
      2,
      'any'
    ],
    'yoda': 2,
    'brace-style': [
      2,
      '1tbs',
      {
        'allowSingleLine': true
      }
    ],
    'camelcase': [
      2,
      {
        'properties': 'never'
      }
    ],
    'comma-spacing': [
      2,
      {
        'before': false,
        'after': true
      }
    ],
    'comma-style': [
      2,
      'last'
    ],
    'eol-last': 2,
    'func-names': 0,
    'key-spacing': [
      2,
      {
        'beforeColon': false,
        'afterColon': true
      }
    ],
    'new-cap': [
      2,
      {
        'newIsCap': true
      }
    ],
    'no-multiple-empty-lines': [
      2,
      {
        'max': 2
      }
    ],
    'no-nested-ternary': 2,
    'no-new-object': 2,
    'no-spaced-func': 2,
    'no-trailing-spaces': 2,
    'no-extra-parens': [
      2,
      'functions'
    ],
    'no-underscore-dangle': 0,
    'one-var': [
      2,
      'never'
    ],
    'padded-blocks': 0,
    'semi': [
      2,
      'always'
    ],
    'semi-spacing': [
      2,
      {
        'before': false,
        'after': true
      }
    ],
    'space-after-keywords': 2,
    'space-before-blocks': 2,
    'space-before-function-paren': [
      2,
      'never'
    ],
    'space-infix-ops': 2,
    'space-return-throw-case': 2,
    'spaced-comment': [
      2,
      'always',
      {
        'exceptions': [
          '-',
          '+'
        ],
        'markers': [
          '=',
          '!'
        ]
      }
    ]
  }
}<|endoftext|>


<commit_before>
const _                 = require('ramda');
const Check             = require('./lib/check');
const Field             = require('./lib/field');
const Action            = require('./lib/action');

const MSG_USER_CTX      = 'context parameter (ctx) must be an object';
const MSG_FIELD_FACTORY = 'field_factory parameter must be a function';
const MSG_FIELD_CONFIG  = 'field_factory must return an object';

const checkParam = (test, msg) =>
  _.unless(test, () => { throw new TypeError(msg) });

const getValidated = _.prop('validated');

const getData = _.prop('data');

const hasError = _.compose(
  _.reduce(_.or, false)
, _.map(_.compose(_.not, _.isNil))
, _.values
, getValidated
);

const parseActions = (user_ctx, field_factory) => _.compose(
  _.values
, Field.configToActionList
, checkParam(_.is(Object), MSG_FIELD_CONFIG)
, field_factory
)(Check, user_ctx)

const Awesomize = _.curry((user_ctx, field_factory) => {
  checkParam(_.is(Object), MSG_USER_CTX)(user_ctx)
  checkParam(_.is(Function), MSG_FIELD_FACTORY)(field_factory);

  const actions = parseActions(user_ctx, field_factory);

  return (request, current) => Action.Runner({ request, current }, actions);
});

Awesomize.MSG  = Check.MSG;

const dataOrError = (error) => _.curry((user_ctx, field_factory) => {

  return _.composeP(
    _.ifElse(hasError, _.compose(error, getValidated), getData)
  , Awesomize(user_ctx, field_factory)
  );

});

Awesomize.Result      = { hasError };
Awesomize.dataOrError = dataOrError

module.exports = Awesomize;
<commit_msg>move MSG attachment to bottom where all the other exports are.<commit_after>
const _                 = require('ramda');
const Check             = require('./lib/check');
const Field             = require('./lib/field');
const Action            = require('./lib/action');

const MSG_USER_CTX      = 'context parameter (ctx) must be an object';
const MSG_FIELD_FACTORY = 'field_factory parameter must be a function';
const MSG_FIELD_CONFIG  = 'field_factory must return an object';

const checkParam = (test, msg) =>
  _.unless(test, () => { throw new TypeError(msg) });

const getValidated = _.prop('validated');

const getData = _.prop('data');

const hasError = _.compose(
  _.reduce(_.or, false)
, _.map(_.compose(_.not, _.isNil))
, _.values
, getValidated
);

const parseActions = (user_ctx, field_factory) => _.compose(
  _.values
, Field.configToActionList
, checkParam(_.is(Object), MSG_FIELD_CONFIG)
, field_factory
)(Check, user_ctx)

const Awesomize = _.curry((user_ctx, field_factory) => {
  checkParam(_.is(Object), MSG_USER_CTX)(user_ctx)
  checkParam(_.is(Function), MSG_FIELD_FACTORY)(field_factory);

  const actions = parseActions(user_ctx, field_factory);

  return (request, current) => Action.Runner({ request, current }, actions);
});

const dataOrError = (error) => _.curry((user_ctx, field_factory) => {

  return _.composeP(
    _.ifElse(hasError, _.compose(error, getValidated), getData)
  , Awesomize(user_ctx, field_factory)
  );

});

Awesomize.Result      = { hasError };
Awesomize.dataOrError = dataOrError
Awesomize.MSG  = Check.MSG;

module.exports = Awesomize;
<|endoftext|>


<commit_before>import { get } from 'lodash/object'
import getMockCodefuelSearchResults from 'js/components/Search/getMockCodefuelSearchResults'

const ITEMS = 'Items'
const PLACEMENT_POLE = 'Pole'
const PLACEMENT_MAINLINE = 'Mainline'
const PLACEMENT_SIDEBAR = 'Sidebar'

// CodeFuel's top-level keys for each result type.
const CODEFUEL_RESULT_TYPE_KEY_WEBPAGE = 'OrganicResults'
const CODEFUEL_RESULT_TYPE_KEY_VIDEO = 'VideoResults'

// Result types used internally in components.
const RESULT_TYPE_WEBPAGES = 'WebPages'
const RESULT_TYPE_VIDEOS = 'Videos'

// Create a generic search result object
const createSearchResult = ({
  type,
  key,
  pixelUrl,
  placement,
  rank,
  value,
}) => ({
  type,
  key,
  pixelUrl,
  placement,
  rank,
  value,
})

// Takes an object (raw CodeFuel organic webpage data) and returns our
// internal webpage result object.
const createWebpageResult = data => {
  return createSearchResult({
    type: RESULT_TYPE_WEBPAGES,
    key: data.TargetedUrl, // assume unique
    pixelUrl: data.PixelUrl, // TODO: utilize this in the result component
    placement: data.PlacementHint,
    rank: data.Rank,
    value: {
      displayUrl: data.DisplayUrl,
      deepLinks: get(data, 'DeepLinks', []).map(deepLink => ({
        name: deepLink.Title,
        url: deepLink.TargetedUrl,
        snippet: deepLink.Description,
      })),
      id: data.TargetedUrl, // assume unique
      name: data.Title,
      snippet: data.Description,
      url: data.TargetedUrl,
    },
  })
}

// Takes an array (all videos, raw CodeFuel data) and returns an array
// of our video result objects.
const createVideoResults = (data = []) => {
  if (!data.length) {
    return []
  }
  const firstItem = data[0]
  return createSearchResult({
    type: RESULT_TYPE_VIDEOS,
    key: firstItem.TargetedUrl,
    pixelUrl: firstItem.PixelUrl, // TODO: utilize this in the result component
    placement: firstItem.PlacementHint, // all items have the same placement
    value: data.map(videoItem => ({
      allowHttpsEmbed: videoItem.AllowHttpsEmbed,
      allowMobileEmbed: videoItem.AllowMobileEmbed,
      // contentUrl: undefined,
      datePublished: videoItem.DatePublished,
      description: videoItem.Description,
      duration: videoItem.Duration,
      embedHtml: videoItem.EmbedHtml,
      // encodingFormat: undefined,
      // height: undefined,
      // hostPageDisplayUrl: '',
      hostPageUrl: videoItem.TargetedUrl,
      // hostPageUrlPingSuffix: undefined,
      // isAccessibleForFree: undefined,
      // isSuperfresh: undefined,
      // motionThumbnailUrl: undefined,
      name: videoItem.Title,
      publisher: [
        {
          name: videoItem.Publisher,
        },
      ],
      thumbnail: {
        width: videoItem.ThumbnailWidth,
        height: videoItem.ThumbnailHeight,
      },
      thumbnailUrl: videoItem.ThumbnailUrl,
      viewCount: videoItem.ViewCount,
      // webSearchUrl: undefined,
      // webSearchUrlPingSuffix: undefined,
      // width: undefined,
    })),
  })
}

const formatSearchResults = rawSearchResults => {
  console.log('raw search results:', rawSearchResults)

  const poleResults = []
  const mainlineResults = []
  const sidebarResults = []

  // Iterate through result data, formatting each result's data
  // and assigning them to the appropriate position (mainline,
  // sidebar, etc).
  const webpageResults = get(
    rawSearchResults,
    [CODEFUEL_RESULT_TYPE_KEY_WEBPAGE, ITEMS],
    []
  ).map(item => createWebpageResult(item))

  const videoResults = createVideoResults(
    get(rawSearchResults, [CODEFUEL_RESULT_TYPE_KEY_VIDEO, ITEMS], [])
  )

  const allResults = [].concat(webpageResults).concat(videoResults)
  allResults.forEach(item => {
    switch (item.placement) {
      case PLACEMENT_POLE: {
        poleResults.push(item)
        break
      }
      case PLACEMENT_MAINLINE: {
        mainlineResults.push(item)
        break
      }
      case PLACEMENT_SIDEBAR: {
        sidebarResults.push(item)
        break
      }
      default:
        break
    }
  })
  return {
    resultsCount: get(rawSearchResults, [
      CODEFUEL_RESULT_TYPE_KEY_WEBPAGE,
      'NumResults',
    ]),
    results: {
      pole: poleResults,
      mainline: mainlineResults,
      sidebar: sidebarResults,
    },
  }
}

const fetchCodefuelSearchResults = async () => {
  console.log('Fetch CodeFuel search results.')
  const rawSearchResults = await getMockCodefuelSearchResults()
  const formattedSearchResults = formatSearchResults(rawSearchResults)
  return formattedSearchResults
}

export default fetchCodefuelSearchResults
<commit_msg>Fix some bugs with video results<commit_after>import { get } from 'lodash/object'
import getMockCodefuelSearchResults from 'js/components/Search/getMockCodefuelSearchResults'

const ITEMS = 'Items'
const PLACEMENT_POLE = 'Pole'
const PLACEMENT_MAINLINE = 'Mainline'
const PLACEMENT_SIDEBAR = 'Sidebar'

// CodeFuel's top-level keys for each result type.
const CODEFUEL_RESULT_TYPE_KEY_WEBPAGE = 'OrganicResults'
const CODEFUEL_RESULT_TYPE_KEY_VIDEO = 'VideoResults'

// Result types used internally in components.
const RESULT_TYPE_WEBPAGES = 'WebPages'
const RESULT_TYPE_VIDEOS = 'Videos'

// Create a generic search result object
const createSearchResult = ({
  type,
  key,
  pixelUrl,
  placement,
  rank,
  value,
}) => {
  if (!key) {
    throw new Error(`Search result expected a "key" value.`)
  }
  if (!placement) {
    throw new Error(`Search result expected a "placement" value.`)
  }
  if (!rank) {
    throw new Error(`Search result expected a "rank" value.`)
  }
  return {
    type,
    key,
    pixelUrl,
    placement,
    rank,
    value,
  }
}

// Takes an object (raw CodeFuel organic webpage data) and returns our
// internal webpage result object.
const createWebpageResult = data => {
  return createSearchResult({
    type: RESULT_TYPE_WEBPAGES,
    key: data.TargetedUrl, // assume unique
    pixelUrl: data.PixelUrl, // TODO: utilize this in the result component
    placement: data.PlacementHint,
    rank: data.Rank,
    value: {
      displayUrl: data.DisplayUrl,
      deepLinks: get(data, 'DeepLinks', []).map(deepLink => ({
        name: deepLink.Title,
        url: deepLink.TargetedUrl,
        snippet: deepLink.Description,
      })),
      id: data.TargetedUrl, // assume unique
      name: data.Title,
      snippet: data.Description,
      url: data.TargetedUrl,
    },
  })
}

// Takes an array (all videos, raw CodeFuel data) and returns our
// our video results object.
const createVideoResults = (data = []) => {
  if (!data.length) {
    return []
  }
  const firstItem = data[0]
  return createSearchResult({
    type: RESULT_TYPE_VIDEOS,
    key: firstItem.TargetedUrl,
    pixelUrl: firstItem.PixelUrl, // TODO: utilize this in the result component
    placement: firstItem.PlacementHint, // all items have the same placement
    rank: firstItem.Rank, // all items have the same rank
    value: data.map(videoItem => ({
      allowHttpsEmbed: !!videoItem.AllowHttpsEmbed,
      allowMobileEmbed: !!videoItem.AllowMobileEmbed,
      // contentUrl: undefined,
      datePublished: videoItem.DatePublished,
      description: videoItem.Description,
      duration: videoItem.Duration,
      embedHtml: videoItem.EmbedHtml,
      // encodingFormat: undefined,
      // height: undefined,
      // hostPageDisplayUrl: '',
      hostPageUrl: videoItem.TargetedUrl,
      // hostPageUrlPingSuffix: undefined,
      // isAccessibleForFree: undefined,
      // isSuperfresh: undefined,
      // motionThumbnailUrl: undefined,
      name: videoItem.Title,
      publisher: [
        {
          name: videoItem.Publisher,
        },
      ],
      thumbnail: {
        width: videoItem.ThumbnailWidth,
        height: videoItem.ThumbnailHeight,
      },
      thumbnailUrl: videoItem.ThumbnailUrl,
      viewCount: videoItem.ViewCount,
      // webSearchUrl: undefined,
      // webSearchUrlPingSuffix: undefined,
      // width: undefined,
    })),
  })
}

const formatSearchResults = rawSearchResults => {
  console.log('raw search results:', rawSearchResults)

  const poleResults = []
  const mainlineResults = []
  const sidebarResults = []

  // Iterate through result data, formatting each result's data
  // and assigning them to the appropriate position (mainline,
  // sidebar, etc).
  const webpageResults = get(
    rawSearchResults,
    [CODEFUEL_RESULT_TYPE_KEY_WEBPAGE, ITEMS],
    []
  ).map(item => createWebpageResult(item))

  const videoResults = createVideoResults(
    get(rawSearchResults, [CODEFUEL_RESULT_TYPE_KEY_VIDEO, ITEMS], [])
  )

  const allResults = [].concat(webpageResults).concat(videoResults)
  allResults.forEach(item => {
    switch (item.placement) {
      case PLACEMENT_POLE: {
        poleResults.push(item)
        break
      }
      case PLACEMENT_MAINLINE: {
        mainlineResults.push(item)
        break
      }
      case PLACEMENT_SIDEBAR: {
        sidebarResults.push(item)
        break
      }
      default:
        break
    }
  })
  return {
    resultsCount: get(rawSearchResults, [
      CODEFUEL_RESULT_TYPE_KEY_WEBPAGE,
      'NumResults',
    ]),
    results: {
      pole: poleResults,
      mainline: mainlineResults,
      sidebar: sidebarResults,
    },
  }
}

const fetchCodefuelSearchResults = async () => {
  console.log('Fetch CodeFuel search results.')
  const rawSearchResults = await getMockCodefuelSearchResults()
  const formattedSearchResults = formatSearchResults(rawSearchResults)
  return formattedSearchResults
}

export default fetchCodefuelSearchResults
<|endoftext|>


<commit_before>'use strict';

var q = require('q');
var urlResolver = require('url');
var request = require('request');
var cheerio = require('cheerio');

var resolveCssImportUrls = require('resolve-css-import-urls');
var getLinkContents = require('./utils/get-link-contents');
var resolveUrl = require('./utils/resolve-url');

module.exports = function(url, options){

  var deferred = q.defer();

  var options = options || {};
  var parsed = 0;
  var total = 0;

  var result = {
    links: [],
    styles: [],
    css: ''
  };

  options.timeout = options.timeout || 5000;

  function handleResolve() {
    if (parsed >= total) {
      deferred.resolve(result);
    }
  }

  function parseHtml(html) {
    var $ = cheerio.load(html);
    result.pageTitle = $('title').text();

    $('[rel=stylesheet]').each(function() {
      var link = $(this).attr('href');
      var resolvedUrl = resolveUrl(url, link);
      result.links.push({ link: link, url: resolvedUrl });
    });

    $('style').each(function() {
      result.styles.push( $(this).text() );
    });

    total = result.links.length + result.styles.length;

    if (!total) deferred.resolve(false);
    result.links.forEach(function(link) {
      getLinkContents(link.url, options)
        .then(function(css) {
          link.css = css;
          result.css += css;

          if (options.followImports) {
            // Handle potential @import url(foo.css) statements in the CSS.
            link.imports = resolveCssImportUrls(link.url, css);
            total += link.imports.length;
            link.imports.forEach(function(importUrl) {
              getLinkContents(importUrl, options)
                .then(function(css) {
                  result.css += css;
                  parsed++;
                  handleResolve();
                })
                .catch(function(error) {
                  link.error = error;
                  parsed++;
                  handleResolve();
                });
            });
          }

          parsed++;
          handleResolve();
        })
        .catch(function(error) {
          link.error = error;
          parsed++;
          handleResolve();
        });
    });
    result.styles.forEach(function(css) {
      result.css += css;
      parsed++;
      handleResolve();
    });
  }

  request({ url: url, timeout: options.timeout }, function(error, response, body) {
    if (error) deferred.reject(error);
    parseHtml(body);
  });

  return deferred.promise;
};
<commit_msg>Remove require that is no longer needed<commit_after>'use strict';

var q = require('q');
var request = require('request');
var cheerio = require('cheerio');

var resolveCssImportUrls = require('resolve-css-import-urls');
var getLinkContents = require('./utils/get-link-contents');
var resolveUrl = require('./utils/resolve-url');

module.exports = function(url, options){

  var deferred = q.defer();

  var options = options || {};
  var parsed = 0;
  var total = 0;

  var result = {
    links: [],
    styles: [],
    css: ''
  };

  options.timeout = options.timeout || 5000;

  function handleResolve() {
    if (parsed >= total) {
      deferred.resolve(result);
    }
  }

  function parseHtml(html) {
    var $ = cheerio.load(html);
    result.pageTitle = $('title').text();

    $('[rel=stylesheet]').each(function() {
      var link = $(this).attr('href');
      var resolvedUrl = resolveUrl(url, link);
      result.links.push({ link: link, url: resolvedUrl });
    });

    $('style').each(function() {
      result.styles.push( $(this).text() );
    });

    total = result.links.length + result.styles.length;

    if (!total) deferred.resolve(false);
    result.links.forEach(function(link) {
      getLinkContents(link.url, options)
        .then(function(css) {
          link.css = css;
          result.css += css;

          if (options.followImports) {
            // Handle potential @import url(foo.css) statements in the CSS.
            link.imports = resolveCssImportUrls(link.url, css);
            total += link.imports.length;
            link.imports.forEach(function(importUrl) {
              getLinkContents(importUrl, options)
                .then(function(css) {
                  result.css += css;
                  parsed++;
                  handleResolve();
                })
                .catch(function(error) {
                  link.error = error;
                  parsed++;
                  handleResolve();
                });
            });
          }

          parsed++;
          handleResolve();
        })
        .catch(function(error) {
          link.error = error;
          parsed++;
          handleResolve();
        });
    });
    result.styles.forEach(function(css) {
      result.css += css;
      parsed++;
      handleResolve();
    });
  }

  request({ url: url, timeout: options.timeout }, function(error, response, body) {
    if (error) deferred.reject(error);
    parseHtml(body);
  });

  return deferred.promise;
};
<|endoftext|>


<commit_before>const find = (list, match) => {
  for (let i = 0; i < list.length; i++) {
    if (match(list[i])) {
      return list[i]
    }
  }
  return undefined
}

const productsGroupedByStatus = (stock) => {
  return Object.keys(stock).reduce((grouped, product) => {
    const status = stock[product].status
    if (status) {
      grouped[status].push(product)
    } else {
      grouped['unknown'].push(product)
    }
    return grouped
  }, { understock: [], 're-stock': [], ok: [], overstock: [], unknown: [] })
}

// TODO: make sure stock_statuses is availalbe
class StateIndicatorsService {
  constructor (
    $q,
    STOCK_STATUSES,
    lgasService,
    statesService,
    zonesService,
    thresholdsService,
    productListService
  ) {
    this.$q = $q
    this.STOCK_STATUSES = STOCK_STATUSES
    this.lgasService = lgasService
    this.statesService = statesService
    this.zonesService = zonesService
    this.thresholdsService = thresholdsService
    this.productListService = productListService
  }

  decorateWithIndicators (stockCounts) {
    let lgas
    let states
    let zones
    let products

    const getLocation = (lgas, states, zones, stockCount) => {
      const lga = stockCount.location.lga
      const state = stockCount.location.state
      if (lga) {
        return find(lgas, (lgaDoc) => lgaDoc.id === lga)
      } else if (state) {
        return find(states, (stateDoc) => stateDoc.id === state)
      } else {
        const zone = stockCount.location.zone
        return find(zones, (zoneDoc) => zoneDoc.id === zone)
      }
    }

    const addRequiredAllocations = (thresholds, requiredAllocation) => {
      return Object.keys(thresholds).reduce((withAllocations, threshold) => {
        withAllocations[threshold] += requiredAllocation
        return withAllocations
      }, thresholds)
    }

    const decorateStockField = (requiredAllocations, stockCount) => {
      const location = getLocation(lgas, states, zones, stockCount)
      let locationThresholds
      if (location && location.level === 'zone') {
        locationThresholds = this.thresholdsService.calculateThresholds(location, stockCount, products, requiredAllocations[location.id])
      } else {
        locationThresholds = this.thresholdsService.calculateThresholds(location, stockCount, products)
      }
      const stock = stockCount.stock

      const decoratedStock = Object.keys(stock).reduce((decorated, product) => {
        let amount = stock[product]
        let status
        let allocation
        let productThresholds
        let selectedProduct = find(products, (prod) => {
          return prod._id === product
        })

        if (locationThresholds) {
          productThresholds = locationThresholds[product]

          if (productThresholds) {
            if (location && location.level === 'zone' && requiredAllocations && requiredAllocations[product]) {
              productThresholds = addRequiredAllocations(productThresholds, requiredAllocations[product])
            }

            status = 'overstock'
            if (amount < productThresholds.min) {
              status = 'understock'
            } else if (amount < productThresholds.reOrder) {
              status = 're-stock'
            } else if (amount <= productThresholds.max) {
              status = 'ok'
            }

            const productBalance = productThresholds.max - amount
            allocation = productBalance
            if (selectedProduct) {
              const unitBalance = productBalance % selectedProduct.presentation
              allocation = unitBalance > 0 ? productBalance + (selectedProduct.presentation - unitBalance) : productBalance
            }
          }
        }

        decorated[product] = {
          status: status,
          amount: amount,
          allocation: allocation,
          thresholds: productThresholds
        }

        return decorated
      }, {})

      stockCount.stock = decoratedStock
      return stockCount
    }

    const addReStockField = (stockCount) => {
      const groupedByStatus = productsGroupedByStatus(stockCount.stock)
      stockCount.reStockNeeded = !!(groupedByStatus.understock.length + groupedByStatus['re-stock'].length)
      return stockCount
    }

    const addStockLevelStatusField = (stockCount) => {
      const unknownProducts = productsGroupedByStatus(stockCount.stock).unknown.length
      const understockedProducts = productsGroupedByStatus(stockCount.stock).understock.length

      if (stockCount.location) {
        if (understockedProducts >= this.STOCK_STATUSES.alert.threshold) {
          stockCount.stockLevelStatus = this.STOCK_STATUSES.alert.id
        } else if (understockedProducts >= this.STOCK_STATUSES.warning.threshold) {
          stockCount.stockLevelStatus = this.STOCK_STATUSES.warning.id
        } else if (unknownProducts) {
          stockCount.stockLevelStatus = 'unknown'
        } else {
          stockCount.stockLevelStatus = this.STOCK_STATUSES.ok.id
        }
      }

      return stockCount
    }

    const hasNonEmptyStock = (stockCount) => {
      return (stockCount.stock && Object.keys(stockCount.stock).length)
    }

    const isZoneStockCount = (stockCount) => {
      return (stockCount.location && stockCount.location.zone && !stockCount.location.state)
    }

    const isNonZoneStockCount = (stockCount) => {
      return !isZoneStockCount(stockCount)
    }

    const sumAllocations = (sum, stock) => {
      return Object.keys(stock).reduce((total, product) => {
        total[product] = total[product] || 0
        total[product] += stock[product].allocation
        return total
      }, sum)
    }

    const zoneRequiredAllocations = (stockCounts) => {
      return stockCounts.reduce((allocations, stockCount) => {
        if (stockCount.location && stockCount.location.state && !stockCount.location.lga) {
          const zone = stockCount.location.zone
          allocations[zone] = allocations[zone] || {}
          allocations[zone] = sumAllocations(allocations[zone], stockCount.stock)
        }
        return allocations
      }, {})
    }

    const decorateStockCounts = (nonZoneStockCounts, zoneStockCounts, promiseResults) => {
      lgas = promiseResults.lgas
      states = promiseResults.states
      zones = promiseResults.zones || [] // not available for the state dashboard
      products = promiseResults.products

      nonZoneStockCounts = nonZoneStockCounts.map(decorateStockField.bind(null, null))
      zoneStockCounts = zoneStockCounts.map(decorateStockField.bind(null, zoneRequiredAllocations(nonZoneStockCounts)))

      return nonZoneStockCounts.concat(zoneStockCounts)
              .map(addReStockField)
              .map(addStockLevelStatusField)
    }

    let promises = {
      lgas: this.lgasService.list(),
      states: this.statesService.list(),
      products: this.productListService.relevant()
    }

    stockCounts = stockCounts.filter(hasNonEmptyStock)

    if (!stockCounts.length) {
      return this.$q.when(stockCounts)
    }

    let zoneStockCounts = stockCounts.filter(isZoneStockCount)
    let nonZoneStockCounts = stockCounts.filter(isNonZoneStockCount)

    if (zoneStockCounts.length) {
      promises.zones = this.zonesService.list()
    }

    return this.$q
            .all(promises)
            .then(decorateStockCounts.bind(null, nonZoneStockCounts, zoneStockCounts))
  }
}

StateIndicatorsService.$inject = ['$q', 'STOCK_STATUSES', 'lgasService', 'statesService', 'zonesService', 'thresholdsService', 'productListService']

export default StateIndicatorsService
<commit_msg>fix(#26): zones & states require restock if below max level<commit_after>const find = (list, match) => {
  for (let i = 0; i < list.length; i++) {
    if (match(list[i])) {
      return list[i]
    }
  }
  return undefined
}

const productsGroupedByStatus = (stock) => {
  return Object.keys(stock).reduce((grouped, product) => {
    const status = stock[product].status
    if (status) {
      grouped[status].push(product)
    } else {
      grouped['unknown'].push(product)
    }
    return grouped
  }, { understock: [], 're-stock': [], ok: [], overstock: [], unknown: [] })
}

// TODO: make sure stock_statuses is availalbe
class StateIndicatorsService {
  constructor (
    $q,
    STOCK_STATUSES,
    lgasService,
    statesService,
    zonesService,
    thresholdsService,
    productListService
  ) {
    this.$q = $q
    this.STOCK_STATUSES = STOCK_STATUSES
    this.lgasService = lgasService
    this.statesService = statesService
    this.zonesService = zonesService
    this.thresholdsService = thresholdsService
    this.productListService = productListService
  }

  decorateWithIndicators (stockCounts) {
    let lgas
    let states
    let zones
    let products

    const getLocation = (lgas, states, zones, stockCount) => {
      const lga = stockCount.location.lga
      const state = stockCount.location.state
      if (lga) {
        return find(lgas, (lgaDoc) => lgaDoc.id === lga)
      } else if (state) {
        return find(states, (stateDoc) => stateDoc.id === state)
      } else {
        const zone = stockCount.location.zone
        return find(zones, (zoneDoc) => zoneDoc.id === zone)
      }
    }

    const addRequiredAllocations = (thresholds, requiredAllocation) => {
      return Object.keys(thresholds).reduce((withAllocations, threshold) => {
        withAllocations[threshold] += requiredAllocation
        return withAllocations
      }, thresholds)
    }

    const decorateStockField = (requiredAllocations, stockCount) => {
      const location = getLocation(lgas, states, zones, stockCount)
      let locationThresholds
      if (location && location.level === 'zone') {
        locationThresholds = this.thresholdsService.calculateThresholds(location, stockCount, products, requiredAllocations[location.id])
      } else {
        locationThresholds = this.thresholdsService.calculateThresholds(location, stockCount, products)
      }
      const stock = stockCount.stock

      const decoratedStock = Object.keys(stock).reduce((decorated, product) => {
        let amount = stock[product]
        let status
        let allocation
        let productThresholds
        let selectedProduct = find(products, (prod) => {
          return prod._id === product
        })

        if (locationThresholds) {
          productThresholds = locationThresholds[product]

          if (productThresholds) {
            if (location && location.level === 'zone' && requiredAllocations && requiredAllocations[product]) {
              productThresholds = addRequiredAllocations(productThresholds, requiredAllocations[product])
            }

            status = 'overstock'
            if (amount < productThresholds.min) {
              status = 'understock'
            } else if (amount < productThresholds.reOrder) {
              status = 're-stock'
            } else if (amount <= productThresholds.max) {
              status = 'ok'
            }

            const productBalance = productThresholds.max - amount
            allocation = productBalance
            if (selectedProduct) {
              const unitBalance = productBalance % selectedProduct.presentation
              allocation = unitBalance > 0 ? productBalance + (selectedProduct.presentation - unitBalance) : productBalance
            }
          }
        }

        decorated[product] = {
          status: status,
          amount: amount,
          allocation: allocation,
          thresholds: productThresholds
        }

        return decorated
      }, {})

      stockCount.stock = decoratedStock
      return stockCount
    }

    const addReStockField = (stockCount) => {
      const addAllocationIfPositive = (sum, productId) => {
        if (stockCount.stock[productId].allocation > 0) {
          sum = sum + stockCount.stock[productId].allocation
        }
        return sum
      }

      if (stockCount.location && stockCount.location.lga) {
        const groupedByStatus = productsGroupedByStatus(stockCount.stock)
        stockCount.reStockNeeded = !!(groupedByStatus.understock.length + groupedByStatus['re-stock'].length)
      } else { // states and zones
        if (stockCount.stock) {
          const sumOfPositiveAllocations = Object.keys(stockCount.stock).reduce(addAllocationIfPositive, 0)
          stockCount.reStockNeeded = sumOfPositiveAllocations > 0
        }
      }
      return stockCount
    }

    const addStockLevelStatusField = (stockCount) => {
      const unknownProducts = productsGroupedByStatus(stockCount.stock).unknown.length
      const understockedProducts = productsGroupedByStatus(stockCount.stock).understock.length

      if (stockCount.location) {
        if (understockedProducts >= this.STOCK_STATUSES.alert.threshold) {
          stockCount.stockLevelStatus = this.STOCK_STATUSES.alert.id
        } else if (understockedProducts >= this.STOCK_STATUSES.warning.threshold) {
          stockCount.stockLevelStatus = this.STOCK_STATUSES.warning.id
        } else if (unknownProducts) {
          stockCount.stockLevelStatus = 'unknown'
        } else {
          stockCount.stockLevelStatus = this.STOCK_STATUSES.ok.id
        }
      }

      return stockCount
    }

    const hasNonEmptyStock = (stockCount) => {
      return (stockCount.stock && Object.keys(stockCount.stock).length)
    }

    const isZoneStockCount = (stockCount) => {
      return (stockCount.location && stockCount.location.zone && !stockCount.location.state)
    }

    const isNonZoneStockCount = (stockCount) => {
      return !isZoneStockCount(stockCount)
    }

    const sumAllocations = (sum, stock) => {
      return Object.keys(stock).reduce((total, product) => {
        total[product] = total[product] || 0
        total[product] += stock[product].allocation
        return total
      }, sum)
    }

    const zoneRequiredAllocations = (stockCounts) => {
      return stockCounts.reduce((allocations, stockCount) => {
        if (stockCount.location && stockCount.location.state && !stockCount.location.lga) {
          const zone = stockCount.location.zone
          allocations[zone] = allocations[zone] || {}
          allocations[zone] = sumAllocations(allocations[zone], stockCount.stock)
        }
        return allocations
      }, {})
    }

    const decorateStockCounts = (nonZoneStockCounts, zoneStockCounts, promiseResults) => {
      lgas = promiseResults.lgas
      states = promiseResults.states
      zones = promiseResults.zones || [] // not available for the state dashboard
      products = promiseResults.products

      nonZoneStockCounts = nonZoneStockCounts.map(decorateStockField.bind(null, null))
      zoneStockCounts = zoneStockCounts.map(decorateStockField.bind(null, zoneRequiredAllocations(nonZoneStockCounts)))

      return nonZoneStockCounts.concat(zoneStockCounts)
              .map(addReStockField)
              .map(addStockLevelStatusField)
    }

    let promises = {
      lgas: this.lgasService.list(),
      states: this.statesService.list(),
      products: this.productListService.relevant()
    }

    stockCounts = stockCounts.filter(hasNonEmptyStock)

    if (!stockCounts.length) {
      return this.$q.when(stockCounts)
    }

    let zoneStockCounts = stockCounts.filter(isZoneStockCount)
    let nonZoneStockCounts = stockCounts.filter(isNonZoneStockCount)

    if (zoneStockCounts.length) {
      promises.zones = this.zonesService.list()
    }

    return this.$q
            .all(promises)
            .then(decorateStockCounts.bind(null, nonZoneStockCounts, zoneStockCounts))
  }
}

StateIndicatorsService.$inject = ['$q', 'STOCK_STATUSES', 'lgasService', 'statesService', 'zonesService', 'thresholdsService', 'productListService']

export default StateIndicatorsService
<|endoftext|>


<commit_before>import React, { PureComponent } from 'react';

import Actions from './Actions';
import './Idea.css';

class Idea extends PureComponent {
  constructor() {
    super();
    this.state = {
      class: '',
    };
  }
  handleRequestDelete = () => {
    this.setState({
      class: 'will-be-deleted',
    }, () => {
      setTimeout(() => {
        this.setState({
          class: '',
        }, () => {
          this.props.onRequestDelete && this.props.onRequestDelete(this.props.index);
          this.props.onRequestSnackbar && this.props.onRequestSnackbar('Idea deleted');
        });
      }, 1000);
    });
  }
  render() {
    return (
      <div className={`Idea ${this.state.class}`}>

{this.props.text}

        <Actions
          onRequestEditDialogOpen={() => this.props.onRequestEditDialogOpen(this.props.index)}
          onRequestDelete={this.handleRequestDelete}
          onRequestConvertDialogOpen={() => this.props.onRequestConvertDialogOpen(this.props.index)}
        />

    );
  }
}

export default Idea;
<commit_msg>Remove old idea animations<commit_after>import React, { PureComponent } from 'react';

import Actions from './Actions';
import './Idea.css';

class Idea extends PureComponent {
  constructor() {
    super();
    this.state = {
      class: '',
    };
  }
  handleRequestDelete = () => {
    this.props.onRequestDelete && this.props.onRequestDelete(this.props.index);
    this.props.onRequestSnackbar && this.props.onRequestSnackbar('Idea deleted');
  }
  render() {
    return (
      <div className={`Idea ${this.state.class}`}>

{this.props.text}

        <Actions
          onRequestEditDialogOpen={() => this.props.onRequestEditDialogOpen(this.props.index)}
          onRequestDelete={this.handleRequestDelete}
          onRequestConvertDialogOpen={() => this.props.onRequestConvertDialogOpen(this.props.index)}
        />

    );
  }
}

export default Idea;
<|endoftext|>


<commit_before>
/* Simple block-based file storage for Copy on Write implementations */

var q = require('q');
var Index = require('./Index.js');

/** Constructor */
function Indexes(opts) {
	var self = this;
	opts = opts || {};
	self._indexes = {};
}

/** Get index from location x */
Indexes.prototype.get = function(x) {
	var self = this;
	return self._indexes[x];
};

/** Save index to location x */
Indexes.prototype.set = function(x, i) {
	var self = this;
	if(!(i instanceof 'Index')) throw new TypeError("Argument for Indexes.prototype.set is not a Index!");
	self._indexes[x] = i;
	return self;
};

/** Save indexes to file */
Indexes.prototype.save = function(file) {
};

/** Read indexes from index file */
Indexes.open = function(file) {
};

/** Build indexes from data file */
Indexes.rebuild = function(path) {
	var file;
	var Indexes = new Indexes(path);
	return File.open(path, 'r').then(function(f) {
		file = f;
		var data_offset = 0;
		var s = new File.TextReadStream(f, {buffer_size:1024});
		s.on('data', errors.catchfail(function(data) {
			var rows = data.split("\n");
			rows.map(function(row) {
				console.error("DEBUG: row = '" + row + "' at " + data_offset + "-" + (row.length + 1));
				data_offset += row.length + 1;
			});
		}));
		s.on('end', errors.catchfail(function() {
		}));
		return s.read();
	}).fin(function() {
		if(file) file.close();
	}).fail(function(err) {
		errors.print(err);
	});
};

//
module.exports = Indexes;

/* EOF */
<commit_msg>Updated<commit_after>
/* Simple block-based file storage for Copy on Write implementations */

var q = require('q');
var Index = require('./Index.js');

function resolve_data_path(p) {
	return path.resolve(path.dirname(p), path.basename(p, path.extname(p)) + ".json");
}

function resolve_index_path(p) {
	return path.resolve(path.dirname(p), path.basename(p, path.extname(p)) + ".index");
}

/** Constructor */
function Indices(opts) {
	var self = this;
	opts = opts || {};
	self._indices = {};
}

/** Get index from location x */
Indices.prototype.get = function(x) {
	var self = this;
	return self._indices[x];
};

/** Save index to location x */
Indices.prototype.set = function(x, i) {
	var self = this;
	if(!(i instanceof 'Index')) throw new TypeError("Argument for Indices.prototype.set is not a Index!");
	self._indices[x] = i;
	return self;
};

/** Save indices to file */
Indices.prototype.save = function(file) {
};

/** Read indices from index file */
Indices.open = function(file) {
};

/** Build indices from data file */
Indices.rebuild = function(data_path) {
	data_path = resolve_data_path(data_path);
	var data_file;
	var indices = new Indices(resolve_index_path(data_path));
	return File.open(data_path, 'r').then(function(f) {
		data_file = f;
		var data_offset = 0;
		var s = new File.TextReadStream(f, {buffer_size:1024});
		s.on('data', errors.catchfail(function(data) {
			var rows = data.split("\n");
			rows.map(function(row) {
				console.error("DEBUG: row = '" + row + "' at " + data_offset + "-" + (row.length + 1));
				data_offset += row.length + 1;
			});
		}));
		s.on('end', errors.catchfail(function() {
		}));
		return s.read();
	}).fin(function() {
		if(data_file) data_file.close();
	}).fail(function(err) {
		errors.print(err);
	});
};

//
module.exports = Indices;

/* EOF */
<|endoftext|>


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

/* eslint-env node */
'use strict';

const devScp = require( '../common/devScp' );
const fs = require( 'graceful-fs' ); //eslint-disable-line
const winston = require( 'winston' );
const writeFile = require( './writeFile' );

/**
 * Writes the htaccess file to password protect the exclusive content for phet-io sims
 * @param {string} passwordProtectPath - deployment location
 * @param {object} [latestOption] - if provided, then write the /latest/ redirect .htaccess file.
 *                                - this is only to be used for production deploys by the build-server
 * @param {string} [devVersionPath] - if provided, scp the htaccess files to here, relatively
 * @property {string} latestOption.simName
 * @property {string} latestOption.version
 * @property {string} latestOption.directory
 */
module.exports = async function writePhetioHtaccess( passwordProtectPath, latestOption, devVersionPath ) {
  const authFilepath = '/etc/httpd/conf/phet-io_pw';

  // This option is for production deploys by the build-server
  // If we are provided a simName and version then write a .htaccess file to redirect
  // https://phet-io.colorado.edu/sims/{{sim-name}}/latest to https://phet-io.colorado.edu/sims/{{sim-name}}/{{version}}
  if ( latestOption ) {
    if ( latestOption.simName && latestOption.version && latestOption.directory ) {
      const redirectFilepath = latestOption.directory + latestOption.simName + '/.htaccess';
      const latestRedirectContents = 'RewriteEngine on\n' +
                                     'RewriteBase /sims/' + latestOption.simName + '/\n' +
                                     'RewriteRule latest(.*) ' + latestOption.version + '$1\n' +
                                     'RewriteCond %{QUERY_STRING} =download\n' +
                                     'RewriteRule ([^/]*)$ - [L,E=download:$1]\n' +
                                     'Header onsuccess set Content-disposition "attachment; filename=%{download}e" env=download\n';
      try {
        await writeFile( redirectFilepath, latestRedirectContents );
      }
      catch( err ) {
        return Promise.reject( err );
      }
    }
    else {
      winston.error( `simName: ${latestOption.simName}` );
      winston.error( `version: ${latestOption.version}` );
      winston.error( `directory: ${latestOption.directory}` );
      return Promise.reject( 'latestOption is missing one of the required parameters (simName, version, or directory)' );
    }
  }

  // Always write a file to add authentication to the ./wrappers directory
  try {
    const passwordProtectWrapperContents = 'AuthType Basic\n' +
                                           'AuthName "PhET-iO Password Protected Area"\n' +
                                           'AuthUserFile ' + authFilepath + '\n' +
                                           'Require valid-user\n';
    let filePath = 'wrappers/.htaccess';
    await writeFile( `${passwordProtectPath}/${filePath}`, passwordProtectWrapperContents );
    if ( devVersionPath ) {
      await devScp( `${passwordProtectPath}/${filePath}`, `${devVersionPath}/phet-io/${filePath}` );
    }

    const phetioPackage = JSON.parse( fs.readFileSync( '../phet-io/package.json' ) );
    if ( phetioPackage.phet && phetioPackage.phet.addRootHTAccessFile ) {
      const passwordProtectIndexContents = '<FilesMatch "index.html">\n'
                                           + passwordProtectWrapperContents
                                           + '</FilesMatch>\n';
      filePath = '.htaccess';
      await writeFile( `${passwordProtectPath}/${filePath}`, passwordProtectIndexContents );
      if ( devVersionPath ) {
        await devScp( `${passwordProtectPath}/${filePath}`, `${devVersionPath}/phet-io/${filePath}` );
      }
    }
  }
  catch( err ) {
    return Promise.reject( err );
  }
};
<commit_msg>Changed root level auth logic to protect index.* phetsims/phet-io-wrappers#135<commit_after>// Copyright 2017-2018, University of Colorado Boulder

/* eslint-env node */
'use strict';

const devScp = require( '../common/devScp' );
const fs = require( 'graceful-fs' ); //eslint-disable-line
const winston = require( 'winston' );
const writeFile = require( './writeFile' );

/**
 * Writes the htaccess file to password protect the exclusive content for phet-io sims
 * @param {string} passwordProtectPath - deployment location
 * @param {object} [latestOption] - if provided, then write the /latest/ redirect .htaccess file.
 *                                - this is only to be used for production deploys by the build-server
 * @param {string} [devVersionPath] - if provided, scp the htaccess files to here, relatively
 * @property {string} latestOption.simName
 * @property {string} latestOption.version
 * @property {string} latestOption.directory
 */
module.exports = async function writePhetioHtaccess( passwordProtectPath, latestOption, devVersionPath ) {
  const authFilepath = '/etc/httpd/conf/phet-io_pw';

  // This option is for production deploys by the build-server
  // If we are provided a simName and version then write a .htaccess file to redirect
  // https://phet-io.colorado.edu/sims/{{sim-name}}/latest to https://phet-io.colorado.edu/sims/{{sim-name}}/{{version}}
  if ( latestOption ) {
    if ( latestOption.simName && latestOption.version && latestOption.directory ) {
      const redirectFilepath = latestOption.directory + latestOption.simName + '/.htaccess';
      const latestRedirectContents = 'RewriteEngine on\n' +
                                     'RewriteBase /sims/' + latestOption.simName + '/\n' +
                                     'RewriteRule latest(.*) ' + latestOption.version + '$1\n' +
                                     'RewriteCond %{QUERY_STRING} =download\n' +
                                     'RewriteRule ([^/]*)$ - [L,E=download:$1]\n' +
                                     'Header onsuccess set Content-disposition "attachment; filename=%{download}e" env=download\n';
      try {
        await writeFile( redirectFilepath, latestRedirectContents );
      }
      catch( err ) {
        return Promise.reject( err );
      }
    }
    else {
      winston.error( `simName: ${latestOption.simName}` );
      winston.error( `version: ${latestOption.version}` );
      winston.error( `directory: ${latestOption.directory}` );
      return Promise.reject( 'latestOption is missing one of the required parameters (simName, version, or directory)' );
    }
  }

  // Always write a file to add authentication to the ./wrappers directory
  try {
    const passwordProtectWrapperContents = 'AuthType Basic\n' +
                                           'AuthName "PhET-iO Password Protected Area"\n' +
                                           'AuthUserFile ' + authFilepath + '\n' +
                                           'Require valid-user\n';
    let filePath = 'wrappers/.htaccess';
    await writeFile( `${passwordProtectPath}/${filePath}`, passwordProtectWrapperContents );
    if ( devVersionPath ) {
      await devScp( `${passwordProtectPath}/${filePath}`, `${devVersionPath}/phet-io/${filePath}` );
    }

    const phetioPackage = JSON.parse( fs.readFileSync( '../phet-io/package.json' ) );
    if ( phetioPackage.phet && phetioPackage.phet.addRootHTAccessFile ) {
      const passwordProtectIndexContents = '<FilesMatch "index.*">\n'
                                           + passwordProtectWrapperContents
                                           + '</FilesMatch>\n';
      filePath = '.htaccess';
      await writeFile( `${passwordProtectPath}/${filePath}`, passwordProtectIndexContents );
      if ( devVersionPath ) {
        await devScp( `${passwordProtectPath}/${filePath}`, `${devVersionPath}/phet-io/${filePath}` );
      }
    }
  }
  catch( err ) {
    return Promise.reject( err );
  }
};
<|endoftext|>


<commit_before>openerp.web_list_view_sticky = function (instance) {
    var _t = instance.web._t,
        _lt = instance.web._lt;
    var QWeb = instance.web.qweb;

    //Sticky Table Header
    instance.web.ListView.include({
        load_list: function () {
            var self = this;
            self._super.apply(this, arguments);
            var offset = self.$el.parents('.oe_view_manager.oe_view_manager_current').find('.oe_view_manager_header').offset().top;
            var scrollArea = self.$el.parents('.oe_view_manager.oe_view_manager_current').find('.oe_view_manager_wrapper .oe_view_manager_body')[0];
            self.$el.find('table.oe_list_content').each(function(){
                $(this).stickyTableHeaders({scrollableArea: scrollArea})
            });
        },
    });
};<commit_msg>Update LeftOffset to current parent left offset<commit_after>openerp.web_list_view_sticky = function (instance) {
    var _t = instance.web._t,
        _lt = instance.web._lt;
    var QWeb = instance.web.qweb;

    //Sticky Table Header
    instance.web.ListView.include({
        load_list: function () {
            var self = this;
            self._super.apply(this, arguments);
            var scrollArea = self.$el.parents('.oe_view_manager.oe_view_manager_current').find('.oe_view_manager_wrapper .oe_view_manager_body')[0];
            if(scrollArea){
                self.$el.find('table.oe_list_content').each(function(){
                    $(this).stickyTableHeaders({scrollableArea: scrollArea, leftOffset: scrollArea})
                });
            }
        },
    });
};
<|endoftext|>


<commit_before>/**
 * amortization table calculations
 * ===============================
 * calculates the monthly payment
 * calculates remaining loan balance
 * calculates sum of interest payments
 * calculates sum of principal payments
 * @param {number} amount
 * @param {number} rate
 * @param {number} totalTerm
 * @param {number} amortizeTerm
 * @returns {object}
 */
var amortizationCalc = function(amount, rate, totalTerm, amortizeTerm) {
  var periodInt,
      monthlyPayment,
      summedInterest = 0,
      summedPrincipal = 0,
      monthlyIntPaid,
      monthlyPrincPaid,
      summedAmortize = {};

  // Calculate monthly interest rate and monthly payment
  periodInt = (rate / 12) / 100;
  monthlyPayment = amount * (periodInt / (1 - Math.pow(1 + periodInt, -(totalTerm))));
  // If zero or NaN is returned (i.e. if the rate is 0) calculate the payment without interest
  monthlyPayment = monthlyPayment || amount / totalTerm;

  // Calculate the interest, principal, and remaining balance for each period
  var i = 0;
  while( i < amortizeTerm) {
    monthlyIntPaid = amount * periodInt;
    monthlyPrincPaid = monthlyPayment - monthlyIntPaid;
    summedInterest = summedInterest + monthlyIntPaid;
    summedPrincipal = summedPrincipal + monthlyPrincPaid;
    amount = amount - monthlyPrincPaid;
    i += 1;
  }

  summedAmortize.interest = summedInterest;
  summedAmortize.principal = summedPrincipal;
  summedAmortize.balance = amount;
  summedAmortize.payment = monthlyPayment;

  return summedAmortize;

};

/**
 * Throw an error if a string or number below 0 is passed
 * @param {object}
 * @returns {object}
 */
var errorCheck = function(opts) {
  for (var key in opts) {
    if (opts.hasOwnProperty(key)) {
      if (typeof opts[key] === 'undefined' || isNaN(parseFloat(opts[key])) || opts[key] < 0) {
        throw new Error('Loan ' + key + ' must be a non-negative value.');
      }
    }
  }
  return opts;
};

/**
 * Round values to two decimal places
 * @param {object}
 * @returns {object}
 */
var roundNum = function(numObj) {
  for (var property in numObj) {
    numObj[property + 'Round'] = (Math.round(numObj[property] * 100) / 100).toFixed(2);
  }
  return numObj;
};

/**
 * Pass values and return output
 * @param {object} amount, rate, totalTerm, amortizeTerm
 * @example amortize({amount: 180000, rate: 4.25, totalTerm: 360, amortizeTerm: 60})
 * @returns {object}
 */
var amortize = function(opts) {
  opts = errorCheck(opts);
  var amortized = amortizationCalc(opts.amount, opts.rate, opts.totalTerm, opts.amortizeTerm);
  return roundNum(amortized);
};

module.exports = amortize;<commit_msg>Improve object iteration garbage collection<commit_after>/**
 * amortization table calculations
 * ===============================
 * calculates the monthly payment
 * calculates remaining loan balance
 * calculates sum of interest payments
 * calculates sum of principal payments
 * @param {number} amount
 * @param {number} rate
 * @param {number} totalTerm
 * @param {number} amortizeTerm
 * @returns {object}
 */
var amortizationCalc = function(amount, rate, totalTerm, amortizeTerm) {
  var periodInt,
      monthlyPayment,
      summedInterest = 0,
      summedPrincipal = 0,
      monthlyIntPaid,
      monthlyPrincPaid,
      summedAmortize = {};

  // Calculate monthly interest rate and monthly payment
  periodInt = (rate / 12) / 100;
  monthlyPayment = amount * (periodInt / (1 - Math.pow(1 + periodInt, -(totalTerm))));
  // If zero or NaN is returned (i.e. if the rate is 0) calculate the payment without interest
  monthlyPayment = monthlyPayment || amount / totalTerm;

  // Calculate the interest, principal, and remaining balance for each period
  var i = 0;
  while( i < amortizeTerm) {
    monthlyIntPaid = amount * periodInt;
    monthlyPrincPaid = monthlyPayment - monthlyIntPaid;
    summedInterest = summedInterest + monthlyIntPaid;
    summedPrincipal = summedPrincipal + monthlyPrincPaid;
    amount = amount - monthlyPrincPaid;
    i += 1;
  }

  summedAmortize.interest = summedInterest;
  summedAmortize.principal = summedPrincipal;
  summedAmortize.balance = amount;
  summedAmortize.payment = monthlyPayment;

  return summedAmortize;

};

/**
 * Throw an error if a string or number below 0 is passed
 * @param {object}
 * @returns {object}
 */
var errorCheck = function(opts) {
  for (var key in opts) {
    if (opts.hasOwnProperty(key)) {
      if (typeof opts[key] === 'undefined' || isNaN(parseFloat(opts[key])) || opts[key] < 0) {
        throw new Error('Loan ' + key + ' must be a non-negative value.');
      }
    }
  }
};

/**
 * Round values to two decimal places
 * @param {object}
 * @returns {object}
 */
var roundNum = function(numObj) {
  var tmp = {};
  for (var property in numObj) {
    tmp[property] = numObj[property];
    tmp[property + 'Round'] = (Math.round(numObj[property] * 100) / 100).toFixed(2);
  }
  return tmp;
};

/**
 * Pass values and return output
 * @param {object} amount, rate, totalTerm, amortizeTerm
 * @example amortize({amount: 180000, rate: 4.25, totalTerm: 360, amortizeTerm: 60})
 * @returns {object}
 */
var amortize = function(opts) {
  errorCheck(opts);
  var amortized = amortizationCalc(opts.amount, opts.rate, opts.totalTerm, opts.amortizeTerm);
  return roundNum(amortized);
};

module.exports = amortize;<|endoftext|>


<commit_before>define(['logger', 'voc', 'underscore', 'data/CopyMachine', 'data/Data' ], function(Logger, Voc, _, CopyMachine, Data){
    var m = Object.create(Data);
    m.init = function(vie) {
        this.LOG.debug("initialize OrganizeData");
        this.vie = vie;
        this.vie.entities.on('add', this.filter, this);
        this.setIntegrityCheck(Voc.belongsToVersion, Voc.VERSION, Voc.hasWidget);
        this.setIntegrityCheck(Voc.hasCircle, Voc.CIRCLE);
        this.setIntegrityCheck(Voc.hasEntity, Voc.ORGAENTITY);
    };
    m.LOG = Logger.get('OrganizeData');
    /**
     * Filters entities from added entities to vie.entities
     */
    m.filter= function(model, collection, options) {
        if(model.isof(Voc.ORGANIZE)){
            this.checkIntegrity(model, options);
            if( !model.isNew()) {
                this.fetchCircles(model);
                this.fetchEntities(model);
            }
        }
    };
    m.createItem= function(organize, item, options, type, relation) {
        options = options || {};
        this.LOG.debug('options', options);
        if( !item.isEntity) item = new this.vie.Entity(item);
        item.set({
            '@type': type,
        }, options);
        item.set(Voc.belongsToOrganize, organize.getSubject(), options);

        this.vie.entities.addOrUpdate(item, {'addOptions' : options});
        //var items = Backbone.Data.prototype.get.call(
            //organize, this.vie.namespaces.uri(relation)) || [];
        //if(!_.isArray(items)) items = [items];
        //else items = _.clone(items);
        //items.push(item.getSubject());
        //organize.set(relation, items, options);
        item.save();
        return item;
    };
    m.createCircle= function(organize, circle, options) {
        var type = organize.get(Voc.circleType);
        if( type.isEntity ) type = type.getSubject();
        return this.createItem(organize, circle, options, type, Voc.hasCircle);
    };
    m.createEntity= function(organize, entity, options) {
        var type = organize.get(Voc.orgaEntityType);
        if( type.isEntity ) type = type.getSubject();
        return this.createItem(organize, entity, options, type, Voc.hasEntity);
    };
    m.fetchStuff= function(organize, type, relation) {
        var that = this;
        this.vie.load({
            'organize' : organize.getSubject(),
            'type' : this.vie.types.get(type)
        }).from('sss').execute().success(
            function(items) {
                that.LOG.debug('items fetched', items);
                _.each(items, function(item){
                    item[Voc.belongsToOrganize] = organize.getSubject();
                });
                items = that.vie.entities.addOrUpdate(items);
                // Loading entities in case type is Organize Entity
                if ( type == Voc.ORGAENTITY ) {
                    var entityUris = [];
                    _.each(items, function(item){
                        var entity = item.get(Voc.hasResource);
                        if( entity.isEntity) entity = entity.getSubject();
                        entityUris.push(entity);
                    });

                    if ( !_.isEmpty(entityUris) ) {
                        that.fetchData(entityUris);
                    }
                }
            }
        );
    };
    m.fetchCircles= function(organize) {
        this.fetchStuff(organize, Voc.CIRCLE, Voc.hasCircle);
    };
    m.fetchEntities= function(organize) {
        this.fetchStuff(organize, Voc.ORGAENTITY, Voc.hasEntity);
    };
    m.copy= function(organize, overrideAttributes) {
        var newAttr = _.clone(organize.attributes);
        delete newAttr[organize.idAttribute];
        delete newAttr[this.vie.namespaces.uri(Voc.hasCircle)];
        delete newAttr[this.vie.namespaces.uri(Voc.hasEntity)];
        newAttr = _.extend(newAttr, overrideAttributes || {});

        var newOrganize = new this.vie.Entity(newAttr);
        this.vie.entities.addOrUpdate(newOrganize);
        newOrganize.save();
        var that = this;
        _.each([Voc.hasCircle, Voc.hasEntity], function(rel) {
            var items = organize.get(rel) || [];
            if(!_.isArray(items)) items = [items];
            var newItems = [];
            _.each(items,function(item){
                var overrideAttributes = {};
                overrideAttributes[that.vie.namespaces.uri(Voc.belongsToOrganize)]
                    = newOrganize.getSubject();
                var newItem = CopyMachine.copy(item, overrideAttributes);
                newItems.push( newItem.getSubject() );
            });
            newOrganize.set(rel, newItems);
        });
        return newOrganize;
    };
    m.fetchData = function(entityUris) {
        var that = this;
        this.vie.analyze({
            'service' : 'EntityDescsGet',
            'entities' : entityUris
        }).from('sss').execute().success(function(entities) {
            that.vie.entities.addOrUpdate(entities);
        });
    };
    return m;
});
<commit_msg>refactor: adapt entityDescsGet in OrganizeData<commit_after>define(['logger', 'voc', 'underscore', 'data/CopyMachine', 'data/Data' ], function(Logger, Voc, _, CopyMachine, Data){
    var m = Object.create(Data);
    m.init = function(vie) {
        this.LOG.debug("initialize OrganizeData");
        this.vie = vie;
        this.vie.entities.on('add', this.filter, this);
        this.setIntegrityCheck(Voc.belongsToVersion, Voc.VERSION, Voc.hasWidget);
        this.setIntegrityCheck(Voc.hasCircle, Voc.CIRCLE);
        this.setIntegrityCheck(Voc.hasEntity, Voc.ORGAENTITY);
    };
    m.LOG = Logger.get('OrganizeData');
    /**
     * Filters entities from added entities to vie.entities
     */
    m.filter= function(model, collection, options) {
        if(model.isof(Voc.ORGANIZE)){
            this.checkIntegrity(model, options);
            if( !model.isNew()) {
                this.fetchCircles(model);
                this.fetchEntities(model);
            }
        }
    };
    m.createItem= function(organize, item, options, type, relation) {
        options = options || {};
        this.LOG.debug('options', options);
        if( !item.isEntity) item = new this.vie.Entity(item);
        item.set({
            '@type': type,
        }, options);
        item.set(Voc.belongsToOrganize, organize.getSubject(), options);

        this.vie.entities.addOrUpdate(item, {'addOptions' : options});
        //var items = Backbone.Data.prototype.get.call(
            //organize, this.vie.namespaces.uri(relation)) || [];
        //if(!_.isArray(items)) items = [items];
        //else items = _.clone(items);
        //items.push(item.getSubject());
        //organize.set(relation, items, options);
        item.save();
        return item;
    };
    m.createCircle= function(organize, circle, options) {
        var type = organize.get(Voc.circleType);
        if( type.isEntity ) type = type.getSubject();
        return this.createItem(organize, circle, options, type, Voc.hasCircle);
    };
    m.createEntity= function(organize, entity, options) {
        var type = organize.get(Voc.orgaEntityType);
        if( type.isEntity ) type = type.getSubject();
        return this.createItem(organize, entity, options, type, Voc.hasEntity);
    };
    m.fetchStuff= function(organize, type, relation) {
        var that = this;
        this.vie.load({
            'organize' : organize.getSubject(),
            'type' : this.vie.types.get(type)
        }).from('sss').execute().success(
            function(items) {
                that.LOG.debug('items fetched', items);
                _.each(items, function(item){
                    item[Voc.belongsToOrganize] = organize.getSubject();
                });
                items = that.vie.entities.addOrUpdate(items);
                // Loading entities in case type is Organize Entity
                if ( type == Voc.ORGAENTITY ) {
                    var entityUris = [];
                    _.each(items, function(item){
                        var entity = item.get(Voc.hasResource);
                        if( entity.isEntity) entity = entity.getSubject();
                        entityUris.push(entity);
                    });

                    if ( !_.isEmpty(entityUris) ) {
                        that.fetchData(entityUris);
                    }
                }
            }
        );
    };
    m.fetchCircles= function(organize) {
        this.fetchStuff(organize, Voc.CIRCLE, Voc.hasCircle);
    };
    m.fetchEntities= function(organize) {
        this.fetchStuff(organize, Voc.ORGAENTITY, Voc.hasEntity);
    };
    m.copy= function(organize, overrideAttributes) {
        var newAttr = _.clone(organize.attributes);
        delete newAttr[organize.idAttribute];
        delete newAttr[this.vie.namespaces.uri(Voc.hasCircle)];
        delete newAttr[this.vie.namespaces.uri(Voc.hasEntity)];
        newAttr = _.extend(newAttr, overrideAttributes || {});

        var newOrganize = new this.vie.Entity(newAttr);
        this.vie.entities.addOrUpdate(newOrganize);
        newOrganize.save();
        var that = this;
        _.each([Voc.hasCircle, Voc.hasEntity], function(rel) {
            var items = organize.get(rel) || [];
            if(!_.isArray(items)) items = [items];
            var newItems = [];
            _.each(items,function(item){
                var overrideAttributes = {};
                overrideAttributes[that.vie.namespaces.uri(Voc.belongsToOrganize)]
                    = newOrganize.getSubject();
                var newItem = CopyMachine.copy(item, overrideAttributes);
                newItems.push( newItem.getSubject() );
            });
            newOrganize.set(rel, newItems);
        });
        return newOrganize;
    };
    m.fetchData = function(entityUris) {
        var that = this;
        this.vie.load({
            'service' : 'entityDescsGet',
            'data' : {
                'entities' : entityUris
            }
        }).from('sss').execute().success(function(entities) {
            that.vie.entities.addOrUpdate(entities);
        });
    };
    return m;
});
<|endoftext|>


<commit_before>'use strict';

var dashboardPage = require('../pages/dashboard');

describe('tasklist dashboard - ', function() {

  describe('start test', function () {

    it('should login', function () {

      // when
      dashboardPage.navigateTo();
      dashboardPage.authentication.userLogin('jonny1', 'jonny1');

      // then
      dashboardPage.isActive();
    });

  });

  describe('filter list', function() {

    it('should select MINES filter', function() {

      // when
      dashboardPage.filter.selectFilter(1);

      // then
      dashboardPage.filter.isFilterSelected(1);
      dashboardPage.filter.isFilterNotSelected(0);
      expect(dashboardPage.tasks.taskList().count()).toBe(1);
    });

    describe('Start a process', function() {

      it('should search and start process', function() {

        // when
        dashboardPage.selectNavbarItem('Process');
        dashboardPage.startProcess.searchProcessInput().sendKeys('invoice receipt');

        // then
        expect(dashboardPage.startProcess.foundProcesses().count()).toBe(2);
      });

      it('should start process', function() {

        // when
        dashboardPage.startProcess.selectProcessFromSearchResult(1);

        // then
        expect(dashboardPage.startProcess.invoiceStartForm.creditorInput().isDisplayed()).toBe(true);
      });

      it('should enter start form data', function() {

        dashboardPage.startProcess.invoiceStartForm.creditorInput().sendKeys('Bier');
        dashboardPage.startProcess.invoiceStartForm.amountInput().sendKeys('85746€');
        dashboardPage.startProcess.invoiceStartForm.invoiceNumberInput().sendKeys('4711');
        dashboardPage.startProcess.invoiceStartForm.startButton().click();
      });

    });

    it('should check filter refresh', function() {

      // then
      expect(dashboardPage.tasks.taskList().count()).toBe(2);
    });

  });

  xdescribe('tasks', function() {

    it('should open my tasks', function() {

      // when
      dashboardPage.filter.selectFilter(1);

      // then
      expect(dashboardPage.tasks.taskList().count()).toBe(1);
    });

    it('should select a task', function() {

      // when
      dashboardPage.tasks.selectTask(0);

      // then
      expect(dashboardPage.task.taskName()).toBe('Assign Approver');
      expect(dashboardPage.task.processName()).toBe('invoice receipt');
    });

    it('should enter my task data', function() {

      // when
      dashboardPage.startProcess.invoiceStartForm.approverInput().sendKeys('jonny1');
      dashboardPage.task.completeButton().click();

      // then
      expect(dashboardPage.tasks.taskList().count()).toBe(1);
      expect(dashboardPage.tasks.taskTitle(0)).not.toBe('Approve Invoice');
    });

  });

  xdescribe('end test', function() {

    it('should logout', function() {

    });

  });

});<commit_msg>test(UI-TEST/tasklist): Complete a Task<commit_after>'use strict';

var dashboardPage = require('../pages/dashboard');
var cockpitPage = require('../../cockpit/pages/dashboard');
var cockpitProcessDefinitionPage = require('../../cockpit/pages/process-definition');
var cockpitProcessInstancePage = require('../../cockpit/pages/process-instance');

describe('tasklist dashboard - ', function() {

  describe('start test', function () {

    it('should login', function () {

      // when
      dashboardPage.navigateTo();
      dashboardPage.authentication.userLogin('jonny1', 'jonny1');

      // then
      dashboardPage.isActive();
    });

  });

  describe("claim and unclaim", function () {

    it("should claim a task", function () {

      // given
      dashboardPage.filter.selectFilter(0);

      // when
      var taskName = dashboardPage.tasks.taskTitle(0);
      dashboardPage.tasks.selectTask(0);
      dashboardPage.task.claim();
      dashboardPage.filter.selectFilter(1);

      // then
      expect(dashboardPage.tasks.taskList().count()).toBe(2);
      expect(dashboardPage.tasks.taskTitle(1)).toEqual(taskName);
    });

    it("schould unclaim a task", function () {

      // when
      dashboardPage.tasks.selectTask(1);
      dashboardPage.task.unclaim();

      // then
      expect(dashboardPage.tasks.taskList().count()).toBe(1);
    });

  });

  describe('filter list', function() {

    it('should select MINES filter', function() {

      // when
      dashboardPage.filter.selectFilter(1);

      // then
      dashboardPage.filter.isFilterSelected(1);
      dashboardPage.filter.isFilterNotSelected(0);
      expect(dashboardPage.tasks.taskList().count()).toBe(1);
    });

    describe('Start a process', function() {

      it('should search and start process', function() {

        // when
        dashboardPage.selectNavbarItem('Process');
        dashboardPage.startProcess.searchProcessInput().sendKeys('invoice receipt');

        // then
        expect(dashboardPage.startProcess.foundProcesses().count()).toBe(2);
      });

      it('should start process', function() {

        // when
        dashboardPage.startProcess.selectProcessFromSearchResult(1);

        // then
        expect(dashboardPage.startProcess.invoiceStartForm.creditorInput().isDisplayed()).toBe(true);
      });

      it('should enter start form data', function() {

        dashboardPage.startProcess.invoiceStartForm.creditorInput().sendKeys('Bier');
        dashboardPage.startProcess.invoiceStartForm.amountInput().sendKeys('85746€');
        dashboardPage.startProcess.invoiceStartForm.invoiceNumberInput().sendKeys('4711');
        dashboardPage.startProcess.invoiceStartForm.startButton().click();
      });

    });

    it('should check filter refresh', function() {

      // then
      expect(dashboardPage.tasks.taskList().count()).toBe(2);
    });

  });

  describe('work on task', function() {

    it('should select a task', function() {

      // when
      dashboardPage.filter.selectFilter(1);
      dashboardPage.tasks.selectTask(0);

      // then
      expect(dashboardPage.task.taskName()).toBe('Assign Approver');
      expect(dashboardPage.task.processName()).toBe('invoice receipt');
    });

    it('should enter my task data', function() {

      // when
      dashboardPage.startProcess.invoiceStartForm.approverInput().sendKeys('jonny1');
      dashboardPage.task.completeButton().click();

      // then
      expect(dashboardPage.tasks.taskList().count()).toBe(1);
      expect(dashboardPage.tasks.taskTitle(0)).not.toBe('Approve Invoice');
    });

  });

  describe('end test', function() {

    it('should logout', function() {

      cockpitPage.navigateTo();
      cockpitPage.deployedProcessesList.selectProcess(12);
      cockpitProcessDefinitionPage.table.processInstancesTab.selectProcessInstance(0);
      cockpitProcessInstancePage.actionButton.cancelInstance();

    });

  });

});<|endoftext|>


<commit_before>// !! This module implements the state object of a ProseMirror editor.

const {Mark} = require("../model")
const {Mapping} = require("../transform")

const {Selection, TextSelection, NodeSelection} = require("./selection")
exports.Selection = Selection; exports.TextSelection = TextSelection; exports.NodeSelection = NodeSelection
const {EditorTransform} = require("./transform")
exports.EditorTransform = EditorTransform

function currentMarks(doc, selection) {
  return selection.head == null ? Mark.none : doc.marksAt(selection.head)
}

const nullOptions = {}

function hasProp(obj, prop) {
  return Object.prototype.hasOwnProperty.call(obj, prop)
}

class ViewState {
  constructor(inDOMChange, domChangeMapping, scrollToSelection) {
    this.inDOMChange = inDOMChange
    this.domChangeMapping = domChangeMapping
    this.scrollToSelection = scrollToSelection
  }
}
ViewState.initial = new ViewState(null, null, false)
exports.ViewState = ViewState

const baseFields = {
  doc: {
    init(doc) { return doc },
    applyTransform(state, transform) {
      if (!transform.before.eq(state.doc))
        throw new RangeError("Applying a transform that does not start with the current document")
      return transform.doc
    }
  },
  selection: {
    init(_, selection) { return selection },
    applyTransform(state, transform, options) {
      return options.selection || state.selection.map(transform.doc, transform.mapping)
    },
    applySelection(_, selection) { return selection }
  },
  storedMarks: {
    init() { return null },
    applyTransform(state, _, options) { return options.selection ? null : state.storedMarks },
    applySelection() { return null }
  },

  view: {
    init() { return ViewState.initial },
    applyTransform(state, transform, options) {
      return new ViewState(state.view.inDOMChange,
                           state.view.domChangeMapping && state.view.domChangeMapping.copy().appendMapping(transform.mapping),
                           options.scrollIntoView ? true : options.selection ? false : state.view.scrollToSelection)
    },
    applySelection(state, _, options) {
      return new ViewState(state.view.inDOMChange, state.view.domChangeMapping, !!options.scrollIntoView)
    }
  }
}

function makeStateClass(plugins = []) {
  let fieldNames, descs = {}

  class EditorState {
    // :: (Object) → EditorState
    // Create a new state object by updating some of the fields in the
    // current object.
    update(fields) {
      let newInstance = new EditorState
      for (let i = 0; i < fieldNames.length; i++) {
        let name = fieldNames[i]
        newInstance[name] = hasProp(fields, name) ? fields[name] : this[name]
      }
      return newInstance
    }

    // :: Schema
    get schema() {
      return this.doc.type.schema
    }

    applyTransform(transform, options = nullOptions) {
      let newInstance = new EditorState
      for (let i = 0; i < fieldNames.length; i++) {
        let name = fieldNames[i], desc = descs[name]
        newInstance[name] = desc.applyTransform ? desc.applyTransform(this, transform, options) : this[name]
      }
      return newInstance
    }

    applySelection(selection, options = nullOptions) {
      let newInstance = new EditorState
      for (let i = 0; i < fieldNames.length; i++) {
        let name = fieldNames[i], desc = descs[name]
        newInstance[name] = desc.applySelection ? desc.applySelection(this, selection, options) : this[name]
      }
      return newInstance
    }

    addActiveMark(mark) {
      let set = this.storedMarks
      if (this.selection.empty) set = mark.addToSet(set || currentMarks(this.doc, this.selection))
      return set == this.storedMarks ? this : this.update({storedMarks: set})
    }

    removeActiveMark(markType) {
      let set = this.storedMarks
      if (this.selection.empty) set = markType.removeFromSet(set || currentMarks(this.doc, this.selection))
      return set == this.storedMarks ? this : this.update({storedMarks: set})
    }

    startDOMChange(id) {
      return this.update({view: new ViewState(id, new Mapping, this.view.scrollToSelection)})
    }

    endDOMChange() {
      return this.update({view: new ViewState(null, null, this.view.scrollToSelection)})
    }

    // :: EditorTransform
    // Create a selection-aware `Transform` object.
    get tr() { return new EditorTransform(this) }

    static fromDoc(doc, selection) {
      if (!selection) selection = Selection.atStart(doc)
      let instance = new EditorState
      for (let i = 0; i < fieldNames.length; i++) {
        let name = fieldNames[i]
        instance[name] = descs[name].init(doc, selection)
      }
      return instance
    }

    static fromSchema(schema) {
      return this.fromDoc(schema.nodes.doc.createAndFill())
    }
  }

  Object.keys(baseFields).forEach(name => descs[name] = baseFields[name])
  plugins.forEach(plugin => {
    Object.keys(plugin.stateFields || {}).forEach(field => {
      if (hasProp(descs, field) || hasProp(EditorState.prototype, field))
        throw new Error("Conflicting definition for state property " + field)
      descs[field] = plugin.stateFields[field]
    })
    Object.keys(plugin.stateMethods || {}).forEach(method => {
      if (hasProp(descs, method) || hasProp(EditorState.prototype, method))
        throw new Error("Conflicting definition for state property " + method)
      EditorState.prototype[method] = plugin.stateMethods[method]
    })
  })
  fieldNames = Object.keys(descs)

  return EditorState
}
exports.makeStateClass = makeStateClass

exports.EditorState = makeStateClass([])
<commit_msg>Remove the concept of plugins, extend state class differently<commit_after>// !! This module implements the state object of a ProseMirror editor.

const {Mark} = require("../model")
const {Mapping} = require("../transform")

const {Selection, TextSelection, NodeSelection} = require("./selection")
exports.Selection = Selection; exports.TextSelection = TextSelection; exports.NodeSelection = NodeSelection
const {EditorTransform} = require("./transform")
exports.EditorTransform = EditorTransform

function currentMarks(doc, selection) {
  return selection.head == null ? Mark.none : doc.marksAt(selection.head)
}

const nullOptions = {}

function hasProp(obj, prop) {
  return Object.prototype.hasOwnProperty.call(obj, prop)
}

class ViewState {
  constructor(inDOMChange, domChangeMapping, scrollToSelection) {
    this.inDOMChange = inDOMChange
    this.domChangeMapping = domChangeMapping
    this.scrollToSelection = scrollToSelection
  }
}
ViewState.initial = new ViewState(null, null, false)
exports.ViewState = ViewState

class FieldDesc {
  constructor(name, desc) {
    this.init = desc.init
    this.applyTransform = desc.applyTransform || (state => state[name])
    this.applySelection = desc.applySelection || (state => state[name])
  }
}

function makeStateClass(fields, methods) {
  let fieldNames = Object.keys(fields)

  class EditorState {
    // :: Schema
    get schema() {
      return this.doc.type.schema
    }

    // :: (Object) → EditorState
    // Create a new state object by updating some of the fields in the
    // current object.
    update(updated) {
      let newInstance = new EditorState
      for (let i = 0; i < fieldNames.length; i++) {
        let name = fieldNames[i]
        newInstance[name] = hasProp(updated, name) ? updated[name] : this[name]
      }
      return newInstance
    }

    applyTransform(transform, options = nullOptions) {
      let newInstance = new EditorState
      for (let i = 0; i < fieldNames.length; i++)
        newInstance[fieldNames[i]] = fields[fieldNames[i]].applyTransform(this, transform, options)
      return newInstance
    }

    applySelection(selection, options = nullOptions) {
      let newInstance = new EditorState
      for (let i = 0; i < fieldNames.length; i++)
        newInstance[fieldNames[i]] = fields[fieldNames[i]].applySelection(this, selection, options)
      return newInstance
    }

    addActiveMark(mark) {
      let set = this.storedMarks
      if (this.selection.empty) set = mark.addToSet(set || currentMarks(this.doc, this.selection))
      return set == this.storedMarks ? this : this.update({storedMarks: set})
    }

    removeActiveMark(markType) {
      let set = this.storedMarks
      if (this.selection.empty) set = markType.removeFromSet(set || currentMarks(this.doc, this.selection))
      return set == this.storedMarks ? this : this.update({storedMarks: set})
    }

    startDOMChange(id) {
      return this.update({view: new ViewState(id, new Mapping, this.view.scrollToSelection)})
    }

    endDOMChange() {
      return this.update({view: new ViewState(null, null, this.view.scrollToSelection)})
    }

    // :: EditorTransform
    // Create a selection-aware `Transform` object.
    get tr() { return new EditorTransform(this) }

    static fromDoc(doc, selection) {
      if (!selection) selection = Selection.atStart(doc)
      let instance = new EditorState
      for (let i = 0; i < fieldNames.length; i++)
        instance[fieldNames[i]] = fields[fieldNames[i]].init(doc, selection)
      return instance
    }

    static fromSchema(schema) {
      return this.fromDoc(schema.nodes.doc.createAndFill())
    }

    static extend(spec) {
      let fieldCopy = {}, methodCopy = {}
      Object.keys(fields).forEach(name => fieldCopy[name] = fields[name])
      Object.keys(methods).forEach(name => methodCopy[name] = methods[name])

      Object.keys(spec.fields || {}).forEach(name => {
        if (hasProp(fields, name) || hasProp(EditorState.prototype, name))
          throw new Error("Conflicting definition for state property " + name)
        fieldCopy[name] = new FieldDesc(name, spec.fields[name])
      })
      Object.keys(spec.methods || {}).forEach(name => {
        if (hasProp(fields, name) || hasProp(EditorState.prototype, name))
          throw new Error("Conflicting definition for state property " + name)
        methodCopy[name] = spec.methods[name]
      })
      return makeStateClass(fieldCopy, methodCopy)
    }
  }

  Object.keys(methods).forEach(name => EditorState.prototype[name] = methods[name])

  return EditorState
}

exports.EditorState = makeStateClass({
  doc: new FieldDesc("doc", {
    init(doc) { return doc },
    applyTransform(state, transform) {
      if (!transform.before.eq(state.doc))
        throw new RangeError("Applying a transform that does not start with the current document")
      return transform.doc
    }
  }),

  selection: new FieldDesc("selection", {
    init(_, selection) { return selection },
    applyTransform(state, transform, options) {
      return options.selection || state.selection.map(transform.doc, transform.mapping)
    },
    applySelection(_, selection) { return selection }
  }),

  storedMarks: new FieldDesc("storedMarks", {
    init() { return null },
    applyTransform(state, _, options) { return options.selection ? null : state.storedMarks },
    applySelection() { return null }
  }),

  view: new FieldDesc("view", {
    init() { return ViewState.initial },
    applyTransform(state, transform, options) {
      return new ViewState(state.view.inDOMChange,
                           state.view.domChangeMapping && state.view.domChangeMapping.copy().appendMapping(transform.mapping),
                           options.scrollIntoView ? true : options.selection ? false : state.view.scrollToSelection)
    },
    applySelection(state, _, options) {
      return new ViewState(state.view.inDOMChange, state.view.domChangeMapping, !!options.scrollIntoView)
    }
  })
}, {})
<|endoftext|>