<commit_before>import React from 'react';
import styled from 'styled-components';
import { colors, fonts } from '../../styles';
import { connect } from 'react-redux';
import { openLogModal } from '../../actions';

const Label = styled.span`
  font-family: ${fonts.latoRegular};
  color: ${colors.secondaryText};
  font-size: 14px;
  padding-right: 8px;
`;

const Value = styled.span`
  font-family: ${fonts.latoBold};
  color: ${colors.primaryText};
  font-size: 14px;
  padding-right: 20px;
`;

const Link = styled.a`
  &::before {
    content: ${props => (props.withSeperator ? '"|"' : '')};
    margin: ${props => (props.withSeperator ? '0 10px' : '')};
  }
`;

export class LogDetails extends React.Component {
  onClick (log, event) {
    const { openLogModal } = this.props;
    event.preventDefault();
    openLogModal(log);
  }

  render () {
    const { referenceLog, testLog } = this.props;
    if (!referenceLog && !testLog) return [];
    return (

        view log:
        <Value>
        {
            testLog
              ? <Link href="#" onClick={ this.onClick.bind(this, testLog) } >
                  test
                </Link>
              : []
          }
          {
            referenceLog
              ? <Link withSeperator href="#" onClick={ this.onClick.bind(this, referenceLog) } >
                  reference
                </Link>
              : []
          }
        </Value>

    );
  }
}

const mapStateToProps = state => {
  return {};
};

const mapDispatchToProps = dispatch => {
  return {
    openLogModal: value => {
      dispatch(openLogModal(value));
    }
  };
};

const LogDetailsContainer = connect(mapStateToProps, mapDispatchToProps)(
  LogDetails
);

export default LogDetailsContainer;
<commit_msg>Browser report label tweak<commit_after>import React from 'react';
import styled from 'styled-components';
import { colors, fonts } from '../../styles';
import { connect } from 'react-redux';
import { openLogModal } from '../../actions';

const Label = styled.span`
  font-family: ${fonts.latoRegular};
  color: ${colors.secondaryText};
  font-size: 14px;
  padding-right: 8px;
`;

const Value = styled.span`
  font-family: ${fonts.latoBold};
  color: ${colors.primaryText};
  font-size: 14px;
  padding-right: 20px;
`;

const Link = styled.a`
  &::before {
    content: ${props => (props.withSeperator ? '"|"' : '')};
    margin: ${props => (props.withSeperator ? '0 10px' : '')};
  }
`;

export class LogDetails extends React.Component {
  onClick (log, event) {
    const { openLogModal } = this.props;
    event.preventDefault();
    openLogModal(log);
  }

  render () {
    const { referenceLog, testLog } = this.props;
    if (!referenceLog && !testLog) return [];
    return (

        browser log:
        <Value>
        {
            testLog
              ? <Link href="#" onClick={ this.onClick.bind(this, testLog) } >
                  test
                </Link>
              : []
          }
          {
            referenceLog
              ? <Link withSeperator href="#" onClick={ this.onClick.bind(this, referenceLog) } >
                  reference
                </Link>
              : []
          }
        </Value>

    );
  }
}

const mapStateToProps = state => {
  return {};
};

const mapDispatchToProps = dispatch => {
  return {
    openLogModal: value => {
      dispatch(openLogModal(value));
    }
  };
};

const LogDetailsContainer = connect(mapStateToProps, mapDispatchToProps)(
  LogDetails
);

export default LogDetailsContainer;
<|endoftext|>


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

var assert = require('assert');
var raptorRegexp = require('raptor-regexp');
var propertyHandlers = require('property-handlers');
var Taglib = require('./Taglib');

function AttrHandlers(attr){
    assert.ok(attr);
    assert.equal(typeof attr, 'object');
    this.attr = attr;
}

AttrHandlers.prototype = {
    /**
     * The attribute type. One of the following:
     * - string (the default)
     * - expression (a JavaScript expression)
     * - number
     * - integer
     * - int
     * - boolean
     * - float
     * - double
     * - object
     * - array
     *
     */
    type: function(value) {
        var attr = this.attr;
        attr.type = value;
    },

    /**
     * The name of the target property to use when mapping
     * the attribute to a property on the target object.
     */
    targetProperty: function(value) {
        var attr = this.attr;
        attr.targetProperty = value;
    },
    /**
     * The "default-value" property allows a default value
     * to be provided when the attribute is not declared
     * on the custom tag.
     */
    defaultValue: function(value) {
        var attr = this.attr;
        attr.defaultValue = value;
    },
    /**
     * The "pattern" property allows the attribute
     * to be matched based on a simplified regular expression.
     *
     * Example:
     *
     * "pattern": "myprefix-*"
     */
    pattern: function(value) {
        var attr = this.attr;
        if (value === true) {
            var patternRegExp = raptorRegexp.simple(attr.name);
            attr.pattern = patternRegExp;
        }
    },

    /**
     * If "allow-expressions" is set to true (the default) then
     * the the attribute value will be parsed to find any dynamic
     * parts.
     */
    allowExpressions: function(value) {
        var attr = this.attr;
        attr.allowExpressions = value;
    },

    /**
     * By default, the Marko compiler maps an attribute
     * to a property by removing all dashes from the attribute
     * name and converting each character after a dash to
     * an uppercase character (e.g. "my-attr" --> "myAttr").
     *
     * Setting "preserve-name" to true will prevent this from
     * happening for the attribute.
     */
    preserveName: function(value) {
        var attr = this.attr;
        attr.preserveName = value;
    },
    /**
     * Declares an attribute as required. Currently, this is
     * not enforced and is only used for documentation purposes.
     *
     * Example:
     * "required": true
     */
    required: function(value) {
        var attr = this.attr;
        attr.required = value === true;
    },
    /**
     * This is the opposite of "preserve-name" and will result
     * in dashes being removed from the attribute if set to true.
     */
    removeDashes: function(value) {
        var attr = this.attr;
        attr.removeDashes = value === true;
    },
    /**
     * The description of the attribute. Only used for documentation.
     */
    description: function() {

    },

    /**
     * The "set-flag" property allows a "flag" to be added to a Node instance
     * at compile time if the attribute is found on the node. This is helpful
     * if an attribute uses a pattern and a transformer wants to have a simple
     * check to see if the Node has an attribute that matched the pattern.
     *
     * Example:
     *
     * "set-flag": "myCustomFlag"
     *
     * A Node instance can be checked if it has a flag set as shown below:
     *
     * if (node.hasFlag('myCustomFlag')) { ... }
     *
     *
     */
    setFlag: function(value) {
        var attr = this.attr;
        attr.setFlag = value;
    },
    /**
     * An attribute can be marked for ignore. Ignored attributes
     * will be ignored during compilation.
     */
    ignore: function(value) {
        var attr = this.attr;
        if (value === true) {
            attr.ignore = true;
        }
    },

    autocomplete: function(value) {
        this.attr.autocomplete = value;
    }
};

exports.isSupportedProperty = function(name) {
    return AttrHandlers.prototype.hasOwnProperty(name);
};

exports.loadAttribute = function loadAttribute(attrName, attrProps, path) {
    var attr = new Taglib.Attribute(attrName);

    if (attrProps == null) {
        attrProps = {};
    } else if (typeof attrProps === 'string') {
        attrProps = {
            type: attrProps
        };
    }

    var attrHandlers = new AttrHandlers(attr);
    propertyHandlers(attrProps, attrHandlers, path);
    return attr;
};<commit_msg>Added support for an "enum" attribute value<commit_after>/*
* Copyright 2011 eBay Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*    http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

var assert = require('assert');
var raptorRegexp = require('raptor-regexp');
var propertyHandlers = require('property-handlers');
var Taglib = require('./Taglib');

function AttrHandlers(attr){
    assert.ok(attr);
    assert.equal(typeof attr, 'object');
    this.attr = attr;
}

AttrHandlers.prototype = {
    /**
     * The attribute type. One of the following:
     * - string (the default)
     * - expression (a JavaScript expression)
     * - number
     * - integer
     * - int
     * - boolean
     * - float
     * - double
     * - object
     * - array
     *
     */
    type: function(value) {
        var attr = this.attr;
        attr.type = value;
    },

    /**
     * The name of the target property to use when mapping
     * the attribute to a property on the target object.
     */
    targetProperty: function(value) {
        var attr = this.attr;
        attr.targetProperty = value;
    },
    /**
     * The "default-value" property allows a default value
     * to be provided when the attribute is not declared
     * on the custom tag.
     */
    defaultValue: function(value) {
        var attr = this.attr;
        attr.defaultValue = value;
    },
    /**
     * The "pattern" property allows the attribute
     * to be matched based on a simplified regular expression.
     *
     * Example:
     *
     * "pattern": "myprefix-*"
     */
    pattern: function(value) {
        var attr = this.attr;
        if (value === true) {
            var patternRegExp = raptorRegexp.simple(attr.name);
            attr.pattern = patternRegExp;
        }
    },

    /**
     * If "allow-expressions" is set to true (the default) then
     * the the attribute value will be parsed to find any dynamic
     * parts.
     */
    allowExpressions: function(value) {
        var attr = this.attr;
        attr.allowExpressions = value;
    },

    /**
     * By default, the Marko compiler maps an attribute
     * to a property by removing all dashes from the attribute
     * name and converting each character after a dash to
     * an uppercase character (e.g. "my-attr" --> "myAttr").
     *
     * Setting "preserve-name" to true will prevent this from
     * happening for the attribute.
     */
    preserveName: function(value) {
        var attr = this.attr;
        attr.preserveName = value;
    },
    /**
     * Declares an attribute as required. Currently, this is
     * not enforced and is only used for documentation purposes.
     *
     * Example:
     * "required": true
     */
    required: function(value) {
        var attr = this.attr;
        attr.required = value === true;
    },
    /**
     * This is the opposite of "preserve-name" and will result
     * in dashes being removed from the attribute if set to true.
     */
    removeDashes: function(value) {
        var attr = this.attr;
        attr.removeDashes = value === true;
    },
    /**
     * The description of the attribute. Only used for documentation.
     */
    description: function() {

    },

    /**
     * The "set-flag" property allows a "flag" to be added to a Node instance
     * at compile time if the attribute is found on the node. This is helpful
     * if an attribute uses a pattern and a transformer wants to have a simple
     * check to see if the Node has an attribute that matched the pattern.
     *
     * Example:
     *
     * "set-flag": "myCustomFlag"
     *
     * A Node instance can be checked if it has a flag set as shown below:
     *
     * if (node.hasFlag('myCustomFlag')) { ... }
     *
     *
     */
    setFlag: function(value) {
        var attr = this.attr;
        attr.setFlag = value;
    },
    /**
     * An attribute can be marked for ignore. Ignored attributes
     * will be ignored during compilation.
     */
    ignore: function(value) {
        var attr = this.attr;
        if (value === true) {
            attr.ignore = true;
        }
    },

    autocomplete: function(value) {
        this.attr.autocomplete = value;
    },

    enum: function(value) {
        this.attr.enum = value;
    }
};

exports.isSupportedProperty = function(name) {
    return AttrHandlers.prototype.hasOwnProperty(name);
};

