<commit_before>import { Trans } from "@lingui/macro";
import PropTypes from "prop-types";
import React from "react";

import DSLCombinerTypes from "#SRC/js/constants/DSLCombinerTypes";
import DSLExpression from "#SRC/js/structs/DSLExpression";
import DSLExpressionPart from "#SRC/js/structs/DSLExpressionPart";
import DSLFormWithExpressionUpdates from "#SRC/js/components/DSLFormWithExpressionUpdates";
import DSLUtil from "#SRC/js/utils/DSLUtil";
import FieldInput from "#SRC/js/components/form/FieldInput";
import FieldLabel from "#SRC/js/components/form/FieldLabel";
import FormGroup from "#SRC/js/components/form/FormGroup";

import DSLFilterTypes from "#SRC/js/constants/DSLFilterTypes";
import { FilterNode } from "#SRC/js/structs/DSLASTNodes";
import DSLUpdateUtil from "#SRC/js/utils/DSLUpdateUtil";

const EXPRESSION_PARTS = {
  text: DSLExpressionPart.fuzzy
};

const METHODS_TO_BIND = ["handleTextChange"];

class FuzzyTextDSLSection extends React.Component {
  constructor() {
    super(...arguments);

    this.state = {
      data: {
        text: ""
      }
    };

    METHODS_TO_BIND.forEach(method => {
      this[method] = this[method].bind(this);
    });
  }

  componentWillReceiveProps(nextProps) {
    const { expression } = nextProps;
    const data = DSLUtil.getPartValues(expression, EXPRESSION_PARTS);

    this.setState({ data });
  }

  handleTextChange(event) {
    const { onChange, expression } = this.props;
    const { target } = event;
    event.stopPropagation();

    const value = target.value;
    this.setState({
      data: Object.assign({}, this.state.data, {
        text: value
      })
    });

    // TODO: find better abstraction here (DCOS-40235)
    const newFuzzyNodes = value
      .replace(":", " ")
      .split(" ")
      .map(text => {
        return new FilterNode(0, 0, DSLFilterTypes.FUZZY, { text });
      });

    const updateNode = EXPRESSION_PARTS["text"];
    // The node(s) relevant to the property we are updating
    const matchingNodes = DSLUtil.findNodesByFilter(expression.ast, updateNode);

    // And replace the existing fuzzy nodes
    const newExpression = DSLUpdateUtil.applyReplace(
      expression,
      matchingNodes,
      newFuzzyNodes,
      {
        newCombiner: DSLCombinerTypes.AND
      }
    );

    onChange(newExpression);
  }

  render() {
    const { data } = this.state;
    const { expression, onApply, onChange } = this.props;
    const enabled = DSLUtil.canProcessParts(expression, EXPRESSION_PARTS);

    return (
      <DSLFormWithExpressionUpdates
        expression={expression}
        groupCombiner={DSLCombinerTypes.AND}
        itemCombiner={DSLCombinerTypes.OR}
        onChange={onChange}
        onSubmit={onApply}
        parts={EXPRESSION_PARTS}
      >
        <FormGroup>
          <FieldLabel>
            <Trans render="span">Has the words</Trans>
          </FieldLabel>
          <FieldInput
            disabled={!enabled}
            name="text"
            onChange={this.handleTextChange}
            placeholder="Enter words found in name"
            value={data.text || ""}
          />
        </FormGroup>
      </DSLFormWithExpressionUpdates>
    );
  }
}

FuzzyTextDSLSection.propTypes = {
  onApply: PropTypes.func,
  onChange: PropTypes.func.isRequired,
  expression: PropTypes.instanceOf(DSLExpression).isRequired
};

module.exports = FuzzyTextDSLSection;
<commit_msg>feat(FuzzyTextDSLSection): pretranslate placeholder<commit_after>import { Trans, t } from "@lingui/macro";
import { withI18n } from "@lingui/react";
import PropTypes from "prop-types";
import React from "react";

import DSLCombinerTypes from "#SRC/js/constants/DSLCombinerTypes";
import DSLExpression from "#SRC/js/structs/DSLExpression";
import DSLExpressionPart from "#SRC/js/structs/DSLExpressionPart";
import DSLFormWithExpressionUpdates from "#SRC/js/components/DSLFormWithExpressionUpdates";
import DSLUtil from "#SRC/js/utils/DSLUtil";
import FieldInput from "#SRC/js/components/form/FieldInput";
import FieldLabel from "#SRC/js/components/form/FieldLabel";
import FormGroup from "#SRC/js/components/form/FormGroup";

import DSLFilterTypes from "#SRC/js/constants/DSLFilterTypes";
import { FilterNode } from "#SRC/js/structs/DSLASTNodes";
import DSLUpdateUtil from "#SRC/js/utils/DSLUpdateUtil";

const EXPRESSION_PARTS = {
  text: DSLExpressionPart.fuzzy
};

const METHODS_TO_BIND = ["handleTextChange"];

class FuzzyTextDSLSection extends React.Component {
  constructor() {
    super(...arguments);

    this.state = {
      data: {
        text: ""
      }
    };

    METHODS_TO_BIND.forEach(method => {
      this[method] = this[method].bind(this);
    });
  }

  componentWillReceiveProps(nextProps) {
    const { expression } = nextProps;
    const data = DSLUtil.getPartValues(expression, EXPRESSION_PARTS);

    this.setState({ data });
  }

  handleTextChange(event) {
    const { onChange, expression } = this.props;
    const { target } = event;
    event.stopPropagation();

    const value = target.value;
    this.setState({
      data: Object.assign({}, this.state.data, {
        text: value
      })
    });

    // TODO: find better abstraction here (DCOS-40235)
    const newFuzzyNodes = value
      .replace(":", " ")
      .split(" ")
      .map(text => {
        return new FilterNode(0, 0, DSLFilterTypes.FUZZY, { text });
      });

    const updateNode = EXPRESSION_PARTS["text"];
    // The node(s) relevant to the property we are updating
    const matchingNodes = DSLUtil.findNodesByFilter(expression.ast, updateNode);

    // And replace the existing fuzzy nodes
    const newExpression = DSLUpdateUtil.applyReplace(
      expression,
      matchingNodes,
      newFuzzyNodes,
      {
        newCombiner: DSLCombinerTypes.AND
      }
    );

    onChange(newExpression);
  }

  render() {
    const { data } = this.state;
    const { expression, onApply, onChange, i18n } = this.props;
    const enabled = DSLUtil.canProcessParts(expression, EXPRESSION_PARTS);

    return (
      <DSLFormWithExpressionUpdates
        expression={expression}
        groupCombiner={DSLCombinerTypes.AND}
        itemCombiner={DSLCombinerTypes.OR}
        onChange={onChange}
        onSubmit={onApply}
        parts={EXPRESSION_PARTS}
      >
        <FormGroup>
          <FieldLabel>
            <Trans render="span">Has the words</Trans>
          </FieldLabel>
          <FieldInput
            disabled={!enabled}
            name="text"
            onChange={this.handleTextChange}
            placeholder={i18n._(t`Enter words found in name`)}
            value={data.text || ""}
          />
        </FormGroup>
      </DSLFormWithExpressionUpdates>
    );
  }
}

FuzzyTextDSLSection.propTypes = {
  onApply: PropTypes.func,
  onChange: PropTypes.func.isRequired,
  expression: PropTypes.instanceOf(DSLExpression).isRequired
};

module.exports = withI18n()(FuzzyTextDSLSection);
<|endoftext|>


<commit_before>/**
 * @fileoverview Generates JSON output based on exportable symbols (those with
 * an api tag) and boolean defines (with a define tag and a default value).
 */
var assert = require('assert');
var fs = require('fs');
var path = require('path');

/**
 * Publish hook for the JSDoc template.  Writes to JSON stdout.
 * @param {function} data The root of the Taffy DB containing doclet records.
 * @param {Object} opts Options.
 */
exports.publish = function(data, opts) {
  var cwd = process.cwd();

  // get all doclets with the "api" property or define (excluding enums,
  // typedefs and events)
  var docs = data(
      [{define: {isObject: true}}, {api: {isString: true}}],
      {isEnum: {'!is': true}},
      {kind: {'!is': 'typedef'}},
      {kind: {'!is': 'event'}}).get();

  // get symbols data, filter out those that are members of private classes
  var symbols = [];
  var defines = [];
  docs.filter(function(doc) {
    var include = true;
    var constructor = doc.memberof;
    if (constructor && constructor.substr(-1) === '_') {
      assert.strictEqual(doc.inherited, true,
          'Unexpected export on private class: ' + doc.longname);
      include = false;
    }
    return include;
  }).forEach(function(doc) {
    if (doc.define) {
      defines.push({
        name: doc.longname,
        description: doc.description,
        path: path.join(doc.meta.path, doc.meta.filename),
        default: doc.define.default
      });
    } else {
      symbols.push({
        name: doc.longname,
        kind: doc.kind,
        description: doc.classdesc || doc.description,
        path: path.join(doc.meta.path, doc.meta.filename)
      });
    }
  });

  process.stdout.write(
      JSON.stringify({symbols: symbols, defines: defines}, null, 2));

};
<commit_msg>Handle exports of classes constructors (through @api)<commit_after>/**
 * @fileoverview Generates JSON output based on exportable symbols (those with
 * an api tag) and boolean defines (with a define tag and a default value).
 */
var assert = require('assert');
var fs = require('fs');
var path = require('path');

/**
 * Publish hook for the JSDoc template.  Writes to JSON stdout.
 * @param {function} data The root of the Taffy DB containing doclet records.
 * @param {Object} opts Options.
 */
exports.publish = function(data, opts) {
  var cwd = process.cwd();

  // get all doclets with the "api" property or define (excluding enums,
  // typedefs and events)
  var docs = data(
      [{define: {isObject: true}}, {api: {isString: true}}],
      {isEnum: {'!is': true}},
      {kind: {'!is': 'typedef'}},
      {kind: {'!is': 'event'}}).get();

  // get symbols data, filter out those that are members of private classes
  var symbols = [];
  var defines = [];
  docs.filter(function(doc) {
    var include = true;
    var constructor = doc.memberof;
    if (constructor && constructor.substr(-1) === '_') {
      assert.strictEqual(doc.inherited, true,
          'Unexpected export on private class: ' + doc.longname);
      include = false;
    }
    return include;
  }).forEach(function(doc) {
    var longname = doc.longname.replace(/.*~/, '')
    if (doc.define) {
      defines.push({
        name: longname,
        description: doc.description,
        path: path.join(doc.meta.path, doc.meta.filename),
        default: doc.define.default
      });
    } else {
      symbols.push({
        name: longname,
        kind: doc.kind,
        description: doc.classdesc || doc.description,
        path: path.join(doc.meta.path, doc.meta.filename)
      });
    }
  });

  process.stdout.write(
      JSON.stringify({symbols: symbols, defines: defines}, null, 2));

};
<|endoftext|>


