<commit_before>/*-
 * #%L
 * FWAPP Framework
 * %%
 * Copyright (C) 2016 - 2017 Open Design Flow
 * %%
 * This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * #L%
 */
// GUI Initialisation
//-------------------
$(function() {

	$('.popup-hover').popup({
		inline : true,
		hoverable : true

	});

	$('.popup-activate').popup({
		on : 'click'
	});

	$('.ui.dropdown.item').dropdown();

});

// Functions for main Framework
// ------------
fwapp.ui.impl = {

	currentModal : "",

	disable : function(target) {
		$(target).prop('disabled', true);
	},

	enable : function(target) {
		$(target).prop('disabled', false);
	},

	waitStart : function(target) {
		console.log("Wait start");
		var html = $('

Waiting for action to stop

')
		//var html = $.get()
		currentModal = $(html).modal({
			blurring : true,
			closable : false
		}).modal('show');
	},

	waitStop : function(target) {
		console.log("Wait stop");
		//$('.ui.modal').modal('close');

		/*var wait = $.Deferred();
		currentModal.onHidden = function() {
			console.log("Closed");
			wait.done();
		};*/
		currentModal.modal('close');
		//wait
		currentModal = "";
	}

};
<commit_msg>fixed dropdown activation selector<commit_after>/*-
 * #%L
 * FWAPP Framework
 * %%
 * Copyright (C) 2016 - 2017 Open Design Flow
 * %%
 * This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * #L%
 */
// GUI Initialisation
//-------------------
$(function() {

	$('.popup-hover').popup({
		inline : true,
		hoverable : true

	});

	$('.popup-activate').popup({
		on : 'click'
	});

	$('.ui.dropdown').dropdown();

});

// Functions for main Framework
// ------------
fwapp.ui.impl = {

	currentModal : "",

	disable : function(target) {
		$(target).prop('disabled', true);
	},

	enable : function(target) {
		$(target).prop('disabled', false);
	},

	waitStart : function(target) {
		console.log("Wait start");
		var html = $('

Waiting for action to stop

')
		//var html = $.get()
		currentModal = $(html).modal({
			blurring : true,
			closable : false
		}).modal('show');
	},

	waitStop : function(target) {
		console.log("Wait stop");
		//$('.ui.modal').modal('close');

		/*var wait = $.Deferred();
		currentModal.onHidden = function() {
			console.log("Closed");
			wait.done();
		};*/
		currentModal.modal('close');
		//wait
		currentModal = "";
	}

};
<|endoftext|>


<commit_before>// import {readFile} from 'fs';
import test from 'ava';
// import isPromise from 'is-promise';
import {processing, read} from './utils';
import beautify from '../src';

test('plugin beautify must be function', t => {
    t.plan(2);
    t.true(typeof beautify === 'function');
    t.true(typeof beautify() === 'function');
});

test('plugin beautify should return Error with use option sync', t => {
    const error = t.throws(() => {
        beautify()();
    }, TypeError);

    t.is(error.message, 'tree is not Array');
});

test('plugin beautify should return the passed value with use option sync', t => {
    const tree = [];

    t.deepEqual(tree, beautify()(tree));
});

test('processing with plugin beautify should not lost native api', async t => {
    t.plan(3);
    const fixture = '

\n\n

';
    t.true(
        Object.prototype.hasOwnProperty.call(
            (await processing(fixture, [beautify({rules: {eof: false}})])).tree,
            'walk'
        )
    );
    t.true(
        Object.prototype.hasOwnProperty.call(
            (await processing(fixture, [beautify({rules: {eof: false}})])).tree,
            'match'
        )
    );
});

test('processing with plugin beautify should return equal html', async t => {
    const fixture = '

\n\n

';
    t.deepEqual(fixture, (await processing(fixture, [beautify({rules: {eof: false}})])).html);
});

test('processing with plugin beautify should removing trailing slash in self-closing', async t => {
    const fixture = '';
    const expected = '';
    t.deepEqual(expected, (await processing(fixture, [beautify({rules: {eof: false}})])).html);
});

test('processing with plugin beautify should removing empty attribute', async t => {
    const fixture = '';
    const expected = '';
    t.deepEqual(expected, (await processing(fixture, [beautify({rules: {eof: false}, mini: {removeAttribute: 'empty'}})])).html);
});

test('processing with plugin beautify should removes spaces at the equal sign', async t => {
    const fixture = '';
    const expected = '';
    t.deepEqual(expected, (await processing(fixture, [beautify({rules: {eof: false}})])).html);
});

test('processing with plugin beautify should return boolean attribute', async t => {
    const fixture = '<input type="email" required>';
    const expected = '<input type="email" required>';
    t.deepEqual(expected, (await processing(fixture, [beautify({rules: {eof: false}})])).html);
});

test('processing with plugin beautify should return trim attribute', async t => {
    const fixture = '';
    const expected = '';
    t.deepEqual(expected, (await processing(fixture, [beautify({rules: {eof: false}})])).html);
});

test('processing with plugin beautify should transform lower case attribute names', async t => {
    const fixture = '

';
    const expected = '

';
    t.deepEqual(expected, (await processing(fixture, [beautify({rules: {eof: false}})])).html);
});

test('processing with plugin beautify should transform lower case tag name', async t => {
    const fixture = '

';
    const expected = '

';
    t.deepEqual(expected, (await processing(fixture, [beautify({rules: {eof: false}})])).html);
});

test('processing with plugin beautify should return with indent', async t => {
    t.deepEqual(
        (await read('test/expected/output-indent.html')),
        (await processing(await read('test/fixtures/input-indent.html'), [beautify()])).html
    );
});

test('processing with plugin beautify should return with without blankLines', async t => {
    t.deepEqual(
        (await read('test/expected/output-blank-lines.html')),
        (await processing(await read('test/fixtures/input-blank-lines.html'), [beautify({rules: {blankLines: false}})])).html
    );
});

test('processing with plugin beautify and modules should return equal html using plugin posthtml-modules', async t => {
    t.deepEqual(
        (await read('test/expected/output-posthtml-modules.html')),
        (await processing(await read('test/fixtures/input-posthtml-modules.html'), [require('posthtml-modules')(), beautify()])).html
    );
});

test('processing with plugin beautify and include should return equal html using plugin posthtml-include', async t => {
    const expected = await read('test/expected/output-posthtml-include.html');
    const fixtures = (await processing(await read('test/fixtures/input-posthtml-include.html'), [require('posthtml-include')(), beautify()])).html;
    t.deepEqual(expected, fixtures);
});

test('processing with plugin beautify and include should return equal html which IE conditional comment', async t => {
    const expected = await read('test/expected/output-conditional-comment.html');
    const fixtures = (await processing(await read('test/fixtures/input-conditional-comment.html'), [require('posthtml-include')(), beautify()])).html;
    t.deepEqual(expected, fixtures);
});
<commit_msg>test: fix forgot change plain<commit_after>// import {readFile} from 'fs';
import test from 'ava';
// import isPromise from 'is-promise';
import {processing, read} from './utils';
import beautify from '../src';

test('plugin beautify must be function', t => {
    t.plan(2);
    t.true(typeof beautify === 'function');
    t.true(typeof beautify() === 'function');
});

test('plugin beautify should return Error with use option sync', t => {
    const error = t.throws(() => {
        beautify()();
    }, TypeError);

    t.is(error.message, 'tree is not Array');
});

test('plugin beautify should return the passed value with use option sync', t => {
    const tree = [];

    t.deepEqual(tree, beautify()(tree));
});

test('processing with plugin beautify should not lost native api', async t => {
    t.plan(2);
    const fixture = '

\n\n

';
    t.true(
        Object.prototype.hasOwnProperty.call(
            (await processing(fixture, [beautify({rules: {eof: false}})])).tree,
            'walk'
        )
    );
    t.true(
        Object.prototype.hasOwnProperty.call(
            (await processing(fixture, [beautify({rules: {eof: false}})])).tree,
            'match'
        )
    );
});

test('processing with plugin beautify should return equal html', async t => {
    const fixture = '

\n\n

';
    t.deepEqual(fixture, (await processing(fixture, [beautify({rules: {eof: false}})])).html);
});

test('processing with plugin beautify should removing trailing slash in self-closing', async t => {
    const fixture = '';
    const expected = '';
    t.deepEqual(expected, (await processing(fixture, [beautify({rules: {eof: false}})])).html);
});

test('processing with plugin beautify should removing empty attribute', async t => {
    const fixture = '';
    const expected = '';
    t.deepEqual(expected, (await processing(fixture, [beautify({rules: {eof: false}, mini: {removeAttribute: 'empty'}})])).html);
});

test('processing with plugin beautify should removes spaces at the equal sign', async t => {
    const fixture = '';
    const expected = '';
    t.deepEqual(expected, (await processing(fixture, [beautify({rules: {eof: false}})])).html);
});

test('processing with plugin beautify should return boolean attribute', async t => {
    const fixture = '<input type="email" required>';
    const expected = '<input type="email" required>';
    t.deepEqual(expected, (await processing(fixture, [beautify({rules: {eof: false}})])).html);
});

test('processing with plugin beautify should return trim attribute', async t => {
    const fixture = '';
    const expected = '';
    t.deepEqual(expected, (await processing(fixture, [beautify({rules: {eof: false}})])).html);
});

test('processing with plugin beautify should transform lower case attribute names', async t => {
    const fixture = '

';
    const expected = '

';
    t.deepEqual(expected, (await processing(fixture, [beautify({rules: {eof: false}})])).html);
});

test('processing with plugin beautify should transform lower case tag name', async t => {
    const fixture = '

';
    const expected = '

';
    t.deepEqual(expected, (await processing(fixture, [beautify({rules: {eof: false}})])).html);
});

test('processing with plugin beautify should return with indent', async t => {
    t.deepEqual(
        (await read('test/expected/output-indent.html')),
        (await processing(await read('test/fixtures/input-indent.html'), [beautify()])).html
    );
});

test('processing with plugin beautify should return with without blankLines', async t => {
    t.deepEqual(
        (await read('test/expected/output-blank-lines.html')),
        (await processing(await read('test/fixtures/input-blank-lines.html'), [beautify({rules: {blankLines: false}})])).html
    );
});

test('processing with plugin beautify and modules should return equal html using plugin posthtml-modules', async t => {
    t.deepEqual(
        (await read('test/expected/output-posthtml-modules.html')),
        (await processing(await read('test/fixtures/input-posthtml-modules.html'), [require('posthtml-modules')(), beautify()])).html
    );
});

test('processing with plugin beautify and include should return equal html using plugin posthtml-include', async t => {
    const expected = await read('test/expected/output-posthtml-include.html');
    const fixtures = (await processing(await read('test/fixtures/input-posthtml-include.html'), [require('posthtml-include')(), beautify()])).html;
    t.deepEqual(expected, fixtures);
});

test('processing with plugin beautify and include should return equal html which IE conditional comment', async t => {
    const expected = await read('test/expected/output-conditional-comment.html');
    const fixtures = (await processing(await read('test/fixtures/input-conditional-comment.html'), [require('posthtml-include')(), beautify()])).html;
    t.deepEqual(expected, fixtures);
});
<|endoftext|>


<commit_before>import { Settings } from "api"
import Model, {
  createYupObjectShape,
  NOTE_TYPE,
  yupDate
} from "components/Model"
import _isEmpty from "lodash/isEmpty"
import { Report } from "models"
import TASKS_ICON from "resources/tasks.png"
import utils from "utils"
import * as yup from "yup"

function createTaskAssessmentSchema(customFieldsConfig) {
  const taskAssessmentSchemaShape = createYupObjectShape(
    customFieldsConfig,
    "taskAssessment"
  )
  return yup.object().shape({
    taskAssessment: taskAssessmentSchemaShape
  })
}

export const {
  shortLabel,
  longLabel,
  customFieldRef1,
  customField,
  customFieldEnum1,
  customFieldEnum2,
  plannedCompletion,
  projectedCompletion,
  responsiblePositions
} = Settings.fields.task

export default class Task extends Model {
  static resourceName = "Task"
  static listName = "taskList"
  static getInstanceName = "task"
  static relatedObjectType = "tasks"

  static displayName() {
    return shortLabel
  }

  static STATUS = {
    ACTIVE: "ACTIVE",
    INACTIVE: "INACTIVE"
  }

  static APPROVAL_STEP_TYPE = {
    PLANNING_APPROVAL: "PLANNING_APPROVAL",
    REPORT_APPROVAL: "REPORT_APPROVAL"
  }

  // create yup schema for the customFields, based on the customFields config
  static customFieldsSchema = createYupObjectShape(
    Settings.fields.task.customFields
  )

  static topLevelAssessmentCustomFieldsSchema = createTaskAssessmentSchema(
    Settings.fields.task.topLevel.assessment.customFields
  )

  static subLevelAssessmentCustomFieldsSchema = createTaskAssessmentSchema(
    Settings.fields.task.subLevel.assessment.customFields
  )

  static yupSchema = yup
    .object()
    .shape({
      shortName: yup
        .string()
        .required()
        .default("")
        .label(Settings.fields.task.shortName.label),
      longName: yup
        .string()
        .nullable()
        .default("")
        .label(Settings.fields.task.longName.label),
      category: yup.string().nullable().default(""),
      taskedOrganizations: yup
        .array()
        .nullable()
        .default([])
        .label(Settings.fields.task.taskedOrganizations.label),
      customFieldRef1: yup
        .object()
        .nullable()
        .default({})
        .label(customFieldRef1 && customFieldRef1.label),
      customFieldEnum1: yup
        .string()
        .nullable()
        .default("")
        .label(customFieldEnum1 && customFieldEnum1.label),
      customFieldEnum2: yup
        .string()
        .nullable()
        .default("")
        .label(customFieldEnum2 && customFieldEnum2.label),
      customField: yup
        .string()
        .nullable()
        .default("")
        .label(customField && customField.label),
      projectedCompletion: yupDate
        .nullable()
        .default(null)
        .label(projectedCompletion && projectedCompletion.label),
      plannedCompletion: yupDate
        .nullable()
        .default(null)
        .label(plannedCompletion && plannedCompletion.label),
      status: yup
        .string()
        .required()
        .default(() => Task.STATUS.ACTIVE),
      responsiblePositions: yup
        .array()
        .nullable()
        .default([])
        .label(responsiblePositions && responsiblePositions.label),
      // FIXME: resolve code duplication in yup schema for approval steps
      planningApprovalSteps: yup
        .array()
        .of(
          yup.object().shape({
            name: yup
              .string()
              .required("You must provide the step name")
              .default(""),
            type: yup
              .string()
              .required()
              .default(() => Task.APPROVAL_STEP_TYPE.PLANNING_APPROVAL),
            approvers: yup
              .array()
              .required("You must select at least one approver")
              .default([])
          })
        )
        .nullable()
        .default([]),
      approvalSteps: yup
        .array()
        .of(
          yup.object().shape({
            name: yup
              .string()
              .required("You must provide the step name")
              .default(""),
            type: yup
              .string()
              .required()
              .default(() => Task.APPROVAL_STEP_TYPE.REPORT_APPROVAL),
            approvers: yup
              .array()
              .required("You must select at least one approver")
              .default([])
          })
        )
        .nullable()
        .default([]),
      // not actually in the database, the database contains the JSON customFields
      formCustomFields: Task.customFieldsSchema.nullable()
    })
    .concat(Model.yupSchema)

  static autocompleteQuery =
    "uuid, shortName, longName, customFieldRef1 { uuid, shortName } taskedOrganizations { uuid, shortName }, customFields"

  static humanNameOfStatus(status) {
    return utils.sentenceCase(status)
  }

  constructor(props) {
    super(Model.fillObject(props, Task.yupSchema))
  }

  isTopLevelTask() {
    return _isEmpty(this.customFieldRef1)
  }

  fieldSettings() {
    return this.isTopLevelTask()
      ? Settings.fields.task.topLevel
      : Settings.fields.task.subLevel
  }

  periodAssessmentYupSchema() {
    return this.isTopLevelTask()
      ? Task.topLevelAssessmentCustomFieldsSchema
      : Task.subLevelAssessmentCustomFieldsSchema
  }

  periodAssessmentConfig() {
    return this.fieldSettings().assessment?.customFields
  }

  iconUrl() {
    return TASKS_ICON
  }

  toString() {
    return `${this.shortName}`
  }

  getAssessmentResults(dateRange) {
    const publishedReportsUuids = this.publishedReports.map(r => r.uuid)
    const taskAssessmentNotes = this.notes
      .filter(
        n =>
          n.type === NOTE_TYPE.ASSESSMENT &&
          n.noteRelatedObjects.length === 2 &&
          n.noteRelatedObjects.filter(
            ro =>
              ro.relatedObjectType === Report.relatedObjectType &&
              publishedReportsUuids.includes(ro.relatedObjectUuid)
          ).length &&
          (!dateRange ||
            (n.createdAt <= dateRange.end && n.createdAt >= dateRange.start))
      )
      .map(ta => JSON.parse(ta.text))
    const assessmentResults = {}
    taskAssessmentNotes.forEach(o =>
      Object.keys(o).forEach(k => {
        assessmentResults[k] = assessmentResults[k] || []
        assessmentResults[k].push(o[k])
      })
    )
    return assessmentResults
  }

  getLastAssessment(dateRange) {
    const notesToAssessments = this.notes
      .filter(n => {
        return (
          n.type === NOTE_TYPE.ASSESSMENT &&
          n.noteRelatedObjects.length === 1 &&
          (!dateRange ||
            (n.createdAt <= dateRange.end && n.createdAt >= dateRange.start))
        )
      })
      .sort((a, b) => b.createdAt - a.createdAt) // desc sorted
      .map(ta => ({
        uuid: ta.uuid,
        assessment: JSON.parse(ta.text)
      }))
    return notesToAssessments.length ? notesToAssessments[0].assessment : null
  }
}
<commit_msg>NCI-Agency/anet#2926: Fix validation of add assessment form<commit_after>import { Settings } from "api"
import Model, {
  createYupObjectShape,
  NOTE_TYPE,
  yupDate
} from "components/Model"
import _isEmpty from "lodash/isEmpty"
import { Report } from "models"
import TASKS_ICON from "resources/tasks.png"
import utils from "utils"
import * as yup from "yup"

function createTaskAssessmentSchema(customFieldsConfig) {
  const taskAssessmentSchemaShape = createYupObjectShape(
    customFieldsConfig,
    "entityAssessment"
  )
  return yup.object().shape({
    entityAssessment: taskAssessmentSchemaShape
  })
}

export const {
  shortLabel,
  longLabel,
  customFieldRef1,
  customField,
  customFieldEnum1,
  customFieldEnum2,
  plannedCompletion,
  projectedCompletion,
  responsiblePositions
} = Settings.fields.task

export default class Task extends Model {
  static resourceName = "Task"
  static listName = "taskList"
  static getInstanceName = "task"
  static relatedObjectType = "tasks"

  static displayName() {
    return shortLabel
  }

  static STATUS = {
    ACTIVE: "ACTIVE",
    INACTIVE: "INACTIVE"
  }

  static APPROVAL_STEP_TYPE = {
    PLANNING_APPROVAL: "PLANNING_APPROVAL",
    REPORT_APPROVAL: "REPORT_APPROVAL"
  }

  // create yup schema for the customFields, based on the customFields config
  static customFieldsSchema = createYupObjectShape(
    Settings.fields.task.customFields
  )

  static topLevelAssessmentCustomFieldsSchema = createTaskAssessmentSchema(
    Settings.fields.task.topLevel.assessment.customFields
  )

  static subLevelAssessmentCustomFieldsSchema = createTaskAssessmentSchema(
    Settings.fields.task.subLevel.assessment.customFields
  )

  static yupSchema = yup
    .object()
    .shape({
      shortName: yup
        .string()
        .required()
        .default("")
        .label(Settings.fields.task.shortName.label),
      longName: yup
        .string()
        .nullable()
        .default("")
        .label(Settings.fields.task.longName.label),
      category: yup.string().nullable().default(""),
      taskedOrganizations: yup
        .array()
        .nullable()
        .default([])
        .label(Settings.fields.task.taskedOrganizations.label),
      customFieldRef1: yup
        .object()
        .nullable()
        .default({})
        .label(customFieldRef1 && customFieldRef1.label),
      customFieldEnum1: yup
        .string()
        .nullable()
        .default("")
        .label(customFieldEnum1 && customFieldEnum1.label),
      customFieldEnum2: yup
        .string()
        .nullable()
        .default("")
        .label(customFieldEnum2 && customFieldEnum2.label),
      customField: yup
        .string()
        .nullable()
        .default("")
        .label(customField && customField.label),
      projectedCompletion: yupDate
        .nullable()
        .default(null)
        .label(projectedCompletion && projectedCompletion.label),
      plannedCompletion: yupDate
        .nullable()
        .default(null)
        .label(plannedCompletion && plannedCompletion.label),
      status: yup
        .string()
        .required()
        .default(() => Task.STATUS.ACTIVE),
      responsiblePositions: yup
        .array()
        .nullable()
        .default([])
        .label(responsiblePositions && responsiblePositions.label),
      // FIXME: resolve code duplication in yup schema for approval steps
      planningApprovalSteps: yup
        .array()
        .of(
          yup.object().shape({
            name: yup
              .string()
              .required("You must provide the step name")
              .default(""),
            type: yup
              .string()
              .required()
              .default(() => Task.APPROVAL_STEP_TYPE.PLANNING_APPROVAL),
            approvers: yup
              .array()
              .required("You must select at least one approver")
              .default([])
          })
        )
        .nullable()
        .default([]),
      approvalSteps: yup
        .array()
        .of(
          yup.object().shape({
            name: yup
              .string()
              .required("You must provide the step name")
              .default(""),
            type: yup
              .string()
              .required()
              .default(() => Task.APPROVAL_STEP_TYPE.REPORT_APPROVAL),
            approvers: yup
              .array()
              .required("You must select at least one approver")
              .default([])
          })
        )
        .nullable()
        .default([]),
      // not actually in the database, the database contains the JSON customFields
      formCustomFields: Task.customFieldsSchema.nullable()
    })
    .concat(Model.yupSchema)

  static autocompleteQuery =
    "uuid, shortName, longName, customFieldRef1 { uuid, shortName } taskedOrganizations { uuid, shortName }, customFields"

  static humanNameOfStatus(status) {
    return utils.sentenceCase(status)
  }

  constructor(props) {
    super(Model.fillObject(props, Task.yupSchema))
  }

  isTopLevelTask() {
    return _isEmpty(this.customFieldRef1)
  }

  fieldSettings() {
    return this.isTopLevelTask()
      ? Settings.fields.task.topLevel
      : Settings.fields.task.subLevel
  }

  periodAssessmentYupSchema() {
    return this.isTopLevelTask()
      ? Task.topLevelAssessmentCustomFieldsSchema
      : Task.subLevelAssessmentCustomFieldsSchema
  }

  periodAssessmentConfig() {
    return this.fieldSettings().assessment?.customFields
  }

  iconUrl() {
    return TASKS_ICON
  }

  toString() {
    return `${this.shortName}`
  }

  getAssessmentResults(dateRange) {
    const publishedReportsUuids = this.publishedReports.map(r => r.uuid)
    const taskAssessmentNotes = this.notes
      .filter(
        n =>
          n.type === NOTE_TYPE.ASSESSMENT &&
          n.noteRelatedObjects.length === 2 &&
          n.noteRelatedObjects.filter(
            ro =>
              ro.relatedObjectType === Report.relatedObjectType &&
              publishedReportsUuids.includes(ro.relatedObjectUuid)
          ).length &&
          (!dateRange ||
            (n.createdAt <= dateRange.end && n.createdAt >= dateRange.start))
      )
      .map(ta => JSON.parse(ta.text))
    const assessmentResults = {}
    taskAssessmentNotes.forEach(o =>
      Object.keys(o).forEach(k => {
        assessmentResults[k] = assessmentResults[k] || []
        assessmentResults[k].push(o[k])
      })
    )
    return assessmentResults
  }

  getLastAssessment(dateRange) {
    const notesToAssessments = this.notes
      .filter(n => {
        return (
          n.type === NOTE_TYPE.ASSESSMENT &&
          n.noteRelatedObjects.length === 1 &&
          (!dateRange ||
            (n.createdAt <= dateRange.end && n.createdAt >= dateRange.start))
        )
      })
      .sort((a, b) => b.createdAt - a.createdAt) // desc sorted
      .map(ta => ({
        uuid: ta.uuid,
        assessment: JSON.parse(ta.text)
      }))
    return notesToAssessments.length ? notesToAssessments[0].assessment : null
  }
}
<|endoftext|>


<commit_before>// ==UserScript==
// @name       ZJU-CS-WEB
// @namespace  http://www.senorsen.com
// @version    0.3.5alpha2
// @description  Make ZJU-Computer science basic course webpage more beautiful & compatible in mordern browsers.
// @match      http://blackwhite.8866.org/cstcx/web/index.asp?*
// @match      http://10.71.45.100/cstcx/web/index.asp?*
// @match      http://blackwhite.8866.org/
// @match      http://10.71.45.100/
// @match      http://10.77.30.31/
// @match      http://10.77.30.33/
// @match      http://10.77.30.30/
// @updateURL   https://userscripts.org/scripts/source/178811.meta.js
// @downloadURL https://userscripts.org/scripts/source/178811.user.js
// @copyright  2013-2014, Senorsen
// @run-at document-body
// ==/UserScript==

/**
 * ZJU-CSWEB Tempermonkey Javascript
 * @author Senorsen
 * @link http://project.qsc.senorsen.com
 * @description
 **/
var url_wrap = 'http://project.qsc.senorsen.com/zju-csweb/source/';
/* Lazyload js: https://github.com/rgrove/lazyload */
LazyLoad=(function(doc){var env,head,pending={},pollCount=0,queue={css:[],js:[]},styleSheets=doc.styleSheets;function createNode(name,attrs){var node=doc.createElement(name),attr;for(attr in attrs){if(attrs.hasOwnProperty(attr)){node.setAttribute(attr,attrs[attr])}}return node}function finish(type){var p=pending[type],callback,urls;if(p){callback=p.callback;urls=p.urls;urls.shift();pollCount=0;if(!urls.length){callback&&callback.call(p.context,p.obj);pending[type]=null;queue[type].length&&load(type)}}}function getEnv(){var ua=navigator.userAgent;env={async:doc.createElement('script').async===true};(env.webkit=/AppleWebKit\//.test(ua))||(env.ie=/MSIE|Trident/.test(ua))||(env.opera=/Opera/.test(ua))||(env.gecko=/Gecko\//.test(ua))||(env.unknown=true)}function load(type,urls,callback,obj,context){var _finish=function(){finish(type)},isCSS=type==='css',nodes=[],i,len,node,p,pendingUrls,url;env||getEnv();if(urls){urls=typeof urls==='string'?[urls]:urls.concat();if(isCSS||env.async||env.gecko||env.opera){queue[type].push({urls:urls,callback:callback,obj:obj,context:context})}else{for(i=0,len=urls.length;i<len;++i){queue[type].push({urls:[urls[i]],callback:i===len-1?callback:null,obj:obj,context:context})}}}if(pending[type]||!(p=pending[type]=queue[type].shift())){return}head||(head=doc.head||doc.getElementsByTagName('head')[0]);pendingUrls=p.urls.concat();for(i=0,len=pendingUrls.length;i<len;++i){url=pendingUrls[i];if(isCSS){node=env.gecko?createNode('style'):createNode('link',{href:url,rel:'stylesheet'})}else{node=createNode('script',{src:url});node.async=false}node.className='lazyload';node.setAttribute('charset','utf-8');if(env.ie&&!isCSS&&'onreadystatechange'in node&&!('draggable'in node)){node.onreadystatechange=function(){if(/loaded|complete/.test(node.readyState)){node.onreadystatechange=null;_finish()}}}else if(isCSS&&(env.gecko||env.webkit)){if(env.webkit){p.urls[i]=node.href;pollWebKit()}else{node.innerHTML='@import "'+url+'";';pollGecko(node)}}else{node.onload=node.onerror=_finish}nodes.push(node)}for(i=0,len=nodes.length;i<len;++i){head.appendChild(nodes[i])}}function pollGecko(node){var hasRules;try{hasRules=!!node.sheet.cssRules}catch(ex){pollCount+=1;if(pollCount<200){setTimeout(function(){pollGecko(node)},50)}else{hasRules&&finish('css')}return}finish('css')}function pollWebKit(){var css=pending.css,i;if(css){i=styleSheets.length;while(--i>=0){if(styleSheets[i].href===css.urls[0]){finish('css');break}}pollCount+=1;if(css){if(pollCount<200){setTimeout(pollWebKit,50)}else{finish('css')}}}}return{css:function(urls,callback,obj,context){load('css',urls,callback,obj,context)},js:function(urls,callback,obj,context){load('js',urls,callback,obj,context)}}})(this.document);
var js_path = [url_wrap + 'all.js'];
LazyLoad.js(js_path);

<commit_msg>roll to 0.3.5beta1<commit_after>// ==UserScript==
// @name       ZJU-CS-WEB
// @namespace  http://www.senorsen.com
// @version    0.3.5beta1
// @description  Make ZJU-Computer science basic course webpage more beautiful & compatible in mordern browsers.
// @match      http://blackwhite.8866.org/cstcx/web/index.asp?*
// @match      http://10.71.45.100/cstcx/web/index.asp?*
// @match      http://blackwhite.8866.org/
// @match      http://10.71.45.100/
// @match      http://10.77.30.31/
// @match      http://10.77.30.33/
// @match      http://10.77.30.30/
// @updateURL   https://userscripts.org/scripts/source/178811.meta.js
// @downloadURL https://userscripts.org/scripts/source/178811.user.js
// @copyright  2013-2014, Senorsen
// @run-at document-body
// ==/UserScript==

/**
 * ZJU-CSWEB Tempermonkey Javascript
 * @author Senorsen
 * @link http://project.qsc.senorsen.com
 * @description
 **/
var url_wrap = 'http://project.qsc.senorsen.com/zju-csweb/source/';
/* Lazyload js: https://github.com/rgrove/lazyload */
LazyLoad=(function(doc){var env,head,pending={},pollCount=0,queue={css:[],js:[]},styleSheets=doc.styleSheets;function createNode(name,attrs){var node=doc.createElement(name),attr;for(attr in attrs){if(attrs.hasOwnProperty(attr)){node.setAttribute(attr,attrs[attr])}}return node}function finish(type){var p=pending[type],callback,urls;if(p){callback=p.callback;urls=p.urls;urls.shift();pollCount=0;if(!urls.length){callback&&callback.call(p.context,p.obj);pending[type]=null;queue[type].length&&load(type)}}}function getEnv(){var ua=navigator.userAgent;env={async:doc.createElement('script').async===true};(env.webkit=/AppleWebKit\//.test(ua))||(env.ie=/MSIE|Trident/.test(ua))||(env.opera=/Opera/.test(ua))||(env.gecko=/Gecko\//.test(ua))||(env.unknown=true)}function load(type,urls,callback,obj,context){var _finish=function(){finish(type)},isCSS=type==='css',nodes=[],i,len,node,p,pendingUrls,url;env||getEnv();if(urls){urls=typeof urls==='string'?[urls]:urls.concat();if(isCSS||env.async||env.gecko||env.opera){queue[type].push({urls:urls,callback:callback,obj:obj,context:context})}else{for(i=0,len=urls.length;i<len;++i){queue[type].push({urls:[urls[i]],callback:i===len-1?callback:null,obj:obj,context:context})}}}if(pending[type]||!(p=pending[type]=queue[type].shift())){return}head||(head=doc.head||doc.getElementsByTagName('head')[0]);pendingUrls=p.urls.concat();for(i=0,len=pendingUrls.length;i<len;++i){url=pendingUrls[i];if(isCSS){node=env.gecko?createNode('style'):createNode('link',{href:url,rel:'stylesheet'})}else{node=createNode('script',{src:url});node.async=false}node.className='lazyload';node.setAttribute('charset','utf-8');if(env.ie&&!isCSS&&'onreadystatechange'in node&&!('draggable'in node)){node.onreadystatechange=function(){if(/loaded|complete/.test(node.readyState)){node.onreadystatechange=null;_finish()}}}else if(isCSS&&(env.gecko||env.webkit)){if(env.webkit){p.urls[i]=node.href;pollWebKit()}else{node.innerHTML='@import "'+url+'";';pollGecko(node)}}else{node.onload=node.onerror=_finish}nodes.push(node)}for(i=0,len=nodes.length;i<len;++i){head.appendChild(nodes[i])}}function pollGecko(node){var hasRules;try{hasRules=!!node.sheet.cssRules}catch(ex){pollCount+=1;if(pollCount<200){setTimeout(function(){pollGecko(node)},50)}else{hasRules&&finish('css')}return}finish('css')}function pollWebKit(){var css=pending.css,i;if(css){i=styleSheets.length;while(--i>=0){if(styleSheets[i].href===css.urls[0]){finish('css');break}}pollCount+=1;if(css){if(pollCount<200){setTimeout(pollWebKit,50)}else{finish('css')}}}}return{css:function(urls,callback,obj,context){load('css',urls,callback,obj,context)},js:function(urls,callback,obj,context){load('js',urls,callback,obj,context)}}})(this.document);
var js_path = [url_wrap + 'all.js'];
LazyLoad.js(js_path);

<|endoftext|>


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

/**
 * This toggle button uses a boolean property and a trueNode and falseNode to display its content.
 */
define( function( require ) {
  'use strict';

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

  /**
   * @param {Node} trueNode
   * @param {Node} falseNode
   * @param booleanProperty
   * @param {Object} [options]
   * @constructor
   */
  function BooleanRectangularToggleButton( trueNode, falseNode, booleanProperty, options ) {

    options = _.extend( { tandem: Tandem.required }, options );

    assert && assert( !options.content, 'options.content cannot be set' );
    options.content = new BooleanToggleNode( trueNode, falseNode, booleanProperty, {
      tandem: options.tandem.createTandem( 'toggleNode' )
    } );

    RectangularToggleButton.call( this, false, true, booleanProperty, options );
  }

  sun.register( 'BooleanRectangularToggleButton', BooleanRectangularToggleButton );

  return inherit( RectangularToggleButton, BooleanRectangularToggleButton );
} );
<commit_msg>Implement dispose on BooleanRectangularToggleButton, see https://github.com/phetsims/sun/issues/121<commit_after>// Copyright 2013-2017, University of Colorado Boulder

/**
 * This toggle button uses a boolean property and a trueNode and falseNode to display its content.
 */
define( function( require ) {
  'use strict';

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

  /**
   * @param {Node} trueNode
   * @param {Node} falseNode
   * @param booleanProperty
   * @param {Object} [options]
   * @constructor
   */
  function BooleanRectangularToggleButton( trueNode, falseNode, booleanProperty, options ) {

    options = _.extend( { tandem: Tandem.required }, options );

    assert && assert( !options.content, 'options.content cannot be set' );
    options.content = new BooleanToggleNode( trueNode, falseNode, booleanProperty, {
      tandem: options.tandem.createTandem( 'toggleNode' )
    } );

    RectangularToggleButton.call( this, false, true, booleanProperty, options );

    // @private {function} - internally used disposal function
    this.disposeBooleanRectangularToggleButton = function() {
      options.content.dispose();
    };
  }

  sun.register( 'BooleanRectangularToggleButton', BooleanRectangularToggleButton );

  return inherit( RectangularToggleButton, BooleanRectangularToggleButton, {
    /**
     * @public
     */
    dispose: function() {
      this.disposeBooleanRectangularToggleButton();
      RectangularToggleButton.prototype.dispose.call( this );
    }
  } );
} );
<|endoftext|>


<commit_before>
// requestAnim shim layer by Paul Irish
window.requestAnimationFrame = (function(){
  return window.requestAnimationFrame      ||
        window.webkitRequestAnimationFrame ||
        window.mozRequestAnimationFrame    ||
        window.oRequestAnimationFrame      ||
        window.msRequestAnimationFrame     ||
        function(callback, element){
          // should '60' here be framerate?
          window.setTimeout(callback, 1000 / 60);
        };
})();

// use window.performance() to get max fast and accurate time in milliseconds
window.performance = window.performance || {};
window.performance.now = (function(){
  var load_date = Date.now();
  return window.performance.now        ||
        window.performance.mozNow      ||
        window.performance.msNow       ||
        window.performance.oNow        ||
        window.performance.webkitNow   ||
        function () {
          return Date.now() - load_date;
        };
})();

/*
// http://paulirish.com/2011/requestanimationframe-for-smart-animating/
// http://my.opera.com/emoller/blog/2011/12/20/
// requestanimationframe-for-smart-er-animating
// requestAnimationFrame polyfill by Erik Möller
// fixes from Paul Irish and Tino Zijdel
(function() {
  var lastTime = 0;
  var vendors = ['ms', 'moz', 'webkit', 'o'];
  for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
    window.requestAnimationFrame =
      window[vendors[x]+'RequestAnimationFrame'];
    window.cancelAnimationFrame =
      window[vendors[x]+'CancelAnimationFrame'] ||
      window[vendors[x]+'CancelRequestAnimationFrame'];
  }

  if (!window.requestAnimationFrame) {
    window.requestAnimationFrame = function(callback, element) {
      var currTime = new Date().getTime();
      var timeToCall = Math.max(0, 16 - (currTime - lastTime));
      var id = window.setTimeout(function()
        { callback(currTime + timeToCall); }, timeToCall);
      lastTime = currTime + timeToCall;
      return id;
    };
  }

  if (!window.cancelAnimationFrame) {
    window.cancelAnimationFrame = function(id) {
      clearTimeout(id);
    };
  }
}());
*/

/**
 * shim for Uint8ClampedArray.slice
 * (allows arrayCopy to work with pixels[])
 * with thanks to http://halfpapstudios.com/blog/tag/html5-canvas/
 */
(function () {
  'use strict';

  if (typeof Uint8ClampedArray !== 'undefined') {
    //Firefox and Chrome
    Uint8ClampedArray.prototype.slice = Array.prototype.slice;
  }
}());

<commit_msg>Fixes shim.js object pollution for for...in<commit_after>
// requestAnim shim layer by Paul Irish
window.requestAnimationFrame = (function(){
  return window.requestAnimationFrame      ||
        window.webkitRequestAnimationFrame ||
        window.mozRequestAnimationFrame    ||
        window.oRequestAnimationFrame      ||
        window.msRequestAnimationFrame     ||
        function(callback, element){
          // should '60' here be framerate?
          window.setTimeout(callback, 1000 / 60);
        };
})();

// use window.performance() to get max fast and accurate time in milliseconds
window.performance = window.performance || {};
window.performance.now = (function(){
  var load_date = Date.now();
  return window.performance.now        ||
        window.performance.mozNow      ||
        window.performance.msNow       ||
        window.performance.oNow        ||
        window.performance.webkitNow   ||
        function () {
          return Date.now() - load_date;
        };
})();

/*
// http://paulirish.com/2011/requestanimationframe-for-smart-animating/
// http://my.opera.com/emoller/blog/2011/12/20/
// requestanimationframe-for-smart-er-animating
// requestAnimationFrame polyfill by Erik Möller
// fixes from Paul Irish and Tino Zijdel
(function() {
  var lastTime = 0;
  var vendors = ['ms', 'moz', 'webkit', 'o'];
  for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
    window.requestAnimationFrame =
      window[vendors[x]+'RequestAnimationFrame'];
    window.cancelAnimationFrame =
      window[vendors[x]+'CancelAnimationFrame'] ||
      window[vendors[x]+'CancelRequestAnimationFrame'];
  }

  if (!window.requestAnimationFrame) {
    window.requestAnimationFrame = function(callback, element) {
      var currTime = new Date().getTime();
      var timeToCall = Math.max(0, 16 - (currTime - lastTime));
      var id = window.setTimeout(function()
        { callback(currTime + timeToCall); }, timeToCall);
      lastTime = currTime + timeToCall;
      return id;
    };
  }

  if (!window.cancelAnimationFrame) {
    window.cancelAnimationFrame = function(id) {
      clearTimeout(id);
    };
  }
}());
*/

/**
 * shim for Uint8ClampedArray.slice
 * (allows arrayCopy to work with pixels[])
 * with thanks to http://halfpapstudios.com/blog/tag/html5-canvas/
 * Enumerable set to false to protect for...in from
 * Uint8ClampedArray.prototype pollution.
 */
(function () {
  'use strict';
  if (typeof Uint8ClampedArray !== 'undefined' &&
      !Uint8ClampedArray.prototype.slice) {
    Object.defineProperty(Uint8ClampedArray.prototype, 'slice', {
      value: Array.prototype.slice,
      writable: true, configurable: true, enumerable: false
    });
  }
}());
<|endoftext|>


<commit_before>import test from 'ava'

import { setupPptrTab, teardownPptrTab, changeMode, getActiveTool }
from '../../tests/helpers'

const tool            = 'boxshadow'
const test_selector   = '[intro] b'

const getShadowValues = (str) => {
    const pattern = /([^\)]+\)) ([^\s]+) ([^\s]+) ([^\s]+) ([^\s]+)/
    const matches = pattern.exec(str)
    console.log(matches)
    return {
        color : matches[1],
        x : matches[2],
        y : matches[3],
        blur : matches[4],
        spread : matches[5],
    }
}

test.beforeEach(async t => {
  await setupPptrTab(t)

  await changeMode({
    tool,
    page: t.context.page,
  })
})

// test('Can Be Activated', async t => {
//   const { page } = t.context
//   t.is(await getActiveTool(page), tool)
//   t.pass()
// })

// test('Can adjust X position', async t => {
//   const { page } = t.context

//   await page.click(test_selector)

//   t.pass()
// })

test('Can adjust Y position', async t => {
  const { page } = t.context

  await page.click(test_selector)
  console.log(await page.$eval(test_selector, el => performance.now()))
  await page.keyboard.down('ArrowDown')
  await page.keyboard.up('ArrowDown')
  await page.waitFor(1000)
  await page.keyboard.down('ArrowDown')

  await page.keyboard.up('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.waitFor(1000)
  await page.keyboard.down('ArrowDown')

  await page.keyboard.up('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.waitFor(1000)
  await page.keyboard.down('ArrowDown')

  await page.keyboard.up('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.waitFor(1000)
  await page.keyboard.down('ArrowDown')

  await page.keyboard.up('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.keyboard.press('ArrowDown')
  await page.waitFor(10000)
  console.log(await page.$eval(test_selector, el => performance.now()))
  const shadowStr = await page.$eval(test_selector, el => el.style.boxShadow)
  const shadow = getShadowValues(shadowStr)
  t.true(shadow.y == "1px")

  t.pass()
})

test.afterEach(teardownPptrTab)
<commit_msg>filling out boxshadow tests<commit_after>import test from 'ava'

import { setupPptrTab, teardownPptrTab, changeMode, getActiveTool }
from '../../tests/helpers'

const tool            = 'boxshadow'
const test_selector   = '[intro] b'

const getShadowValues = (str) => {
    const pattern = /([^\)]+\)) ([^\s]+) ([^\s]+) ([^\s]+) ([^\s]+)/
    const matches = pattern.exec(str)

    return {
        color : matches[1],
        x : matches[2],
        y : matches[3],
        blur : matches[4],
        spread : matches[5],
    }
}

test.beforeEach(async t => {
  await setupPptrTab(t)

  await changeMode({
    tool,
    page: t.context.page,
  })
})

test('Can Be Activated', async t => {
  const { page } = t.context
  t.is(await getActiveTool(page), tool)
  t.pass()
})

test('Can adjust X position', async t => {
  const { page } = t.context

  await page.click(test_selector)
  await page.keyboard.press('ArrowRight')
  const shadowStr = await page.$eval(test_selector, el => el.style.boxShadow)
  const shadow = getShadowValues(shadowStr)
  t.true(shadow.x == "1px")

  t.pass()
})

test('Can adjust Y position', async t => {
  const { page } = t.context

  await page.click(test_selector)
  await page.keyboard.press('ArrowDown')
  const shadowStr = await page.$eval(test_selector, el => el.style.boxShadow)
  const shadow = getShadowValues(shadowStr)
  t.true(shadow.y == "1px")

  t.pass()
})

test('Shadow Blur Works', async t => {
  const { page } = t.context

  await page.click(test_selector)
  await page.keyboard.press('ArrowDown')
  await page.keyboard.down('Shift')
  await page.keyboard.press('ArrowUp')
  const shadowStr = await page.$eval(test_selector, el => el.style.boxShadow)
  const shadow = getShadowValues(shadowStr)
  console.log(shadow)
  t.true(shadow.blur == "1px")

  t.pass()
})

test('Shadow Spread Works', async t => {
  const { page } = t.context

  await page.click(test_selector)
  await page.keyboard.press('ArrowDown')
  await page.keyboard.down('Shift')
  await page.keyboard.press('ArrowRight')
  const shadowStr = await page.$eval(test_selector, el => el.style.boxShadow)
  const shadow = getShadowValues(shadowStr)
  t.true(shadow.spread == "1px")

  t.pass()
})

test.afterEach(teardownPptrTab)
<|endoftext|>


<commit_before>module.exports = function(min_width, callback) {
  var events = require('events');
  var _ = require('underscore');
  var Flickr = require('flickrapi');
  var ATOM = require('atom');
  var config = require('./config_provider');

  var emitter = new events.EventEmitter();

  min_width = min_width || 1920;

  var flickrOptions = {
    api_key: config.get('FLICKR_API_KEY'),
    secret: config.get('FLICKR_API_SECRET')
  };

  Flickr.tokenOnly(flickrOptions, function(error, flickr) {
    flickr.interestingness.getList({ perpage: 500, extras: ['url_o', 'url_z'] }, function(e, result) {
      var count = result.photos.photo.length;
      _.each(result.photos.photo, function(photo_info) {
        if(photo_info.url_o) {
          if(photo_info.width_o > min_width && (parseFloat(photo_info.width_o) / parseFloat(photo_info.height_o) >= 1.2)) {
            feed.item({
              id: photo_info.id,
              title: photo_info.title,
              content: [{
                _attr: {
                  type: 'html'
                }},
                '
' + photo_info.title + '
' +
                '

'
              ],
              date: new Date(),
              updated: new Date(),
              link: {
                _attr: {
                  rel: 'enclosure',
                  type: 'image/jpeg',
                  href: photo_info.url_o
                }
              },
              alternate: {
                _attr: {
                  rel: 'alternate',
                  type: 'text/html',
                  href: photo_info.url_o
                }
              }
            });
          }
        }
        count--;
        if(count === 0) {
          emitter.emit('feed-ready');
        }
      });
    });
  });

  var feedUrl = config.get('SERVER_ROOT') + '/explore.atom';

  var feed = new ATOM({
    title: "Flickr Explore",
    id: "tag: Flickr Explore",
    description: "Flickr Favorites in their original image sizes",
    feed_url: feedUrl,
    site_url: "https://www.flickr.com/explore",
    author: "Flickr"
  });

  emitter.on('feed-ready', function() {
    feed.items = _.sortBy(feed.items, 'date').reverse();
    callback(feed.xml('  '));
  });
};
<commit_msg>added dates to explore feed<commit_after>module.exports = function(min_width, callback) {
  var events = require('events');
  var _ = require('underscore');
  var Flickr = require('flickrapi');
  var ATOM = require('atom');
  var config = require('./config_provider');

  var emitter = new events.EventEmitter();

  min_width = min_width || 1920;

  var flickrOptions = {
    api_key: config.get('FLICKR_API_KEY'),
    secret: config.get('FLICKR_API_SECRET')
  };

  Flickr.tokenOnly(flickrOptions, function(error, flickr) {
    flickr.interestingness.getList({ perpage: 500, extras: ['url_o', 'url_z', 'date_upload', 'last_update'] }, function(e, result) {
      var count = result.photos.photo.length;
      _.each(result.photos.photo, function(photo_info) {
        console.log(photo_info.date_upload);
        console.log(photo_info.last_update);
        if(photo_info.url_o) {
          if(photo_info.width_o > min_width && (parseFloat(photo_info.width_o) / parseFloat(photo_info.height_o) >= 1.2)) {
            feed.item({
              id: photo_info.id,
              title: photo_info.title,
              content: [{
                _attr: {
                  type: 'html'
                }},
                '
' + photo_info.title + '
' +
                '

'
              ],
              date: new Date(photo_info.dateupload * 1000),
              updated: new Date(photo_info.lastupdate * 1000),
              link: {
                _attr: {
                  rel: 'enclosure',
                  type: 'image/jpeg',
                  href: photo_info.url_o
                }
              },
              alternate: {
                _attr: {
                  rel: 'alternate',
                  type: 'text/html',
                  href: photo_info.url_o
                }
              }
            });
          }
        }
        count--;
        if(count === 0) {
          emitter.emit('feed-ready');
        }
      });
    });
  });

  var feedUrl = config.get('SERVER_ROOT') + '/explore.atom';

  var feed = new ATOM({
    title: "Flickr Explore",
    id: "tag: Flickr Explore",
    description: "Flickr Favorites in their original image sizes",
    feed_url: feedUrl,
    site_url: "https://www.flickr.com/explore",
    author: "Flickr"
  });

  emitter.on('feed-ready', function() {
    feed.items = _.sortBy(feed.items, 'date').reverse();
    callback(feed.xml('  '));
  });
};
<|endoftext|>


<commit_before>var adjustRangeToInsert = require('ve-range-utils/adjustRangeToInsert');
var spliceString = require('string-splice');
var validateAndTidyUpSequenceData = require('./validateAndTidyUpSequenceData');
var ac = require('ve-api-check');
module.exports = function insertSequenceDataAtPosition(sequenceDataToInsert, existingSequenceData, caretPosition) {
    // ac.throw([
    //     ac.sequenceData,
    //     ac.sequenceData,
    //     ac.posInt
    // ], arguments);
    ac.throw(ac.postInt, caretPosition);
    sequenceDataToInsert = validateAndTidyUpSequenceData(sequenceDataToInsert);

    var newSequenceData = validateAndTidyUpSequenceData({}); //makes a new blank sequence

    var insertLength = sequenceDataToInsert.sequence.length;
    //splice the underlying sequence
    newSequenceData.sequence = spliceString(existingSequenceData.sequence, caretPosition, 0, sequenceDataToInsert.sequence);
    newSequenceData.features = newSequenceData.features.concat(adjustAnnotationsToInsert(existingSequenceData.features, caretPosition, insertLength));
    newSequenceData.parts = newSequenceData.parts.concat(adjustAnnotationsToInsert(existingSequenceData.parts, caretPosition, insertLength));
    newSequenceData.translations = newSequenceData.translations.concat(adjustAnnotationsToInsert(existingSequenceData.translations, caretPosition, insertLength));
    newSequenceData.features = newSequenceData.features.concat(adjustAnnotationsToInsert(sequenceDataToInsert.features, 0, caretPosition));
    newSequenceData.parts = newSequenceData.parts.concat(adjustAnnotationsToInsert(sequenceDataToInsert.parts, 0, caretPosition));
    newSequenceData.translations = newSequenceData.translations.concat(adjustAnnotationsToInsert(sequenceDataToInsert.translations, 0, caretPosition));
    // ac.throw(ac.sequenceData, newSequenceData) //tnr: passing it through this check before returning just to make sure everything is still okay
    return newSequenceData;
}

function adjustAnnotationsToInsert(annotationsToBeAdjusted, insertStart, insertLength) {
    ac.throw([ac.arrayOf(ac.range), ac.posInt, ac.posInt], arguments)
    return annotationsToBeAdjusted.map(function(annotation) {
        return adjustRangeToInsert(annotation, insertStart, insertLength);
    });
}<commit_msg>adding comment<commit_after>var adjustRangeToInsert = require('ve-range-utils/adjustRangeToInsert');
var spliceString = require('string-splice');
var validateAndTidyUpSequenceData = require('./validateAndTidyUpSequenceData');
var ac = require('ve-api-check');
module.exports = function insertSequenceDataAtPosition(sequenceDataToInsert, existingSequenceData, caretPosition) {
    // ac.throw([
    //     ac.sequenceData,
    //     ac.sequenceData,
    //     ac.posInt
    // ], arguments);
    // tnrtodo: add more validation here!
    ac.throw(ac.postInt, caretPosition);
    sequenceDataToInsert = validateAndTidyUpSequenceData(sequenceDataToInsert);

    var newSequenceData = validateAndTidyUpSequenceData({}); //makes a new blank sequence

    var insertLength = sequenceDataToInsert.sequence.length;
    //splice the underlying sequence
    newSequenceData.sequence = spliceString(existingSequenceData.sequence, caretPosition, 0, sequenceDataToInsert.sequence);
    newSequenceData.features = newSequenceData.features.concat(adjustAnnotationsToInsert(existingSequenceData.features, caretPosition, insertLength));
    newSequenceData.parts = newSequenceData.parts.concat(adjustAnnotationsToInsert(existingSequenceData.parts, caretPosition, insertLength));
    newSequenceData.translations = newSequenceData.translations.concat(adjustAnnotationsToInsert(existingSequenceData.translations, caretPosition, insertLength));
    newSequenceData.features = newSequenceData.features.concat(adjustAnnotationsToInsert(sequenceDataToInsert.features, 0, caretPosition));
    newSequenceData.parts = newSequenceData.parts.concat(adjustAnnotationsToInsert(sequenceDataToInsert.parts, 0, caretPosition));
    newSequenceData.translations = newSequenceData.translations.concat(adjustAnnotationsToInsert(sequenceDataToInsert.translations, 0, caretPosition));
    // ac.throw(ac.sequenceData, newSequenceData) //tnr: passing it through this check before returning just to make sure everything is still okay
    return newSequenceData;
}

function adjustAnnotationsToInsert(annotationsToBeAdjusted, insertStart, insertLength) {
    ac.throw([ac.arrayOf(ac.range), ac.posInt, ac.posInt], arguments)
    return annotationsToBeAdjusted.map(function(annotation) {
        return adjustRangeToInsert(annotation, insertStart, insertLength);
    });
}<|endoftext|>


<commit_before>// mobafire.js -- champion guide shortcut for Mobafire
//
// Copyright (C) 2015 Dan Poggi
//
// This software may be modified and distributed under the terms
// of the MIT license. See the LICENSE file for details.

(function () {
  var name, key, id;

  // In the event of new champions, get_champ_ids.rb will generate
  // an up-to-date version of this object.
  const champIds = {
    "aatrox": 114,
    "ahri": 89,
    "akali": 50,
    "alistar": 4,
    "amumu": 23,
    "anivia": 25,
    "annie": 1,
    "ashe": 13,
    "azir": 121,
    "bard": 124,
    "blitzcrank": 34,
    "brand": 74,
    "braum": 119,
    "caitlyn": 67,
    "cassiopeia": 66,
    "chogath": 22,
    "corki": 31,
    "darius": 98,
    "diana": 102,
    "dr mundo": 26,
    "draven": 99,
    "ekko": 125,
    "elise": 106,
    "evelynn": 19,
    "ezreal": 47,
    "fiddlesticks": 38,
    "fiora": 94,
    "fizz": 87,
    "galio": 57,
    "gangplank": 30,
    "garen": 51,
    "gnar": 120,
    "gragas": 45,
    "graves": 85,
    "hecarim": 96,
    "heimerdinger": 40,
    "illaoi": 128,
    "irelia": 64,
    "janna": 29,
    "jarvan iv": 71,
    "jax": 15,
    "jayce": 100,
    "jinx": 116,
    "kalista": 122,
    "karma": 69,
    "karthus": 21,
    "kassadin": 27,
    "katarina": 36,
    "kayle": 2,
    "kennen": 49,
    "khazix": 105,
    "kindred": 127,
    "kogmaw": 54,
    "leblanc": 63,
    "lee sin": 73,
    "leona": 79,
    "lissandra": 113,
    "lucian": 115,
    "lulu": 95,
    "lux": 62,
    "malphite": 35,
    "malzahar": 52,
    "maokai": 70,
    "master yi": 3,
    "miss fortune": 59,
    "mordekaiser": 46,
    "morgana": 16,
    "nami": 108,
    "nasus": 37,
    "nautilus": 93,
    "nidalee": 42,
    "nocturne": 72,
    "nunu": 12,
    "olaf": 53,
    "orianna": 77,
    "pantheon": 44,
    "poppy": 43,
    "quinn": 111,
    "rammus": 24,
    "reksai": 123,
    "renekton": 68,
    "rengar": 103,
    "riven": 83,
    "rumble": 75,
    "ryze": 5,
    "sejuani": 91,
    "shaco": 41,
    "shen": 48,
    "shyvana": 86,
    "singed": 18,
    "sion": 6,
    "sivir": 7,
    "skarner": 81,
    "sona": 60,
    "soraka": 8,
    "swain": 61,
    "syndra": 104,
    "tahm kench": 126,
    "talon": 82,
    "taric": 32,
    "teemo": 9,
    "thresh": 110,
    "tristana": 10,
    "trundle": 65,
    "tryndamere": 14,
    "twisted fate": 28,
    "twitch": 20,
    "udyr": 39,
    "urgot": 58,
    "varus": 97,
    "vayne": 76,
    "veigar": 33,
    "velkoz": 118,
    "vi": 109,
    "viktor": 90,
    "vladimir": 56,
    "volibear": 88,
    "warwick": 11,
    "wukong": 80,
    "xerath": 84,
    "xin zhao": 55,
    "yasuo": 117,
    "yorick": 78,
    "zac": 112,
    "zed": 107,
    "ziggs": 92,
    "zilean": 17,
    "zyra": 101
  };

  function champKey(name) {
    return name.toLowerCase().replace(/[^a-z ]/g, "");
  }
  function champUrl(id) {
    return "http://www.mobafire.com/league-of-legends/browse?sort_type=score_weighted&sort_order=&champion_id=" + id + "&lane=&role=&map=&guide_type=&threshold=all&freshness=S6&author=";
  }

  // Will jump directly to top rated guides/builds, Season 6 only, for
  // a given champion. Saves 4-5 page loads depending where you're at.
  name = prompt("Enter champion name:");
  if (name !== null && name !== "") {
    key = champKey(name);
    id = champIds[key];

    if (typeof id !== "undefined") {
      window.location.href = champURL(champName);
    }
  }
})();
<commit_msg>Mobafire typo<commit_after>// mobafire.js -- champion guide shortcut for Mobafire
//
// Copyright (C) 2015 Dan Poggi
//
// This software may be modified and distributed under the terms
// of the MIT license. See the LICENSE file for details.

(function () {
  var name, key, id;

  // In the event of new champions, get_champ_ids.rb will generate
  // an up-to-date version of this object.
  const champIds = {
    "aatrox": 114,
    "ahri": 89,
    "akali": 50,
    "alistar": 4,
    "amumu": 23,
    "anivia": 25,
    "annie": 1,
    "ashe": 13,
    "azir": 121,
    "bard": 124,
    "blitzcrank": 34,
    "brand": 74,
    "braum": 119,
    "caitlyn": 67,
    "cassiopeia": 66,
    "chogath": 22,
    "corki": 31,
    "darius": 98,
    "diana": 102,
    "dr mundo": 26,
    "draven": 99,
    "ekko": 125,
    "elise": 106,
    "evelynn": 19,
    "ezreal": 47,
    "fiddlesticks": 38,
    "fiora": 94,
    "fizz": 87,
    "galio": 57,
    "gangplank": 30,
    "garen": 51,
    "gnar": 120,
    "gragas": 45,
    "graves": 85,
    "hecarim": 96,
    "heimerdinger": 40,
    "illaoi": 128,
    "irelia": 64,
    "janna": 29,
    "jarvan iv": 71,
    "jax": 15,
    "jayce": 100,
    "jinx": 116,
    "kalista": 122,
    "karma": 69,
    "karthus": 21,
    "kassadin": 27,
    "katarina": 36,
    "kayle": 2,
    "kennen": 49,
    "khazix": 105,
    "kindred": 127,
    "kogmaw": 54,
    "leblanc": 63,
    "lee sin": 73,
    "leona": 79,
    "lissandra": 113,
    "lucian": 115,
    "lulu": 95,
    "lux": 62,
    "malphite": 35,
    "malzahar": 52,
    "maokai": 70,
    "master yi": 3,
    "miss fortune": 59,
    "mordekaiser": 46,
    "morgana": 16,
    "nami": 108,
    "nasus": 37,
    "nautilus": 93,
    "nidalee": 42,
    "nocturne": 72,
    "nunu": 12,
    "olaf": 53,
    "orianna": 77,
    "pantheon": 44,
    "poppy": 43,
    "quinn": 111,
    "rammus": 24,
    "reksai": 123,
    "renekton": 68,
    "rengar": 103,
    "riven": 83,
    "rumble": 75,
    "ryze": 5,
    "sejuani": 91,
    "shaco": 41,
    "shen": 48,
    "shyvana": 86,
    "singed": 18,
    "sion": 6,
    "sivir": 7,
    "skarner": 81,
    "sona": 60,
    "soraka": 8,
    "swain": 61,
    "syndra": 104,
    "tahm kench": 126,
    "talon": 82,
    "taric": 32,
    "teemo": 9,
    "thresh": 110,
    "tristana": 10,
    "trundle": 65,
    "tryndamere": 14,
    "twisted fate": 28,
    "twitch": 20,
    "udyr": 39,
    "urgot": 58,
    "varus": 97,
    "vayne": 76,
    "veigar": 33,
    "velkoz": 118,
    "vi": 109,
    "viktor": 90,
    "vladimir": 56,
    "volibear": 88,
    "warwick": 11,
    "wukong": 80,
    "xerath": 84,
    "xin zhao": 55,
    "yasuo": 117,
    "yorick": 78,
    "zac": 112,
    "zed": 107,
    "ziggs": 92,
    "zilean": 17,
    "zyra": 101
  };

  function champKey(name) {
    return name.toLowerCase().replace(/[^a-z ]/g, "");
  }
  function champUrl(id) {
    return "http://www.mobafire.com/league-of-legends/browse?sort_type=score_weighted&sort_order=&champion_id=" + id + "&lane=&role=&map=&guide_type=&threshold=all&freshness=S6&author=";
  }

  // Will jump directly to top rated guides/builds, Season 6 only, for
  // a given champion. Saves 4-5 page loads depending where you're at.
  name = prompt("Enter champion name:");
  if (name !== null && name !== "") {
    key = champKey(name);
    id = champIds[key];

    if (typeof id !== "undefined") {
      window.location.href = champUrl(champName);
    }
  }
})();
<|endoftext|>


<commit_before>import React from 'react';
import cx from 'classnames';
import { pure, props, t, skinnable } from '../utils';
import Icon from '../Icon/Icon';
import FlexView from '../flex/FlexView';

@pure
@skinnable()
@props({
  children: t.ReactChildren,
  expanded: t.Boolean,
  onExpandedChange: t.Function,
  icons: t.struct({
    expanded: t.String,
    collapsed: t.String
  }),
  wrapperProps: t.maybe(t.Object),
  className: t.maybe(t.String),
  style: t.maybe(t.Object)
})
export default class MoreOrLess extends React.Component {

  toggleExpanded = () => {
    this.props.onExpandedChange(!this.props.expanded);
  };

  getLocals() {
    const {
      props: { children, className, style, expanded, icons, wrapperProps },
      toggleExpanded
    } = this;

    const panelState = expanded ? 'more' : 'less';
    const icon = expanded ? icons.expanded : icons.collapsed;
    return {
      children,
      icon,
      toggleExpanded,
      wrapperProps: {
        ...wrapperProps,
        style,
        className: cx('more-or-less', panelState, className)
      }
    };
  }

  templateExpandButton = ({ icon, toggleExpanded }) => {
    return (
      <FlexView
        hAlignContent='center'
        vAlignContent='center'
        className='expand-button'
        onClick={toggleExpanded}
        shrink={false}
      >
        <Icon icon={icon} className='expand-button-icon' />
      </FlexView>
    );
  };

  template({ children, wrapperProps, icon, toggleExpanded }) {
    return (
      <FlexView column shrink={false} {...wrapperProps}>
        {children}
        {this.templateExpandButton({ icon, toggleExpanded })}
      </FlexView>
    );
  }
}
<commit_msg>add comments to MoreOrLess<commit_after>import React from 'react';
import cx from 'classnames';
import { pure, props, t, skinnable } from '../utils';
import Icon from '../Icon/Icon';
import FlexView from '../flex/FlexView';

/**
 * A panel used to alternately display short or long version of the content
 * @param children - panel content
 * @param expanded - whether the panel should be expanded or not
 * @param onExpandedChange - called on toggle
 * @param icons - icons for expanded and collapsed panel
 * @param wrapperProps - props for wrapper FlexView
 */
@pure
@skinnable()
@props({
  children: t.ReactChildren,
  expanded: t.Boolean,
  onExpandedChange: t.Function,
  icons: t.struct({
    expanded: t.String,
    collapsed: t.String
  }),
  wrapperProps: t.maybe(t.Object),
  className: t.maybe(t.String),
  style: t.maybe(t.Object)
})
export default class MoreOrLess extends React.Component {

  toggleExpanded = () => {
    this.props.onExpandedChange(!this.props.expanded);
  };

  getLocals() {
    const {
      props: { children, className, style, expanded, icons, wrapperProps },
      toggleExpanded
    } = this;

    const panelState = expanded ? 'more' : 'less';
    const icon = expanded ? icons.expanded : icons.collapsed;
    return {
      children,
      icon,
      toggleExpanded,
      wrapperProps: {
        ...wrapperProps,
        style,
        className: cx('more-or-less', panelState, className)
      }
    };
  }

  templateExpandButton = ({ icon, toggleExpanded }) => {
    return (
      <FlexView
        hAlignContent='center'
        vAlignContent='center'
        className='expand-button'
        onClick={toggleExpanded}
        shrink={false}
      >
        <Icon icon={icon} className='expand-button-icon' />
      </FlexView>
    );
  };

  template({ children, wrapperProps, icon, toggleExpanded }) {
    return (
      <FlexView column shrink={false} {...wrapperProps}>
        {children}
        {this.templateExpandButton({ icon, toggleExpanded })}
      </FlexView>
    );
  }
}
<|endoftext|>


<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

cr.define('options', function() {

  var OptionsPage = options.OptionsPage;

  // State variables.
  var syncEnabled = false;
  var syncSetupCompleted = false;

  //
  // PersonalOptions class
  // Encapsulated handling of personal options page.
  //
  function PersonalOptions() {
    OptionsPage.call(this, 'personal', templateData.personalPage,
                     'personalPage');
  }

  cr.addSingletonGetter(PersonalOptions);

  PersonalOptions.prototype = {
    // Inherit PersonalOptions from OptionsPage.
    __proto__: options.OptionsPage.prototype,

    // Initialize PersonalOptions page.
    initializePage: function() {
      // Call base class implementation to starts preference initialization.
      OptionsPage.prototype.initializePage.call(this);

      var self = this;
      $('customize-sync').onclick = function(event) {
        OptionsPage.showPageByName('sync');
      };
      $('start-stop-sync').onclick = function(event) {
        if (self.syncSetupCompleted)
          self.showStopSyncingOverlay_();
        else
          self.showSyncLoginDialog_();
      };
      $('privacy-dashboard-link').onclick = function(event) {
        chrome.send('openPrivacyDashboardTabAndActivate');
      };

      $('showpasswords').onclick = function(event) {
        PasswordsExceptions.load();
        OptionsPage.showPageByName('passwordsExceptions');
        OptionsPage.showTab($('passwords-nav-tab'));
        chrome.send('coreOptionsUserMetricsAction',
            ['Options_ShowPasswordsExceptions']);
      };

      $('autofill_options').onclick = function(event) {
        OptionsPage.showPageByName('autoFillOptions');
        chrome.send('coreOptionsUserMetricsAction',
            ['Options_ShowAutoFillSettings']);
      };

      if (!cr.isChromeOS) {
        $('import_data').onclick = function(event) {
          OptionsPage.showOverlay('importDataOverlay');
          chrome.send('coreOptionsUserMetricsAction', ['Import_ShowDlg']);
        };
      }

      if (!cr.isChromeOS && navigator.platform.match(/linux|BSD/i)) {
        $('themes_GTK_button').onclick = function(event) {
          chrome.send('themesSetGTK');
        };

        $('themes_set_classic').onclick = function(event) {
          chrome.send('themesReset');
        };
        $('themes-gallery').onclick = function(event) {
          chrome.send('themesGallery');
        }
      }

      if (cr.isMac || cr.isWindows || cr.isChromeOS) {
        $('themes_reset').onclick = function(event) {
          chrome.send('themesReset');
        };
        $('themes-gallery').onclick = function(event) {
          chrome.send('themesGallery');
        }
      }

      if (cr.isChromeOS) {
        chrome.send('loadAccountPicture');
      }
    },

    showStopSyncingOverlay_: function(event) {
      AlertOverlay.show(
          localStrings.getString('stop_syncing_title'),
          localStrings.getString('stop_syncing_explanation'),
          localStrings.getString('stop_syncing_confirm_button_label'),
          undefined,
          function() { chrome.send('stopSyncing'); });
    },

    showSyncLoginDialog_: function(event) {
      chrome.send('showSyncLoginDialog');
    },

    setElementVisible_: function(element, visible) {
      element.style.display = visible ? 'inline' : 'none';
    },

    setElementClassSyncError_: function(element, visible) {
      visible ? element.classList.add('sync-error') :
                element.classList.remove('sync-error');
    },

    setSyncEnabled_: function(enabled) {
      this.syncEnabled = enabled;
    },

    setSyncSetupCompleted_: function(completed) {
      this.syncSetupCompleted = completed;
    },

    setAccountPicture_: function(image) {
      $('account-picture').src = image;
    },

    setSyncStatus_: function(status) {
      $('sync-status').textContent = status;
    },

    setSyncStatusErrorVisible_: function(visible) {
      this.setElementClassSyncError_($('sync-status'), visible);
    },

    setSyncActionLinkErrorVisible_: function(visible) {
      this.setElementClassSyncError_($('sync-action-link'), visible);
    },

    setSyncActionLinkEnabled_: function(enabled) {
      $('sync-action-link').disabled = !enabled;
    },

    setSyncActionLinkLabel_: function(status) {
      $('sync-action-link').textContent = status;

      // link-button does is not zero-area when the contents of the button are
      // empty, so explicitly hide the element.
      this.setElementVisible_($('sync-action-link'), status.length != 0);
    },

    setStartStopButtonVisible_: function(visible) {
      this.setElementVisible_($('start-stop-sync'), visible);
    },

    setStartStopButtonEnabled_: function(enabled) {
      $('start-stop-sync').disabled = !enabled;
    },

    setStartStopButtonLabel_: function(label) {
      $('start-stop-sync').textContent = label;
    },

    setCustomizeButtonVisible_: function(visible) {
      this.setElementVisible_($('customize-sync'), visible);
    },

    setCustomizeButtonEnabled_: function(enabled) {
      $('customize-sync').disabled = !enabled;
    },

    setCustomizeButtonLabel_: function(label) {
      $('customize-sync').textContent = label;
    },

    setGtkThemeButtonEnabled_: function(enabled) {
      if (!cr.isChromeOS && navigator.platform.match(/linux|BSD/i)) {
        $('themes_GTK_button').disabled = !enabled;
      }
    },

    setClassicThemeButtonEnabled_: function(enabled) {
      if (!cr.isChromeOS && navigator.platform.match(/linux|BSD/i)) {
        $('themes_set_classic').disabled = !enabled;
      }
    },
  };

  // Forward public APIs to private implementations.
  [
    'setSyncEnabled',
    'setSyncSetupCompleted',
    'setAccountPicture',
    'setSyncStatus',
    'setSyncStatusErrorVisible',
    'setSyncActionLinkErrorVisible',
    'setSyncActionLinkEnabled',
    'setSyncActionLinkLabel',
    'setStartStopButtonVisible',
    'setStartStopButtonEnabled',
    'setStartStopButtonLabel',
    'setCustomizeButtonVisible',
    'setCustomizeButtonEnabled',
    'setCustomizeButtonLabel',
    'setGtkThemeButtonEnabled',
    'setClassicThemeButtonEnabled',
  ].forEach(function(name) {
    PersonalOptions[name] = function(value) {
      PersonalOptions.getInstance()[name + '_'](value);
    };
  });

  // Export
  return {
    PersonalOptions: PersonalOptions
  };

});
<commit_msg>DOMUI: Show the sync login dialog when the user presses the sync-action-link button.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

cr.define('options', function() {

  var OptionsPage = options.OptionsPage;

  // State variables.
  var syncEnabled = false;
  var syncSetupCompleted = false;

  //
  // PersonalOptions class
  // Encapsulated handling of personal options page.
  //
  function PersonalOptions() {
    OptionsPage.call(this, 'personal', templateData.personalPage,
                     'personalPage');
  }

  cr.addSingletonGetter(PersonalOptions);

  PersonalOptions.prototype = {
    // Inherit PersonalOptions from OptionsPage.
    __proto__: options.OptionsPage.prototype,

    // Initialize PersonalOptions page.
    initializePage: function() {
      // Call base class implementation to starts preference initialization.
      OptionsPage.prototype.initializePage.call(this);

      var self = this;
      $('customize-sync').onclick = function(event) {
        OptionsPage.showPageByName('sync');
      };
      $('sync-action-link').onclick = function(event) {
        chrome.send('showSyncLoginDialog');
      };
      $('start-stop-sync').onclick = function(event) {
        if (self.syncSetupCompleted)
          self.showStopSyncingOverlay_();
        else
          chrome.send('showSyncLoginDialog');
      };
      $('privacy-dashboard-link').onclick = function(event) {
        chrome.send('openPrivacyDashboardTabAndActivate');
      };
      $('showpasswords').onclick = function(event) {
        PasswordsExceptions.load();
        OptionsPage.showPageByName('passwordsExceptions');
        OptionsPage.showTab($('passwords-nav-tab'));
        chrome.send('coreOptionsUserMetricsAction',
            ['Options_ShowPasswordsExceptions']);
      };
      $('autofill_options').onclick = function(event) {
        OptionsPage.showPageByName('autoFillOptions');
        chrome.send('coreOptionsUserMetricsAction',
            ['Options_ShowAutoFillSettings']);
      };

      if (!cr.isChromeOS) {
        $('import_data').onclick = function(event) {
          OptionsPage.showOverlay('importDataOverlay');
          chrome.send('coreOptionsUserMetricsAction', ['Import_ShowDlg']);
        };
      }

      if (!cr.isChromeOS && navigator.platform.match(/linux|BSD/i)) {
        $('themes_GTK_button').onclick = function(event) {
          chrome.send('themesSetGTK');
        };
        $('themes_set_classic').onclick = function(event) {
          chrome.send('themesReset');
        };
        $('themes-gallery').onclick = function(event) {
          chrome.send('themesGallery');
        }
      }

      if (cr.isMac || cr.isWindows || cr.isChromeOS) {
        $('themes_reset').onclick = function(event) {
          chrome.send('themesReset');
        };
        $('themes-gallery').onclick = function(event) {
          chrome.send('themesGallery');
        }
      }

      if (cr.isChromeOS) {
        chrome.send('loadAccountPicture');
      }
    },

    showStopSyncingOverlay_: function(event) {
      AlertOverlay.show(
          localStrings.getString('stop_syncing_title'),
          localStrings.getString('stop_syncing_explanation'),
          localStrings.getString('stop_syncing_confirm_button_label'),
          undefined,
          function() { chrome.send('stopSyncing'); });
    },

    setElementVisible_: function(element, visible) {
      element.style.display = visible ? 'inline' : 'none';
    },

    setElementClassSyncError_: function(element, visible) {
      visible ? element.classList.add('sync-error') :
                element.classList.remove('sync-error');
    },

    setSyncEnabled_: function(enabled) {
      this.syncEnabled = enabled;
    },

    setSyncSetupCompleted_: function(completed) {
      this.syncSetupCompleted = completed;
    },

    setAccountPicture_: function(image) {
      $('account-picture').src = image;
    },

    setSyncStatus_: function(status) {
      $('sync-status').textContent = status;
    },

    setSyncStatusErrorVisible_: function(visible) {
      this.setElementClassSyncError_($('sync-status'), visible);
    },

    setSyncActionLinkErrorVisible_: function(visible) {
      this.setElementClassSyncError_($('sync-action-link'), visible);
    },

    setSyncActionLinkEnabled_: function(enabled) {
      $('sync-action-link').disabled = !enabled;
    },

    setSyncActionLinkLabel_: function(status) {
      $('sync-action-link').textContent = status;

      // link-button does is not zero-area when the contents of the button are
      // empty, so explicitly hide the element.
      this.setElementVisible_($('sync-action-link'), status.length != 0);
    },

    setStartStopButtonVisible_: function(visible) {
      this.setElementVisible_($('start-stop-sync'), visible);
    },

    setStartStopButtonEnabled_: function(enabled) {
      $('start-stop-sync').disabled = !enabled;
    },

    setStartStopButtonLabel_: function(label) {
      $('start-stop-sync').textContent = label;
    },

    setCustomizeButtonVisible_: function(visible) {
      this.setElementVisible_($('customize-sync'), visible);
    },

    setCustomizeButtonEnabled_: function(enabled) {
      $('customize-sync').disabled = !enabled;
    },

    setCustomizeButtonLabel_: function(label) {
      $('customize-sync').textContent = label;
    },

    setGtkThemeButtonEnabled_: function(enabled) {
      if (!cr.isChromeOS && navigator.platform.match(/linux|BSD/i)) {
        $('themes_GTK_button').disabled = !enabled;
      }
    },

    setClassicThemeButtonEnabled_: function(enabled) {
      if (!cr.isChromeOS && navigator.platform.match(/linux|BSD/i)) {
        $('themes_set_classic').disabled = !enabled;
      }
    },
  };

  // Forward public APIs to private implementations.
  [
    'setSyncEnabled',
    'setSyncSetupCompleted',
    'setAccountPicture',
    'setSyncStatus',
    'setSyncStatusErrorVisible',
    'setSyncActionLinkErrorVisible',
    'setSyncActionLinkEnabled',
    'setSyncActionLinkLabel',
    'setStartStopButtonVisible',
    'setStartStopButtonEnabled',
    'setStartStopButtonLabel',
    'setCustomizeButtonVisible',
    'setCustomizeButtonEnabled',
    'setCustomizeButtonLabel',
    'setGtkThemeButtonEnabled',
    'setClassicThemeButtonEnabled',
  ].forEach(function(name) {
    PersonalOptions[name] = function(value) {
      PersonalOptions.getInstance()[name + '_'](value);
    };
  });

  // Export
  return {
    PersonalOptions: PersonalOptions
  };

});
<|endoftext|>


<commit_before>// FIRST TIME ONLY- run:
//   ./node_modules/.bin/webdriver-manager update
//
//   Try: `npm run webdriver:update`
//
// AND THEN EVERYTIME ...
//   1. Compile with `tsc`
//   2. Make sure the test server (e.g., http-server: localhost:8080) is running.
//   3. ./node_modules/.bin/protractor protractor.config.js
//
//   To do all steps, try:  `npm run e2e`

var fs = require('fs');
var path = require('canonical-path');
var _ = require('lodash');

exports.config = {
  directConnect: true,

  // Capabilities to be passed to the webdriver instance.
  capabilities: {
    'browserName': 'chrome'
  },

  // Framework to use. Jasmine is recommended.
  framework: 'jasmine',

  // Spec patterns are relative to this config file
  specs: ['**/*e2e-spec.js' ],

  // For angular2 tests
  useAllAngular2AppRoots: true,

  // Base URL for application server
  baseUrl: 'http://localhost:8080',

  // doesn't seem to work.
  // resultJsonOutputFile: "foo.json",

  onPrepare: function() {
    //// SpecReporter
    //var SpecReporter = require('jasmine-spec-reporter');
    //jasmine.getEnv().addReporter(new SpecReporter({displayStacktrace: 'none'}));
    //// jasmine.getEnv().addReporter(new SpecReporter({displayStacktrace: 'all'}));

    // debugging
    // console.log('browser.params:' + JSON.stringify(browser.params));

    var appDir = browser.params.appDir;
    if (appDir) {
      if (appDir.match('/ts') != null) {
        browser.appIsTs = true;
      } else if (appDir.match('/js') != null) {
        browser.appIsJs = true;
      } else if (appDir.match('/dart') != null) {
        browser.appIsDart = true;
      } else {
        browser.appIsUnknown = true;
      }
    } else {
      browser.appIsUnknown = true;
    }
    jasmine.getEnv().addReporter(new Reporter( browser.params )) ;
    global.describeIf = describeIf;
    global.itIf = itIf;
    global.sendKeys = sendKeys;

    // Allow changing bootstrap mode to NG1 for upgrade tests
    global.setProtractorToNg1Mode = function() {
      browser.useAllAngular2AppRoots = false;
      browser.rootEl = 'body';
    };
  },

  jasmineNodeOpts: {
    // defaultTimeoutInterval: 60000,
    defaultTimeoutInterval: 10000,
    showTiming: true,
    print: function() {}
  }
};

function describeIf(cond, name, func) {
  if (cond) {
    describe(name, func);
  } else {
    xdescribe(name, func);
  }
}

function itIf(cond, name, func) {
  if (cond) {
    it(name, func);
  } else {
    xit(name, func);
  }
}

// Hack - because of bug with protractor send keys
function sendKeys(element, str) {
  return str.split('').reduce(function (promise, char) {
    return promise.resolve(element.sendKeys(char));
  }, element.getAttribute('value'));
}

function Reporter(options) {
  var _defaultOutputFile = path.resolve(process.cwd(), "../../", 'protractor-results.txt');
  options.outputFile = options.outputFile || _defaultOutputFile;

  var _root = { appDir: options.appDir, suites: [] };
  log('AppDir: ' + options.appDir, +1);
  var _currentSuite;

  this.suiteStarted = function(suite) {
    _currentSuite = { description: suite.description, status: null, specs: [] };
    _root.suites.push(_currentSuite);
    log('Suite: ' + suite.description, +1);
  };

  this.suiteDone = function(suite) {
    var statuses = _currentSuite.specs.map(function(spec) {
      return spec.status;
    });
    statuses = _.uniq(statuses);
    var status = statuses.indexOf('failed') >= 0 ? 'failed' : statuses.join(', ');
    _currentSuite.status = status;
    log('Suite ' + _currentSuite.status + ': ' + suite.description, -1);
  };

  this.specStarted = function(spec) {

  };

  this.specDone = function(spec) {
    var currentSpec = {
      description: spec.description,
      status: spec.status
    };
    if (spec.failedExpectations.length > 0) {
      currentSpec.failedExpectations = spec.failedExpectations;
    }

    _currentSuite.specs.push(currentSpec);
    log(spec.status + ' - ' + spec.description);
  };

  this.jasmineDone = function() {
    outputFile = options.outputFile;
    //// Alternate approach - just stringify the _root - not as pretty
    //// but might be more useful for automation.
    // var output = JSON.stringify(_root, null, 2);
    var output = formatOutput(_root);
    fs.appendFileSync(outputFile, output);
  };

  // for output file output
  function formatOutput(output) {
    var indent = '  ';
    var pad = '  ';
    var results = [];
    results.push('AppDir:' + output.appDir);
    output.suites.forEach(function(suite) {
      results.push(pad + 'Suite: ' + suite.description + ' -- ' + suite.status);
      pad+=indent;
      suite.specs.forEach(function(spec) {
        results.push(pad + spec.status + ' - ' + spec.description);
        if (spec.failedExpectations) {
          pad+=indent;
          spec.failedExpectations.forEach(function (fe) {
            results.push(pad + 'message: ' + fe.message);
          });
          pad=pad.substr(2);
        }
      });
      pad = pad.substr(2);
      results.push('');
    });
    results.push('');
    return results.join('\n');
  }

  // for console output
  var _pad;
  function log(str, indent) {
    _pad = _pad || '';
    if (indent == -1) {
      _pad = _pad.substr(2);
    }
    console.log(_pad + str);
    if (indent == 1) {
      _pad = _pad + '  ';
    }
  }

}
<commit_msg>chore: revert `sendKeys` change from e1862887 closes #1175<commit_after>// FIRST TIME ONLY- run:
//   ./node_modules/.bin/webdriver-manager update
//
//   Try: `npm run webdriver:update`
//
// AND THEN EVERYTIME ...
//   1. Compile with `tsc`
//   2. Make sure the test server (e.g., http-server: localhost:8080) is running.
//   3. ./node_modules/.bin/protractor protractor.config.js
//
//   To do all steps, try:  `npm run e2e`

var fs = require('fs');
var path = require('canonical-path');
var _ = require('lodash');

exports.config = {
  directConnect: true,

  // Capabilities to be passed to the webdriver instance.
  capabilities: {
    'browserName': 'chrome'
  },

  // Framework to use. Jasmine is recommended.
  framework: 'jasmine',

  // Spec patterns are relative to this config file
  specs: ['**/*e2e-spec.js' ],

  // For angular2 tests
  useAllAngular2AppRoots: true,

  // Base URL for application server
  baseUrl: 'http://localhost:8080',

  // doesn't seem to work.
  // resultJsonOutputFile: "foo.json",

  onPrepare: function() {
    //// SpecReporter
    //var SpecReporter = require('jasmine-spec-reporter');
    //jasmine.getEnv().addReporter(new SpecReporter({displayStacktrace: 'none'}));
    //// jasmine.getEnv().addReporter(new SpecReporter({displayStacktrace: 'all'}));

    // debugging
    // console.log('browser.params:' + JSON.stringify(browser.params));

    var appDir = browser.params.appDir;
    if (appDir) {
      if (appDir.match('/ts') != null) {
        browser.appIsTs = true;
      } else if (appDir.match('/js') != null) {
        browser.appIsJs = true;
      } else if (appDir.match('/dart') != null) {
        browser.appIsDart = true;
      } else {
        browser.appIsUnknown = true;
      }
    } else {
      browser.appIsUnknown = true;
    }
    jasmine.getEnv().addReporter(new Reporter( browser.params )) ;
    global.describeIf = describeIf;
    global.itIf = itIf;
    global.sendKeys = sendKeys;

    // Allow changing bootstrap mode to NG1 for upgrade tests
    global.setProtractorToNg1Mode = function() {
      browser.useAllAngular2AppRoots = false;
      browser.rootEl = 'body';
    };
  },

  jasmineNodeOpts: {
    // defaultTimeoutInterval: 60000,
    defaultTimeoutInterval: 10000,
    showTiming: true,
    print: function() {}
  }
};

function describeIf(cond, name, func) {
  if (cond) {
    describe(name, func);
  } else {
    xdescribe(name, func);
  }
}

function itIf(cond, name, func) {
  if (cond) {
    it(name, func);
  } else {
    xit(name, func);
  }
}

// Hack - because of bug with protractor send keys
// Hack - because of bug with send keys
function sendKeys(element, str) {
  return str.split('').reduce(function (promise, char) {
    return promise.then(function () {
      return element.sendKeys(char);
    });
  }, element.getAttribute('value'));
  // better to create a resolved promise here but ... don't know how with protractor;
  }

function Reporter(options) {
  var _defaultOutputFile = path.resolve(process.cwd(), "../../", 'protractor-results.txt');
  options.outputFile = options.outputFile || _defaultOutputFile;

  var _root = { appDir: options.appDir, suites: [] };
  log('AppDir: ' + options.appDir, +1);
  var _currentSuite;

  this.suiteStarted = function(suite) {
    _currentSuite = { description: suite.description, status: null, specs: [] };
    _root.suites.push(_currentSuite);
    log('Suite: ' + suite.description, +1);
  };

  this.suiteDone = function(suite) {
    var statuses = _currentSuite.specs.map(function(spec) {
      return spec.status;
    });
    statuses = _.uniq(statuses);
    var status = statuses.indexOf('failed') >= 0 ? 'failed' : statuses.join(', ');
    _currentSuite.status = status;
    log('Suite ' + _currentSuite.status + ': ' + suite.description, -1);
  };

  this.specStarted = function(spec) {

  };

  this.specDone = function(spec) {
    var currentSpec = {
      description: spec.description,
      status: spec.status
    };
    if (spec.failedExpectations.length > 0) {
      currentSpec.failedExpectations = spec.failedExpectations;
    }

    _currentSuite.specs.push(currentSpec);
    log(spec.status + ' - ' + spec.description);
  };

  this.jasmineDone = function() {
    outputFile = options.outputFile;
    //// Alternate approach - just stringify the _root - not as pretty
    //// but might be more useful for automation.
    // var output = JSON.stringify(_root, null, 2);
    var output = formatOutput(_root);
    fs.appendFileSync(outputFile, output);
  };

  // for output file output
  function formatOutput(output) {
    var indent = '  ';
    var pad = '  ';
    var results = [];
    results.push('AppDir:' + output.appDir);
    output.suites.forEach(function(suite) {
      results.push(pad + 'Suite: ' + suite.description + ' -- ' + suite.status);
      pad+=indent;
      suite.specs.forEach(function(spec) {
        results.push(pad + spec.status + ' - ' + spec.description);
        if (spec.failedExpectations) {
          pad+=indent;
          spec.failedExpectations.forEach(function (fe) {
            results.push(pad + 'message: ' + fe.message);
          });
          pad=pad.substr(2);
        }
      });
      pad = pad.substr(2);
      results.push('');
    });
    results.push('');
    return results.join('\n');
  }

  // for console output
  var _pad;
  function log(str, indent) {
    _pad = _pad || '';
    if (indent == -1) {
      _pad = _pad.substr(2);
    }
    console.log(_pad + str);
    if (indent == 1) {
      _pad = _pad + '  ';
    }
  }

}
<|endoftext|>