exports.loadAttribute = function loadAttribute(attrName, attrProps, path) {
    var attr = new Taglib.Attribute(attrName);

    if (attrProps == null) {
        attrProps = {};
    } else if (typeof attrProps === 'string') {
        attrProps = {
            type: attrProps
        };
    }

    var attrHandlers = new AttrHandlers(attr);
    propertyHandlers(attrProps, attrHandlers, path);
    return attr;
};<|endoftext|>


<commit_before>// ==UserScript==
// @name         Toggl - Weekly report
// @namespace    https://github.com/fabiencrassat
// @version      0.7.1
// @description  Calculate and display the work day percentages
// @author       Fabien Crassat <fabien@crassat.com>
// @include      https://toggl.com/app/*
// @grant        none
// ==/UserScript==

/*global $, console */

/*eslint no-console: ["error", { allow: ["info", "warn", "error"] }] */

"use strict";

const weekDaysPlusTotal = [0, 1, 2, 3, 4, 5, 6, 7];
const urlToFollow = /^https:\/\/toggl\.com\/app\/reports\/weekly\/\d+\/period\/([a-z])\w+/;
const apiUrlToFollow = "https://toggl.com/reports/api/v2/weekly.json";
const decimalLenght = 2;

var oldFetch = fetch; // must be on the global scope

const buildFetch = function(doSomethingWithResponse) {
    fetch = function(url, options) {
        var promise = oldFetch(url, options);
        // Do something with the promise
        promise.then(doSomethingWithResponse).catch(function(error) {
            console.error("Error in fetch processing", error);
        });
        return promise;
    };
}
const backFetch = function() {
    fetch = oldFetch;
}

function sleep() {
    return new Promise((resolve) => setTimeout(resolve, 1000));
}

const cleanDisplay = function() {
    $(".fcr-toggl").remove();
}

const percentage = function(numerator, denumerator) {
    if (!numerator || !denumerator || denumerator === 0) {
        return 0;
    }
    return (numerator / denumerator);
};

const extractOneDay = function(data, dayNumber, totalDay) {
    var dataDay = [];
    data.forEach(function(dataLine) {
        dataDay.push(percentage(dataLine.totals[dayNumber], totalDay));
    });
    return dataDay;
};

const calculate = function(weeklyData) {
    let dataDaysPlusTotal = [];
    weekDaysPlusTotal.forEach(function(dayOrTotal, index) {
        dataDaysPlusTotal.push(extractOneDay(weeklyData.data, index, weeklyData.week_totals[index]));
    });

    let result = [];
    weeklyData.data.forEach(function(data, index) {
        let dataDayPlusTotal = dataDaysPlusTotal.map((value) => value[index]);
        result.push({ client: data.title.client, project: data.title.project, data: dataDayPlusTotal });
    });

    return result;
}

const filterDataFromProject = function(data, lineElement) {
    const text = $(lineElement).find(".col-grouping").text();
    if (text.trim() === "(no project)") {
        return data.find((value) => value.project === null && value.client === null);
    }
    return data.find((value) => value.project + " " + value.client === text);
}