<commit_before>// adopted from: <https://github.com/jonschlinkert/omit-value>
// Copyright (c) 2015, Jon Schlinkert. (MIT)

var isObject = require('../lang/isObject')
var isString = require('../lang/isString')
var omit     = require('./omit')
var look     = require('./look')
var set      = require('./set')
var assert   = require('assert')

function omitValue (obj, prop, keys) {
  assert(isObject(obj), 'omitValue expects first arg to be an object.')
  assert(isString(prop), 'omitValue expects prop to be a string')

  if (typeof keys === undefined) return omit(obj, prop)

  var val = look(obj, prop)
  set(obj, prop, omit(val, keys))
  return obj
}

module.exports = omitValue
<commit_msg>update object/omitValue -- use object/get<commit_after>// adopted from: <https://github.com/jonschlinkert/omit-value>
// Copyright (c) 2015, Jon Schlinkert. (MIT)

var isObject = require('../lang/isObject')
var isString = require('../lang/isString')
var omit     = require('./omit')
var get      = require('./get')
var set      = require('./set')
var assert   = require('assert')

function omitValue (obj, prop, keys) {
  assert(isObject(obj), 'omitValue expects first arg to be an object.')
  assert(isString(prop), 'omitValue expects prop to be a string')

  if (typeof keys === undefined) return omit(obj, prop)

  var val = get(obj, prop)
  set(obj, prop, omit(val, keys))
  return obj
}

module.exports = omitValue
<|endoftext|>


<commit_before>'use strict';

/*!
 * V4Fire Client Core
 * https://github.com/V4Fire/Client
 *
 * Released under the MIT license
 * https://github.com/V4Fire/Client/blob/master/LICENSE
 */

const
	path = require('path'),
	{src} = require('config'),
	{config: {dependencies}} = require('@pzlr/build-core'),
	{normalizeSep} = include('build/helpers');

const
	deps = dependencies.map((el) => RegExp.escape(el || el.src)),
	importRgxp = new RegExp(`('|")(${deps.join('|')})(.*?)\\1`, 'g');

/**
 * Monic replacer for TS import declarations
 *
 * @param {string} str
 * @param {string} file
 * @returns {string}
 */
module.exports = function (str, file) {
	if (!deps.length) {
		return txt;
	}

	return str.replace(importRgxp, (str, $1, root, url) =>
		`'${normalizeSep(path.relative(path.dirname(file), path.join(src.lib(), root, 'src', url)))}'`
	);
};
<commit_msg>Fixed the typo<commit_after>'use strict';

/*!
 * V4Fire Client Core
 * https://github.com/V4Fire/Client
 *
 * Released under the MIT license
 * https://github.com/V4Fire/Client/blob/master/LICENSE
 */

const
	path = require('path'),
	{src} = require('config'),
	{config: {dependencies}} = require('@pzlr/build-core'),
	{normalizeSep} = include('build/helpers');

const
	deps = dependencies.map((el) => RegExp.escape(el || el.src)),
	importRgxp = new RegExp(`('|")(${deps.join('|')})(.*?)\\1`, 'g');

/**
 * Monic replacer for TS import declarations
 *
 * @param {string} str
 * @param {string} file
 * @returns {string}
 */
module.exports = function (str, file) {
	if (!deps.length) {
		return str;
	}

	return str.replace(importRgxp, (str, $1, root, url) =>
		`'${normalizeSep(path.relative(path.dirname(file), path.join(src.lib(), root, 'src', url)))}'`
	);
};
<|endoftext|>


<commit_before>

Task = function(){
    this.name;
    this.priority;
    this.dueDate;
    this.project;
    this.projectName;
    this.done;
    this.spot = 0;
}

TaskList = function () {
    var tasks = [];
    var _this = this;
    _this.name;
    _this.rank;
    _this.finished;

    this.getTasks = function () {
        return tasks;
    }

    this.addTask = function (newTask) {
        tasks.push(newTask);
        newTask.spot = tasks.length - 1;

    }

    this.removeTask = function (task) {
        tasks.splice(task.spot, 1);
        for (var i = 0; i < tasks.length; i++) {
            tasks[i].spot = i;
        }
    }
    this.display = function () {

        table = document.getElementById(_this.name);

        if (table.rows.length > 0) {
            for (i = 0; i < tasks.length; i++) {
                table.deleteRow();
            }
        }

        headerRow = document.createElement('tr');
        pBox = document.createElement('input');
        pBox.type = 'checkbox';
        pBox.id = _this.rank;
        pBox.onclick = projectDone;
        header = document.createElement('th');
        header.innerHTML = _this.name;

        table.appendChild(headerRow);
        headerRow.appendChild(pBox);
        headerRow.appendChild(header);

        //table.appendChild(pBox);
        //table.appendChild(header);

        header.onclick = function () {
            console.log(_this.getTasks().length);
            for (var i = 0; i < _this.getTasks().length; i++) {
                thisTask = _this.getTasks()[i];
                row = document.querySelector('#' + thisTask.projectName + thisTask.spot.toString());

                if (row.style.display == 'none') {
                    alert('hidden');
                    row.style.display = 'inline';

                } else {
                    row.style.display = 'none';

                }

            }

        }

        for (i = 0; i < tasks.length; i++) {

            row = document.createElement('tr');
            //row.className = _this.name;
            //row.style.display = 'none';
            taskPlace = document.createElement('td');
            date = document.createElement('td');

            task = tasks[i];

            row.id = task.projectName + task.spot.toString();

            row.style.display = 'none';
            checkBox = document.createElement('input');

            checkBox.type = 'checkbox';
            checkBox.id = task.spot.toString();
            checkBox.onclick = taskDone;
            checkBox.className = _this.rank;
            taskPlace.innerHTML = task.name;
            taskPlace.className = task.priority;
            date.innerHTML = task.dueDate;

            table.appendChild(row);
            row.appendChild(checkBox);
            row.appendChild(taskPlace);
            row.appendChild(date);
        }

    }

}

saveAll = function () {
    res = [];
    var i;
    var j;
    for (j = 0; j < projectList.length; j++) {
        tasks = projectList[j].getTasks();
        for (i = 0; i < tasks.length; i++) {
            if (!tasks[i].done) {
                res.push(tasks[i]);
            }
        }
    }

    localStorage.setItem("todoDatabase", JSON.stringify(res));
}

restoreAll = function () {
    projectList = [];
    oldList = JSON.parse(localStorage.getItem("todoDatabase"));

    var current;
    var project;

    for (i = 0; i < oldList.length; i++) {
        current = oldList[i];
        if (current.spot == 0) {

            project = new TaskList();
            project.name = current.projectName;
            project.addTask(current);
            newTable = document.createElement('table');
            newTable.id = project.name;

            listSection = document.querySelector('article');
            listSection.appendChild(newTable);

            project.rank = projectList.length;
            project.finished = false;
            projectList.push(project);

            document.querySelector('#newProject').value = "";

            newOption = document.createElement('option');
            newOption.value = project.name;
            newOption.innerHTML = project.name;

            dropMenu = document.querySelector('#project');
            dropMenu.appendChild(newOption);

            project.display();
        } else {
            project = projectList[projectList.length - 1];
            project.addTask(current);
            project.display();
        }
    }
}

taskDone = function () {
    var place = parseInt(this.id);
    var project = projectList[this.className];
    var task = project.getTasks()[place];
    var name = this.nextSibling;
    var date = name.nextSibling;

    if (!task.done) {
        name.style.textDecoration = 'line-through';
        date.style.textDecoration = 'line-through';
        task.done = true;

    } else {
        name.style.textDecoration = 'none';
        date.style.textDecoration = 'none';
        task.done = false;
    }
    saveAll();
}

projectDone = function () {
    var place = this.id;
    var thisProject = projectList[place];
    var text = this.nextSibling;

    if (!thisProject.finished) {
        text.style.textDecoration = 'line-through';
        thisProject.finished = true;

    } else {
        text.style.textDecoration = 'none';
        thisProject.finished = false;
    }
    saveAll();
}

addProject = function () {
    project = new TaskList();
    project.name = document.querySelector("#newProject").value;
    newTable = document.createElement('table');
    newTable.id = project.name;

    listSection = document.querySelector('article');
    listSection.appendChild(newTable);

    project.rank = projectList.length;
    project.finished = false;
    projectList.push(project);

    project.display();
    document.querySelector('#newProject').value = "";

    newOption = document.createElement('option');
    newOption.value = project.name;
    newOption.innerHTML = project.name;

    dropMenu = document.querySelector('#project');
    dropMenu.appendChild(newOption);

    saveAll();
}

addTask = function () {

    newTask = new Task();

    projectName = document.querySelector('#project').value;

    for (var i = 0; i < projectList.length; i++) {
        if (projectList[i].name == projectName) {
            project = projectList[i];
        }
    }

    newTask.name = document.querySelector('#newTask').value;

    newTask.projectName = project.name;

    newTask.priority = document.querySelector('#priority').value;

    newTask.dueDate = document.querySelector('#date').value;

    newTask.done = false;

    newTask.project = project;

    table = document.querySelector('#' + projectName);

    project.addTask(newTask);

    project.display();

    document.querySelector('#newTask').value = "";
    saveAll();
}

<commit_msg>Delete todo.js<commit_after><|endoftext|>


<commit_before>/**
 * @author AnnatarHe
 * @email iamhele1994@gmail.com
 * @date 2016.10.20
 */

const config = require('./webpack.base.config')

config.devtool = 'eval'

config.devServer = {
    hot: true,
    inline: true,
    hisoryApiFallback: {
        index: '/'
    },
    proxy: {
        '/api/*': {
            target: 'http://127.0.0.1:9999',
            secure: false
        }
    }
}

module.exports = config

<commit_msg>add hot reload<commit_after>/**
 * @author AnnatarHe
 * @email iamhele1994@gmail.com
 * @date 2016.10.20
 */

const webpack = require('webpack')
const config = require('./webpack.base.config')

config.devtool = 'eval'
config.plugins.push(new webpack.HotModuleReplacementPlugin())

config.devServer = {
    historyApiFallback: true,
    proxy: {
        '/api/*': {
            target: 'http://127.0.0.1:9999',
            secure: false
        }
    }
}

module.exports = config

<|endoftext|>


<commit_before>// var chai = require('chai');
// expect = chai.expect;
var expect = require('chai').expect;

var taskList = []

// I can list my tasks
/* var i = 0
function listTasks (i){
  for (var i = 0; i < taskList.length; i++){
    return taskList[i];
  }
}*/

// I can add a task to my list

function addTaskToList(task, list){
  // What is the task? parameter task
  // Where is the task goin? parameter list
  // What order / priority? lowest, on the bottom
  return list.push(task)
}

function deleteTask(task, list){
  return list.splice(task, 1);

}

function editTask(position, newTaskName){
  taskList[position] = newTaskName;
  return newTaskName;

}

function prioritizeTask(task, list){

}

function completeTask(task, position){
  return task[position] = ("[X] " + task[position]);

}

expect(taskList.length).to.equal(0);
addTaskToList("Remember the milk", taskList);
expect(taskList[0]).to.equal("Remember the milk");
expect(taskList.length).to.equal(1);
expect(taskList.length).to.equal(1);
addTaskToList("Take out the trash", taskList);
expect(taskList[1]).to.equal("Take out the trash");
expect(taskList.length).to.equal(2);

expect(completeTask).to.exist;
completeTask(taskList, 1);
expect(taskList[1]).to.equal("[X] Take out the trash");
console.log(taskList);
// listTasks();
// expect(listTasks()).to.equal("Remember the milk", "Take out the trash");
expect(taskList[0]).to.equal("Remember the milk");
editTask(0, "Remember the milk and eggs");
expect(taskList[0]).to.equal("Remember the milk and eggs");
console.log(taskList);

expect(taskList.length).to.equal(2);
deleteTask(1, taskList);
expect(taskList.length).to.equal(1);
expect(taskList[0]).to.equal("Remember the milk and eggs");
console.log(taskList)
<commit_msg>move function add<commit_after>// var chai = require('chai');
// expect = chai.expect;
var expect = require('chai').expect;

var taskList = []

// I can list my tasks
/* var i = 0
function listTasks (i){
  for (var i = 0; i < taskList.length; i++){
    return taskList[i];
  }
}*/

// I can add a task to my list

function addTaskToList(task, list){
  // What is the task? parameter task
  // Where is the task goin? parameter list
  // What order / priority? lowest, on the bottom
  return list.push(task)
}

function deleteTask(task, list){
  return list.splice(task, 1);

}

function editTask(position, newTaskName){
  taskList[position] = newTaskName;
  return newTaskName;

}

Array.prototype.move = function(from, to){
  this.splice(to, 0, this.splice(from, 1)[0]);
  return this;
}
)
/*function prioritizeTask(task, list){

}*/

function completeTask(task, position){
  return task[position] = ("[X] " + task[position]);

}

expect(taskList.length).to.equal(0);
addTaskToList("Remember the milk", taskList);
expect(taskList[0]).to.equal("Remember the milk");
expect(taskList.length).to.equal(1);
expect(taskList.length).to.equal(1);
addTaskToList("Take out the trash", taskList);
expect(taskList[1]).to.equal("Take out the trash");
expect(taskList.length).to.equal(2);

expect(completeTask).to.exist;
completeTask(taskList, 1);
expect(taskList[1]).to.equal("[X] Take out the trash");
console.log(taskList);
// listTasks();
// expect(listTasks()).to.equal("Remember the milk", "Take out the trash");
expect(taskList[0]).to.equal("Remember the milk");
editTask(0, "Remember the milk and eggs");
expect(taskList[0]).to.equal("Remember the milk and eggs");
console.log(taskList);

expect(taskList.length).to.equal(2);
deleteTask(1, taskList);
expect(taskList.length).to.equal(1);
expect(taskList[0]).to.equal("Remember the milk and eggs");
console.log(taskList)
<|endoftext|>


<commit_before>import fetch from 'unfetch';
// eslint-disable-next-line import/no-extraneous-dependencies
import deepFreeze from 'deep-freeze'; // This is a devDependency because it is bundled in.
import ServerInterface from './server-interface';
import PromiseQueue from './promise-queue';

/**
 * Check if the target experiment is loaded on the server.
 * @param  {Object}  serverInterface the server interface.
 * @param  {string}  experimentId    the id of the target experiment.
 * @return {Promise}                 true if the experiment is loaded on the server.
 */
export async function isExperimentLoadedOnServer(
  serverInterface,
  experimentId
) {
  const experiments = await serverInterface.experiments();
  return !!experiments[experimentId];
}

/**
 * Fetch the given experiment design xml file and post it to be imported on the server.
 * @param  {Object}  serverInterface      the server interface.
 * @param  {string}  experimentDesignAddr the address where to downlad the experiment design.
 * @return {Promise}                      resolves when the experiment has been imported.
 */
export async function importExperimentOnServer(
  serverInterface,
  experimentDesignAddr
) {
  const designReq = await fetch(experimentDesignAddr);
  const design = await designReq.text();
  return serverInterface.postExperimentDesign(design);
}

/**
 * Select a run from the server.
 * @param  {Object}  serverInterface
 * @param  {string}  experimentId
 * @param  {string}  [runId]
 * @return {Promise}
 */
export async function selectRun(serverInterface, experimentId, runId) {
  const runInfo = runId
    ? await serverInterface.run(experimentId, runId)
    : await serverInterface.availableRun(experimentId);
  // Check if the ids are consistant.
  if (runInfo.experimentId !== experimentId) {
    throw new Error(
      'Received experiment id is inconsistant with the one that has been requested.'
    );
  } else if (runId && runInfo.id !== runId) {
    throw new Error(
      'Received run id is inconsistant with the one that has been requested.'
    );
  }
  return runInfo;
}

/**
 * Connect to a run (and lock it on the server)
 * @param  {Object}  serverInterface The server interface.
 * @param  {Object}  runInfo         The description of the target run.
 * @return {Promise<{id, experimentId, blocks, currentTrial, lock}>} The run information.
 */
export async function connectToRun(serverInterface, runInfo) {
  // Lock it, fetch the run plan and the current trial (current trial might not be the first
  // on if the run is being resumed).
  const [lock, blocksInfo, currentTrialInfo] = await Promise.all([
    serverInterface.lock(runInfo.experimentId, runInfo.id),
    serverInterface.plan(runInfo.experimentId, runInfo.id),
    serverInterface.currentTrial(runInfo.experimentId, runInfo.id)
  ]);

  return {
    id: runInfo.id,
    experimentId: runInfo.experimentId,
    blocks: blocksInfo,
    currentTrial: currentTrialInfo,
    lock
  };
}

/**
 * Consolidate a run by appending back references toward block on trials, and back references
 * toward the run on blocks
 * @param  {{id, experimentId, blocks}} runInfo The description of the run.
 * @return {{id, experimentId, blocks}}         The run consolidated and frozen.
 */
export function consolidateRun(runInfo) {
  const run = {
    id: runInfo.id,
    experimentId: runInfo.experimentId
  };
  // Insert backrefs to the parent block on each trials, and backrefs to the run on each
  // blocks.
  run.blocks = runInfo.blocks.map(block => {
    const newBlock = Object.assign({}, block, { run });
    newBlock.trials = block.trials.map(trial =>
      Object.assign({}, trial, { block: newBlock })
    );
    return newBlock;
  });
  deepFreeze(run);
  return run;
}

/**
 * RunConnection class.
 * @param  {string} run
 * @param  {string} token
 * @param  {int} startTrialNum
 * @param  {int} startBlockNum
 * @param  {PromiseQueue} postQueue
 * @param  {function} postTrial
 * @return {RunConnection}
 */
export default function RunConnection(
  run,
  token,
  startBlockNum,
  startTrialNum,
  postQueue,
  postTrial
) {
  // Maintain the current trial.
  let currentTrial = run.blocks[startBlockNum].trials[startTrialNum];
  // Register the promise of the last trial result post request. Used to make sure a post request
  // is done before sending a new one.
  let lastTrialResultPost;
  // Create the connection object.

  /**
   * Resolves with the connected run.
   * @return {Promise<Object>}
   */
  this.getRun = async () => run;

  /**
   * Resolves with the current block.
   * @return {Promise<Object>}
   */
  this.getCurrentBlock = async () => currentTrial && currentTrial.block;

  /**
   * Resolves with the current trial.
   * @return {Promise}
   */
  this.getCurrentTrial = async () => currentTrial;

  /**
   * Resolves with the next trial.
   * @return {Promise}
   */
  this.getNextTrial = async () => {
    let nextTrialNum = currentTrial.number + 1;
    let currentBlock = currentTrial.block;
    if (nextTrialNum >= currentBlock.trials.length) {
      currentBlock = run.blocks[currentBlock.number + 1];
      nextTrialNum = 0;
    }
    if (!currentBlock) {
      return undefined;
    }
    return currentBlock.trials[nextTrialNum];
  };

  /**
   * Disconnect (does nothing).
   * @return {Promise}
   */
  this.disconnect = async () => {
    // Nothing to do here.
  };

  /**
   * End a trial by posting its result to the server.
   * @param  {Object}  measures   The trial result.
   * @return {Promise}            A promise resolved when the trial results have been successfuly
   *                              pushed to the server
   */
  this.endCurrentTrial = async measures => {
    const previousTrial = await this.getCurrentTrial();
    if (!previousTrial) {
      throw new Error(
        'Cannot end current trial: it is unknown. ' +
          ' It might be because the run is not connected or it is already finished.'
      );
    }
    // Update the current trial.
    currentTrial = await this.getNextTrial();
    // Post the results.
    lastTrialResultPost = Promise.resolve(lastTrialResultPost).then(() =>
      postTrial(
        run.experimentId,
        run.id,
        previousTrial.block.number,
        previousTrial.number,
        { token, measures }
      )
    );
    // Push the post promise in the queue to monitor unfinished posts.
    postQueue.push(lastTrialResultPost);
    return currentTrial;
  };

  /**
   * Flush the trial result post queue.
   * @param  {int} maxLength  The maximum number of pending trial result post requests before
   *                          resolving the promise
   * @return {Promise}        A promise that resolves when there is maxLength or less pending
   *                          trial results. Resolves immediately if this is already the case
   *                          when the function is called.
   */
  this.flush = maxLength => postQueue.flush(maxLength);
}

/**
 * Create a connection to a run.
 * @param  {string|Object} serverAddressOrInterface The address of the server. Alternatively,
 *                                                  this can be provided as a server interface.
 * @param  {string}       experimentId The id of the experiment.
 * @param  {string}       [runId]  The id of the run.
 * @param  {string}       [experimentDesignAddr] The address of the experiment design (used to)
 *                                               import the experiment on the server if not already
 *                                               loaded.
 * @param  {PromiseQueue} [postQueue=new PromiseQueue()] Post queue that will monitor pending result
 *                                                       posts.
 * @return {Promise<Object>} The run connection.
 */