const displayInTheLine = function(lineElement, data) {
    $(lineElement).find("td[class^='day-'], td.col-total").each(function(indexColumn) {
        const dataInCeil = data.data[indexColumn];
        if (dataInCeil !== 0) {
            $(this).append("
" + dataInCeil.toFixed(decimalLenght) + "
");
        }
    });
}

const display = function(data = []) {
    const displayLines = $("table.data-table tr:not(:first, .subgroup, :last)");
    if (!displayLines || displayLines.length === 0) {
        console.warn("There is no display line", displayLines);
        return;
    }
    displayLines.each(function() {
        displayInTheLine(this, filterDataFromProject(data, this));
    });
}

const calculateAndDisplay = async function(data) {
    await sleep(); // Need to wait to the table built
    cleanDisplay();
    display(calculate(data));
}

const response = function(response) {
    const responseClone = response.clone(); // clone to consume json body stream response
    if(!responseClone.ok || responseClone.status !== 200) return;

    const url = response.url;
    if (url && url.startsWith(apiUrlToFollow)) {
        console.info("Url to follow found!", url);
        responseClone.json().then(calculateAndDisplay);
    }
}

const fireOnChange = function(url = "") {
    // Check if we are in the good page
    if (urlToFollow.test(url)) {
        buildFetch(response);
        return true;
    }
    backFetch();
    return false;
};

console.info("== Toggl - Weekly report ==");
// Follow the HTML5 url change in the API browser
(function (old) {
    window.history.pushState = function () {
        old.apply(window.history, arguments);
        fireOnChange(window.location.href);
    };
}(window.history.pushState));
fireOnChange(location.href);
<commit_msg>Fixes from Codacy #2<commit_after>// ==UserScript==
// @name         Toggl - Weekly report
// @namespace    https://github.com/fabiencrassat
// @version      0.7.2
// @description  Calculate and display the work day percentages
// @author       Fabien Crassat <fabien@crassat.com>
// @include      https://toggl.com/app/*
// @grant        none
// ==/UserScript==

/*global $, console */

/*eslint no-console: ["error", { allow: ["info", "warn", "error"] }] */

"use strict";

const weekDaysPlusTotal = [0, 1, 2, 3, 4, 5, 6, 7];
const urlToFollow = /^https:\/\/toggl\.com\/app\/reports\/weekly\/\d+\/period\/([a-z])\w+/;
const apiUrlToFollow = "https://toggl.com/reports/api/v2/weekly.json";
const decimalLenght = 2;

var oldFetch = fetch; // must be on the global scope

const buildFetch = function(doSomethingWithResponse) {
    fetch = function(url, options) {
        var promise = oldFetch(url, options);
        // Do something with the promise
        promise.then(doSomethingWithResponse).catch(function(error) {
            console.error("Error in fetch processing", error);
        });
        return promise;
    };
};
const backFetch = function() {
    fetch = oldFetch;
};

function sleep() {
    return new Promise((resolve) => setTimeout(resolve, 1000));
};

const cleanDisplay = function() {
    $(".fcr-toggl").remove();
};

const percentage = function(numerator, denumerator) {
    if (!numerator || !denumerator || denumerator === 0) {
        return 0;
    }
    return (numerator / denumerator);
};

const extractOneDay = function(data, dayNumber, totalDay) {
    var dataDay = [];
    data.forEach(function(dataLine) {
        dataDay.push(percentage(dataLine.totals[dayNumber], totalDay));
    });
    return dataDay;
};

const calculate = function(weeklyData) {
    let dataDaysPlusTotal = [];
    weekDaysPlusTotal.forEach(function(dayOrTotal, index) {
        dataDaysPlusTotal.push(extractOneDay(weeklyData.data, index, weeklyData.week_totals[index]));
    });

    let result = [];
    weeklyData.data.forEach(function(data, index) {
        let dataDayPlusTotal = dataDaysPlusTotal.map((value) => value[index]);
        result.push({ client: data.title.client, project: data.title.project, data: dataDayPlusTotal });
    });

    return result;
};

const filterDataFromProject = function(data, lineElement) {
    const text = $(lineElement).find(".col-grouping").text();
    if (text.trim() === "(no project)") {
        return data.find((value) => value.project === null && value.client === null);
    }
    return data.find((value) => value.project + " " + value.client === text);
};

const displayInTheLine = function(lineElement, data) {
    $(lineElement).find("td[class^='day-'], td.col-total").each(function(indexColumn) {
        const dataInCeil = data.data[indexColumn];
        if (dataInCeil !== 0) {
            $(this).append("
" + dataInCeil.toFixed(decimalLenght) + "
");
        }
    });
};

const display = function(data = []) {
    const displayLines = $("table.data-table tr:not(:first, .subgroup, :last)");
    if (!displayLines || displayLines.length === 0) {
        console.warn("There is no display line", displayLines);
        return;
    }
    displayLines.each(function() {
        displayInTheLine(this, filterDataFromProject(data, this));
    });
};

const calculateAndDisplay = async function(data) {
    await sleep(); // Need to wait to the table built
    cleanDisplay();
    display(calculate(data));
};

const checkResponseAndUrl = function(response, url) {
    return response.ok && response.status === 200 && url && url.startsWith(apiUrlToFollow);
};

const response = function(response) {
    const responseClone = response.clone(); // clone to consume json body stream response
    const url = response.url;
    if (checkResponseAndUrl(responseClone, url)) {
        console.info("Url to follow found!", url);
        responseClone.json().then(calculateAndDisplay);
    }
};

const fireOnChange = function(url = "") {
    // Check if we are in the good page
    if (urlToFollow.test(url)) {
        buildFetch(response);
        return true;
    }
    backFetch();
    return false;
};

console.info("== Toggl - Weekly report ==");
// Follow the HTML5 url change in the API browser
(function (old) {
    window.history.pushState = function () {
        old.apply(window.history, arguments);
        fireOnChange(window.location.href);
    };
}(window.history.pushState));
fireOnChange(location.href);
<|endoftext|>


<commit_before>define(["Tone/core/Tone", "Tone/source/BufferSource", "Tone/core/Buffers",
	"Tone/source/Source", "Tone/component/Volume"],
function (Tone) {

	/**
	 *  @class Tone.MultiPlayer is well suited for one-shots, multi-sampled instruments
	 *         or any time you need to play a bunch of audio buffers.
	 *
	 *  @deprecated Use Tone.Players instead.
	 *  @param  {Object|Array|Tone.Buffers}  buffers  The buffers which are available
	 *                                                to the MultiPlayer
	 *  @param {Function} onload The callback to invoke when all of the buffers are loaded.
	 *  @extends {Tone}
	 *  @example
	 * var multiPlayer = new MultiPlayer({
	 * 	"kick" : "path/to/kick.mp3",
	 * 	"snare" : "path/to/snare.mp3",
	 * }, function(){
	 * 	multiPlayer.start("kick");
	 * });
	 *  @example
	 * //can also store the values in an array
	 * var multiPlayer = new MultiPlayer(["path/to/kick.mp3", "path/to/snare.mp3"],
	 * function(){
	 * 	//if an array is passed in, the samples are referenced to by index
	 * 	multiPlayer.start(1);
	 * });
	 */
	Tone.MultiPlayer = function(urls){

		console.warn("Tone.MultiPlayer is deprecated. Use Tone.Players instead.");

		//remove the urls from the options
		if (arguments.length === 1 && !Tone.isUndef(arguments[0]) && !arguments[0].hasOwnProperty("urls")){
			urls = { "urls" : urls };
		}
		var options = Tone.defaults(arguments, ["urls", "onload"], Tone.MultiPlayer);
		Tone.Source.call(this, options);

		if (options.urls instanceof Tone.Buffers){
			/**
			 *  All the buffers belonging to the player.
			 *  @type  {Tone.Buffers}
			 */
			this.buffers = options.urls;
		} else {
			this.buffers = new Tone.Buffers(options.urls, options.onload);
		}

		/**
		 *  Keeps track of the currently playing sources.
		 *  @type  {Object}
		 *  @private
		 */
		this._activeSources = {};

		/**
		 *  The fade in envelope which is applied
		 *  to the beginning of the BufferSource
		 *  @type  {Time}
		 */
		this.fadeIn = options.fadeIn;

		/**
		 *  The fade out envelope which is applied
		 *  to the end of the BufferSource
		 *  @type  {Time}
		 */
		this.fadeOut = options.fadeOut;
	};

	Tone.extend(Tone.MultiPlayer, Tone.Source);

	/**
	 *  The defaults
	 *  @type  {Object}
	 */
	Tone.MultiPlayer.defaults = {
		"onload" : Tone.noOp,
		"fadeIn" : 0,
		"fadeOut" : 0
	};

	/**
	 * Make the source from the buffername
	 * @param  {String} bufferName
	 * @return {Tone.BufferSource}
	 * @private
	 */
	Tone.MultiPlayer.prototype._makeSource = function(bufferName){
		var buffer;
		if (Tone.isString(bufferName) || Tone.isNumber(bufferName)){
			buffer = this.buffers.get(bufferName).get();
		} else if (bufferName instanceof Tone.Buffer){
			buffer = bufferName.get();
		} else if (bufferName instanceof AudioBuffer){
			buffer = bufferName;
		}
		var source = new Tone.BufferSource(buffer).connect(this.output);
		if (!this._activeSources.hasOwnProperty(bufferName)){
			this._activeSources[bufferName] = [];
		}
		this._activeSources[bufferName].push(source);
		return source;
	};

	/**
	 *  Start a buffer by name. The `start` method allows a number of options
	 *  to be passed in such as offset, interval, and gain. This is good for multi-sampled
	 *  instruments and sound sprites where samples are repitched played back at different velocities.
	 *  @param  {String}  bufferName    The name of the buffer to start.
	 *  @param  {Time}  time      When to start the buffer.
	 *  @param  {Time}  [offset=0]    The offset into the buffer to play from.
	 *  @param  {Time=}  duration   How long to play the buffer for.
	 *  @param  {Interval}  [pitch=0]  The interval to repitch the buffer.
	 *  @param  {Gain}  [gain=1]      The gain to play the sample at.
	 *  @return  {Tone.MultiPlayer}  this
	 */
	Tone.MultiPlayer.prototype.start = function(bufferName, time, offset, duration, pitch, gain){
		time = this.toSeconds(time);
		var source = this._makeSource(bufferName);
		source.start(time, offset, duration, Tone.defaultArg(gain, 1), this.fadeIn);
		if (duration){
			source.stop(time + this.toSeconds(duration), this.fadeOut);
		}
		pitch = Tone.defaultArg(pitch, 0);
		source.playbackRate.value = Tone.intervalToFrequencyRatio(pitch);
		return this;
	};

	/**
	 *  Start a looping buffer by name. Similar to `start`, but the buffer
	 *  is looped instead of played straight through. Can still be stopped with `stop`.
	 *  @param  {String}  bufferName    The name of the buffer to start.
	 *  @param  {Time}  time      When to start the buffer.
	 *  @param  {Time}  [offset=0]    The offset into the buffer to play from.
	 *  @param  {Time=}  loopStart   The start of the loop.
	 *  @param  {Time=}  loopEnd	The end of the loop.
	 *  @param  {Interval}  [pitch=0]  The interval to repitch the buffer.
	 *  @param  {Gain}  [gain=1]      The gain to play the sample at.
	 *  @return  {Tone.MultiPlayer}  this
	 */
	Tone.MultiPlayer.prototype.startLoop = function(bufferName, time, offset, loopStart, loopEnd, pitch, gain){
		time = this.toSeconds(time);
		var source = this._makeSource(bufferName);
		source.loop = true;
		source.loopStart = this.toSeconds(Tone.defaultArg(loopStart, 0));
		source.loopEnd = this.toSeconds(Tone.defaultArg(loopEnd, 0));
		source.start(time, offset, undefined, Tone.defaultArg(gain, 1), this.fadeIn);
		pitch = Tone.defaultArg(pitch, 0);
		source.playbackRate.value = Tone.intervalToFrequencyRatio(pitch);
		return this;
	};

	/**
	 *  Stop the first played instance of the buffer name.
	 *  @param  {String}  bufferName  The buffer to stop.
	 *  @param  {Time=}  time    When to stop the buffer
	 *  @return  {Tone.MultiPlayer}  this
	 */
	Tone.MultiPlayer.prototype.stop = function(bufferName, time){
		if (this._activeSources[bufferName] && this._activeSources[bufferName].length){
			time = this.toSeconds(time);
			this._activeSources[bufferName].shift().stop(time, this.fadeOut);
		} else {
			throw new Error("Tone.MultiPlayer: cannot stop a buffer that hasn't been started or is already stopped");
		}
		return this;
	};

	/**
	 *  Stop all currently playing buffers at the given time.
	 *  @param  {Time=}  time  When to stop the buffers.
	 *  @return  {Tone.MultiPlayer}  this
	 */
	Tone.MultiPlayer.prototype.stopAll = function(time){
		time = this.toSeconds(time);
		for (var bufferName in this._activeSources){
			var sources = this._activeSources[bufferName];
			for (var i = 0; i < sources.length; i++){
				sources[i].stop(time);
			}
		}
		return this;
	};

	/**
	 *  Add another buffer to the available buffers.
	 *  @param {String} name The name to that the buffer is refered
	 *                       to in start/stop methods.
	 *  @param {String|Tone.Buffer} url The url of the buffer to load
	 *                                  or the buffer.
	 *  @param {Function} callback The function to invoke after the buffer is loaded.
	 */
	Tone.MultiPlayer.prototype.add = function(name, url, callback){
		this.buffers.add(name, url, callback);
		return this;
	};

	/**
	 *  Returns the playback state of the source. "started"
	 *  if there are any buffers playing. "stopped" otherwise.
	 *  @type {Tone.State}
	 *  @readOnly
	 *  @memberOf Tone.MultiPlayer#
	 *  @name state
	 */
	Object.defineProperty(Tone.MultiPlayer.prototype, "state", {
		get : function(){
			return this._activeSources.length > 0 ? Tone.State.Started : Tone.State.Stopped;
		}
	});

	/**
	 * Mute the output.
	 * @memberOf Tone.MultiPlayer#
	 * @type {boolean}
	 * @name mute
	 * @example
	 * //mute the output
	 * source.mute = true;
	 */
	Object.defineProperty(Tone.MultiPlayer.prototype, "mute", {
		get : function(){
			return this._volume.mute;
		},
		set : function(mute){
			this._volume.mute = mute;
		}
	});

	/**
	 *  Clean up.
	 *  @return  {Tone.MultiPlayer}  this
	 */
	Tone.MultiPlayer.prototype.dispose = function(){
		Tone.Source.prototype.dispose.call(this);
		for (var bufferName in this._activeSources){
			this._activeSources[bufferName].forEach(function(source){
				source.dispose();
			});
		}
		this.buffers.dispose();
		this.buffers = null;
		this._activeSources = null;
		return this;
	};

	return Tone.MultiPlayer;
});<commit_msg>added link in deprecation notice<commit_after>define(["Tone/core/Tone", "Tone/source/BufferSource", "Tone/core/Buffers",
	"Tone/source/Source", "Tone/component/Volume"],
function (Tone) {

	/**
	 *  @class Tone.MultiPlayer is well suited for one-shots, multi-sampled instruments
	 *         or any time you need to play a bunch of audio buffers.
	 *
	 *  @deprecated Use [Tone.Players](Players) instead.
	 *  @param  {Object|Array|Tone.Buffers}  buffers  The buffers which are available
	 *                                                to the MultiPlayer
	 *  @param {Function} onload The callback to invoke when all of the buffers are loaded.
	 *  @extends {Tone}
	 *  @example
	 * var multiPlayer = new MultiPlayer({
	 * 	"kick" : "path/to/kick.mp3",
	 * 	"snare" : "path/to/snare.mp3",
	 * }, function(){
	 * 	multiPlayer.start("kick");
	 * });
	 *  @example
	 * //can also store the values in an array
	 * var multiPlayer = new MultiPlayer(["path/to/kick.mp3", "path/to/snare.mp3"],
	 * function(){
	 * 	//if an array is passed in, the samples are referenced to by index
	 * 	multiPlayer.start(1);
	 * });
	 */
	Tone.MultiPlayer = function(urls){

		console.warn("Tone.MultiPlayer is deprecated. Use Tone.Players instead.");

		//remove the urls from the options
		if (arguments.length === 1 && !Tone.isUndef(arguments[0]) && !arguments[0].hasOwnProperty("urls")){
			urls = { "urls" : urls };
		}
		var options = Tone.defaults(arguments, ["urls", "onload"], Tone.MultiPlayer);
		Tone.Source.call(this, options);

		if (options.urls instanceof Tone.Buffers){
			/**
			 *  All the buffers belonging to the player.
			 *  @type  {Tone.Buffers}
			 */
			this.buffers = options.urls;
		} else {
			this.buffers = new Tone.Buffers(options.urls, options.onload);
		}

		/**
		 *  Keeps track of the currently playing sources.
		 *  @type  {Object}
		 *  @private
		 */
		this._activeSources = {};

		/**
		 *  The fade in envelope which is applied
		 *  to the beginning of the BufferSource
		 *  @type  {Time}
		 */
		this.fadeIn = options.fadeIn;

		/**
		 *  The fade out envelope which is applied
		 *  to the end of the BufferSource
		 *  @type  {Time}
		 */
		this.fadeOut = options.fadeOut;
	};

	Tone.extend(Tone.MultiPlayer, Tone.Source);

	/**
	 *  The defaults
	 *  @type  {Object}
	 */
	Tone.MultiPlayer.defaults = {
		"onload" : Tone.noOp,
		"fadeIn" : 0,
		"fadeOut" : 0
	};

	/**
	 * Make the source from the buffername
	 * @param  {String} bufferName
	 * @return {Tone.BufferSource}
	 * @private
	 */
	Tone.MultiPlayer.prototype._makeSource = function(bufferName){
		var buffer;
		if (Tone.isString(bufferName) || Tone.isNumber(bufferName)){
			buffer = this.buffers.get(bufferName).get();
		} else if (bufferName instanceof Tone.Buffer){
			buffer = bufferName.get();
		} else if (bufferName instanceof AudioBuffer){
			buffer = bufferName;
		}
		var source = new Tone.BufferSource(buffer).connect(this.output);
		if (!this._activeSources.hasOwnProperty(bufferName)){
			this._activeSources[bufferName] = [];
		}
		this._activeSources[bufferName].push(source);
		return source;
	};

	/**
	 *  Start a buffer by name. The `start` method allows a number of options
	 *  to be passed in such as offset, interval, and gain. This is good for multi-sampled
	 *  instruments and sound sprites where samples are repitched played back at different velocities.
	 *  @param  {String}  bufferName    The name of the buffer to start.
	 *  @param  {Time}  time      When to start the buffer.
	 *  @param  {Time}  [offset=0]    The offset into the buffer to play from.
	 *  @param  {Time=}  duration   How long to play the buffer for.
	 *  @param  {Interval}  [pitch=0]  The interval to repitch the buffer.
	 *  @param  {Gain}  [gain=1]      The gain to play the sample at.
	 *  @return  {Tone.MultiPlayer}  this
	 */
	Tone.MultiPlayer.prototype.start = function(bufferName, time, offset, duration, pitch, gain){
		time = this.toSeconds(time);
		var source = this._makeSource(bufferName);
		source.start(time, offset, duration, Tone.defaultArg(gain, 1), this.fadeIn);
		if (duration){
			source.stop(time + this.toSeconds(duration), this.fadeOut);
		}
		pitch = Tone.defaultArg(pitch, 0);
		source.playbackRate.value = Tone.intervalToFrequencyRatio(pitch);
		return this;
	};

	/**
	 *  Start a looping buffer by name. Similar to `start`, but the buffer
	 *  is looped instead of played straight through. Can still be stopped with `stop`.
	 *  @param  {String}  bufferName    The name of the buffer to start.
	 *  @param  {Time}  time      When to start the buffer.
	 *  @param  {Time}  [offset=0]    The offset into the buffer to play from.
	 *  @param  {Time=}  loopStart   The start of the loop.
	 *  @param  {Time=}  loopEnd	The end of the loop.
	 *  @param  {Interval}  [pitch=0]  The interval to repitch the buffer.
	 *  @param  {Gain}  [gain=1]      The gain to play the sample at.
	 *  @return  {Tone.MultiPlayer}  this
	 */
	Tone.MultiPlayer.prototype.startLoop = function(bufferName, time, offset, loopStart, loopEnd, pitch, gain){
		time = this.toSeconds(time);
		var source = this._makeSource(bufferName);
		source.loop = true;
		source.loopStart = this.toSeconds(Tone.defaultArg(loopStart, 0));
		source.loopEnd = this.toSeconds(Tone.defaultArg(loopEnd, 0));
		source.start(time, offset, undefined, Tone.defaultArg(gain, 1), this.fadeIn);
		pitch = Tone.defaultArg(pitch, 0);
		source.playbackRate.value = Tone.intervalToFrequencyRatio(pitch);
		return this;
	};

	/**
	 *  Stop the first played instance of the buffer name.
	 *  @param  {String}  bufferName  The buffer to stop.
	 *  @param  {Time=}  time    When to stop the buffer
	 *  @return  {Tone.MultiPlayer}  this
	 */
	Tone.MultiPlayer.prototype.stop = function(bufferName, time){
		if (this._activeSources[bufferName] && this._activeSources[bufferName].length){
			time = this.toSeconds(time);
			this._activeSources[bufferName].shift().stop(time, this.fadeOut);
		} else {
			throw new Error("Tone.MultiPlayer: cannot stop a buffer that hasn't been started or is already stopped");
		}
		return this;
	};

	/**
	 *  Stop all currently playing buffers at the given time.
	 *  @param  {Time=}  time  When to stop the buffers.
	 *  @return  {Tone.MultiPlayer}  this
	 */
	Tone.MultiPlayer.prototype.stopAll = function(time){
		time = this.toSeconds(time);
		for (var bufferName in this._activeSources){
			var sources = this._activeSources[bufferName];
			for (var i = 0; i < sources.length; i++){
				sources[i].stop(time);
			}
		}
		return this;
	};

	/**
	 *  Add another buffer to the available buffers.
	 *  @param {String} name The name to that the buffer is refered
	 *                       to in start/stop methods.
	 *  @param {String|Tone.Buffer} url The url of the buffer to load
	 *                                  or the buffer.
	 *  @param {Function} callback The function to invoke after the buffer is loaded.
	 */
	Tone.MultiPlayer.prototype.add = function(name, url, callback){
		this.buffers.add(name, url, callback);
		return this;
	};

	/**
	 *  Returns the playback state of the source. "started"
	 *  if there are any buffers playing. "stopped" otherwise.
	 *  @type {Tone.State}
	 *  @readOnly
	 *  @memberOf Tone.MultiPlayer#
	 *  @name state
	 */
	Object.defineProperty(Tone.MultiPlayer.prototype, "state", {
		get : function(){
			return this._activeSources.length > 0 ? Tone.State.Started : Tone.State.Stopped;
		}
	});

	/**
	 * Mute the output.
	 * @memberOf Tone.MultiPlayer#
	 * @type {boolean}
	 * @name mute
	 * @example
	 * //mute the output
	 * source.mute = true;
	 */
	Object.defineProperty(Tone.MultiPlayer.prototype, "mute", {
		get : function(){
			return this._volume.mute;
		},
		set : function(mute){
			this._volume.mute = mute;
		}
	});

	/**
	 *  Clean up.
	 *  @return  {Tone.MultiPlayer}  this
	 */
	Tone.MultiPlayer.prototype.dispose = function(){
		Tone.Source.prototype.dispose.call(this);
		for (var bufferName in this._activeSources){
			this._activeSources[bufferName].forEach(function(source){
				source.dispose();
			});
		}
		this.buffers.dispose();
		this.buffers = null;
		this._activeSources = null;
		return this;
	};

	return Tone.MultiPlayer;
});<|endoftext|>


<commit_before>// ==UserScript==
// @name            Top auto scrollbar
// @name:ru         %name%
// @description     Automatic appearing top scrollbar if the page length is more than twice the height of the screen
// @description:ru  %description%
// @namespace       github.com/totalamd
// @match           *://*/*
// @exclude
// @version         1.0.1
// @downloadURL
// @updateURL
// @grant           GM_listValues
// @grant           GM_setValue
// @grant           GM_getValue
// @grant           GM_deleteValue
// @grant           GM_registerMenuCommand
// @noframes
// ==/UserScript==

"use strict";
const l = function(){}, i = function(){};

(function(){
	const l = console.log.bind(console), i = console.info.bind(console);

	function addToList() {
		let locations = GM_getValue('locations') || {};
		locations[location.hostname] = true;
		GM_setValue('locations', locations);
		location.reload();
	}

	function delFromList() {
		let locations = GM_getValue('locations');
		delete locations[location.hostname];
		GM_setValue('locations', locations);
		location.reload();
	}

	function clearList() {
		if (confirm('Are you sure?')) {
			console.log('Anti-activation list was:\n', GM_getValue('locations'));
			GM_deleteValue('locations');
		}
	}

	function showList() {
		if (!GM_getValue('locations')) {
			console.log('Anti-activation list is empty.');
		} else {
			console.log('Activation list:');
			for (let item in GM_getValue('locations')) {
				console.log(item);
			}
		}
	}

	function setHeight(){
		let height;
		if ((height = parseInt(prompt('enter height, in px', 5))) && (height > 0)) {
			GM_setValue('height', height + 'px');
			divContainer.style.height = height + 'px';
		}
	}

	function setOpacity(){
		let opacity;
		if ((opacity = parseFloat(prompt('enter opacity, from 0 to 1', 0.8))) && (opacity > 0) && (opacity <= 1)) {
			GM_setValue('opacity', opacity);
			divContainer.style.opacity = opacity;
		}
	}

	function update() {
		divBar.style.width = Math.min(window.scrollY / (document.body.scrollHeight - window.innerHeight), 1) * 100 + '%';
		divContainer.title = parseFloat(divBar.style.width).toFixed() + '%' + '\nPage ' + (document.body.scrollHeight / window.innerHeight).toFixed(1) + ' times the length of the screen';
	}

	if (!(location.hostname in (GM_getValue('locations') || {}))) {
		GM_registerMenuCommand("Don't activate scrollbar on this site", addToList);
	} else {
		GM_registerMenuCommand("Reactivate scrollbar on this site", delFromList);
	}
	GM_registerMenuCommand("Clear anti-activation list", clearList);
	GM_registerMenuCommand("Show anti-activation list", showList);
	GM_registerMenuCommand("Set bar height", setHeight);
	GM_registerMenuCommand("Set bar opacity", setOpacity);

	if (document.body.scrollHeight / window.innerHeight <= 3) {
		l('page\'s too short');
		return;
	} else if (location.hostname in (GM_getValue('locations') || {})) {
		l(`'${location.hostname}' is in the anti-activation list.`);
		return;
	}

	const divContainer = document.createElement('div');
	const divBar = document.createElement('div');
	divContainer.style.position = 'fixed';
	divContainer.style.opacity = GM_getValue('opacity') || 0.8;
	divContainer.style.height = GM_getValue('height') || '5px';
	divContainer.style.width = '100%';
	divContainer.style.top = '0';
	divContainer.style.left = '0';
	divContainer.style.backgroundColor = 'blue';
	divContainer.style.zIndex = '2147483647';
	divBar.style.height = '100%';
	divBar.style.backgroundColor = 'hotpink';
	divBar.style.width = '0';
	divContainer.appendChild(divBar);
	document.body.appendChild(divContainer);

	update();
	window.addEventListener('scroll', update);
}())
<commit_msg>clarify console msg; change container bg color<commit_after>// ==UserScript==
// @name            Top auto scrollbar
// @name:ru         %name%
// @description     Automatic appearing top scrollbar if the page length is more than twice the height of the screen
// @description:ru  %description%
// @namespace       github.com/totalamd
// @match           *://*/*
// @exclude
// @version         1.0.1
// @downloadURL
// @updateURL
// @grant           GM_listValues
// @grant           GM_setValue
// @grant           GM_getValue
// @grant           GM_deleteValue
// @grant           GM_registerMenuCommand
// @noframes
// ==/UserScript==

"use strict";
const l = function(){}, i = function(){};

(function(){
	const l = console.log.bind(console), i = console.info.bind(console);

	function addToList() {
		let locations = GM_getValue('locations') || {};
		locations[location.hostname] = true;
		GM_setValue('locations', locations);
		location.reload();
	}

	function delFromList() {
		let locations = GM_getValue('locations');
		delete locations[location.hostname];
		GM_setValue('locations', locations);
		location.reload();
	}

	function clearList() {
		if (confirm('Are you sure?')) {
			console.log('Anti-activation list was:\n', GM_getValue('locations'));
			GM_deleteValue('locations');
		}
	}

	function showList() {
		if (!GM_getValue('locations')) {
			console.log('Anti-activation list is empty.');
		} else {
			console.log('Activation list:');
			for (let item in GM_getValue('locations')) {
				console.log(item);
			}
		}
	}

	function setHeight(){
		let height;
		if ((height = parseInt(prompt('enter height, in px', 5))) && (height > 0)) {
			GM_setValue('height', height + 'px');
			divContainer.style.height = height + 'px';
		}
	}

	function setOpacity(){
		let opacity;
		if ((opacity = parseFloat(prompt('enter opacity, from 0 to 1', 0.8))) && (opacity > 0) && (opacity <= 1)) {
			GM_setValue('opacity', opacity);
			divContainer.style.opacity = opacity;
		}
	}

	function update() {
		divBar.style.width = Math.min(window.scrollY / (document.body.scrollHeight - window.innerHeight), 1) * 100 + '%';
		divContainer.title = parseFloat(divBar.style.width).toFixed() + '%' + '\nPage ' + (document.body.scrollHeight / window.innerHeight).toFixed(1) + ' times the length of the screen';
	}

	if (!(location.hostname in (GM_getValue('locations') || {}))) {
		GM_registerMenuCommand("Don't activate scrollbar on this site", addToList);
	} else {
		GM_registerMenuCommand("Reactivate scrollbar on this site", delFromList);
	}
	GM_registerMenuCommand("Clear anti-activation list", clearList);
	GM_registerMenuCommand("Show anti-activation list", showList);
	GM_registerMenuCommand("Set bar height", setHeight);
	GM_registerMenuCommand("Set bar opacity", setOpacity);

	if (document.body.scrollHeight / window.innerHeight <= 3) {
		l('Top scrollbar: page\'s too short');
		return;
	} else if (location.hostname in (GM_getValue('locations') || {})) {
		l(`'${location.hostname}' is in the anti-activation list.`);
		return;
	}

	const divContainer = document.createElement('div');
	const divBar = document.createElement('div');
	divContainer.style.position = 'fixed';
	divContainer.style.opacity = GM_getValue('opacity') || 0.8;
	divContainer.style.height = GM_getValue('height') || '5px';
	divContainer.style.width = '100%';
	divContainer.style.top = '0';
	divContainer.style.left = '0';
	divContainer.style.backgroundColor = 'cornflowerblue';
	divContainer.style.zIndex = '2147483647';
	divContainer.style.cursor = 'auto';
	divBar.style.height = '100%';
	divBar.style.backgroundColor = 'hotpink';
	divBar.style.width = '0';
	divContainer.appendChild(divBar);
	document.body.appendChild(divContainer);

	update();
	window.addEventListener('scroll', update);
}())
<|endoftext|>


<commit_before>// ==UserScript==
// @name        OH GOD
// @description OH GOD I'M DOING IT AGAIN
// @namespace   GOD@HELP.ME
// @include     http://aimgames.forummotion.com/
// @version     FUCKING CHRIST
// @grant       none
// @license     MIT License (Expat); opensource.org/licenses/MIT
// ==/UserScript==

// JQuery chatbox frame document
var c$;
var chatDocument;

if ($('#frame_chatbox').length > 0) { //running in forum

  // chatbox++ logo
  if ($('#i_logo').length > 0) //null in chatbox frame; not undefined, keep note
      $('#i_logo').prop('src', 'http://i.imgur.com/LjuijqL.png');

  chatDocument = $('#frame_chatbox')[0].contentWindow.document;
  // ex. c$.find('.chatbox_row_1.clearfix')
  c$ = $(chatDocument);
}
<commit_msg>chatbox++ v2 progress<commit_after>// ==UserScript==
// @name        OH GOD
// @description OH GOD I'M DOING IT AGAIN
// @namespace   GOD@HELP.ME
// @include     http://aimgames.forummotion.com/
// @version     FUCKING CHRIST.2
// @grant       none
// @license     MIT License (Expat); opensource.org/licenses/MIT
// ==/UserScript==

// JQuery chatbox frame document
var c$;
// DOM chatbox frame document
var chatDocument;
// JQuery chatbox element
var chat;

var css = {
  box: '

text will go here

',
  // ES6-compliant strings with newlines... aren't they beautiful?
  ribbon: `
@import url('http://fonts.googleapis.com/css?family=Noto+Sans:400,700');
.box {
    width: 0px;
    height: 0px;
    position: relative;
    border: 0px solid #BBB;
    background: #EEE;
    font-family: 'Noto Sans', sans-serif
}
.box.invisibox {
    display: none;
}
.ribbon {
    width: 200px;
    background: #e43;
    position: absolute;
    top: 0px;
    left: -10px;
    text-align: center;
    line-height: 50px;
    letter-spacing: 1px;
    color: #ff0000;
    font-size: 18px
}
.ribbon span {
    width: 200px;
    background: #e43;
    position: absolute;
    top: 25px;
    left: -50px;
    text-align: center;
    line-height: 50px;
    letter-spacing: 1px;
    color: #f0f0f0;
    transform: rotate(-45deg);
    -webkit-transform: rotate(-45deg);
    font-size: 18px
}
.ribbon span::before {
    content: "";
    position: absolute;
    left: 0px;
    top: 100%;
    z-index: -1;
    border-left: 3px solid #8F0808;
    border-right: 3px solid transparent;
    border-bottom: 3px solid transparent;
    border-top: 3px solid #8F0808
}
.ribbon span::after {
    content: "";
    position: absolute;
    right: 0px;
    top: 100%;
    z-index: -1;
    border-left: 3px solid transparent;
    border-right: 3px solid #8F0808;
    border-bottom: 3px solid transparent;
    border-top: 3px solid #8F0808
}`
};

function checkForNewMessages() {
  //c$.find('.chatbox_row_1.clearfix');
  //c$.find('.chatbox_row_1.clearfix');

  //or

  oldMsgs = newMsgs;
  newMsgs = c$.find('#chatbox').children() - oldMsgs;
}

var oldMsgs = 0;
var newMsgs = 0;

var theBox = $(css.box);
// ex. boxText.text("changed")
var boxText = theBox.find('span');

function getScroll() { //// http://stackoverflow.com/questions/6691558/how-do-i-make-a-div-follow-me-as-i-scroll-down-the-page
  //simpler:
  //return window.scrollY || window.pageYOffset || ((d = document.documentElement).clientHeight && d.scrollTop) || document.body.scrollTop;

  //proper:
  if (window.scrollY !== undefined)
      return window.scrollY;

  if (typeof window.pageYOffset !== 'undefined') {
      // Most browsers
      return window.pageYOffset;
  }

  var d = document.documentElement;
  if (d.clientHeight) {
      // IE in standards mode
      return d.scrollTop;
  }

  // IE in quirks mode
  return document.body.scrollTop;
}

/**
 * Makes the 'new message!' box
 */
function makeBox() {

  console.log('is at cbox - ' + (getScroll() > 1400) + ' new msgs - ' + newMsgs);

  if (getScroll() <= 1400) { //are we not at cbox (doesnt work in bchat, may bug in different resolutions) --- 1700 w/ console 1400 otherwise
    if (newMsgs > 0) {
      if (newMsgs === 1)
        boxText.text('1 new msg');
      else
        boxText.text(newMsgs + ' new msgs');
      //show ribbon
    } else {
      //hide ribbon
    }
  } else {
    //update msg count
    //hide ribbon
  }
}

if ($('#frame_chatbox').length > 0) { //running in forum

  // chatbox++ logo
  if ($('#i_logo').length > 0) //null in chatbox frame; not undefined, keep note
      $('#i_logo').prop('src', 'http://i.imgur.com/LjuijqL.png');

  chatDocument = $('#frame_chatbox')[0].contentWindow.document;
  // ex. c$.find('.chatbox_row_1.clearfix')
  c$ = $(chatDocument);

  chat = c$.find('#chatbox');

  // add the ribbon css
  $('').appendTo('head');

  // add the invisible ribbon holder
  $(document.body).append(theBox);

  // add the listeners (TODO: add the mutationobserver as well)
  $(document).scroll(makeBox);

}

<|endoftext|>


<commit_before>var cliArgs = require('command-line-args');
var koa = require('koa');
var router = require('koa-router')();
var datasets = require('./db/datasets');
var user = require('./db/user');
var action = require('./db/actions');
var appreciate = require('./db/appreciate');
var browse = require('./db/browse');
var view = require('./db/view');
var tag = require('./db/tag');
var comment = require('./db/comment');
var download = require('./db/download');
var path = require('path');
//var koaBody = require('koa-body')({
//    multipart: true,
//    formidable: {uploadDir: './../assets/user-images'},
//    keepExtensions: true
//});
var r = require('./dash');
var apikey = require('./apikey')();

// Look for changes on the users table. If a change it detected then invalidate
// the apikey cache so it will be reloaded.
const apikeyCache = require('./apikey-cache')();
r.db('materialscommons').table('users').changes().toStream().on('data', function() {
    apikeyCache.clear()
});

var app = koa();
app.use(apikey);
router.get('/datasets', datasets.getAll);
router.get('/datasets/count', datasets.getAllCount);
router.get('/datasets/recent', datasets.getRecent);
router.get('/datasets/views', datasets.getTopViews);
router.get('/datasets/:id/user/:user_id', datasets.getOne);
router.get('/user/:email', user.get);
router.get('/actions/:dataset_id', action.getAll);
router.post('/appreciate', appreciate.addAppreciate);
router.put('/appreciate/remove', appreciate.removeAppreciation);
router.post('/views', view.addView);
router.post('/comments', comment.addComment);
router.post('/tags', tag.addTag);
router.put('/tags', tag.removeTag);
router.get('/tags', tag.getAllTags);
router.get('/tags/count', tag.getAllCount);
router.get('/tags/bycount', tag.getTagsByCount);
router.get('/tags/:id/datasets', tag.getDatasetsByTag);
router.get('/processes/types', browse.getProcessTypes);
router.get('/samples', browse.getSamples);
router.get('/authors/count', browse.getAllAuthorsCount);
router.get('/authors/datasets', browse.getAuthors);
//router.post('/upload', koaBody, user.upload);

app.use(router.routes());
app.use(router.allowedMethods());

if (!module.parent) {
    var cli = cliArgs([
        {name: 'port', type: Number, alias: 'p', description: 'Port to listen on'}
    ]);

    var options = cli.parse();
    var port = options.port || 5006;
    console.log('MCPUB listening on port: ' + port + ' pid: ' + process.pid);
    app.listen(5006);
}

<commit_msg>Use the passed in port to listen on for mcpub.<commit_after>var cliArgs = require('command-line-args');
var koa = require('koa');
var router = require('koa-router')();
var datasets = require('./db/datasets');
var user = require('./db/user');
var action = require('./db/actions');
var appreciate = require('./db/appreciate');
var browse = require('./db/browse');
var view = require('./db/view');
var tag = require('./db/tag');
var comment = require('./db/comment');
var download = require('./db/download');
var path = require('path');
//var koaBody = require('koa-body')({
//    multipart: true,
//    formidable: {uploadDir: './../assets/user-images'},
//    keepExtensions: true
//});
var r = require('./dash');
var apikey = require('./apikey')();

// Look for changes on the users table. If a change it detected then invalidate
// the apikey cache so it will be reloaded.
const apikeyCache = require('./apikey-cache')();
r.db('materialscommons').table('users').changes().toStream().on('data', function() {
    apikeyCache.clear()
});

var app = koa();
app.use(apikey);
router.get('/datasets', datasets.getAll);
router.get('/datasets/count', datasets.getAllCount);
router.get('/datasets/recent', datasets.getRecent);
router.get('/datasets/views', datasets.getTopViews);
router.get('/datasets/:id/user/:user_id', datasets.getOne);
router.get('/user/:email', user.get);
router.get('/actions/:dataset_id', action.getAll);
router.post('/appreciate', appreciate.addAppreciate);
router.put('/appreciate/remove', appreciate.removeAppreciation);
router.post('/views', view.addView);
router.post('/comments', comment.addComment);
router.post('/tags', tag.addTag);
router.put('/tags', tag.removeTag);
router.get('/tags', tag.getAllTags);
router.get('/tags/count', tag.getAllCount);
router.get('/tags/bycount', tag.getTagsByCount);
router.get('/tags/:id/datasets', tag.getDatasetsByTag);
router.get('/processes/types', browse.getProcessTypes);
router.get('/samples', browse.getSamples);
router.get('/authors/count', browse.getAllAuthorsCount);
router.get('/authors/datasets', browse.getAuthors);
//router.post('/upload', koaBody, user.upload);

app.use(router.routes());
app.use(router.allowedMethods());

if (!module.parent) {
    var cli = cliArgs([
        {name: 'port', type: Number, alias: 'p', description: 'Port to listen on'}
    ]);

    var options = cli.parse();
    var port = options.port || 5006;
    console.log('MCPUB listening on port: ' + port + ' pid: ' + process.pid);
    app.listen(port);
}

<|endoftext|>


<commit_before>(function () {
  'use strict';

  /**
   * @ignore
   * @summary
   * Uses SP builtin dependency management to load a specific dependency.
   * @function sputils.helpers.resolveDependency
   * @param {object} dep
   *

   * {
   *   file: {string},
   *   namespace: {string}
   * }
   * - `file` is the filename of the module, e.g. sp.taxonomy.js
   * - `namespace` is the namespace provided by the SP module, e.g. SP.Taxonomy
   *

   * @returns {Promise<Void>} - resolved when the SP dependency is loaded.
   */
  var resolveDependency = function (dep) {
    var file = dep.file,
        namespace = dep.namespace;

    return new Promise(function (resolve, reject) {
      SP.SOD.registerSod(file, SP.Utilities.Utility.getLayoutsPageUrl(file));
      SP.SOD.executeFunc(file, namespace, resolve);
    });
  };

  /**
   * Returns a promise which resolves when
   * all the specified dependencies are loaded.
   *
   * Takes a list of strings which correspond
   * to SP JS dependencies. Each dependency is
   * registered and loaded.
   *
   * Uses SP builtin dependency management to load a specific dependency.
   *
   * @function sputils.helpers.withSharePointDependencies
   * @param {Array<dep>} deps
   * An array containing hashes with the following keys: {file, namespace}
   *

   * [ { file: string, namespace: string } ]
   *

   * @returns {Promise<Void>} - resolved when all deps are loaded.
   */
  var withSharePointDependencies = function (deps) {
    return new Promise(function (resolve, reject) {
      // sp.js is a dependency for our resolveDependency
      // function, so we load it separately before
      // the rest.
      SP.SOD.executeFunc('sp.js', 'SP.ClientContext', function () {
        var promises = deps.map(resolveDependency);
        Promise.all(promises).then(resolve);
      });
    });
  };

  /**
  * Get the relative (to the root) portion of an absolute url.
  *
  * @function sputils.helpers.abs2rel
  * @param {string} - the absolute url
  * @returns {string} - the relative url
  * @example
  * var aurl = 'http://example.com/a/path/to.html';
  * var rurl = sputils.helpers.abs2rel(aurl);
  * rurl === '/a/path/to.html';
  **/
  var abs2rel = function (absUrl) {
    var hostname = sputils.lib.getval('location.hostname');

    // splitting on the hostname should yield an array with 2 elements
    // the 1st element should be empty string and the second the rel path.
    // coalesce into an array with the result being a '/'
    var parts = (absUrl || '').split(hostname);

    return parts[1] || '/';
  };

  /**
   * @function sputils.helpers.parseQueryString
   * @param {Optional<string>} optArg
   * a query string, as in the form of "?k1=v1&k2=v2"
   * @returns {Object}
   * an object representing the dictionary of the query string.
   * @example
   * console.log(location.search); // => '?a=1&b=some value'
   * var qsHash = parseQueryString(); // no argument, will use the current browsing context's location.search
   * // qsHash ~=~ {a:1, b: 'some value'};
   * parseQueryString('?a=1&b=some value'); // ~=~ qsHash
   **/
  var parseQueryString = function (optArg) {
    var result = {};
    var qs = (optArg || sputils.lib.getval('location.search')).replace('?', '');
    var parts = qs.split('&');
    parts = fjs.filter(function (a) {
      return a !== '';
    }, parts);
    fjs.each(function (part) {
      var kvp = part.split('=');
      result[kvp[0]] = kvp[1];
    }, parts);
    return result;
  };

  /**
  * Get a promise for a client context that could be on another
  * site/web.
  *
  * This client context is augmented to contain extra info in the
  * `_info` property.
  *
  * @function sputils.helpers.clientContextForWeb
  * @param {string} absoluteUrl the absolute url of the listitem, file or other asset.
  * @returns {Promise<SP.ClientContext>} - the promise of a client context
  * @example
  * console.log(location);// => http://contoso.com/sub1
  * var fileUrl = 'http://contoso.com/sub21231/Shared Documents/file1.docx';
  * var cctxPromise = sputils.helpers.clientContext(fileUrl);
  * cctxPromise.then(function (cctx) {
  *   var webUrl = cctx._info.WebFullUrl;
  *   var web = cctx.get_web();
  *   var file = web.getFileByServerRelativeUrl(sputils.helpers.abs2rel(fileUrl));
  *   // ...
  * });
  **/
  var clientContext = function (absoluteUrl) {
    // TODO: handle URLs to sites/webs
    var url = absoluteUrl.substring(
      0, absoluteUrl.lastIndexOf('/')) ;

    return sputils.rest.contextInfo(url).then(function (info) {
      // create the context and set the extra prop.
      var cctx = new SP.ClientContext(info.WebFullUrl);
      cctx._info = info;

      return cctx;
    });
  };

  /** @namespace */
  sputils.helpers = {
    withSharePointDependencies: withSharePointDependencies,
    abs2rel: abs2rel,
    clientContext: clientContext,
    parseQueryString: parseQueryString
  };
})();
<commit_msg>add downloadContent helper<commit_after>(function () {
  'use strict';

  /**
   * @ignore
   * @summary
   * Uses SP builtin dependency management to load a specific dependency.
   * @function sputils.helpers.resolveDependency
   * @param {object} dep
   *

   * {
   *   file: {string},
   *   namespace: {string}
   * }
   * - `file` is the filename of the module, e.g. sp.taxonomy.js
   * - `namespace` is the namespace provided by the SP module, e.g. SP.Taxonomy
   *

   * @returns {Promise<Void>} - resolved when the SP dependency is loaded.
   */
  var resolveDependency = function (dep) {
    var file = dep.file,
        namespace = dep.namespace;

    return new Promise(function (resolve, reject) {
      SP.SOD.registerSod(file, SP.Utilities.Utility.getLayoutsPageUrl(file));
      SP.SOD.executeFunc(file, namespace, resolve);
    });
  };

  /**
   * Returns a promise which resolves when
   * all the specified dependencies are loaded.
   *
   * Takes a list of strings which correspond
   * to SP JS dependencies. Each dependency is
   * registered and loaded.
   *
   * Uses SP builtin dependency management to load a specific dependency.
   *
   * @function sputils.helpers.withSharePointDependencies
   * @param {Array<dep>} deps
   * An array containing hashes with the following keys: {file, namespace}
   *

   * [ { file: string, namespace: string } ]
   *

   * @returns {Promise<Void>} - resolved when all deps are loaded.
   */
  var withSharePointDependencies = function (deps) {
    return new Promise(function (resolve, reject) {
      // sp.js is a dependency for our resolveDependency
      // function, so we load it separately before
      // the rest.
      SP.SOD.executeFunc('sp.js', 'SP.ClientContext', function () {
        var promises = deps.map(resolveDependency);
        Promise.all(promises).then(resolve);
      });
    });
  };

  /**
  * Get the relative (to the root) portion of an absolute url.
  *
  * @function sputils.helpers.abs2rel
  * @param {string} - the absolute url
  * @returns {string} - the relative url
  * @example
  * var aurl = 'http://example.com/a/path/to.html';
  * var rurl = sputils.helpers.abs2rel(aurl);
  * rurl === '/a/path/to.html';
  **/
  var abs2rel = function (absUrl) {
    var hostname = sputils.lib.getval('location.hostname');

    // splitting on the hostname should yield an array with 2 elements
    // the 1st element should be empty string and the second the rel path.
    // coalesce into an array with the result being a '/'
    var parts = (absUrl || '').split(hostname);

    return parts[1] || '/';
  };

  /**
   * @function sputils.helpers.parseQueryString
   * @param {Optional<string>} optArg
   * a query string, as in the form of "?k1=v1&k2=v2"
   * @returns {Object}
   * an object representing the dictionary of the query string.
   * @example
   * console.log(location.search); // => '?a=1&b=some value'
   * var qsHash = parseQueryString(); // no argument, will use the current browsing context's location.search
   * // qsHash ~=~ {a:1, b: 'some value'};
   * parseQueryString('?a=1&b=some value'); // ~=~ qsHash
   **/
  var parseQueryString = function (optArg) {
    var result = {};
    var qs = (optArg || sputils.lib.getval('location.search')).replace('?', '');
    var parts = qs.split('&');
    parts = fjs.filter(function (a) {
      return a !== '';
    }, parts);
    fjs.each(function (part) {
      var kvp = part.split('=');
      result[kvp[0]] = kvp[1];
    }, parts);
    return result;
  };

  /**
  * Get a promise for a client context that could be on another
  * site/web.
  *
  * This client context is augmented to contain extra info in the
  * `_info` property.
  *
  * @function sputils.helpers.clientContextForWeb
  * @param {string} absoluteUrl the absolute url of the listitem, file or other asset.
  * @returns {Promise<SP.ClientContext>} - the promise of a client context
  * @example
  * console.log(location);// => http://contoso.com/sub1
  * var fileUrl = 'http://contoso.com/sub21231/Shared Documents/file1.docx';
  * var cctxPromise = sputils.helpers.clientContext(fileUrl);
  * cctxPromise.then(function (cctx) {
  *   var webUrl = cctx._info.WebFullUrl;
  *   var web = cctx.get_web();
  *   var file = web.getFileByServerRelativeUrl(sputils.helpers.abs2rel(fileUrl));
  *   // ...
  * });
  **/
  var clientContext = function (absoluteUrl) {
    // TODO: handle URLs to sites/webs
    var url = absoluteUrl.substring(
      0, absoluteUrl.lastIndexOf('/')) ;

    return sputils.rest.contextInfo(url).then(function (info) {
      // create the context and set the extra prop.
      var cctx = new SP.ClientContext(info.WebFullUrl);
      cctx._info = info;

      return cctx;
    });
  };
  /**
  * Download a file using javascript
  * Useful to implement Export functionality in Search.
  *
  * You can download as csv or text. The function triggers the download
  * not the actual csv creation.
  *
  * Works with utf-8
  *
  * @function sputils.helpers.downloadContent
  * @param {Array<string>} options.
  * @returns {nil}
  * @example
  * var separator = ';';
  * downloadContent({
  *   type: 'text/csv;charset=utf-8',
  *   filename: 'tolle.csv',
  *   content: ['ASCII', separator,
  *      'Åbäcka sig', separator,
  *      'to się podoba: żźćąęłć',
  *      separator, 'Яшлӑхӑма туйаймарӑм'].join('')
  * });
  **/
  var downloadContent = function (options) {
    if (!options || !options.content) {
      throw 'You have at least to provide content to download';
    }
    options.filename = options.filename || 'tolle.txt';
    options.type = options.type || 'text/plain;charset=utf-8';
    options.bom = options.bom || decodeURIComponent('%ef%bb%bf');
    if (window.navigator.msSaveBlob) {
      var blob = new Blob([options.bom + options.content],
                 {type: options.type});
      window.navigator.msSaveBlob(blob, options.filename);
    }
    else {
      var link = document.createElement('a');
      var content = options.bom + options.content;
      var uriScheme = ['data:', options.type, ','].join('');
      link.href = uriScheme + content;
      link.download = options.filename;
      link.click();
      link.remove();
    }
  };

  /** @namespace */
  sputils.helpers = {
    withSharePointDependencies: withSharePointDependencies,
    abs2rel: abs2rel,
    clientContext: clientContext,
    parseQueryString: parseQueryString
  };
})();
<|endoftext|>


<commit_before>/* eslint-env es6 */
/* global THREE, VertexIndices, computeCentroid */
window.lerpBoxVertices = (function() {
  'use strict';

  const centroidA = new THREE.Vector3();
  const centroidB = new THREE.Vector3();
  const delta = new THREE.Vector3();

  return function lerp( geometryA, verticesA, geometryB, verticesB, t ) {
    const indicesA = VertexIndices[ verticesA.toUpperCase() ];
    const indicesB = VertexIndices[ verticesB.toUpperCase() ];

    computeCentroid( geometryA, indicesA, centroidA );
    computeCentroid( geometryB, indicesB, centroidB );

    delta.subVectors( centroidB, centroidA ).multiplyScalar( t );

    if ( Array.isArray( indicesA ) ) {
      indicesA.forEach( index =>
        geometryA.vertices[ index ].add( delta )
      );
    } else {
      geometryA.vertices[ indicesA ].add( delta );
    }

    return geometryA;
  };
}());
<commit_msg>lathe[cuboid]: Separate lerpBoxVertices() & relativeLerpBoxVertices().<commit_after>/* eslint-env es6 */
/* global THREE, VertexIndices, computeCentroid */
window.lerpBoxVertices = (function() {
  'use strict';

  return function lerp( geometry, vertices, vector, t ) {
    const indices = VertexIndices[ vertices.toUpperCase() ];

    if ( Array.isArray( indices ) ) {
      indices.forEach( index =>
        geometry.vertices[ index ].lerp( vector, t )
      );
    } else {
      geometry.vertices[ indices ].lerp( vector, t );
    }

    return geometry;
  };
}());

window.relativeLerpBoxVertices = (function() {
  'use strict';

  const centroidA = new THREE.Vector3();
  const centroidB = new THREE.Vector3();
  const delta = new THREE.Vector3();

  return function relativeLerp( geometryA, verticesA, geometryB, verticesB, t ) {
    const indicesA = VertexIndices[ verticesA.toUpperCase() ];
    const indicesB = VertexIndices[ verticesB.toUpperCase() ];

    computeCentroid( geometryA, indicesA, centroidA );
    computeCentroid( geometryB, indicesB, centroidB );

    delta.subVectors( centroidB, centroidA ).multiplyScalar( t );

    if ( Array.isArray( indicesA ) ) {
      indicesA.forEach( index =>
        geometryA.vertices[ index ].add( delta )
      );
    } else {
      geometryA.vertices[ indicesA ].add( delta );
    }

    return geometryA;
  };
}());
<|endoftext|>


<commit_before>import 'babel-polyfill';// for async/await
import sqlite3 from 'sqlite3';
import Scraper from './scraper';
import util from './utility';
import config from '../config';

const sqlite3Client = sqlite3.verbose();
const dbPath = `${__dirname}/../out/reviews.sqlite`;
const db = new sqlite3Client.Database(dbPath);
const logger = util.getLogger();

function initTableIfNotExists(tableName) {
  db.serialize(() => {
    db.run(
      `CREATE TABLE IF NOT EXISTS ${tableName}(` +
      'id TEXT PRIMARY KEY, ' +
      'app_name TEXT, ' +
      'title TEXT, ' +
      'content TEXT, ' +
      'rating INTEGER, ' +
      'date TEXT, ' +
      'version TEXT)'
    );
  });
}

function selectIdList(appName, tableName) {
  return new Promise((resolve, reject) => {
    db.serialize(() => {
      db.all(`SELECT id FROM ${tableName} WHERE app_name = $appName`,
        { $appName: appName },
        (err, res) => {
          if (err) {
            logger.error(err);
            reject(err);
          } else {
            resolve(res);
          }
        });
    });
  });
}

function insertReviews(reviews, appName, tableName) {
  db.serialize(() => {
    const query = `INSERT INTO ${tableName}(id, app_name, title, content, rating, date, version) VALUES(?, ?, ?, ?, ?, ?, ?)`;
    const stmt = db.prepare(query);

    for (const review of reviews) {
      stmt.run(review.id, appName, review.title, review.content, parseInt(review.rating, 10), review.date, review.version);
    }

    stmt.finalize();
  });
}

async function archiveAsync(appInfoList, asyncFunc, tableName) {
  try {
    initTableIfNotExists(tableName);

    for (const appInfo of appInfoList) {
      const reviews = await asyncFunc(appInfo.id);
      const savedReviews = await selectIdList(tableName, appInfo.name);

      const reviewIdList = savedReviews.map((review) => {
        return review.id;
      });

      const newReviews = reviews.filter((review) => {
        return !reviewIdList.includes(review.id);
      });

      if (newReviews.length > 0) {
        insertReviews(tableName, appInfo.name, newReviews);
        logger.info(`Inserted ${newReviews.length} number of reviews. [Table Name] ${tableName} [App name] ${appInfo.name}`);
      } else {
        logger.info(`Review is nothing. [Table Name] ${tableName} [App name] ${appInfo.name}`);
      }
    }
  } catch (error) {
    logger.error(error);
  }
}

async function main() {
  const scraper = new Scraper();
  await Promise.all([
    archiveAsync(config.appStore, scraper.fetchReviewFromAppStore, 'appstore'),
    archiveAsync(config.googlePlay, scraper.fetchReviewFromGooglePlay, 'googleplay')
  ]);
}

main();

<commit_msg>Fixed a bug<commit_after>import 'babel-polyfill';// for async/await
import sqlite3 from 'sqlite3';
import Scraper from './scraper';
import util from './utility';
import config from '../config';

const sqlite3Client = sqlite3.verbose();
const dbPath = `${__dirname}/../out/reviews.sqlite`;
const db = new sqlite3Client.Database(dbPath);
const logger = util.getLogger();

function initTableIfNotExists(tableName) {
  db.serialize(() => {
    db.run(
      `CREATE TABLE IF NOT EXISTS ${tableName}(` +
      'id TEXT PRIMARY KEY, ' +
      'app_name TEXT, ' +
      'title TEXT, ' +
      'content TEXT, ' +
      'rating INTEGER, ' +
      'date TEXT, ' +
      'version TEXT)'
    );
  });
}

function selectIdList(appName, tableName) {
  return new Promise((resolve, reject) => {
    db.serialize(() => {
      db.all(`SELECT id FROM ${tableName} WHERE app_name = $appName`,
        { $appName: appName },
        (err, res) => {
          if (err) {
            logger.error(err);
            reject(err);
          } else {
            resolve(res);
          }
        });
    });
  });
}

function insertReviews(reviews, appName, tableName) {
  db.serialize(() => {
    const query = `INSERT INTO ${tableName}(id, app_name, title, content, rating, date, version) VALUES(?, ?, ?, ?, ?, ?, ?)`;
    const stmt = db.prepare(query);

    for (const review of reviews) {
      stmt.run(review.id, appName, review.title, review.content, parseInt(review.rating, 10), review.date, review.version);
    }

    stmt.finalize();
  });
}

async function archiveAsync(appInfoList, asyncFunc, tableName) {
  try {
    initTableIfNotExists(tableName);

    for (const appInfo of appInfoList) {
      const reviews = await asyncFunc(appInfo.id);
      const savedReviews = await selectIdList(appInfo.name, tableName);

      const reviewIdList = savedReviews.map((review) => {
        return review.id;
      });

      const newReviews = reviews.filter((review) => {
        return !reviewIdList.includes(review.id);
      });

      if (newReviews.length > 0) {
        insertReviews(newReviews, appInfo.name, tableName);
        logger.info(`Inserted ${newReviews.length} number of reviews. [Table Name] ${tableName} [App name] ${appInfo.name}`);
      } else {
        logger.info(`Review is nothing. [Table Name] ${tableName} [App name] ${appInfo.name}`);
      }
    }
  } catch (error) {
    logger.error(error);
  }
}

async function main() {
  const scraper = new Scraper();
  await Promise.all([
    archiveAsync(config.appStore, scraper.fetchReviewFromAppStore, 'appstore'),
    archiveAsync(config.googlePlay, scraper.fetchReviewFromGooglePlay, 'googleplay')
  ]);
}

main();

<|endoftext|>


<commit_before>

var api = 'https://devcivicbot.herokuapp.com/';
$(document).ready(function() {
    $.ajax({
        type: "GET",
        url: "https://devcivicbot.herokuapp.com/Private/getContributionList",
        headers: {
            'Authorization': "Bearer "+localStorage.token
        },
        success: function(data) {
            console.log('OK');
            $('#table').bootstrapTable({
                data: data,
                columns: [{
                    field: 'createdAt',
                    title: "Fecha de publicaci&oacuten",
                    align: 'center'
                }, {
                    field: 'photo',
                    title: 'Fotograf&iactutea',
                    align: 'center'
                }, {
                    field: 'label.name',
                    title: 'Categoria',
                    sortable: true,
                    editable: true,
                    footerFormatter: totalFormatter,
                    align: 'center'

                }, {
                    field: 'party.party',
                    title: "Partido pol&iacutetico",
                    sortable: true,
                    editable: true,
                    footerFormatter: totalFormatter,
                    align: 'center'
                }, {
                    field: 'media.media',
                    title: 'Medios de comunicaci&oacuten',
                    sortable: true,
                    editable: true,
                    footerFormatter: totalFormatter,
                    align: 'center'
                },
                    {
                        field: 'publish',
                        title: 'Estado',
                        sortable: true,
                        editable: true,
                        footerFormatter:totalFormatter,
                        align: 'center'
                    },{
                        field: 'operate',
                        align: 'center',
                        title: 'Guardar',
                        events: operateEvents,
                        formatter: operateFormatter
                    }]
            });
        }
    });

    $(function() {
        $(window).resize(function() {
            $('#table').bootstrapTable('resetView');
        });
    });

    $('#salir').on('click', function(){
        logOut();
    })
});

function totalFormatter(data) {
    return data.lenght;
}

function responseHandler(res) {
    $.each(res.rows, function(i, row) {
        row.state = $.inArray(row.id, selections) !== -1;
    });
    return res;
}

function detailFormatter(index, row) {
    var html = [];
    $.each(row, function(key, value) {
        html.push('
' + key + ': ' + value + '
');
    });
    return html.join('');
}

function getHeight() {
    return $(window).height() - $('h1').outerHeight(true);
}

function getIdSelections() {
    return $.map($table.bootstrapTable('getSelections'), function(row) {
        return row.id
    });
}

function operateFormatter(value, row, index) {
    return [
        '',
        '',
        '  '
    ].join('');
}

window.operateEvents = {
    'click .save': function(e, value, row, index) {
        console.log("save")
        setParty(row.id,row.party.id);
        setMedia(row.id,row.media.id);
        setLocation(row.id,row.location.id);
        setLabel(row.id,row.label.id);
    },
    'click .save': function(e, value, row, index) {
        console.log("publish")
        setParty(row.id,row.party.id);
        setMedia(row.id,row.media.id);
        setLocation(row.id,row.location.id);
        setLabel(row.id,row.label.id);
    }
};

function setParty(contribId, partyId) {
    $.ajax({
        type: "POST",
        url: "devcivicbot.herokuapp.com/Private/setParty",
        data: '{"contribId": "' + contribId + '", "partyId" : "' + partyId + '"}',
        headers: {
            'Authorization': "Bearer " + localStorage.token
        },
        success: function() {
            console.log('OK');
        }
    });
}

//TODO: Revisar parámetros en función de arquitectura api
function setMedia(contribId, mediaId) {
    $.ajax({
        type: "POST",
        url: "devcivicbot.herokuapp.com/Private/setMedia",
        data: '{"contribId": "' + contribId + '", "mediaId" : "' + mediaId + '"}',
        headers: {
            'Authorization': "Bearer " + localStorage.token
        },
        success: function() {
            console.log('OK');
        }
    });
}

function setLocation(contribId, locationId) {
    $.ajax({
        type: "POST",
        url: "devcivicbot.herokuapp.com/Private/setLocation",
        data: '{"contribId": "' + contribId + '", "locationId" : "' + locationId + '"}',
        headers: {
            'Authorization': "Bearer " + localStorage.token
        },
        success: function() {
            console.log('OK');
        }
    });
}

function setLabel(contribId, labelId) {
    $.ajax({
        type: "POST",
        url: "devcivicbot.herokuapp.com/Private/setLabel",
        data: '{"contribId": "' + contribId + '", "labelId" : "' + labelId + '"}',
        headers: {
            'Authorization': "Bearer " + localStorage.token
        },
        success: function() {
            console.log('OK');
        }
    });
}

//TODO: Comprobación de "si ya publicado, no publico"
function setToPublish(contribId, publish) {
    $.ajax({
        type: "POST",
        url: "devcivicbot.herokuapp.com/Private/setToPublish",
        data: '{"contribId": "' + contribId + '", "publish" : "' + publish + '"}',
        headers: {
            'Authorization': "Bearer " + localStorage.token
        },
        success: function() {
            console.log('OK');
        }
    });
}

function getPartyList() {
    $.ajax({
        type: "GET",
        url: "devcivicbot.herokuapp.com/Private/getPartyList",
        headers: {
            'Authorization': "Bearer " + localStorage.token
        },
        success: function(data) {
            console.log('OK');
            return data;
        }
    });
}

function getLocationList() {
    $.ajax({
        type: "GET",
        url: "devcivicbot.herokuapp.com/Private/getLocationList",
        headers: {
            'Authorization': "Bearer " + localStorage.token
        },
        success: function(data) {
            console.log('OK');
            return data;
        }
    });
}

function getMediaList() {
    $.ajax({
        type: "GET",
        url: "devcivicbot.herokuapp.com/Private/getMediaList",
        headers: {
            'Authorization': "Bearer " + localStorage.token
        },
        success: function(data) {
            console.log('OK');
            return data;
        }
    });
}

function getLabelList() {
    $.ajax({
        type: "GET",
        url: "devcivicbot.herokuapp.com/Private/getLabelList",
        headers: {
            'Authorization': "Bearer " + localStorage.token
        },
        success: function(data) {
            console.log('OK');
            return data;
        }
    });
}

function getContributionList() {
    $.ajax({
        type: "GET",
        url: "devcivicbot.herokuapp.com/Private/getContributionList",
        headers: {
            'Authorization': "Bearer " + localStorage.token
        },
        success: function(data) {
            console.log('OK');
            return data;
        }
    });
}

function logOut(){
    $.ajax({
        type: 'GET',
        url: api+"Private/logout",
        headers:{
            'Authorization': "Bearer " + localStorage.token
        },
        success: function(data) {
            console.log("LOGOUT OK");
            localStorage.removeItem('token');
            window.location.href='index.html'
        }
    })
}
<commit_msg>Cosmetics: new buttons, column, api<commit_after>

var api = 'https://devcivicbot.herokuapp.com/';
$(document).ready(function() {
    $.ajax({
        type: "GET",
        url: "https://devcivicbot.herokuapp.com/Private/getContributionList",
        headers: {
            'Authorization': "Bearer "+localStorage.token
        },
        success: function(data) {
            console.log('OK');
            $('#table').bootstrapTable({
                data: data,
                columns: [{
                    field: 'createdAt',
                    title: "Fecha de publicaci&oacuten",
                    align: 'center'
                }, {
                    field: 'photo',
                    title: 'Fotografia',
                    align: 'center'
                }, {
                    field: 'label.name',
                    title: 'Categoria',
                    sortable: true,
                    editable: true,
                    footerFormatter: totalFormatter,
                    align: 'center'

                }, {
                    field: 'party.party',
                    title: "Partido pol&iacutetico",
                    sortable: true,
                    editable: true,
                    footerFormatter: totalFormatter,
                    align: 'center'
                }, {
                    field: 'media.media',
                    title: 'Medios de comunicaci&oacuten',
                    sortable: true,
                    editable: true,
                    footerFormatter: totalFormatter,
                    align: 'center'
                },
                    {
                        field: 'published',
                        title: 'Publicado?',
                        sortable: true,
                        footerFormatter:totalFormatter,
                        align: 'center'
                    },
                    {
                        field: 'edited',
                        title: 'Editado?',
                        sortable: true,
                        footerFormatter:totalFormatter,
                        align: 'center'
                    },{
                        field: 'operate',
                        align: 'center',
                        title: 'Guardar',
                        events: operateEvents,
                        formatter: operateFormatter
                    }]
            });
        }
    });

    $(function() {
        $(window).resize(function() {
            $('#table').bootstrapTable('resetView');
        });
    });

    $('#salir').on('click', function(){
        logOut();
    })
});

function totalFormatter(data) {
    return data.lenght;
}

function responseHandler(res) {
    $.each(res.rows, function(i, row) {
        row.state = $.inArray(row.id, selections) !== -1;
    });
    return res;
}

function detailFormatter(index, row) {
    var html = [];
    $.each(row, function(key, value) {
      console.log("key: "+key);
      console.log("value: "+value);

        html.push('
' + key + ': ' + value + '
');

    });
    return html.join('');
}

function getHeight() {
    return $(window).height() - $('h1').outerHeight(true);
}

function getIdSelections() {
    return $.map($table.bootstrapTable('getSelections'), function(row) {
        return row.id
    });
}

function operateFormatter(value, row, index) {
    return [
      '
',
        ' <button type="button" class="btn btn-success"></button>',
        '
',
        '<button type="button" class="btn btn-info publish"></button>',
        '
'
    ].join('');
}

window.operateEvents = {
    'click .btn-success': function(e, value, row, index) {
        console.log("save")
        console.log("row: "+row)
    },
    'click .btn-info': function(e, value, row, index) {
        console.log("publish")
    }
};

function setParty(contribId, partyId) {
    $.ajax({
        type: "POST",
        url: api+"Private/setParty",
        data: '{"contribId": "' + contribId + '", "partyId" : "' + partyId + '"}',
        headers: {
            'Authorization': "Bearer " + localStorage.token
        },
        success: function() {
            console.log('OK');
        }
    });
}

//TODO: Revisar parámetros en función de arquitectura api
function setMedia(contribId, mediaId) {
    $.ajax({
        type: "POST",
        url: api+"Private/setMedia",
        data: '{"contribId": "' + contribId + '", "mediaId" : "' + mediaId + '"}',
        headers: {
            'Authorization': "Bearer " + localStorage.token
        },
        success: function() {
            console.log('OK');
        }
    });
}

function setLocation(contribId, locationId) {
    $.ajax({
        type: "POST",
        url: api+"Private/setLocation",
        data: '{"contribId": "' + contribId + '", "locationId" : "' + locationId + '"}',
        headers: {
            'Authorization': "Bearer " + localStorage.token
        },
        success: function() {
            console.log('OK');
        }
    });
}

function setLabel(contribId, labelId) {
    $.ajax({
        type: "POST",
        url: api+"Private/setLabel",
        data: '{"contribId": "' + contribId + '", "labelId" : "' + labelId + '"}',
        headers: {
            'Authorization': "Bearer " + localStorage.token
        },
        success: function() {
            console.log('OK');
        }
    });
}

//TODO: Comprobación de "si ya publicado, no publico"
function setToPublish(contribId, publish) {
    $.ajax({
        type: "POST",
        url: api+"Private/setToPublish",
        data: '{"contribId": "' + contribId + '", "publish" : "' + publish + '"}',
        headers: {
            'Authorization': "Bearer " + localStorage.token
        },
        success: function() {
            console.log('OK');
        }
    });
}

function getPartyList() {
    $.ajax({
        type: "GET",
        url: api+"Private/getPartyList",
        headers: {
            'Authorization': "Bearer " + localStorage.token
        },
        success: function(data) {
            console.log('OK');
            return data;
        }
    });
}

function getLocationList() {
    $.ajax({
        type: "GET",
        url: api+"Private/getLocationList",
        headers: {
            'Authorization': "Bearer " + localStorage.token
        },
        success: function(data) {
            console.log('OK');
            return data;
        }
    });
}

function getMediaList() {
    $.ajax({
        type: "GET",
        url: api+"Private/getMediaList",
        headers: {
            'Authorization': "Bearer " + localStorage.token
        },
        success: function(data) {
            console.log('OK');
            return data;
        }
    });
}

function getLabelList() {
    $.ajax({
        type: "GET",
        url: api+"Private/getLabelList",
        headers: {
            'Authorization': "Bearer " + localStorage.token
        },
        success: function(data) {
            console.log('OK');
            return data;
        }
    });
}

function getContributionList() {
    $.ajax({
        type: "GET",
        url: api+"Private/getContributionList",
        headers: {
            'Authorization': "Bearer " + localStorage.token
        },
        success: function(data) {
            console.log('OK');
            return data;
        }
    });
}

function logOut(){
    $.ajax({
        type: 'GET',
        url: api+"Private/logout",
        headers:{
            'Authorization': "Bearer " + localStorage.token
        },
        success: function(data) {
            console.log("LOGOUT OK");
            localStorage.removeItem('token');
            window.location.href='index.html'
        }
    })
}
<|endoftext|>