RunConnection.create = async function createRunConnection(
  serverAddressOrInterface,
  experimentId,
  runId,
  experimentDesignAddr,
  postQueue = new PromiseQueue()
) {
  // Create the interface to the server.
  const serverInterface = typeof serverAddressOrInterface === 'string'
    ? new ServerInterface(serverAddressOrInterface)
    : serverAddressOrInterface;

  // Check if the experiment is loaded on the server, and if not load it.
  if (!await isExperimentLoadedOnServer(serverInterface, experimentId)) {
    await importExperimentOnServer(serverInterface, experimentDesignAddr);
  }

  // Connect to the run.
  const runInfo = await connectToRun(
    serverInterface,
    await selectRun(serverInterface, experimentId, runId)
  );

  // Consolidate the run (insert backrefs to blocks in trials and run in blocks, and deep freeze
  // everything).
  const run = consolidateRun(runInfo);

  return new RunConnection(
    run,
    runInfo.lock.token,
    runInfo.currentTrial.blockNumber,
    runInfo.currentTrial.number,
    postQueue,
    serverInterface.postTrial.bind(serverInterface)
  );
};
<commit_msg>Fix RunConnection.create<commit_after>import fetch from 'unfetch';
// eslint-disable-next-line import/no-extraneous-dependencies
import deepFreeze from 'deep-freeze'; // This is a devDependency because it is bundled in.
import ServerInterface from './server-interface';
import PromiseQueue from './promise-queue';

/**
 * Check if the target experiment is loaded on the server.
 * @param  {Object}  serverInterface the server interface.
 * @param  {string}  experimentId    the id of the target experiment.
 * @return {Promise}                 true if the experiment is loaded on the server.
 */
export async function isExperimentLoadedOnServer(
  serverInterface,
  experimentId
) {
  const experiments = await serverInterface.experiments();
  return !!experiments[experimentId];
}

/**
 * Fetch the given experiment design xml file and post it to be imported on the server.
 * @param  {Object}  serverInterface      the server interface.
 * @param  {string}  experimentDesignAddr the address where to downlad the experiment design.
 * @return {Promise}                      resolves when the experiment has been imported.
 */
export async function importExperimentOnServer(
  serverInterface,
  experimentDesignAddr
) {
  const designReq = await fetch(experimentDesignAddr);
  const design = await designReq.text();
  return serverInterface.postExperimentDesign(design);
}

/**
 * Select a run from the server.
 * @param  {Object}  serverInterface
 * @param  {string}  experimentId
 * @param  {string}  [runId]
 * @return {Promise}
 */
export async function selectRun(serverInterface, experimentId, runId) {
  const runInfo = runId
    ? await serverInterface.run(experimentId, runId)
    : await serverInterface.availableRun(experimentId);
  // Check if the ids are consistant.
  if (runInfo.experimentId !== experimentId) {
    throw new Error(
      'Received experiment id is inconsistant with the one that has been requested.'
    );
  } else if (runId && runInfo.id !== runId) {
    throw new Error(
      'Received run id is inconsistant with the one that has been requested.'
    );
  }
  return runInfo;
}

/**
 * Connect to a run (and lock it on the server)
 * @param  {Object}  serverInterface The server interface.
 * @param  {Object}  runInfo         The description of the target run.
 * @return {Promise<{id, experimentId, blocks, currentTrial, lock}>} The run information.
 */
export async function connectToRun(serverInterface, runInfo) {
  // Lock it, fetch the run plan and the current trial (current trial might not be the first
  // on if the run is being resumed).
  const [lock, blocksInfo, currentTrialInfo] = await Promise.all([
    serverInterface.lock(runInfo.experimentId, runInfo.id),
    serverInterface.plan(runInfo.experimentId, runInfo.id),
    serverInterface.currentTrial(runInfo.experimentId, runInfo.id)
  ]);

  return {
    id: runInfo.id,
    experimentId: runInfo.experimentId,
    blocks: blocksInfo,
    currentTrial: currentTrialInfo,
    lock
  };
}

/**
 * Consolidate a run by appending back references toward block on trials, and back references
 * toward the run on blocks
 * @param  {{id, experimentId, blocks}} runInfo The description of the run.
 * @return {{id, experimentId, blocks}}         The run consolidated and frozen.
 */
export function consolidateRun(runInfo) {
  const run = {
    id: runInfo.id,
    experimentId: runInfo.experimentId
  };
  // Insert backrefs to the parent block on each trials, and backrefs to the run on each
  // blocks.
  run.blocks = runInfo.blocks.map(block => {
    const newBlock = Object.assign({}, block, { run });
    newBlock.trials = block.trials.map(trial =>
      Object.assign({}, trial, { block: newBlock })
    );
    return newBlock;
  });
  deepFreeze(run);
  return run;
}

/**
 * RunConnection class.
 * @param  {string} run
 * @param  {string} token
 * @param  {int} startTrialNum
 * @param  {int} startBlockNum
 * @param  {PromiseQueue} postQueue
 * @param  {function} postTrialResults
 * @return {RunConnection}
 */
export default function RunConnection(
  run,
  token,
  startBlockNum,
  startTrialNum,
  postQueue,
  postTrialResults
) {
  // Maintain the current trial.
  let currentTrial = run.blocks[startBlockNum].trials[startTrialNum];
  // Register the promise of the last trial result post request. Used to make sure a post request
  // is done before sending a new one.
  let lastTrialResultPost;
  // Create the connection object.

  /**
   * Resolves with the connected run.
   * @return {Promise<Object>}
   */
  this.getRun = async () => run;

  /**
   * Resolves with the current block.
   * @return {Promise<Object>}
   */
  this.getCurrentBlock = async () => currentTrial && currentTrial.block;

  /**
   * Resolves with the current trial.
   * @return {Promise}
   */
  this.getCurrentTrial = async () => currentTrial;

  /**
   * Resolves with the next trial.
   * @return {Promise}
   */
  this.getNextTrial = async () => {
    let nextTrialNum = currentTrial.number + 1;
    let currentBlock = currentTrial.block;
    if (nextTrialNum >= currentBlock.trials.length) {
      currentBlock = run.blocks[currentBlock.number + 1];
      nextTrialNum = 0;
    }
    if (!currentBlock) {
      return undefined;
    }
    return currentBlock.trials[nextTrialNum];
  };

  /**
   * Disconnect (does nothing).
   * @return {Promise}
   */
  this.disconnect = async () => {
    // Nothing to do here.
  };

  /**
   * End a trial by posting its result to the server.
   * @param  {Object}  measures   The trial result.
   * @return {Promise}            A promise resolved when the trial results have been successfuly
   *                              pushed to the server
   */
  this.endCurrentTrial = async measures => {
    const previousTrial = await this.getCurrentTrial();
    if (!previousTrial) {
      throw new Error(
        'Cannot end current trial: it is unknown. ' +
          ' It might be because the run is not connected or it is already finished.'
      );
    }
    // Update the current trial.
    currentTrial = await this.getNextTrial();
    // Post the results.
    lastTrialResultPost = Promise.resolve(lastTrialResultPost).then(() =>
      postTrialResults(
        run.experimentId,
        run.id,
        previousTrial.block.number,
        previousTrial.number,
        { token, measures }
      )
    );
    // Push the post promise in the queue to monitor unfinished posts.
    postQueue.push(lastTrialResultPost);
    return currentTrial;
  };

  /**
   * Flush the trial result post queue.
   * @param  {int} maxLength  The maximum number of pending trial result post requests before
   *                          resolving the promise
   * @return {Promise}        A promise that resolves when there is maxLength or less pending
   *                          trial results. Resolves immediately if this is already the case
   *                          when the function is called.
   */
  this.flush = maxLength => postQueue.flush(maxLength);
}

/**
 * Create a connection to a run.
 * @param  {string|Object} serverAddressOrInterface The address of the server. Alternatively,
 *                                                  this can be provided as a server interface.
 * @param  {string}       experimentId The id of the experiment.
 * @param  {string}       [runId]  The id of the run.
 * @param  {string}       [experimentDesignAddr] The address of the experiment design (used to)
 *                                               import the experiment on the server if not already
 *                                               loaded.
 * @param  {PromiseQueue} [postQueue=new PromiseQueue()] Post queue that will monitor pending result
 *                                                       posts.
 * @return {Promise<Object>} The run connection.
 */
RunConnection.create = async function createRunConnection(
  serverAddressOrInterface,
  experimentId,
  runId,
  experimentDesignAddr,
  postQueue = new PromiseQueue()
) {
  // Create the interface to the server.
  const serverInterface = typeof serverAddressOrInterface === 'string'
    ? new ServerInterface(serverAddressOrInterface)
    : serverAddressOrInterface;

  // Check if the experiment is loaded on the server, and if not load it.
  if (!await isExperimentLoadedOnServer(serverInterface, experimentId)) {
    await importExperimentOnServer(serverInterface, experimentDesignAddr);
  }

  // Connect to the run.
  const runInfo = await connectToRun(
    serverInterface,
    await selectRun(serverInterface, experimentId, runId)
  );

  // Consolidate the run (insert backrefs to blocks in trials and run in blocks, and deep freeze
  // everything).
  const run = consolidateRun(runInfo);

  return new RunConnection(
    run,
    runInfo.lock.token,
    runInfo.currentTrial.blockNumber,
    runInfo.currentTrial.number,
    postQueue,
    serverInterface.postTrialResults.bind(serverInterface)
  );
};
<|endoftext|>


<commit_before>/*
* Copyright (c) 2012 Sprymix Inc.
* All rights reserved.
*
* See LICENSE for details.
**/

// %from . import sx

sx.crypt = (function() {
    'use strict';

    function utf8_encode(str) {
        if (!str) {
            return '';
        }
        return unescape(encodeURIComponent(String(str)));
    };

    function hex(n) {
        return (n >> 28 & 0xF).toString(16) +
               (n >> 24 & 0xF).toString(16) +
               (n >> 20 & 0xF).toString(16) +
               (n >> 16 & 0xF).toString(16) +
               (n >> 12 & 0xF).toString(16) +
               (n >> 8 & 0xF).toString(16) +
               (n >> 4 & 0xF).toString(16) +
               (n & 0xF).toString(16)
    }

    var sha1 = (function() {
        // Algorithm from http://en.wikipedia.org/wiki/SHA-1

        var fcc = String.fromCharCode,
            pad0 = fcc(0),
            pads = [fcc(0x80), fcc(0x80) + pad0],
            i,
            maxlen = 0xFFFFFFFF / 8;

        for (i = 2; i < 65; i++) {
            pads[i] = pads[i - 1] + fcc(0);
        }

        return function sha1(msg) {
            if (msg.length > maxlen) {
                throw new sx.Error('unable to calculate sha1: message too long');
            }

            msg = utf8_encode(msg);

            var h0 = 0x67452301,
                h1 = 0xEFCDAB89,
                h2 = 0x98BADCFE,
                h3 = 0x10325476,
                h4 = 0xC3D2E1F0,
                len = msg.length,
                a, b, c, d, e, i, j, k, n, tmp,
                w = Array(80);

            msg += pads[((59 - len) % 64 + 64) % 64]; // fix JS 'mod' bugs

            len = len << 3; // length in bits -- len * 8
            msg += fcc((len >> 24) & 0xFF) + fcc((len >> 16) & 0xFF) +
                   fcc((len >> 8) & 0xFF) + fcc(len & 0xFF);

            len = msg.length;

            for (n = 0; n < len; n += 64) {
                a = h0;
                b = h1;
                c = h2;
                d = h3;
                e = h4;

                for (i = j = 0, k = n; j < 16; i += 4, j++, k = n + i) {
                    w[j] = (msg.charCodeAt(k) << 24) | (msg.charCodeAt(k + 1) << 16) |
                           (msg.charCodeAt(k + 2) << 8) | (msg.charCodeAt(k + 3));
                }

                for (i = 16; i < 80; i++) {
                    k = w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16];
                    w[i] = (k << 1) | (k >>> 31);
                }

                for (i = 0; i < 20; i++) {
                    tmp = ((a << 5) | (a >>> 27)) + e + w[i] + 0x5A827999 + ((b & c) | (~b & d));
                    e = d;
                    d = c;
                    c = (b << 30) | (b >>> 2);
                    b = a;
                    a = tmp;
                }

                for (i = 20; i < 40; i++) {
                    tmp = ((a << 5) | (a >>> 27)) + e  + w[i] + 0x6ED9EBA1 + (b ^ c ^ d);
                    e = d;
                    d = c;
                    c = (b << 30) | (b >>> 2);
                    b = a;
                    a = tmp;
                }

                for (i = 40; i < 60; i++) {
                    tmp = ((a << 5) | (a >>> 27)) + e  + w[i] + 0x8F1BBCDC +
                                                                ((b & c) | (b & d) | (c & d));
                    e = d;
                    d = c;
                    c = (b << 30) | (b >>> 2);
                    b = a;
                    a = tmp;
                }

                for (i = 60; i < 80; i++) {
                    tmp = ((a << 5) | (a >>> 27)) + e + w[i] + 0xCA62C1D6 + (b ^ c ^ d);
                    e = d;
                    d = c;
                    c = (b << 30) | (b >>> 2);
                    b = a;
                    a = tmp;
                }

                h0 = (h0 + a) & 0xFFFFFFFF;
                h1 = (h1 + b) & 0xFFFFFFFF;
                h2 = (h2 + c) & 0xFFFFFFFF;
                h3 = (h3 + d) & 0xFFFFFFFF;
                h4 = (h4 + e) & 0xFFFFFFFF;
            }

            return hex(h0) + hex(h1) + hex(h2) + hex(h3) + hex(h4);
        };
    })();

    return {
        sha1: sha1
    };
})();
<commit_msg>utils.lang.js.crypt.sha1: Fix algorithm.<commit_after>/*
* Copyright (c) 2012 Sprymix Inc.
* All rights reserved.
*
* See LICENSE for details.
**/

// %from . import sx

sx.crypt = (function() {
    'use strict';

    function utf8_encode(str) {
        if (!str) {
            return '';
        }
        return unescape(encodeURIComponent(String(str)));
    };

    function hex(n) {
        return (n >> 28 & 0xF).toString(16) +
               (n >> 24 & 0xF).toString(16) +
               (n >> 20 & 0xF).toString(16) +
               (n >> 16 & 0xF).toString(16) +
               (n >> 12 & 0xF).toString(16) +
               (n >> 8 & 0xF).toString(16) +
               (n >> 4 & 0xF).toString(16) +
               (n & 0xF).toString(16)
    }

    var sha1 = (function() {
        // Algorithm from http://en.wikipedia.org/wiki/SHA-1

        var fcc = String.fromCharCode,
            pad0 = fcc(0),
            pads = [fcc(0x80)],
            i,
            maxlen = 0xFFFFFFFF / 8;

        for (i = 1; i < 70; i++) {
            pads[i] = pads[i - 1] + pad0;
        }

        return function sha1(msg) {
            if (msg.length > maxlen) {
                throw new sx.Error('unable to calculate sha1: message too long');
            }

            msg = utf8_encode(msg);

            var h0 = 0x67452301,
                h1 = 0xEFCDAB89,
                h2 = 0x98BADCFE,
                h3 = 0x10325476,
                h4 = 0xC3D2E1F0,
                len = msg.length,
                a, b, c, d, e, i, j, k, n, tmp,
                w = Array(80);

            // pad with zeroes to be congruent to 56 (448 bits, mod 512)
            // + 4 bytes for zeroes, as part of 64bit length (we append
            // only 32 bits later)
            msg += pads[((55 - len) % 64 + 64) % 64 + 4];

            len = len << 3; // length in bits -- len * 8
            // append 32 bit length
            msg += fcc((len >> 24) & 0xFF) + fcc((len >> 16) & 0xFF) +
                   fcc((len >> 8) & 0xFF) + fcc(len & 0xFF);

            len = msg.length;

            for (n = 0; n < len; n += 64) {
                a = h0;
                b = h1;
                c = h2;
                d = h3;
                e = h4;

                for (i = j = 0, k = n; j < 16; i += 4, j++, k = n + i) {
                    w[j] = (msg.charCodeAt(k) << 24) | (msg.charCodeAt(k + 1) << 16) |
                           (msg.charCodeAt(k + 2) << 8) | (msg.charCodeAt(k + 3));
                }

                for (i = 16; i < 80; i++) {
                    k = w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16];
                    w[i] = (k << 1) | (k >>> 31);
                }

                for (i = 0; i < 20; i++) {
                    tmp = ((a << 5) | (a >>> 27)) + e + w[i] + 0x5A827999 + ((b & c) | (~b & d));
                    e = d;
                    d = c;
                    c = (b << 30) | (b >>> 2);
                    b = a;
                    a = tmp;
                }

                for (i = 20; i < 40; i++) {
                    tmp = ((a << 5) | (a >>> 27)) + e  + w[i] + 0x6ED9EBA1 + (b ^ c ^ d);
                    e = d;
                    d = c;
                    c = (b << 30) | (b >>> 2);
                    b = a;
                    a = tmp;
                }

                for (i = 40; i < 60; i++) {
                    tmp = ((a << 5) | (a >>> 27)) + e  + w[i] + 0x8F1BBCDC +
                                                                ((b & c) | (b & d) | (c & d));
                    e = d;
                    d = c;
                    c = (b << 30) | (b >>> 2);
                    b = a;
                    a = tmp;
                }

                for (i = 60; i < 80; i++) {
                    tmp = ((a << 5) | (a >>> 27)) + e + w[i] + 0xCA62C1D6 + (b ^ c ^ d);
                    e = d;
                    d = c;
                    c = (b << 30) | (b >>> 2);
                    b = a;
                    a = tmp;
                }

                h0 = (h0 + a) & 0xFFFFFFFF;
                h1 = (h1 + b) & 0xFFFFFFFF;
                h2 = (h2 + c) & 0xFFFFFFFF;
                h3 = (h3 + d) & 0xFFFFFFFF;
                h4 = (h4 + e) & 0xFFFFFFFF;
            }

            return hex(h0) + hex(h1) + hex(h2) + hex(h3) + hex(h4);
        };
    })();

    return {
        sha1: sha1
    };
})();
<|endoftext|>


<commit_before>/**
 * @module ol/source/Stamen
 */

import {ATTRIBUTION as OSM_ATTRIBUTION} from './OSM.js';
import XYZ from './XYZ.js';

/**
 * @const
 * @type {Array<string>}
 */
const ATTRIBUTIONS = [
  'Map tiles by Stamen Design, ' +
        'under CC BY' +
        ' 3.0.',
  OSM_ATTRIBUTION
];

/**
 * @type {Object<string, {extension: string, opaque: boolean}>}
 */
const LayerConfig = {
  'terrain': {
    extension: 'jpg',
    opaque: true
  },
  'terrain-background': {
    extension: 'jpg',
    opaque: true
  },
  'terrain-labels': {
    extension: 'png',
    opaque: false
  },
  'terrain-lines': {
    extension: 'png',
    opaque: false
  },
  'toner-background': {
    extension: 'png',
    opaque: true
  },
  'toner': {
    extension: 'png',
    opaque: true
  },
  'toner-hybrid': {
    extension: 'png',
    opaque: false
  },
  'toner-labels': {
    extension: 'png',
    opaque: false
  },
  'toner-lines': {
    extension: 'png',
    opaque: false
  },
  'toner-lite': {
    extension: 'png',
    opaque: true
  },
  'watercolor': {
    extension: 'jpg',
    opaque: true
  }
};

/**
 * @type {Object<string, {minZoom: number, maxZoom: number}>}
 */
const ProviderConfig = {
  'terrain': {
    minZoom: 0,
    maxZoom: 18
  },
  'toner': {
    minZoom: 0,
    maxZoom: 20
  },
  'watercolor': {
    minZoom: 0,
    maxZoom: 18
  }
};

/**
 * @typedef {Object} Options
 * @property {number} [cacheSize] Tile cache size. The default depends on the screen size. Will increase if too small.
 * @property {string} layer Layer name.
 * @property {number} [minZoom] Minimum zoom.
 * @property {number} [maxZoom] Maximum zoom.
 * @property {number} [reprojectionErrorThreshold=0.5] Maximum allowed reprojection error (in pixels).
 * Higher values can increase reprojection performance, but decrease precision.
 * @property {import("../Tile.js").LoadFunction} [tileLoadFunction]
 * Optional function to load a tile given a URL. The default is
 * ```js
 * function(imageTile, src) {
 *   imageTile.getImage().src = src;
 * };
 * ```
 * @property {number} [transition] Duration of the opacity transition for rendering.
 * To disable the opacity transition, pass `transition: 0`.
 * @property {string} [url] URL template. Must include `{x}`, `{y}` or `{-y}`, and `{z}` placeholders.
 * @property {boolean} [wrapX=true] Whether to wrap the world horizontally.
 */

/**
 * @classdesc
 * Layer source for the Stamen tile server.
 * @api
 */
class Stamen extends XYZ {
  /**
   * @param {Options} options Stamen options.
   */
  constructor(options) {
    const i = options.layer.indexOf('-');
    const provider = i == -1 ? options.layer : options.layer.slice(0, i);
    const providerConfig = ProviderConfig[provider];

    const layerConfig = LayerConfig[options.layer];

    const url = options.url !== undefined ? options.url :
      'https://stamen-tiles-{a-d}.a.ssl.fastly.net/' + options.layer +
        '/{z}/{x}/{y}.' + layerConfig.extension;

    super({
      attributions: ATTRIBUTIONS,
      cacheSize: options.cacheSize,
      crossOrigin: 'anonymous',
      maxZoom: options.maxZoom != undefined ? options.maxZoom : providerConfig.maxZoom,
      minZoom: options.minZoom != undefined ? options.minZoom : providerConfig.minZoom,
      opaque: layerConfig.opaque,
      reprojectionErrorThreshold: options.reprojectionErrorThreshold,
      tileLoadFunction: options.tileLoadFunction,
      transition: options.transition,
      url: url,
      wrapX: options.wrapX
    });

  }

}

export default Stamen;
<commit_msg>Open default attributions links in new tab/window<commit_after>/**
 * @module ol/source/Stamen
 */

import {ATTRIBUTION as OSM_ATTRIBUTION} from './OSM.js';
import XYZ from './XYZ.js';

/**
 * @const
 * @type {Array<string>}
 */
const ATTRIBUTIONS = [
  'Map tiles by Stamen Design, ' +
        'under CC BY' +
        ' 3.0.',
  OSM_ATTRIBUTION
];

/**
 * @type {Object<string, {extension: string, opaque: boolean}>}
 */
const LayerConfig = {
  'terrain': {
    extension: 'jpg',
    opaque: true
  },
  'terrain-background': {
    extension: 'jpg',
    opaque: true
  },
  'terrain-labels': {
    extension: 'png',
    opaque: false
  },
  'terrain-lines': {
    extension: 'png',
    opaque: false
  },
  'toner-background': {
    extension: 'png',
    opaque: true
  },
  'toner': {
    extension: 'png',
    opaque: true
  },
  'toner-hybrid': {
    extension: 'png',
    opaque: false
  },
  'toner-labels': {
    extension: 'png',
    opaque: false
  },
  'toner-lines': {
    extension: 'png',
    opaque: false
  },
  'toner-lite': {
    extension: 'png',
    opaque: true
  },
  'watercolor': {
    extension: 'jpg',
    opaque: true
  }
};

/**
 * @type {Object<string, {minZoom: number, maxZoom: number}>}
 */
const ProviderConfig = {
  'terrain': {
    minZoom: 0,
    maxZoom: 18
  },
  'toner': {
    minZoom: 0,
    maxZoom: 20
  },
  'watercolor': {
    minZoom: 0,
    maxZoom: 18
  }
};

/**
 * @typedef {Object} Options
 * @property {number} [cacheSize] Tile cache size. The default depends on the screen size. Will increase if too small.
 * @property {string} layer Layer name.
 * @property {number} [minZoom] Minimum zoom.
 * @property {number} [maxZoom] Maximum zoom.
 * @property {number} [reprojectionErrorThreshold=0.5] Maximum allowed reprojection error (in pixels).
 * Higher values can increase reprojection performance, but decrease precision.
 * @property {import("../Tile.js").LoadFunction} [tileLoadFunction]
 * Optional function to load a tile given a URL. The default is
 * ```js
 * function(imageTile, src) {
 *   imageTile.getImage().src = src;
 * };
 * ```
 * @property {number} [transition] Duration of the opacity transition for rendering.
 * To disable the opacity transition, pass `transition: 0`.
 * @property {string} [url] URL template. Must include `{x}`, `{y}` or `{-y}`, and `{z}` placeholders.
 * @property {boolean} [wrapX=true] Whether to wrap the world horizontally.
 */

/**
 * @classdesc
 * Layer source for the Stamen tile server.
 * @api
 */
class Stamen extends XYZ {
  /**
   * @param {Options} options Stamen options.
   */
  constructor(options) {
    const i = options.layer.indexOf('-');
    const provider = i == -1 ? options.layer : options.layer.slice(0, i);
    const providerConfig = ProviderConfig[provider];

    const layerConfig = LayerConfig[options.layer];

    const url = options.url !== undefined ? options.url :
      'https://stamen-tiles-{a-d}.a.ssl.fastly.net/' + options.layer +
        '/{z}/{x}/{y}.' + layerConfig.extension;

    super({
      attributions: ATTRIBUTIONS,
      cacheSize: options.cacheSize,
      crossOrigin: 'anonymous',
      maxZoom: options.maxZoom != undefined ? options.maxZoom : providerConfig.maxZoom,
      minZoom: options.minZoom != undefined ? options.minZoom : providerConfig.minZoom,
      opaque: layerConfig.opaque,
      reprojectionErrorThreshold: options.reprojectionErrorThreshold,
      tileLoadFunction: options.tileLoadFunction,
      transition: options.transition,
      url: url,
      wrapX: options.wrapX
    });

  }

}

export default Stamen;
<|endoftext|>


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

/**
 * External dependencies
 */
import { useContext, useEffect } from 'react';
import { useFeature } from 'flagged';

/**
 * Internal dependencies
 */
import { ApiContext } from '../../api/apiProvider';
import { Toaster, useToastContext } from '../../../components/toaster';
import { ALERT_SEVERITY } from '../../../constants';

function ToasterView() {
  const {
    state: {
      stories: { error: storyError },
      templates: { error: templateError },
      settings: { error: settingsError },
    },
  } = useContext(ApiContext);

  const {
    actions: { removeToast, addToast },
    state: { activeToasts },
  } = useToastContext();

  const enableSettingsView = useFeature('enableSettingsView');

  useEffect(() => {
    if (storyError?.id) {
      addToast({
        message: storyError.message,
        severity: ALERT_SEVERITY.ERROR,
        id: storyError.id,
      });
    }
  }, [storyError, addToast]);

  useEffect(() => {
    if (templateError?.id) {
      addToast({
        message: templateError.message,
        severity: ALERT_SEVERITY.ERROR,
        id: templateError.id,
      });
    }
  }, [templateError, addToast]);

  useEffect(() => {
    if (enableSettingsView && settingsError?.id) {
      addToast({
        message: settingsError.message,
        severity: ALERT_SEVERITY.ERROR,
        id: settingsError.id,
      });
    }
  }, [settingsError, addToast, enableSettingsView]);

  return (
    <Toaster
      activeToasts={activeToasts}
      handleRemoveToast={removeToast}
      isAllowEarlyDismiss
    />
  );
}

export default ToasterView;
<commit_msg>add media errors to toaster<commit_after>/*
 * Copyright 2020 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * External dependencies
 */
import { useContext, useEffect } from 'react';
import { useFeature } from 'flagged';

/**
 * Internal dependencies
 */
import { ApiContext } from '../../api/apiProvider';
import { Toaster, useToastContext } from '../../../components/toaster';
import { ALERT_SEVERITY } from '../../../constants';

function ToasterView() {
  const {
    state: {
      stories: { error: storyError },
      templates: { error: templateError },
      settings: { error: settingsError },
      media: { error: mediaError },
    },
  } = useContext(ApiContext);

  const {
    actions: { removeToast, addToast },
    state: { activeToasts },
  } = useToastContext();

  const enableSettingsView = useFeature('enableSettingsView');

  useEffect(() => {
    if (storyError?.id) {
      addToast({
        message: storyError.message,
        severity: ALERT_SEVERITY.ERROR,
        id: storyError.id,
      });
    }
  }, [storyError, addToast]);

  useEffect(() => {
    if (templateError?.id) {
      addToast({
        message: templateError.message,
        severity: ALERT_SEVERITY.ERROR,
        id: templateError.id,
      });
    }
  }, [templateError, addToast]);

  useEffect(() => {
    if (enableSettingsView && settingsError?.id) {
      addToast({
        message: settingsError.message,
        severity: ALERT_SEVERITY.ERROR,
        id: settingsError.id,
      });
    }
  }, [settingsError, addToast, enableSettingsView]);

  useEffect(() => {
    if (mediaError?.id) {
      addToast({
        message: mediaError.message,
        severity: ALERT_SEVERITY.ERROR,
        id: mediaError.id,
      });
    }
  }, [mediaError, addToast]);

  return (
    <Toaster
      activeToasts={activeToasts}
      handleRemoveToast={removeToast}
      isAllowEarlyDismiss
    />
  );
}

export default ToasterView;
<|endoftext|>


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

/**
 * External dependencies
 */
import PropTypes from 'prop-types';
import styled from 'styled-components';

/**
 * Internal dependencies
 */
import { BUTTON_TYPES, KEYBOARD_USER_SELECTOR } from '../../constants';
import { TypographyPresets } from '../typography';

const StyledButton = styled.button`
  ${TypographyPresets.Small};

  font-weight: ${({ theme }) => theme.typography.weight.bold};
  align-items: center;
  color: ${({ theme }) => theme.colors.white};
  cursor: pointer;
  border: ${({ theme }) => theme.borders.transparent};
  border-radius: ${({ theme }) => theme.button.borderRadius}px;
  display: flex;
  min-width: 100px;
  opacity: 0.75;
  padding: 4px 12px;
  text-decoration: none;

  &:focus,
  &:active,
  &:hover {
    opacity: 1;
    outline: none;
    color: ${({ theme }) => theme.colors.white};
  }

  ${KEYBOARD_USER_SELECTOR} &:focus {
    border-color: ${({ theme }) => theme.colors.action};
  }

  &:disabled {
    opacity: 0.3;
    pointer-events: none;
  }
`;

const PrimaryButton = styled(StyledButton)`
  background-color: ${({ theme }) => theme.colors.bluePrimary};
`;

// TODO: address CTA active styling
const CtaButton = styled(StyledButton)`
  background-color: ${({ theme }) => theme.colors.bluePrimary};
  opacity: 1;
`;

const SecondaryButton = styled(StyledButton)`
  border-radius: 0px;
  background-color: transparent;
  text-shadow: ${({ theme }) => theme.text.shadow};

  &:focus,
  &:active,
  &:hover {
    text-shadow: ${({ theme }) => theme.text.shadow};
  }
`;

const StyledChildren = styled.span`
  margin: 0 auto;
  padding: 0;
  display: flex;
  justify-content: center;
  align-items: center;

  border-bottom: ${({ isSecondary }) =>
    isSecondary ? '0.1em solid currentColor' : 'none'};
`;

StyledChildren.propTypes = {
  isSecondary: PropTypes.bool,
};

const Button = ({
  children,
  isDisabled,
  isLink,
  type = BUTTON_TYPES.PRIMARY,
  ...rest
}) => {
  const ButtonOptions = {
    [BUTTON_TYPES.PRIMARY]: PrimaryButton,
    [BUTTON_TYPES.SECONDARY]: SecondaryButton,
    [BUTTON_TYPES.CTA]: CtaButton,
  };

  const StyledButtonByType = ButtonOptions[type];

  return (
    <StyledButtonByType
      as={isLink ? 'a' : 'button'}
      disabled={isDisabled}
      {...rest}
    >
      <StyledChildren isSecondary={type === BUTTON_TYPES.SECONDARY}>
        {children}
      </StyledChildren>
    </StyledButtonByType>
  );
};

Button.propTypes = {
  children: PropTypes.node.isRequired,
  isCta: PropTypes.bool,
  isDisabled: PropTypes.bool,
  isLink: PropTypes.bool,
  type: PropTypes.oneOf(Object.values(BUTTON_TYPES)),
};

export default Button;
export { default as PaginationButton } from './paginationButton';
<commit_msg>button needed text align center.<commit_after>/*
 * Copyright 2020 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * External dependencies
 */
import PropTypes from 'prop-types';
import styled from 'styled-components';

/**
 * Internal dependencies
 */
import { BUTTON_TYPES, KEYBOARD_USER_SELECTOR } from '../../constants';
import { TypographyPresets } from '../typography';

const StyledButton = styled.button`
  ${TypographyPresets.Small};

  font-weight: ${({ theme }) => theme.typography.weight.bold};
  align-items: center;
  justify-content: center;
  color: ${({ theme }) => theme.colors.white};
  cursor: pointer;
  border: ${({ theme }) => theme.borders.transparent};
  border-radius: ${({ theme }) => theme.button.borderRadius}px;
  display: flex;
  min-width: 100px;
  opacity: 0.75;
  padding: 4px 12px;
  text-decoration: none;
  text-align: center;

  &:focus,
  &:active,
  &:hover {
    opacity: 1;
    outline: none;
    color: ${({ theme }) => theme.colors.white};
  }

  ${KEYBOARD_USER_SELECTOR} &:focus {
    border-color: ${({ theme }) => theme.colors.action};
  }

  &:disabled {
    opacity: 0.3;
    pointer-events: none;
  }
`;

const PrimaryButton = styled(StyledButton)`
  background-color: ${({ theme }) => theme.colors.bluePrimary};
`;

// TODO: address CTA active styling
const CtaButton = styled(StyledButton)`
  background-color: ${({ theme }) => theme.colors.bluePrimary};
  opacity: 1;
`;

const SecondaryButton = styled(StyledButton)`
  border-radius: 0px;
  background-color: transparent;
  text-shadow: ${({ theme }) => theme.text.shadow};

  &:focus,
  &:active,
  &:hover {
    text-shadow: ${({ theme }) => theme.text.shadow};
  }
`;

const StyledChildren = styled.span`
  margin: 0 auto;
  padding: 0;
  display: flex;
  justify-content: center;
  align-items: center;

  border-bottom: ${({ isSecondary }) =>
    isSecondary ? '0.1em solid currentColor' : 'none'};
`;

StyledChildren.propTypes = {
  isSecondary: PropTypes.bool,
};

const Button = ({
  children,
  isDisabled,
  isLink,
  type = BUTTON_TYPES.PRIMARY,
  ...rest
}) => {
  const ButtonOptions = {
    [BUTTON_TYPES.PRIMARY]: PrimaryButton,
    [BUTTON_TYPES.SECONDARY]: SecondaryButton,
    [BUTTON_TYPES.CTA]: CtaButton,
  };

  const StyledButtonByType = ButtonOptions[type];

  return (
    <StyledButtonByType
      as={isLink ? 'a' : 'button'}
      disabled={isDisabled}
      {...rest}
    >
      <StyledChildren isSecondary={type === BUTTON_TYPES.SECONDARY}>
        {children}
      </StyledChildren>
    </StyledButtonByType>
  );
};

Button.propTypes = {
  children: PropTypes.node.isRequired,
  isCta: PropTypes.bool,
  isDisabled: PropTypes.bool,
  isLink: PropTypes.bool,
  type: PropTypes.oneOf(Object.values(BUTTON_TYPES)),
};

export default Button;
export { default as PaginationButton } from './paginationButton';
<|endoftext|>


<commit_before>// ==UserScript==
// @name        FUT Auto Remove Sold Auctions
// @version     0.1.2
// @description Automatically remove sold items from the transfer list
// @license     MIT
// @author      Tim Klingeleers
// @match       https://www.easports.com/fifa/ultimate-team/web-app/*
// @namespace   https://github.com/Mardaneus86
// @updateURL   https://raw.githubusercontent.com/Mardaneus86/futwebapp-tampermonkey/master/remove-sold-auctions.user.js
// @downloadURL https://raw.githubusercontent.com/Mardaneus86/futwebapp-tampermonkey/master/remove-sold-auctions.user.js
// @supportURL  https://github.com/Mardaneus86/futwebapp-tampermonkey/issues
// @grant       GM_notification
// @grant       window.focus
// @grant       GM_xmlhttpRequest
// @grant       GM_getValue
// @grant       GM_setValue
// @connect     maker.ifttt.com
// @require     https://raw.githubusercontent.com/WebReflection/circular-json/v0.3.3/build/circular-json.js
// ==/UserScript==
// ==OpenUserJS==
// @author Mardaneus86
// ==/OpenUserJS==
(function () {
  'use strict';

  var sendToIFTTT = function sendToIFTTT(salePrice, profit, data) {
    var ifttt_maker_key = localStorage.getItem('ifttt_maker_key');
    if (ifttt_maker_key === null) {
      return; // only send to IFTTT if the maker key is set in the settings
    }
    var url = "https://maker.ifttt.com/trigger/market_action/with/key/" + ifttt_maker_key;
    GM_xmlhttpRequest({
      method: "POST",
      headers: {"Content-Type": "application/json"},
      url: url,
      data: CircularJSON.stringify({ "value1" : salePrice, "value2" : profit, "value3" : CircularJSON.stringify(data) })
    });
  };

  gAuthenticationModel.addListener(models.AuthenticationModel.EVENT_AUTHENTICATION_SUCCESSFUL, this, function () {
    setInterval(function () { repositories.Item.getTransferItems().observe(this, _handleExpiredAuctions); }, 60000);

    var _handleExpiredAuctions = function handleExpiredAuctions(observer, data) {
      var unsoldItems = data.items.filter(function(d) { return d.state !== enums.ItemState.INVALID; });

      if (unsoldItems.length > 0) {
        var lastSalePrices = JSON.parse(GM_getValue('auctionlastprices', '{}'));

        for (var j = 0; j < unsoldItems.length; j++) {
          if (lastSalePrices[unsoldItems[j].id] === null) {
            lastSalePrices[unsoldItems[j].id] = {
              lastSalePrice: unsoldItems[j].lastSalePrice
            };
          }
        }
        GM_setValue('auctionlastprices', JSON.stringify(lastSalePrices));
      }

      var soldItems = data.items.filter(function (d) { return d.state === enums.ItemState.INVALID; });
      if (soldItems.length > 0) {
        for (var i = 0; i < soldItems.length; i++) {
          var lastSalePrice = 0;
          var lastSalePricesList = JSON.parse(GM_getValue('auctionlastprices', '{}'));
          var lastSalePriceO = lastSalePricesList[soldItems[i].id];
          if (lastSalePriceO !== null) {
            lastSalePrice = lastSalePriceO.lastSalePrice;
          }
          var profit = (soldItems[i]._auction.currentBid * 0.95) - lastSalePrice; // calculate 5% EA tax
          sendToIFTTT(soldItems[i]._auction.currentBid, profit, {
            lastSalePrice: lastSalePrice,
            salePrice: soldItems[i]._auction.currentBid,
            name: soldItems[i]._staticData.name,
            firstname: soldItems[i]._staticData.firstName,
            lastname: soldItems[i]._staticData.lastName
          });
          if (soldItems[i].type == "player") {
            //var player = repositories.Item.getStaticDataByDefId(soldItems[i].resourceId);

            GM_notification({
              text: soldItems[i]._staticData.firstName + " " + soldItems[i]._staticData.lastName + " sold for " + soldItems[i]._auction.currentBid,
              title: "FUT 18 Web App",
              onclick: function () { window.focus(); },
            });
          } else {
            // TODO: can we get the item name?
            GM_notification({
              text: soldItems[i].type + " item sold for " + soldItems[i]._auction.currentBid,
              title: "FUT 18 Web App",
              onclick: function () { window.focus(); },
            });
          }
        }
        console.log(soldItems.length + " item(s) sold");
        services.Item.clearSoldItems().observe(this, function (observer, data) {
          //noop
        });
      }
    };
  });
})();
<commit_msg>fix: do not report profit if buy price is unknown<commit_after>// ==UserScript==
// @name        FUT Auto Remove Sold Auctions
// @version     0.1.3
// @description Automatically remove sold items from the transfer list
// @license     MIT
// @author      Tim Klingeleers
// @match       https://www.easports.com/fifa/ultimate-team/web-app/*
// @namespace   https://github.com/Mardaneus86
// @updateURL   https://raw.githubusercontent.com/Mardaneus86/futwebapp-tampermonkey/master/remove-sold-auctions.user.js
// @downloadURL https://raw.githubusercontent.com/Mardaneus86/futwebapp-tampermonkey/master/remove-sold-auctions.user.js
// @supportURL  https://github.com/Mardaneus86/futwebapp-tampermonkey/issues
// @grant       GM_notification
// @grant       window.focus
// @grant       GM_xmlhttpRequest
// @grant       GM_getValue
// @grant       GM_setValue
// @connect     maker.ifttt.com
// @require     https://raw.githubusercontent.com/WebReflection/circular-json/v0.3.3/build/circular-json.js
// ==/UserScript==
// ==OpenUserJS==
// @author Mardaneus86
// ==/OpenUserJS==
(function () {
  'use strict';

  var sendToIFTTT = function sendToIFTTT(salePrice, profit, data) {
    var ifttt_maker_key = localStorage.getItem('ifttt_maker_key');
    if (ifttt_maker_key === null) {
      return; // only send to IFTTT if the maker key is set in the settings
    }
    var url = "https://maker.ifttt.com/trigger/market_action/with/key/" + ifttt_maker_key;
    GM_xmlhttpRequest({
      method: "POST",
      headers: {"Content-Type": "application/json"},
      url: url,
      data: CircularJSON.stringify({ "value1" : salePrice, "value2" : profit, "value3" : CircularJSON.stringify(data) })
    });
  };

  gAuthenticationModel.addListener(models.AuthenticationModel.EVENT_AUTHENTICATION_SUCCESSFUL, this, function () {
    setInterval(function () { repositories.Item.getTransferItems().observe(this, _handleExpiredAuctions); }, 60000);

    var _handleExpiredAuctions = function handleExpiredAuctions(observer, data) {
      var unsoldItems = data.items.filter(function(d) { return d.state !== enums.ItemState.INVALID; });

      if (unsoldItems.length > 0) {
        var lastSalePrices = JSON.parse(GM_getValue('auctionlastprices', '{}'));

        for (var j = 0; j < unsoldItems.length; j++) {
          if (lastSalePrices[unsoldItems[j].id] === null) {
            lastSalePrices[unsoldItems[j].id] = {
              lastSalePrice: unsoldItems[j].lastSalePrice
            };
          }
        }
        GM_setValue('auctionlastprices', JSON.stringify(lastSalePrices));
      }

      var soldItems = data.items.filter(function (d) { return d.state === enums.ItemState.INVALID; });
      if (soldItems.length > 0) {
        for (var i = 0; i < soldItems.length; i++) {
          var lastSalePrice = 0;
          var lastSalePriceKnown = false;
          var lastSalePricesList = JSON.parse(GM_getValue('auctionlastprices', '{}'));
          var lastSalePriceO = lastSalePricesList[soldItems[i].id];
          if (!!lastSalePriceO) {
            lastSalePrice = lastSalePriceO.lastSalePrice;
            lastSalePriceKnown = true;
          }
          var profit = (soldItems[i]._auction.currentBid * 0.95) - lastSalePrice; // calculate 5% EA tax
          if (soldItems[i].type == "player") {
            var player = repositories.Item.getStaticDataByDefId(soldItems[i].resourceId);
            var playerName = "Unknown player";
            if (player !== null) {
              playerName = player.name + " (" + player.rating + ")";
            }
            GM_notification({
              text: playerName + " sold for " + soldItems[i]._auction.currentBid,
              title: "FUT 18 Web App",
              onclick: function () { window.focus(); },
            });

            sendToIFTTT(soldItems[i]._auction.currentBid, lastSalePriceKnown ? profit : "", {
              lastSalePrice: lastSalePriceKnown ? lastSalePrice : "",
              salePrice: soldItems[i]._auction.currentBid,
              name: playerName
            });
          } else {
            // TODO: can we get the item name?
            GM_notification({
              text: soldItems[i]._staticData.name + " item sold for " + soldItems[i]._auction.currentBid,
              title: "FUT 18 Web App",
              onclick: function () { window.focus(); },
            });
            sendToIFTTT(soldItems[i]._auction.currentBid, lastSalePriceKnown ? profit : "", {
              lastSalePrice: lastSalePriceKnown ? lastSalePrice : "",
              salePrice: soldItems[i]._auction.currentBid,
              name: soldItems[i]._staticData.name
            });
          }
        }
        console.log(soldItems.length + " item(s) sold");
        services.Item.clearSoldItems().observe(this, function (observer, data) {
          //noop
        });
      }
    };
  });
})();
<|endoftext|>


<commit_before>ManageIQ.angular.app.controller('logCollectionFormController', ['$http', '$scope', 'serverId', '$attrs', 'miqService', 'miqDBBackupService', function($http, $scope, serverId, $attrs, miqService, miqDBBackupService) {
  var init = function() {

    $scope.logCollectionModel = {
      depot_name: '',
      uri: '',
      uri_prefix: '',
      log_protocol: '',
      log_userid: '',
      log_password: '',
      log_verify: ''
    };
    $scope.afterGet = true;
    $scope.modelCopy = angular.copy( $scope.logCollectionModel );
    $scope.logCollectionFormFieldsUrl = $attrs.logCollectionFormFieldsUrl;
    $scope.logProtocolChangedUrl = $attrs.logProtocolChangedUrl;
    $scope.saveUrl = $attrs.saveUrl;
    $scope.validateClicked = miqService.validateWithAjax;
    $scope.model = 'logCollectionModel';

    ManageIQ.angular.scope = $scope;

    if (serverId == 'new') {
      $scope.logCollectionModel.depot_name = '';
      $scope.logCollectionModel.uri = '';
      $scope.logCollectionModel.uri_prefix = '';
      $scope.logCollectionModel.log_userid = '';
      $scope.logCollectionModel.log_password = '';
      $scope.logCollectionModel.log_verify = '';
      $scope.logCollectionModel.log_protocol = '';
      $scope.modelCopy = angular.copy( $scope.logCollectionModel );
    } else {
      $scope.newRecord = false;

      miqService.sparkleOn();

      url = $scope.logCollectionFormFieldsUrl;
      $http.get(url + serverId).success(function(data) {
        $scope.logCollectionModel.log_protocol = data.log_protocol;
        $scope.logCollectionModel.depot_name = data.depot_name;
        $scope.logCollectionModel.uri = data.uri;
        $scope.logCollectionModel.uri_prefix = data.uri_prefix;
        $scope.logCollectionModel.log_userid = data.log_userid;

        if($scope.logCollectionModel.log_userid != '') {
          $scope.logCollectionModel.log_password = $scope.logCollectionModel.log_verify = miqService.storedPasswordPlaceholder;
        }

        $scope.afterGet = true;
        $scope.modelCopy = angular.copy( $scope.logCollectionModel );

        miqService.sparkleOff();
      });
    }
  };

  $scope.logProtocolChanged = function() {
    $scope.$broadcast('setNewRecord');

    if(miqDBBackupService.knownProtocolsList.indexOf($scope.logCollectionModel.log_protocol) == -1 &&
       $scope.logCollectionModel.log_protocol != '') {
      url = $scope.logProtocolChangedUrl;
      miqService.sparkleOn();
      $http.get(url + serverId + '?log_protocol=' + $scope.logCollectionModel.log_protocol).success(function (data) {
        $scope.logCollectionModel.depot_name = data.depot_name;
        $scope.logCollectionModel.uri = data.uri;
        $scope.logCollectionModel.uri_prefix = data.uri_prefix;
        miqService.sparkleOff();
      });
    }
    $scope.$broadcast('reactiveFocus');
    miqDBBackupService.logProtocolChanged($scope.logCollectionModel);
  };

  $scope.isBasicInfoValid = function() {
    if($scope.angularForm.depot_name.$valid &&
      $scope.angularForm.uri.$valid &&
      $scope.angularForm.log_userid.$valid &&
      $scope.angularForm.log_password.$valid &&
      $scope.angularForm.log_verify.$valid)
      return true;
    else
      return false;
  };

  $scope.saveClicked = function() {
    miqService.sparkleOn();
    var url = $scope.saveUrl + serverId + '?button=save';
    moreUrlParams = $.param(miqService.serializeModel($scope.logCollectionModel));
    if(moreUrlParams)
      url += '&' + decodeURIComponent(moreUrlParams);
    miqService.miqAjaxButton(url, false);
    $scope.angularForm.$setPristine(true);
  };

  $scope.resetClicked = function() {
    $scope.$broadcast('resetClicked');
    $scope.logCollectionModel = angular.copy( $scope.modelCopy );
    $scope.angularForm.$setPristine(true);
    miqService.miqFlash("warn", __("All changes have been reset"));
  };

  $scope.cancelClicked = function() {
    miqService.sparkleOn();
    var url = $scope.saveUrl + serverId + '?button=cancel';
    miqService.miqAjaxButton(url, true);
    $scope.angularForm.$setPristine(true);
  };

  $scope.canValidateBasicInfo = function () {
    if ($scope.isBasicInfoValid())
      return true;
    else
      return false;
  }

  init();
}]);
<commit_msg>Save the miqDBBackupService service on the current scope<commit_after>ManageIQ.angular.app.controller('logCollectionFormController', ['$http', '$scope', 'serverId', '$attrs', 'miqService', 'miqDBBackupService', function($http, $scope, serverId, $attrs, miqService, miqDBBackupService) {
  var init = function() {

    $scope.logCollectionModel = {
      depot_name: '',
      uri: '',
      uri_prefix: '',
      log_protocol: '',
      log_userid: '',
      log_password: '',
      log_verify: ''
    };
    $scope.afterGet = true;
    $scope.modelCopy = angular.copy( $scope.logCollectionModel );
    $scope.logCollectionFormFieldsUrl = $attrs.logCollectionFormFieldsUrl;
    $scope.logProtocolChangedUrl = $attrs.logProtocolChangedUrl;
    $scope.saveUrl = $attrs.saveUrl;
    $scope.validateClicked = miqService.validateWithAjax;
    $scope.model = 'logCollectionModel';
    $scope.miqDBBackupService = miqDBBackupService;

    ManageIQ.angular.scope = $scope;

    if (serverId == 'new') {
      $scope.logCollectionModel.depot_name = '';
      $scope.logCollectionModel.uri = '';
      $scope.logCollectionModel.uri_prefix = '';
      $scope.logCollectionModel.log_userid = '';
      $scope.logCollectionModel.log_password = '';
      $scope.logCollectionModel.log_verify = '';
      $scope.logCollectionModel.log_protocol = '';
      $scope.modelCopy = angular.copy( $scope.logCollectionModel );
    } else {
      $scope.newRecord = false;

      miqService.sparkleOn();

      url = $scope.logCollectionFormFieldsUrl;
      $http.get(url + serverId).success(function(data) {
        $scope.logCollectionModel.log_protocol = data.log_protocol;
        $scope.logCollectionModel.depot_name = data.depot_name;
        $scope.logCollectionModel.uri = data.uri;
        $scope.logCollectionModel.uri_prefix = data.uri_prefix;
        $scope.logCollectionModel.log_userid = data.log_userid;

        if($scope.logCollectionModel.log_userid != '') {
          $scope.logCollectionModel.log_password = $scope.logCollectionModel.log_verify = miqService.storedPasswordPlaceholder;
        }

        $scope.afterGet = true;
        $scope.modelCopy = angular.copy( $scope.logCollectionModel );

        miqService.sparkleOff();
      });
    }
  };

  $scope.logProtocolChanged = function() {
    $scope.$broadcast('setNewRecord');

    if(miqDBBackupService.knownProtocolsList.indexOf($scope.logCollectionModel.log_protocol) == -1 &&
       $scope.logCollectionModel.log_protocol != '') {
      url = $scope.logProtocolChangedUrl;
      miqService.sparkleOn();
      $http.get(url + serverId + '?log_protocol=' + $scope.logCollectionModel.log_protocol).success(function (data) {
        $scope.logCollectionModel.depot_name = data.depot_name;
        $scope.logCollectionModel.uri = data.uri;
        $scope.logCollectionModel.uri_prefix = data.uri_prefix;
        miqService.sparkleOff();
      });
    }
    $scope.$broadcast('reactiveFocus');
    miqDBBackupService.logProtocolChanged($scope.logCollectionModel);
  };

  $scope.isBasicInfoValid = function() {
    if($scope.angularForm.depot_name.$valid &&
      $scope.angularForm.uri.$valid &&
      $scope.angularForm.log_userid.$valid &&
      $scope.angularForm.log_password.$valid &&
      $scope.angularForm.log_verify.$valid)
      return true;
    else
      return false;
  };

  $scope.saveClicked = function() {
    miqService.sparkleOn();
    var url = $scope.saveUrl + serverId + '?button=save';
    moreUrlParams = $.param(miqService.serializeModel($scope.logCollectionModel));
    if(moreUrlParams)
      url += '&' + decodeURIComponent(moreUrlParams);
    miqService.miqAjaxButton(url, false);
    $scope.angularForm.$setPristine(true);
  };

  $scope.resetClicked = function() {
    $scope.$broadcast('resetClicked');
    $scope.logCollectionModel = angular.copy( $scope.modelCopy );
    $scope.angularForm.$setPristine(true);
    miqService.miqFlash("warn", __("All changes have been reset"));
  };

  $scope.cancelClicked = function() {
    miqService.sparkleOn();
    var url = $scope.saveUrl + serverId + '?button=cancel';
    miqService.miqAjaxButton(url, true);
    $scope.angularForm.$setPristine(true);
  };

  $scope.canValidateBasicInfo = function () {
    if ($scope.isBasicInfoValid())
      return true;
    else
      return false;
  }

  init();
}]);
<|endoftext|>