<commit_before>'use strict';

const mkdirp = require('./mkdirp');
const writeFile = require('./writeFile');
const writeTag = require('./writeTag');

module.exports = (config, head) => {
  let output = '';

  const createTag = (tag) => {
    output += writeTag(config, tag);
  };

  for (const platform in head) {
    if (head.hasOwnProperty(platform)) {
      head[platform].forEach(createTag);
    }
  }

  return mkdirp(config.output.icons)
    .then(
      () => writeFile(config.output.html, output)
    );
};
<commit_msg>Fix head dir path name<commit_after>'use strict';

const {dirname} = require('path');
const mkdirp = require('./mkdirp');
const writeFile = require('./writeFile');
const writeTag = require('./writeTag');

module.exports = (config, head) => {
  let output = '';

  const createTag = (tag) => {
    output += writeTag(config, tag);
  };

  for (const platform in head) {
    if (head.hasOwnProperty(platform)) {
      head[platform].forEach(createTag);
    }
  }

  return mkdirp(dirname(config.output.html))
    .then(
      () => writeFile(config.output.html, output)
    );
};
<|endoftext|>


<commit_before>exports.jsGlobals = "Infinity undefined NaN Object Function Array String Number Boolean RegExp Date Error SyntaxError ReferenceError URIError EvalError RangeError TypeError parseInt parseFloat isNaN isFinite eval encodeURI encodeURIComponent decodeURI decodeURIComponent Math JSON require console exports module Symbol Promise".split(" ");

exports.browserGlobals = "location Node Element Text Document document XMLDocument HTMLElement HTMLAnchorElement HTMLAreaElement HTMLAudioElement HTMLBaseElement HTMLBodyElement HTMLBRElement HTMLButtonElement HTMLCanvasElement HTMLDataElement HTMLDataListElement HTMLDivElement HTMLDListElement HTMLDocument HTMLEmbedElement HTMLFieldSetElement HTMLFormControlsCollection HTMLFormElement HTMLHeadElement HTMLHeadingElement HTMLHRElement HTMLHtmlElement HTMLIFrameElement HTMLImageElement HTMLInputElement HTMLKeygenElement HTMLLabelElement HTMLLegendElement HTMLLIElement HTMLLinkElement HTMLMapElement HTMLMediaElement HTMLMetaElement HTMLMeterElement HTMLModElement HTMLObjectElement HTMLOListElement HTMLOptGroupElement HTMLOptionElement HTMLOptionsCollection HTMLOutputElement HTMLParagraphElement HTMLParamElement HTMLPreElement HTMLProgressElement HTMLQuoteElement HTMLScriptElement HTMLSelectElement HTMLSourceElement HTMLSpanElement HTMLStyleElement HTMLTableCaptionElement HTMLTableCellElement HTMLTableColElement HTMLTableDataCellElement HTMLTableElement HTMLTableHeaderCellElement HTMLTableRowElement HTMLTableSectionElement HTMLTextAreaElement HTMLTimeElement HTMLTitleElement HTMLTrackElement HTMLUListElement HTMLUnknownElement HTMLVideoElement Attr NodeList HTMLCollection NamedNodeMap DocumentFragment DOMTokenList XPathResult ClientRect Event TouchEvent WheelEvent MouseEvent KeyboardEvent HashChangeEvent ErrorEvent CustomEvent BeforeLoadEvent WebSocket Worker localStorage sessionStorage FileList File Blob FileReader URL Range XMLHttpRequest DOMParser Selection console top parent window opener self devicePixelRatio name closed pageYOffset pageXOffset scrollY scrollX screenTop screenLeft screenY screenX innerWidth innerHeight outerWidth outerHeight frameElement crypto navigator history screen postMessage close blur focus onload onunload onscroll onresize ononline onoffline onmousewheel onmouseup onmouseover onmouseout onmousemove onmousedown onclick ondblclick onmessage onkeyup onkeypress onkeydown oninput onpopstate onhashchange onfocus onblur onerror ondrop ondragstart ondragover ondragleave ondragenter ondragend ondrag oncontextmenu onchange onbeforeunload onabort getSelection alert confirm prompt scrollBy scrollTo scroll setTimeout clearTimeout setInterval clearInterval atob btoa addEventListener removeEventListener dispatchEvent getComputedStyle CanvasRenderingContext2D importScripts MutationObserver indexedDB open requestAnimationFrame cancelAnimationFrame requestIdleCallback cancelIdleCallback customElements performance applicationCache".split(" ");

<commit_msg>Add Map and WeakMap as known globals<commit_after>exports.jsGlobals = "Infinity undefined NaN Object Function Array String Number Boolean RegExp Date Error SyntaxError ReferenceError URIError EvalError RangeError TypeError parseInt parseFloat isNaN isFinite eval encodeURI encodeURIComponent decodeURI decodeURIComponent Math JSON require console exports module Symbol Promise Map WeakMap".split(" ");

exports.browserGlobals = "location Node Element Text Document document XMLDocument HTMLElement HTMLAnchorElement HTMLAreaElement HTMLAudioElement HTMLBaseElement HTMLBodyElement HTMLBRElement HTMLButtonElement HTMLCanvasElement HTMLDataElement HTMLDataListElement HTMLDivElement HTMLDListElement HTMLDocument HTMLEmbedElement HTMLFieldSetElement HTMLFormControlsCollection HTMLFormElement HTMLHeadElement HTMLHeadingElement HTMLHRElement HTMLHtmlElement HTMLIFrameElement HTMLImageElement HTMLInputElement HTMLKeygenElement HTMLLabelElement HTMLLegendElement HTMLLIElement HTMLLinkElement HTMLMapElement HTMLMediaElement HTMLMetaElement HTMLMeterElement HTMLModElement HTMLObjectElement HTMLOListElement HTMLOptGroupElement HTMLOptionElement HTMLOptionsCollection HTMLOutputElement HTMLParagraphElement HTMLParamElement HTMLPreElement HTMLProgressElement HTMLQuoteElement HTMLScriptElement HTMLSelectElement HTMLSourceElement HTMLSpanElement HTMLStyleElement HTMLTableCaptionElement HTMLTableCellElement HTMLTableColElement HTMLTableDataCellElement HTMLTableElement HTMLTableHeaderCellElement HTMLTableRowElement HTMLTableSectionElement HTMLTextAreaElement HTMLTimeElement HTMLTitleElement HTMLTrackElement HTMLUListElement HTMLUnknownElement HTMLVideoElement Attr NodeList HTMLCollection NamedNodeMap DocumentFragment DOMTokenList XPathResult ClientRect Event TouchEvent WheelEvent MouseEvent KeyboardEvent HashChangeEvent ErrorEvent CustomEvent BeforeLoadEvent WebSocket Worker localStorage sessionStorage FileList File Blob FileReader URL Range XMLHttpRequest DOMParser Selection console top parent window opener self devicePixelRatio name closed pageYOffset pageXOffset scrollY scrollX screenTop screenLeft screenY screenX innerWidth innerHeight outerWidth outerHeight frameElement crypto navigator history screen postMessage close blur focus onload onunload onscroll onresize ononline onoffline onmousewheel onmouseup onmouseover onmouseout onmousemove onmousedown onclick ondblclick onmessage onkeyup onkeypress onkeydown oninput onpopstate onhashchange onfocus onblur onerror ondrop ondragstart ondragover ondragleave ondragenter ondragend ondrag oncontextmenu onchange onbeforeunload onabort getSelection alert confirm prompt scrollBy scrollTo scroll setTimeout clearTimeout setInterval clearInterval atob btoa addEventListener removeEventListener dispatchEvent getComputedStyle CanvasRenderingContext2D importScripts MutationObserver indexedDB open requestAnimationFrame cancelAnimationFrame requestIdleCallback cancelIdleCallback customElements performance applicationCache".split(" ");

<|endoftext|>


<commit_before>module.exports = function(grunt) {
  require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks);

  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),

    copy: {
      main: {
        expand: true,
        cwd: 'app/',
        src: ['**', "!js/**"],
        dest: 'dest/'
      }
    },
    clean: {
      main: ["dest"]
    },
    uglify: {
      options: {
        banner: '/*! <%= pkg.author.name %>\'s <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */\n',
        report: "min"
      },
      build: {
        src: ['app/js/*.js'],
        dest: 'dest/libs/helper.min.js'
      }
    },
    cssmin: {
      compress: {
        files: {
          'dest/css/style.css': ['app/css/style.css'],
          'dest/css/style-color.css': ['app/css/style-color.css']
        }
      }
    },
    jshint: {
      options: {
        jshintrc: process.env.HOME + "/.jshintrc"
      },
      files: [ "app/js/*.js" ]
    },
    processhtml: {
      normal: {
        files: {
          'dest/index.html': ['app/index.html']
        }
      }
    },
    express: {
      all: {
        options: {
          port: 9000,
          hostname: "0.0.0.0",
          bases: ['app']
        }
      }
    },
    watch: {
      all: {
        files: "app/**",
        options: {
          livereload: true
        }
      }
    },
    open: {
      all: {
        path: 'http://localhost:<%= express.all.options.port%>',
        app: "Firefox"
      }
    }
  });

  grunt.registerTask('default', ['jshint']);
  grunt.registerTask('deploy', ['jshint', 'clean', 'copy', 'uglify', 'cssmin', 'processhtml']);
  grunt.registerTask('server', ['express', 'open', 'watch']);
};
<commit_msg>Changed destination.<commit_after>module.exports = function(grunt) {
  require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks);

  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),

    copy: {
      main: {
        expand: true,
        cwd: 'app/',
        src: ['**', "!js/**"],
        dest: 'dist/'
      }
    },
    clean: {
      main: ["dist"]
    },
    uglify: {
      options: {
        banner: '/*! <%= pkg.author.name %>\'s <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */\n',
        report: "min"
      },
      build: {
        src: ['app/js/*.js'],
        dest: 'dist/libs/helper.min.js'
      }
    },
    cssmin: {
      compress: {
        files: {
          'dist/css/style.css': ['app/css/style.css'],
          'dist/css/style-color.css': ['app/css/style-color.css']
        }
      }
    },
    jshint: {
      options: {
        jshintrc: process.env.HOME + "/.jshintrc"
      },
      files: [ "app/js/*.js" ]
    },
    processhtml: {
      normal: {
        files: {
          'dist/index.html': ['app/index.html']
        }
      }
    },
    express: {
      all: {
        options: {
          port: 9000,
          hostname: "0.0.0.0",
          bases: ['app']
        }
      }
    },
    watch: {
      all: {
        files: "app/**",
        options: {
          livereload: true
        }
      }
    },
    open: {
      all: {
        path: 'http://localhost:<%= express.all.options.port%>',
        app: "Firefox"
      }
    }
  });

  grunt.registerTask('default', ['jshint']);
  grunt.registerTask('deploy', ['jshint', 'clean', 'copy', 'uglify', 'cssmin', 'processhtml']);
  grunt.registerTask('server', ['express', 'open', 'watch']);
};
<|endoftext|>


<commit_before>var test = require('tap').test
var jsStringEscape = require('../')

test('jsStringEscape invariants', function (t) {
  var allCharacters = ''
  for (var i = 0; i < 65536; i++) {
    allCharacters += String.fromCharCode(i)
  }

  t.equal(eval("'" + jsStringEscape(allCharacters) + "'"), allCharacters)
  t.equal(eval('"' + jsStringEscape(allCharacters) + '"'), allCharacters)
  t.end()
})
<commit_msg>Use t.ok, not t.equal<commit_after>var test = require('tap').test
var jsStringEscape = require('../')

test('jsStringEscape invariants', function (t) {
  var allCharacters = ''
  for (var i = 0; i < 65536; i++) {
    allCharacters += String.fromCharCode(i)
  }

  // Do not use .equal; mega-diffs in the output are not helpful.
  t.ok(eval("'" + jsStringEscape(allCharacters) + "'") === allCharacters)
  t.ok(eval('"' + jsStringEscape(allCharacters) + '"') === allCharacters)
  t.end()
})
<|endoftext|>


<commit_before>/**
 * Patterns toggle - toggle class on click
 *
 * Copyright 2012-2014 Simplon B.V. - Wichert Akkerman
 */
define([
    "jquery",
    "pat-registry",
    "pat-logger",
    "pat-parser",
    "pat-store"
], function($, patterns, logger, Parser, store) {
    var log = logger.getLogger("pat.toggle"),
        parser = new Parser("toggle");

    parser.add_argument("selector");
    parser.add_argument("attr", "class");
    parser.add_argument("value");
    parser.add_argument("store", "none", ["none", "session", "local"]);

    function ClassToggler(values) {
        this.values=values.slice(0);
        if (this.values.length>1)
            this.values.push(values[0]);
    }

    ClassToggler.prototype = {
        toggle: function Toggler_toggle(el) {
            var current = this.get(el),
                next = this.next(current);
            this.set(el, next);
            return next;
        },

        get: function Toggler_get(el) {
            var classes = el.className.split(/\s+/);
            for (var i=0; i<this.values.length;i++)
                if (classes.indexOf(this.values[i])!==-1)
                    return this.values[i];
            return null;
        },

        set: function Toggler_set(el, value) {
            var classes = el.className.split(/\s+/),
                values = this.values;
            classes=classes.filter(function(v) { return v.length && values.indexOf(v)===-1;});
            if (value)
                classes.push(value);
            el.className=classes.join(" ");
        },

        next: function Toggler_next(current) {
            if (this.values.length===1)
                return current ? null : this.values[0];
            for (var i=0; i<(this.values.length-1); i++)
                if (this.values[i]===current)
                    return this.values[i+1];
            return this.values[0];
       }
    };

    function AttributeToggler(attribute) {
        this.attribute=attribute;
    }

    AttributeToggler.prototype = new ClassToggler([]);
    AttributeToggler.prototype.get=function AttributeToggler_get(el) {
        return !!el[this.attribute];
    };

    AttributeToggler.prototype.set=function AttributeToggler_set(el, value) {
        if (value)
            el[this.attribute]=value;
        else
            el.removeAttribute(this.attribute);
    };

    AttributeToggler.prototype.next=function AttributeToggler_next(value) {
        return !value;
    };

    var toggle = {
        name: "toggle",
        trigger: ".pat-toggle",

        // Hook for testing
        _ClassToggler: ClassToggler,
        _AttributeToggler: AttributeToggler,

        init: function toggle_init($el) {
            return $el.each(function toggle_init_el() {
                var $trigger = $(this),
                    options = toggle._validateOptions(this, parser.parse($trigger, true));

                if (!options.length)
                    return;

                for (var i=0; i<options.length; i++)
                    if (options[i].value_storage) {
                        var victims, state, last_state;
                        victims=document.querySelectorAll(options[i].selector);
                        if (!victims.length)
                            continue;
                        state=options[i].toggler.get(victims[0]),
                        last_state=options[i].store_value.get();
                        if (state!==last_state)
                            for (var j=0; j<victims.length; j++)
                                options[i].toggler.set(victims[j], last_state);
                }

                $trigger
                    .off(".toggle")
                    .on("click.toggle", null, options, toggle._onClick)
                    .on("keypress.toggle", null, options, toggle._onKeyPress);
            });
        },

        _makeToggler: function toggle_makeToggler(options) {
            if (options.attr==="class") {
                var values = options.value.split(/\s+/);
                values=values.filter(function(v) { return v.length; });
               return new this._ClassToggler(values);
           } else
                return new this._AttributeToggler(options.attr);
        },

        _validateOptions: function toggle_validateOptions(trigger, options) {
            var correct=[],
                i, option, store_error;

            if (!options.length)
                return correct;

            for (i=0; i<options.length; i++) {
                option=options[i];
                if (!option.selector) {
                    log.error("Toggle pattern requires a selector.");
                    continue;
                }
                if (option.attr!=="class" && option.value) {
                    log.warn("Values are not supported attributes other than class.");
                    continue;
                }
                if (option.attr==="class" && !option.value) {
                    log.error("Toggle pattern needs values for class attributes.");
                    continue;
                }

                if (i && option.store!=="none") {
                    log.warn("store option can only be set on first argument");
                    option.store="none";
                }

                if (option.store!=="none") {
                    if (!trigger.id) {
                        log.warn("state persistance requested, but element has no id");
                        option.store="none";
                    } else if (!store.supported) {
                        store_error="browser does not support webstorage";
                        log.warn("state persistance requested, but browser does not support webstorage");
                        option.store="none";
                    } else {
                        var storage = (option.store==="local" ? store.local : store.session)(toggle.name);
                        option.value_storage = store.ValueStorage(storage, (trigger.id+"-"+i));
                    }
                }
                option.toggler=this._makeToggler(option);
                correct.push(option);
            }

            return correct;
        },

        _onClick: function toggle_onClick(event) {
            var options = event.data,
                victims, toggler, next_state, j;

            for (var i=0; i<options.length; i++) {
                victims=document.querySelectorAll(options[i].selector);
                if (!victims.length)
                    continue;
                toggler=options[i].toggler;
                next_state=toggler.toggle(victims[0]);
                for (j=1; j<victims.length; j++)
                    toggler.set(victims[j], next_state);
            }
            event.preventDefault();
        },

        _onKeyPress : function toggle_onKeyPress(event) {
            var keycode = event.keyCode ? event.keyCode : event.which;
            if (keycode==="13")
                $(this).trigger("click", event);
        }
    };

    patterns.register(toggle);
    return toggle;
});

// vim: sw=4 expandtab
<commit_msg>toggle: fix store handling.<commit_after>/**
 * Patterns toggle - toggle class on click
 *
 * Copyright 2012-2014 Simplon B.V. - Wichert Akkerman
 */
define([
    "jquery",
    "pat-registry",
    "pat-logger",
    "pat-parser",
    "pat-store"
], function($, patterns, logger, Parser, store) {
    var log = logger.getLogger("pat.toggle"),
        parser = new Parser("toggle");

    parser.add_argument("selector");
    parser.add_argument("attr", "class");
    parser.add_argument("value");
    parser.add_argument("store", "none", ["none", "session", "local"]);

    function ClassToggler(values) {
        this.values=values.slice(0);
        if (this.values.length>1)
            this.values.push(values[0]);
    }

    ClassToggler.prototype = {
        toggle: function Toggler_toggle(el) {
            var current = this.get(el),
                next = this.next(current);
            this.set(el, next);
            return next;
        },

        get: function Toggler_get(el) {
            var classes = el.className.split(/\s+/);
            for (var i=0; i<this.values.length;i++)
                if (classes.indexOf(this.values[i])!==-1)
                    return this.values[i];
            return null;
        },

        set: function Toggler_set(el, value) {
            var classes = el.className.split(/\s+/),
                values = this.values;
            classes=classes.filter(function(v) { return v.length && values.indexOf(v)===-1;});
            if (value)
                classes.push(value);
            el.className=classes.join(" ");
        },

        next: function Toggler_next(current) {
            if (this.values.length===1)
                return current ? null : this.values[0];
            for (var i=0; i<(this.values.length-1); i++)
                if (this.values[i]===current)
                    return this.values[i+1];
            return this.values[0];
       }
    };

    function AttributeToggler(attribute) {
        this.attribute=attribute;
    }

    AttributeToggler.prototype = new ClassToggler([]);
    AttributeToggler.prototype.get=function AttributeToggler_get(el) {
        return !!el[this.attribute];
    };

    AttributeToggler.prototype.set=function AttributeToggler_set(el, value) {
        if (value)
            el[this.attribute]=value;
        else
            el.removeAttribute(this.attribute);
    };

    AttributeToggler.prototype.next=function AttributeToggler_next(value) {
        return !value;
    };

    var toggle = {
        name: "toggle",
        trigger: ".pat-toggle",

        // Hook for testing
        _ClassToggler: ClassToggler,
        _AttributeToggler: AttributeToggler,

        init: function toggle_init($el) {
            return $el.each(function toggle_init_el() {
                var $trigger = $(this),
                    options = toggle._validateOptions(this, parser.parse($trigger, true));

                if (!options.length)
                    return;

                for (var i=0; i<options.length; i++)
                    if (options[i].value_storage) {
                        var victims, state, last_state;
                        victims=document.querySelectorAll(options[i].selector);
                        if (!victims.length)
                            continue;
                        state=options[i].toggler.get(victims[0]),
                        last_state=options[i].value_storage.get();
                        if (state!==last_state)
                            for (var j=0; j<victims.length; j++)
                                options[i].toggler.set(victims[j], last_state);
                }

                $trigger
                    .off(".toggle")
                    .on("click.toggle", null, options, toggle._onClick)
                    .on("keypress.toggle", null, options, toggle._onKeyPress);
            });
        },

        _makeToggler: function toggle_makeToggler(options) {
            if (options.attr==="class") {
                var values = options.value.split(/\s+/);
                values=values.filter(function(v) { return v.length; });
               return new this._ClassToggler(values);
           } else
                return new this._AttributeToggler(options.attr);
        },

        _validateOptions: function toggle_validateOptions(trigger, options) {
            var correct=[],
                i, option, store_error;

            if (!options.length)
                return correct;

            for (i=0; i<options.length; i++) {
                option=options[i];
                if (!option.selector) {
                    log.error("Toggle pattern requires a selector.");
                    continue;
                }
                if (option.attr!=="class" && option.value) {
                    log.warn("Values are not supported attributes other than class.");
                    continue;
                }
                if (option.attr==="class" && !option.value) {
                    log.error("Toggle pattern needs values for class attributes.");
                    continue;
                }

                if (i && option.store!=="none") {
                    log.warn("store option can only be set on first argument");
                    option.store="none";
                }

                if (option.store!=="none") {
                    if (!trigger.id) {
                        log.warn("state persistance requested, but element has no id");
                        option.store="none";
                    } else if (!store.supported) {
                        store_error="browser does not support webstorage";
                        log.warn("state persistance requested, but browser does not support webstorage");
                        option.store="none";
                    } else {
                        var storage = (option.store==="local" ? store.local : store.session)(toggle.name);
                        option.value_storage = new store.ValueStorage(storage, (trigger.id+"-"+i));
                    }
                }
                option.toggler=this._makeToggler(option);
                correct.push(option);
            }

            return correct;
        },

        _onClick: function toggle_onClick(event) {
            var options = event.data,
                option, victims, toggler, next_state, j;

            for (var i=0; i<options.length; i++) {
                option=options[i];
                victims=document.querySelectorAll(option.selector);
                if (!victims.length)
                    continue;
                toggler=option.toggler;
                next_state=toggler.toggle(victims[0]);
                for (j=1; j<victims.length; j++)
                    toggler.set(victims[j], next_state);
                if (option.value_storage)
                    option.value_storage.set(next_state);
            }
            event.preventDefault();
        },

        _onKeyPress : function toggle_onKeyPress(event) {
            var keycode = event.keyCode ? event.keyCode : event.which;
            if (keycode==="13")
                $(this).trigger("click", event);
        }
    };

    patterns.register(toggle);
    return toggle;
});
<|endoftext|>


<commit_before>/**
 * Outside click document
 */

import React from 'react';

export default class OutsideClickHandler extends React.Component {
    static propTypes = {
        onOutsideClick: React.PropTypes.func
    };

    componentDidMount() {
        document.addEventListener('click', this.handleDocumentClick.bind(this), false);
    }

    componentWillUnmount() {
        document.removeEventListener('click', this.handleDocumentClick.bind(this), false);
    }

    handleDocumentClick(event) {
        if (this.props.onOutsideClick !== null) {
            return this.props.onOutsideClick(event);
        }
    }

    handleMyClick(event) {
        event.stopPropagation();
        event.nativeEvent.stopImmediatePropagation();
    }

    render() {
        return (

                {this.props.children}

        );
    }
}
<commit_msg>Fix remove event listener in OutsideClickHandler<commit_after>/**
 * Outside click document
 */

import React from 'react';

export default class OutsideClickHandler extends React.Component {
    static propTypes = {
        onOutsideClick: React.PropTypes.func
    };

    componentDidMount() {
        document.addEventListener('click', this.handleDocumentClick, false);
    }

    componentWillUnmount() {
        document.removeEventListener('click', this.handleDocumentClick, false);
    }

    handleDocumentClick = (event) => {
        if (this.props.onOutsideClick === null) {
            return;
        }
        return this.props.onOutsideClick(event);
    }

    handleMyClick = (event) => {
        event.stopPropagation();
        event.nativeEvent.stopImmediatePropagation();
    }

    render() {
        return (

                {this.props.children}

        );
    }
}
<|endoftext|>


<commit_before>/*
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.
Copyright (c) 2014 Mozilla Corporation
*/
import { Meteor } from 'meteor/meteor';

if (Meteor.isServer) {

    //public server-side functions
    Meteor.methods({
        'saySomething': saySomething,
        'loadKibanaDashboards': loadKibanaDashboards,
        'blockip': blockIP,
        'blockfqdn': blockFQDN,
        'ipwhois': ipwhois,
        'ipdshield': ipdshield,
        'ipintel': ipintel,
        'verisstats': verisstats,
        'logincounts': logincounts,
        'getplugins': getplugins
    });

    function saySomething() {
        //debug function
        console.log("something is said");
    }

    function loadKibanaDashboards() {
        console.log('Loading Kibana dashboards... ' + mozdef.rootAPI + '/kibanadashboards');
        var dashboardsRequest = HTTP.get(mozdef.rootAPI + '/kibanadashboards');

        if (dashboardsRequest.statusCode==200 && dashboardsRequest.data) {
            // set the current dashboards in the mongo collection
            console.log("Updating kibana dashboards...");
            kibanadashboards.remove({});
            dashboardsRequest.data.forEach(function(dashboard, index, arr) {
                kibanadashboards.insert(dashboard);
            });
          //console.log(dashboardsRequest.data);
        } else {
            console.log("Could not retrieve kibana dashboards... check settings");
            console.log(mozdef.rootAPI + '/kibanadashboards');
            console.log("returned a " + dashboardsRequest.statusCode);
            console.log(dashboardsRequest.data);
        }
    }

    function blockIP(formobj) {
        var blockIPRequest = HTTP.post(mozdef.rootAPI + '/blockip', {data: formobj});

        if (blockIPRequest.statusCode==200) {
            console.log(JSON.stringify(formobj) + ' successfully sent to ' + mozdef.rootAPI);
            return true;
        } else {
            console.log("Could not send to "+ mozdef.rootAPI + '/blockip ' + JSON.stringify(formobj) );
            return blockIPRequest;
        }
    }

    function blockFQDN(formobj) {
        try{
            var blockFQDNRequest = HTTP.post(mozdef.rootAPI + '/blockfqdn', {data: formobj});

            if (blockFQDNRequest.statusCode==200) {
                console.log(JSON.stringify(formobj) + ' successfully sent to ' + mozdef.rootAPI);
                return true;
            }
        }catch (e) {
            console.log("Error posting to "+ mozdef.rootAPI + '/blockfqdn ' + JSON.stringify(formobj) );
            console.log(e)
            if ( e.response.statusCode == 400 ){
                // rest API set a reason in content
                console.log(e.response.content);
                return e.response.content;
            }else{
                return e;
            }
        }
    }

    function ipwhois(ipaddress){
        //console.log('Posting ' + ipaddress + 'to ' + mozdef.rootAPI + '/ipwhois/');
        var ipwhoisResponse = HTTP.post(mozdef.rootAPI + '/ipwhois/',{data: {'ipaddress':ipaddress}});

        if ( typeof ipwhoisResponse == 'undefined') {
            console.log("ipwhois: no response from server")
            return "";
        } else {
            //console.log(ipwhoisResponse);
            return ipwhoisResponse;
        }
    }

    function ipdshield(ipaddress){
        //console.log('Posting ' + ipaddress + 'to ' + mozdef.rootAPI + '/ipwhois/');
        var ipdshieldResponse = HTTP.post(mozdef.rootAPI + '/ipdshieldquery/',{data: {'ipaddress':ipaddress}});

        if ( typeof ipdshieldResponse == 'undefined') {
            console.log("ipdshield: no response from server")
            return "";
        } else {
            //console.log(ipdshieldResponse);
            return ipdshieldResponse;
        }
    }

    function ipintel(ipaddress){
        //console.log('Posting ' + ipaddress + 'to ' + mozdef.rootAPI + '/ipintel/');
        var ipintelResponse = HTTP.post(mozdef.rootAPI + '/ipintel/',{data: {'ipaddress':ipaddress}});

        if ( typeof ipintelResponse == 'undefined') {
            console.log("ipintel: no response from server")
            return "";
        } else {
            //console.log(ipdshieldResponse);
            return ipintelResponse;
        }
    }

    function verisstats(){
        //console.log('Calling ' + mozdef.rootAPI + '/veris/');
        var verisstatsResponse = HTTP.get(mozdef.rootAPI + '/veris/');

        if ( typeof verisstatsResponse == 'undefined') {
            console.log("verisstats: no response from server")
            return "";
        } else {
            //console.log(verisstatsResponse);
            return verisstatsResponse;
        }
    }

    function logincounts(){
        //console.log('Calling ' + mozdef.rootAPI + '/ldapLogins/');
        var logincountsResponse = HTTP.get(mozdef.rootAPI + '/ldapLogins/');

        if ( typeof logincountsResponse == 'undefined') {
            console.log("logincountsResponse: no response from server")
            return "";
        } else {
            //console.log(logincountsResponse);
            return logincountsResponse;
        }
    }

    function getplugins(endpoint){
        //console.log('Looking up  plugins registered for ' + endpoint + ' from ' + mozdef.rootAPI + '/plugins/' + endpoint);
        if ( typeof endpoint == 'undefined') {
            var response = HTTP.get(mozdef.rootAPI + '/plugins/');

        } else {
            var response = HTTP.get(mozdef.rootAPI + '/plugins/' + endpoint);
        }
        return response
    }

};
<commit_msg>add get server settings function<commit_after>/*
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.
Copyright (c) 2014 Mozilla Corporation
*/
import { Meteor } from 'meteor/meteor';
import { _ } from 'meteor/underscore';

if (Meteor.isServer) {

    //public server-side functions
    Meteor.methods({
        'saySomething': saySomething,
        'loadKibanaDashboards': loadKibanaDashboards,
        'blockip': blockIP,
        'blockfqdn': blockFQDN,
        'ipwhois': ipwhois,
        'ipdshield': ipdshield,
        'ipintel': ipintel,
        'verisstats': verisstats,
        'logincounts': logincounts,
        'getplugins': getplugins,
        'getserversetting': getserversetting
    });

    function saySomething() {
        //debug function
        console.log("something is said");
    }

    function loadKibanaDashboards() {
        console.log('Loading Kibana dashboards... ' + mozdef.rootAPI + '/kibanadashboards');
        var dashboardsRequest = HTTP.get(mozdef.rootAPI + '/kibanadashboards');

        if (dashboardsRequest.statusCode==200 && dashboardsRequest.data) {
            // set the current dashboards in the mongo collection
            console.log("Updating kibana dashboards...");
            kibanadashboards.remove({});
            dashboardsRequest.data.forEach(function(dashboard, index, arr) {
                kibanadashboards.insert(dashboard);
            });
          //console.log(dashboardsRequest.data);
        } else {
            console.log("Could not retrieve kibana dashboards... check settings");
            console.log(mozdef.rootAPI + '/kibanadashboards');
            console.log("returned a " + dashboardsRequest.statusCode);
            console.log(dashboardsRequest.data);
        }
    }

    function blockIP(formobj) {
        var blockIPRequest = HTTP.post(mozdef.rootAPI + '/blockip', {data: formobj});

        if (blockIPRequest.statusCode==200) {
            console.log(JSON.stringify(formobj) + ' successfully sent to ' + mozdef.rootAPI);
            return true;
        } else {
            console.log("Could not send to "+ mozdef.rootAPI + '/blockip ' + JSON.stringify(formobj) );
            return blockIPRequest;
        }
    }

    function blockFQDN(formobj) {
        try{
            var blockFQDNRequest = HTTP.post(mozdef.rootAPI + '/blockfqdn', {data: formobj});

            if (blockFQDNRequest.statusCode==200) {
                console.log(JSON.stringify(formobj) + ' successfully sent to ' + mozdef.rootAPI);
                return true;
            }
        }catch (e) {
            console.log("Error posting to "+ mozdef.rootAPI + '/blockfqdn ' + JSON.stringify(formobj) );
            console.log(e)
            if ( e.response.statusCode == 400 ){
                // rest API set a reason in content
                console.log(e.response.content);
                return e.response.content;
            }else{
                return e;
            }
        }
    }

    function ipwhois(ipaddress){
        //console.log('Posting ' + ipaddress + 'to ' + mozdef.rootAPI + '/ipwhois/');
        var ipwhoisResponse = HTTP.post(mozdef.rootAPI + '/ipwhois/',{data: {'ipaddress':ipaddress}});

        if ( typeof ipwhoisResponse == 'undefined') {
            console.log("ipwhois: no response from server")
            return "";
        } else {
            //console.log(ipwhoisResponse);
            return ipwhoisResponse;
        }
    }

    function ipdshield(ipaddress){
        //console.log('Posting ' + ipaddress + 'to ' + mozdef.rootAPI + '/ipwhois/');
        var ipdshieldResponse = HTTP.post(mozdef.rootAPI + '/ipdshieldquery/',{data: {'ipaddress':ipaddress}});

        if ( typeof ipdshieldResponse == 'undefined') {
            console.log("ipdshield: no response from server")
            return "";
        } else {
            //console.log(ipdshieldResponse);
            return ipdshieldResponse;
        }
    }

    function ipintel(ipaddress){
        //console.log('Posting ' + ipaddress + 'to ' + mozdef.rootAPI + '/ipintel/');
        var ipintelResponse = HTTP.post(mozdef.rootAPI + '/ipintel/',{data: {'ipaddress':ipaddress}});

        if ( typeof ipintelResponse == 'undefined') {
            console.log("ipintel: no response from server")
            return "";
        } else {
            //console.log(ipdshieldResponse);
            return ipintelResponse;
        }
    }

    function verisstats(){
        //console.log('Calling ' + mozdef.rootAPI + '/veris/');
        var verisstatsResponse = HTTP.get(mozdef.rootAPI + '/veris/');

        if ( typeof verisstatsResponse == 'undefined') {
            console.log("verisstats: no response from server")
            return "";
        } else {
            //console.log(verisstatsResponse);
            return verisstatsResponse;
        }
    }

    function logincounts(){
        //console.log('Calling ' + mozdef.rootAPI + '/ldapLogins/');
        var logincountsResponse = HTTP.get(mozdef.rootAPI + '/ldapLogins/');

        if ( typeof logincountsResponse == 'undefined') {
            console.log("logincountsResponse: no response from server")
            return "";
        } else {
            //console.log(logincountsResponse);
            return logincountsResponse;
        }
    }

    function getplugins(endpoint){
        //console.log('Looking up  plugins registered for ' + endpoint + ' from ' + mozdef.rootAPI + '/plugins/' + endpoint);
        if ( typeof endpoint == 'undefined') {
            var response = HTTP.get(mozdef.rootAPI + '/plugins/');

        } else {
            var response = HTTP.get(mozdef.rootAPI + '/plugins/' + endpoint);
        }
        return response
    }

    function getserversetting(settingKey){
        if ( _.has(mozdef,settingKey) ){
            return mozdef[settingKey];
        }else{
            return '';
        }
    }

};
<|endoftext|>


<commit_before>import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';

import PropTypes from "prop-types";
import ReactAudioPlayer from 'react-audio-player';
import axios from "axios";

class AvailableDatalist extends React.Component {

  render() {
    console.log("props during render songs")
    console.log(this.props)
    const ret
    if(this.props[0] != 0){
      ret = this.props.songs.map(c => {

c.songName[0]

c.album

c.author

c.date

      })
    }else{
      ret = {
test
}
    }
    return(ret)
  }
}

AvailableDatalist.propTypes = {
  songs: PropTypes.array.isRequired
};

class SongBoard extends React.Component {
state = {
  songs: [0:{name:"none", album:"none", author:"none"}]
};

componentDidMount() {
  axios
  .get("http://192.168.1.107:8000/album/")
  .then(response => {
    const songs = response.data.map(c => {

      return{
        songName: c.songs.map(d => {return(d.name)}),
        album: c.name,
        author: c.author,
        date: c.release_date
      };
    });

    const newState = Object.assign({}, this.state, {
          songs: songs
    });
    this.setState(newState);
    console.log("state after api request")
    console.log(this.state)

  })
  .catch(error => console.log(error));

}

  render() {

    return(

            <button className="song">
              Song
            </button>
            <button className="album">
              Album
            </button>

          <AvailableDatalist songs={this.state.songs}/> {/*songs={this.state.contacts}*/}

    )
  }
}

class Player extends React.Component {
  render() {
    return(
      <ReactAudioPlayer
        src="my_audio_file.ogg"
        autoPlay
        controls
      />
    )
  }
}

class Site extends React.Component {
  render() {
    return (

          <Player />

          <SongBoard />

    )
  }
}

ReactDOM.render(
  <Site />,
  document.getElementById('root')
);
<commit_msg>songs<commit_after>import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';

import PropTypes from "prop-types";
import ReactAudioPlayer from 'react-audio-player';
import axios from "axios";

class AvailableDatalist extends React.Component {
  getSongs(s){
    console.log("props during render songs")
    console.log(s.props)
    const ret
    if(s.props[0] != 0){
      ret = s.props.songs.map(c => {

c.songName[0]

c.album

c.author

c.date

      })
    }else{
      ret = {
test
}
    }
    return(ret)
  }

  render() {
    return(getSongs(this.state))
  }
}

AvailableDatalist.propTypes = {
  songs: PropTypes.array.isRequired
};

class SongBoard extends React.Component {
state = {
  songs: [0:{name:"none", album:"none", author:"none"}]
};

componentDidMount() {
  axios
  .get("http://192.168.1.107:8000/album/")
  .then(response => {
    const songs = response.data.map(c => {

      return{
        songName: c.songs.map(d => {return(d.name)}),
        album: c.name,
        author: c.author,
        date: c.release_date
      };
    });

    const newState = Object.assign({}, this.state, {
          songs: songs
    });
    this.setState(newState);
    console.log("state after api request")
    console.log(this.state)

  })
  .catch(error => console.log(error));

}

  render() {

    return(

            <button className="song">
              Song
            </button>
            <button className="album">
              Album
            </button>

          <AvailableDatalist songs={this.state.songs}/> {/*songs={this.state.contacts}*/}

    )
  }
}

class Player extends React.Component {
  render() {
    return(
      <ReactAudioPlayer
        src="my_audio_file.ogg"
        autoPlay
        controls
      />
    )
  }
}

class Site extends React.Component {
  render() {
    return (

          <Player />

          <SongBoard />

    )
  }
}

ReactDOM.render(
  <Site />,
  document.getElementById('root')
);
<|endoftext|>


<commit_before>import RBush from 'rbush';

import { dispatch as d3_dispatch } from 'd3-dispatch';
import { json as d3_json } from 'd3-fetch';

import { currentLocale } from '../util/locale';
import { geoExtent, geoVecAdd } from '../geo';
import { qaError } from '../osm';
import { utilRebind, utilTiler, utilQsString } from '../util';
import { services as qaServices } from '../../data/qa_errors.json';

const tiler = utilTiler();
const dispatch = d3_dispatch('loaded');
const _osmoseUrlRoot = 'https://osmose.openstreetmap.fr/en/api/0.3beta';
const _osmoseItems =
  Object.keys(qaServices.osmose.errorIcons)
    .map(s => s.split('-')[0])
    .reduce((unique, item) => unique.indexOf(item) !== -1 ? unique : [...unique, item], []);
const _erZoom = 14;
const _stringCache = {};
const _colorCache = {};

// This gets reassigned if reset
let _erCache;

function abortRequest(controller) {
  if (controller) {
    controller.abort();
  }
}

function abortUnwantedRequests(cache, tiles) {
  Object.keys(cache.inflightTile).forEach(k => {
    let wanted = tiles.find(tile => k === tile.id);
    if (!wanted) {
      abortRequest(cache.inflightTile[k]);
      delete cache.inflightTile[k];
    }
  });
}

function encodeErrorRtree(d) {
  return { minX: d.loc[0], minY: d.loc[1], maxX: d.loc[0], maxY: d.loc[1], data: d };
}

// replace or remove error from rtree
function updateRtree(item, replace) {
  _erCache.rtree.remove(item, (a, b) => a.data.id === b.data.id);

  if (replace) {
    _erCache.rtree.insert(item);
  }
}

// Errors shouldn't obscure eachother
function preventCoincident(loc) {
  let coincident = false;
  do {
    // first time, move marker up. after that, move marker right.
    let delta = coincident ? [0.00001, 0] : [0, 0.00001];
    loc = geoVecAdd(loc, delta);
    let bbox = geoExtent(loc).bbox();
    coincident = _erCache.rtree.search(bbox).length;
  } while (coincident);

  return loc;
}

export default {
  init() {
    if (!_erCache) {
      this.reset();
    }

    this.event = utilRebind(this, dispatch, 'on');
  },

  reset() {
    if (_erCache) {
      Object.values(_erCache.inflightTile).forEach(abortRequest);
    }
    _erCache = {
      data: {},
      loadedTile: {},
      inflightTile: {},
      inflightPost: {},
      closed: {},
      rtree: new RBush()
    };
  },

  loadErrors(projection) {
    let params = {
      // Tiles return a maximum # of errors
      // So we want to filter our request for only types iD supports
      item: _osmoseItems
    };

    // determine the needed tiles to cover the view
    let tiles = tiler
      .zoomExtent([_erZoom, _erZoom])
      .getTiles(projection);

    // abort inflight requests that are no longer needed
    abortUnwantedRequests(_erCache, tiles);

    // issue new requests..
    tiles.forEach(tile => {
      if (_erCache.loadedTile[tile.id] || _erCache.inflightTile[tile.id]) return;

      let [ x, y, z ] = tile.xyz;
      let url = `${_osmoseUrlRoot}/issues/${z}/${x}/${y}.json?` + utilQsString(params);

      let controller = new AbortController();
      _erCache.inflightTile[tile.id] = controller;

      d3_json(url, { signal: controller.signal })
        .then(data => {
          delete _erCache.inflightTile[tile.id];
          _erCache.loadedTile[tile.id] = true;

          if (data.features) {
            data.features.forEach(issue => {
              const { item, class: error_class, uuid: identifier } = issue.properties;
              // Item is the type of error, w/ class tells us the sub-type
              const error_type = `${item}-${error_class}`;

              // Filter out unsupported error types (some are too specific or advanced)
              if (error_type in qaServices.osmose.errorIcons) {
                let loc = issue.geometry.coordinates; // lon, lat
                loc = preventCoincident(loc);

                let d = new qaError({
                  // Info required for every error
                  loc,
                  service: 'osmose',
                  error_type,
                  // Extra details needed for this service
                  identifier, // needed to query and update the error
                  item // category of the issue for styling
                });

                // Setting elems here prevents UI error detail requests
                if (d.item === 8300 || d.item === 8360) {
                  d.elems = [];
                }

                _erCache.data[d.id] = d;
                _erCache.rtree.insert(encodeErrorRtree(d));
              }
            });
          }

          dispatch.call('loaded');
        })
        .catch(() => {
          delete _erCache.inflightTile[tile.id];
          _erCache.loadedTile[tile.id] = true;
        });
    });
  },

  loadErrorDetail(d, callback) {
    // Error details only need to be fetched once
    if (d.elems !== undefined) {
      if (callback) callback(null, d);
      return;
    }

    let url = `${_osmoseUrlRoot}/issue/${d.identifier}?langs=${currentLocale}`;

    d3_json(url)
      .then(data => {
        // Associated elements used for highlighting
        // Assign directly for immediate use in the callback
        d.elems = data.elems.map(e => e.type.substring(0,1) + e.id);

        // Some issues have instance specific detail in a subtitle
        d.detail = data.subtitle;

        this.replaceError(d);
        if (callback) callback(null, d);
      })
      .catch(err => {
        if (callback) callback(err.message);
      });
  },

  loadStrings(callback, locale=currentLocale) {
    const issueTypes = Object.keys(qaServices.osmose.errorIcons);

    if (
      locale in _stringCache
      && Object.keys(_stringCache[locale]).length === issueTypes.length
    ) {
        if (callback) callback(null, _stringCache[locale]);
        return;
    }

    // May be partially populated already if some requests were successful
    if (!(locale in _stringCache)) {
      _stringCache[locale] = {};
    }

    const format = string => {
      // Some strings contain markdown syntax
      string = string.replace(/\[((?:.|\n)+?)\]\((.+?)\)/g, '$1');
      return string.replace(/`(.+?)`/g, '$1');
    };

    // Only need to cache strings for supported issue types
    // Using multiple individual item + class requests to reduce fetched data size
    const allRequests = issueTypes.map(issueType => {
      // No need to request data we already have
      if (issueType in _stringCache[locale]) return;

      const cacheData = data => {
        // Bunch of nested single value arrays of objects
        const [ cat = {items:[]} ] = data.categories;
        const [ item = {class:[]} ] = cat.items;
        const [ cl = null ] = item.class;

        // If null default value is reached, data wasn't as expected (or was empty)
        if (!cl) {
          /* eslint-disable no-console */
          console.log(`Osmose strings request (${issueType}) had unexpected data`);
          /* eslint-enable no-console */
          return;
        }

        // Cache served item colors to automatically style issue markers later
        const { item: itemInt, color } = item;
        if (color.test(/^#[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3}/)) {
          _colorCache[itemInt] = color;
        }

        // Value of root key will be null if no string exists
        // If string exists, value is an object with key 'auto' for string
        const { title, detail, fix, trap } = cl;

        let issueStrings = {};
        if (title) issueStrings.title = title.auto;
        if (detail) issueStrings.detail = format(detail.auto);
        if (trap) issueStrings.trap = format(trap.auto);
        if (fix) issueStrings.fix = format(fix.auto);

        _stringCache[locale][issueType] = issueStrings;
      };

      const [ item, cl ] = issueType.split('-');

      // Osmose API falls back to English strings where untranslated or if locale doesn't exist
      const url = `${_osmoseUrlRoot}/items/${item}/class/${cl}?langs=${locale}`;

      return jsonPromise(url, cacheData);
    });

    Promise.all(allRequests)
      .then(() => { if (callback) callback(null, _stringCache[locale]); })
      .catch(err => { if (callback) callback(err); });
  },

  getStrings(issueType, locale=currentLocale) {
    // No need to fallback to English, Osmose API handles this for us
    return (locale in _stringCache) ? _stringCache[locale][issueType] : {};
  },

  getColor(itemType) {
    return (itemType in _colorCache) ? _colorCache[itemType] : '#FFFFFF';
  },

  postUpdate(d, callback) {
    if (_erCache.inflightPost[d.id]) {
      return callback({ message: 'Error update already inflight', status: -2 }, d);
    }

    // UI sets the status to either 'done' or 'false'
    let url = `${_osmoseUrlRoot}/issue/${d.identifier}/${d.newStatus}`;

    let controller = new AbortController();
    _erCache.inflightPost[d.id] = controller;

    fetch(url, { signal: controller.signal })
      .then(() => {
        delete _erCache.inflightPost[d.id];

        this.removeError(d);
        if (d.newStatus === 'done') {
          // No error identifier, so we give a count of each category
          if (!(d.item in _erCache.closed)) {
            _erCache.closed[d.item] = 0;
          }
          _erCache.closed[d.item] += 1;
        }
        if (callback) callback(null, d);
      })
      .catch(err => {
        delete _erCache.inflightPost[d.id];
        if (callback) callback(err.message);
      });
  },

  // get all cached errors covering the viewport
  getErrors(projection) {
    let viewport = projection.clipExtent();
    let min = [viewport[0][0], viewport[1][1]];
    let max = [viewport[1][0], viewport[0][1]];
    let bbox = geoExtent(projection.invert(min), projection.invert(max)).bbox();

    return _erCache.rtree.search(bbox).map(d => {
      return d.data;
    });
  },

  // get a single error from the cache
  getError(id) {
    return _erCache.data[id];
  },

  // replace a single error in the cache
  replaceError(error) {
    if (!(error instanceof qaError) || !error.id) return;

    _erCache.data[error.id] = error;
    updateRtree(encodeErrorRtree(error), true); // true = replace
    return error;
  },

  // remove a single error from the cache
  removeError(error) {
    if (!(error instanceof qaError) || !error.id) return;

    delete _erCache.data[error.id];
    updateRtree(encodeErrorRtree(error), false); // false = remove
  },

  // Used to populate `closed:osmose:*` changeset tags
  getClosedCounts() {
    return _erCache.closed;
  }
};

function jsonPromise(url, then) {
  return new Promise((resolve, reject) => {
    d3_json(url)
      .then(data => {
        then(data);
        resolve();
      })
      .catch(err => {
        reject(err);
      });
  });
}<commit_msg>Fix use of test() method on color string<commit_after>import RBush from 'rbush';

import { dispatch as d3_dispatch } from 'd3-dispatch';
import { json as d3_json } from 'd3-fetch';

import { currentLocale } from '../util/locale';
import { geoExtent, geoVecAdd } from '../geo';
import { qaError } from '../osm';
import { utilRebind, utilTiler, utilQsString } from '../util';
import { services as qaServices } from '../../data/qa_errors.json';

const tiler = utilTiler();
const dispatch = d3_dispatch('loaded');
const _osmoseUrlRoot = 'https://osmose.openstreetmap.fr/en/api/0.3beta';
const _osmoseItems =
  Object.keys(qaServices.osmose.errorIcons)
    .map(s => s.split('-')[0])
    .reduce((unique, item) => unique.indexOf(item) !== -1 ? unique : [...unique, item], []);
const _erZoom = 14;
const _stringCache = {};
const _colorCache = {};

// This gets reassigned if reset
let _erCache;

function abortRequest(controller) {
  if (controller) {
    controller.abort();
  }
}

function abortUnwantedRequests(cache, tiles) {
  Object.keys(cache.inflightTile).forEach(k => {
    let wanted = tiles.find(tile => k === tile.id);
    if (!wanted) {
      abortRequest(cache.inflightTile[k]);
      delete cache.inflightTile[k];
    }
  });
}

function encodeErrorRtree(d) {
  return { minX: d.loc[0], minY: d.loc[1], maxX: d.loc[0], maxY: d.loc[1], data: d };
}

// replace or remove error from rtree
function updateRtree(item, replace) {
  _erCache.rtree.remove(item, (a, b) => a.data.id === b.data.id);

  if (replace) {
    _erCache.rtree.insert(item);
  }
}

// Errors shouldn't obscure eachother
function preventCoincident(loc) {
  let coincident = false;
  do {
    // first time, move marker up. after that, move marker right.
    let delta = coincident ? [0.00001, 0] : [0, 0.00001];
    loc = geoVecAdd(loc, delta);
    let bbox = geoExtent(loc).bbox();
    coincident = _erCache.rtree.search(bbox).length;
  } while (coincident);

  return loc;
}

export default {
  init() {
    if (!_erCache) {
      this.reset();
    }

    this.event = utilRebind(this, dispatch, 'on');
  },

  reset() {
    if (_erCache) {
      Object.values(_erCache.inflightTile).forEach(abortRequest);
    }
    _erCache = {
      data: {},
      loadedTile: {},
      inflightTile: {},
      inflightPost: {},
      closed: {},
      rtree: new RBush()
    };
  },

  loadErrors(projection) {
    let params = {
      // Tiles return a maximum # of errors
      // So we want to filter our request for only types iD supports
      item: _osmoseItems
    };

    // determine the needed tiles to cover the view
    let tiles = tiler
      .zoomExtent([_erZoom, _erZoom])
      .getTiles(projection);

    // abort inflight requests that are no longer needed
    abortUnwantedRequests(_erCache, tiles);

    // issue new requests..
    tiles.forEach(tile => {
      if (_erCache.loadedTile[tile.id] || _erCache.inflightTile[tile.id]) return;

      let [ x, y, z ] = tile.xyz;
      let url = `${_osmoseUrlRoot}/issues/${z}/${x}/${y}.json?` + utilQsString(params);

      let controller = new AbortController();
      _erCache.inflightTile[tile.id] = controller;

      d3_json(url, { signal: controller.signal })
        .then(data => {
          delete _erCache.inflightTile[tile.id];
          _erCache.loadedTile[tile.id] = true;

          if (data.features) {
            data.features.forEach(issue => {
              const { item, class: error_class, uuid: identifier } = issue.properties;
              // Item is the type of error, w/ class tells us the sub-type
              const error_type = `${item}-${error_class}`;

              // Filter out unsupported error types (some are too specific or advanced)
              if (error_type in qaServices.osmose.errorIcons) {
                let loc = issue.geometry.coordinates; // lon, lat
                loc = preventCoincident(loc);

                let d = new qaError({
                  // Info required for every error
                  loc,
                  service: 'osmose',
                  error_type,
                  // Extra details needed for this service
                  identifier, // needed to query and update the error
                  item // category of the issue for styling
                });

                // Setting elems here prevents UI error detail requests
                if (d.item === 8300 || d.item === 8360) {
                  d.elems = [];
                }

                _erCache.data[d.id] = d;
                _erCache.rtree.insert(encodeErrorRtree(d));
              }
            });
          }

          dispatch.call('loaded');
        })
        .catch(() => {
          delete _erCache.inflightTile[tile.id];
          _erCache.loadedTile[tile.id] = true;
        });
    });
  },

  loadErrorDetail(d, callback) {
    // Error details only need to be fetched once
    if (d.elems !== undefined) {
      if (callback) callback(null, d);
      return;
    }

    let url = `${_osmoseUrlRoot}/issue/${d.identifier}?langs=${currentLocale}`;

    d3_json(url)
      .then(data => {
        // Associated elements used for highlighting
        // Assign directly for immediate use in the callback
        d.elems = data.elems.map(e => e.type.substring(0,1) + e.id);

        // Some issues have instance specific detail in a subtitle
        d.detail = data.subtitle;

        this.replaceError(d);
        if (callback) callback(null, d);
      })
      .catch(err => {
        if (callback) callback(err.message);
      });
  },

  loadStrings(callback, locale=currentLocale) {
    const issueTypes = Object.keys(qaServices.osmose.errorIcons);

    if (
      locale in _stringCache
      && Object.keys(_stringCache[locale]).length === issueTypes.length
    ) {
        if (callback) callback(null, _stringCache[locale]);
        return;
    }

    // May be partially populated already if some requests were successful
    if (!(locale in _stringCache)) {
      _stringCache[locale] = {};
    }

    const format = string => {
      // Some strings contain markdown syntax
      string = string.replace(/\[((?:.|\n)+?)\]\((.+?)\)/g, '$1');
      return string.replace(/`(.+?)`/g, '$1');
    };

    // Only need to cache strings for supported issue types
    // Using multiple individual item + class requests to reduce fetched data size
    const allRequests = issueTypes.map(issueType => {
      // No need to request data we already have
      if (issueType in _stringCache[locale]) return;

      const cacheData = data => {
        // Bunch of nested single value arrays of objects
        const [ cat = {items:[]} ] = data.categories;
        const [ item = {class:[]} ] = cat.items;
        const [ cl = null ] = item.class;

        // If null default value is reached, data wasn't as expected (or was empty)
        if (!cl) {
          /* eslint-disable no-console */
          console.log(`Osmose strings request (${issueType}) had unexpected data`);
          /* eslint-enable no-console */
          return;
        }

        // Cache served item colors to automatically style issue markers later
        const { item: itemInt, color } = item;
        if (/^#[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3}/.test(color)) {
          _colorCache[itemInt] = color;
        }

        // Value of root key will be null if no string exists
        // If string exists, value is an object with key 'auto' for string
        const { title, detail, fix, trap } = cl;

        let issueStrings = {};
        if (title) issueStrings.title = title.auto;
        if (detail) issueStrings.detail = format(detail.auto);
        if (trap) issueStrings.trap = format(trap.auto);
        if (fix) issueStrings.fix = format(fix.auto);

        _stringCache[locale][issueType] = issueStrings;
      };

      const [ item, cl ] = issueType.split('-');

      // Osmose API falls back to English strings where untranslated or if locale doesn't exist
      const url = `${_osmoseUrlRoot}/items/${item}/class/${cl}?langs=${locale}`;

      return jsonPromise(url, cacheData);
    });

    Promise.all(allRequests)
      .then(() => { if (callback) callback(null, _stringCache[locale]); })
      .catch(err => { if (callback) callback(err); });
  },

  getStrings(issueType, locale=currentLocale) {
    // No need to fallback to English, Osmose API handles this for us
    return (locale in _stringCache) ? _stringCache[locale][issueType] : {};
  },

  getColor(itemType) {
    return (itemType in _colorCache) ? _colorCache[itemType] : '#FFFFFF';
  },

  postUpdate(d, callback) {
    if (_erCache.inflightPost[d.id]) {
      return callback({ message: 'Error update already inflight', status: -2 }, d);
    }

    // UI sets the status to either 'done' or 'false'
    let url = `${_osmoseUrlRoot}/issue/${d.identifier}/${d.newStatus}`;

    let controller = new AbortController();
    _erCache.inflightPost[d.id] = controller;

    fetch(url, { signal: controller.signal })
      .then(() => {
        delete _erCache.inflightPost[d.id];

        this.removeError(d);
        if (d.newStatus === 'done') {
          // No error identifier, so we give a count of each category
          if (!(d.item in _erCache.closed)) {
            _erCache.closed[d.item] = 0;
          }
          _erCache.closed[d.item] += 1;
        }
        if (callback) callback(null, d);
      })
      .catch(err => {
        delete _erCache.inflightPost[d.id];
        if (callback) callback(err.message);
      });
  },

  // get all cached errors covering the viewport
  getErrors(projection) {
    let viewport = projection.clipExtent();
    let min = [viewport[0][0], viewport[1][1]];
    let max = [viewport[1][0], viewport[0][1]];
    let bbox = geoExtent(projection.invert(min), projection.invert(max)).bbox();

    return _erCache.rtree.search(bbox).map(d => {
      return d.data;
    });
  },

  // get a single error from the cache
  getError(id) {
    return _erCache.data[id];
  },

  // replace a single error in the cache
  replaceError(error) {
    if (!(error instanceof qaError) || !error.id) return;

    _erCache.data[error.id] = error;
    updateRtree(encodeErrorRtree(error), true); // true = replace
    return error;
  },

  // remove a single error from the cache
  removeError(error) {
    if (!(error instanceof qaError) || !error.id) return;

    delete _erCache.data[error.id];
    updateRtree(encodeErrorRtree(error), false); // false = remove
  },

  // Used to populate `closed:osmose:*` changeset tags
  getClosedCounts() {
    return _erCache.closed;
  }
};

function jsonPromise(url, then) {
  return new Promise((resolve, reject) => {
    d3_json(url)
      .then(data => {
        then(data);
        resolve();
      })
      .catch(err => {
        reject(err);
      });
  });
}
<|endoftext|>


<commit_before>// MulitpleProcess model
// An abstract class that allows us to group some atomic process related entities
// Like: registrations, requirements or processingSteps

'use strict';

var memoize  = require('memoizee/plain')
  , ensureDb = require('dbjs/valid-dbjs');

module.exports = memoize(function (db/*, options*/) {
	var MultipleProcess = ensureDb(db).Object.extend('MultipleProcess', {
		map: { type: db.Object, nested: true },
		applicable: { type: db.Object, multiple: true, value: function (_observe) {
			var result = [];
			this.map.forEach(function (entity) {
				var isApplicable = entity._get ? _observe(entity._isApplicable) : entity.isApplicable;
				if (isApplicable) result.push(entity);
			});
			return result;
		} }
	});
	MultipleProcess.prototype.map._descriptorPrototype_.type = db.Object;
	return MultipleProcess;
}, { normalizer: require('memoizee/normalizers/get-1')() });
<commit_msg>-- typo<commit_after>// MultipleProcess model
// An abstract class that allows us to group some atomic process related entities
// Like: registrations, requirements or processingSteps

'use strict';

var memoize  = require('memoizee/plain')
  , ensureDb = require('dbjs/valid-dbjs');

module.exports = memoize(function (db/*, options*/) {
	var MultipleProcess = ensureDb(db).Object.extend('MultipleProcess', {
		map: { type: db.Object, nested: true },
		applicable: { type: db.Object, multiple: true, value: function (_observe) {
			var result = [];
			this.map.forEach(function (entity) {
				var isApplicable = entity._get ? _observe(entity._isApplicable) : entity.isApplicable;
				if (isApplicable) result.push(entity);
			});
			return result;
		} }
	});
	MultipleProcess.prototype.map._descriptorPrototype_.type = db.Object;
	return MultipleProcess;
}, { normalizer: require('memoizee/normalizers/get-1')() });
<|endoftext|>


<commit_before>/* jshint node: true */

module.exports = function(grunt) {
  "use strict";

  // Project configuration.
  grunt.initConfig({

    // Metadata.
    pkg: grunt.file.readJSON('package.json'),
    banner: '/**\n' +
              '* <%= pkg.name %>.js v<%= pkg.version %> by @fat and @mdo\n' +
              '* Copyright <%= grunt.template.today("yyyy") %> <%= pkg.author %>\n' +
              '* <%= _.pluck(pkg.licenses, "url").join(", ") %>\n' +
              '*/\n',
    jqueryCheck: 'if (!jQuery) { throw new Error(\"Bootstrap requires jQuery\") }\n\n',

    // Task configuration.
    clean: {
      dist: ['dist']
    },

    jshint: {
      options: {
        jshintrc: 'js/.jshintrc'
      },
      gruntfile: {
        src: 'Gruntfile.js'
      },
      src: {
        src: ['js/*.js']
      },
      test: {
        src: ['js/tests/unit/*.js']
      }
    },

    concat: {
      options: {
        banner: '<%= banner %><%= jqueryCheck %>',
        stripBanners: false
      },
      bootstrap: {
        src: [
          'js/transition.js',
          'js/alert.js',
          'js/button.js',
          'js/carousel.js',
          'js/collapse.js',
          'js/dropdown.js',
          'js/modal.js',
          'js/tooltip.js',
          'js/popover.js',
          'js/scrollspy.js',
          'js/tab.js',
          'js/affix.js'
        ],
        dest: 'dist/js/<%= pkg.name %>.js'
      }
    },

    uglify: {
      options: {
        banner: '<%= banner %>'
      },
      bootstrap: {
        src: ['<%= concat.bootstrap.dest %>'],
        dest: 'dist/js/<%= pkg.name %>.min.js'
      }
    },

    recess: {
      options: {
        compile: true
      },
      bootstrap: {
        src: ['less/bootstrap.less'],
        dest: 'dist/css/<%= pkg.name %>.css'
      },
      min: {
        options: {
          compress: true
        },
        src: ['less/bootstrap.less'],
        dest: 'dist/css/<%= pkg.name %>.min.css'
      },
      theme: {
        src: ['less/theme.less'],
        dest: 'dist/css/<%= pkg.name %>-theme.css'
      },
      theme_min: {
        options: {
          compress: true
        },
        src: ['less/theme.less'],
        dest: 'dist/css/<%= pkg.name %>-theme.min.css'
      }
    },

    copy: {
      fonts: {
        expand: true,
        src: ["fonts/*"],
        dest: 'dist/'
      }
    },

    qunit: {
      options: {
        inject: 'js/tests/unit/phantom.js'
      },
      files: ['js/tests/*.html']
    },

    connect: {
      server: {
        options: {
          port: 3000,
          base: '.'
        }
      }
    },

    jekyll: {
      docs: {}
    },

    validation: {
      options: {
        reset: true,
      },
      files: {
        src: ["_gh_pages/**/*.html"]
      }
    },

    watch: {
      src: {
        files: '<%= jshint.src.src %>',
        tasks: ['jshint:src', 'qunit']
      },
      test: {
        files: '<%= jshint.test.src %>',
        tasks: ['jshint:test', 'qunit']
      },
      recess: {
        files: 'less/*.less',
        tasks: ['recess']
      }
    }
  });

  // These plugins provide necessary tasks.
  grunt.loadNpmTasks('grunt-contrib-clean');
  grunt.loadNpmTasks('grunt-contrib-concat');
  grunt.loadNpmTasks('grunt-contrib-connect');
  grunt.loadNpmTasks('grunt-contrib-copy');
  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-contrib-qunit');
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-html-validation');
  grunt.loadNpmTasks('grunt-jekyll');
  grunt.loadNpmTasks('grunt-recess');
  grunt.loadNpmTasks('browserstack-runner');

  // Docs HTML validation task
  grunt.registerTask('validate-html', ['jekyll', 'validation']);

  // Test task.
  var testSubtasks = ['jshint', 'qunit', 'validate-html'];
  // Only run BrowserStack tests under Travis
  if (process.env.TRAVIS) {
    // Only run BrowserStack tests if this is a mainline commit in twbs/bootstrap, or you have your own BrowserStack key
    if ((process.env.TRAVIS_REPO_SLUG === 'twbs/bootstrap' && process.env.TRAVIS_PULL_REQUEST === 'false') || process.env.TWBS_HAVE_OWN_BROWSERSTACK_KEY) {
      testSubtasks.push('browserstack_runner');
    }
  }
  grunt.registerTask('test', testSubtasks);

  // JS distribution task.
  grunt.registerTask('dist-js', ['concat', 'uglify']);

  // CSS distribution task.
  grunt.registerTask('dist-css', ['recess']);

  // Fonts distribution task.
  grunt.registerTask('dist-fonts', ['copy']);

  // Full distribution task.
  grunt.registerTask('dist', ['clean', 'dist-css', 'dist-fonts', 'dist-js']);

  // Default task.
  grunt.registerTask('default', ['test', 'dist', 'build-customizer']);

  // task for building customizer
  grunt.registerTask('build-customizer', 'Add scripts/less files to customizer.', function () {
    var fs = require('fs')

    function getFiles(type) {
      var files = {}
      fs.readdirSync(type)
        .filter(function (path) {
          return new RegExp('\\.' + type + '$').test(path)
        })
        .forEach(function (path) {
          return files[path] = fs.readFileSync(type + '/' + path, 'utf8')
        })
      return 'var __' + type + ' = ' + JSON.stringify(files) + '\n'
    }

    var customize = fs.readFileSync('customize.html', 'utf-8')
    var files = '<!-- generated -->\n<script id="files">\n' + getFiles('js') + getFiles('less') + '<\/script>\n<!-- /generated -->'
    fs.writeFileSync('customize.html', customize.replace(/<!-- generated -->(.|[\n\r])*<!-- \/generated -->/, files))
  });
};
<commit_msg>make Recess part of the Grunt test task to guard against bad LESS<commit_after>/* jshint node: true */

module.exports = function(grunt) {
  "use strict";

  // Project configuration.
  grunt.initConfig({

    // Metadata.
    pkg: grunt.file.readJSON('package.json'),
    banner: '/**\n' +
              '* <%= pkg.name %>.js v<%= pkg.version %> by @fat and @mdo\n' +
              '* Copyright <%= grunt.template.today("yyyy") %> <%= pkg.author %>\n' +
              '* <%= _.pluck(pkg.licenses, "url").join(", ") %>\n' +
              '*/\n',
    jqueryCheck: 'if (!jQuery) { throw new Error(\"Bootstrap requires jQuery\") }\n\n',

    // Task configuration.
    clean: {
      dist: ['dist']
    },

    jshint: {
      options: {
        jshintrc: 'js/.jshintrc'
      },
      gruntfile: {
        src: 'Gruntfile.js'
      },
      src: {
        src: ['js/*.js']
      },
      test: {
        src: ['js/tests/unit/*.js']
      }
    },

    concat: {
      options: {
        banner: '<%= banner %><%= jqueryCheck %>',
        stripBanners: false
      },
      bootstrap: {
        src: [
          'js/transition.js',
          'js/alert.js',
          'js/button.js',
          'js/carousel.js',
          'js/collapse.js',
          'js/dropdown.js',
          'js/modal.js',
          'js/tooltip.js',
          'js/popover.js',
          'js/scrollspy.js',
          'js/tab.js',
          'js/affix.js'
        ],
        dest: 'dist/js/<%= pkg.name %>.js'
      }
    },

    uglify: {
      options: {
        banner: '<%= banner %>'
      },
      bootstrap: {
        src: ['<%= concat.bootstrap.dest %>'],
        dest: 'dist/js/<%= pkg.name %>.min.js'
      }
    },

    recess: {
      options: {
        compile: true
      },
      bootstrap: {
        src: ['less/bootstrap.less'],
        dest: 'dist/css/<%= pkg.name %>.css'
      },
      min: {
        options: {
          compress: true
        },
        src: ['less/bootstrap.less'],
        dest: 'dist/css/<%= pkg.name %>.min.css'
      },
      theme: {
        src: ['less/theme.less'],
        dest: 'dist/css/<%= pkg.name %>-theme.css'
      },
      theme_min: {
        options: {
          compress: true
        },
        src: ['less/theme.less'],
        dest: 'dist/css/<%= pkg.name %>-theme.min.css'
      }
    },

    copy: {
      fonts: {
        expand: true,
        src: ["fonts/*"],
        dest: 'dist/'
      }
    },

    qunit: {
      options: {
        inject: 'js/tests/unit/phantom.js'
      },
      files: ['js/tests/*.html']
    },

    connect: {
      server: {
        options: {
          port: 3000,
          base: '.'
        }
      }
    },

    jekyll: {
      docs: {}
    },

    validation: {
      options: {
        reset: true,
      },
      files: {
        src: ["_gh_pages/**/*.html"]
      }
    },

    watch: {
      src: {
        files: '<%= jshint.src.src %>',
        tasks: ['jshint:src', 'qunit']
      },
      test: {
        files: '<%= jshint.test.src %>',
        tasks: ['jshint:test', 'qunit']
      },
      recess: {
        files: 'less/*.less',
        tasks: ['recess']
      }
    }
  });

  // These plugins provide necessary tasks.
  grunt.loadNpmTasks('grunt-contrib-clean');
  grunt.loadNpmTasks('grunt-contrib-concat');
  grunt.loadNpmTasks('grunt-contrib-connect');
  grunt.loadNpmTasks('grunt-contrib-copy');
  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-contrib-qunit');
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-html-validation');
  grunt.loadNpmTasks('grunt-jekyll');
  grunt.loadNpmTasks('grunt-recess');
  grunt.loadNpmTasks('browserstack-runner');

  // Docs HTML validation task
  grunt.registerTask('validate-html', ['jekyll', 'validation']);

  // Test task.
  var testSubtasks = ['dist-css', 'jshint', 'qunit', 'validate-html'];
  // Only run BrowserStack tests under Travis
  if (process.env.TRAVIS) {
    // Only run BrowserStack tests if this is a mainline commit in twbs/bootstrap, or you have your own BrowserStack key
    if ((process.env.TRAVIS_REPO_SLUG === 'twbs/bootstrap' && process.env.TRAVIS_PULL_REQUEST === 'false') || process.env.TWBS_HAVE_OWN_BROWSERSTACK_KEY) {
      testSubtasks.push('browserstack_runner');
    }
  }
  grunt.registerTask('test', testSubtasks);

  // JS distribution task.
  grunt.registerTask('dist-js', ['concat', 'uglify']);

  // CSS distribution task.
  grunt.registerTask('dist-css', ['recess']);

  // Fonts distribution task.
  grunt.registerTask('dist-fonts', ['copy']);

  // Full distribution task.
  grunt.registerTask('dist', ['clean', 'dist-css', 'dist-fonts', 'dist-js']);

  // Default task.
  grunt.registerTask('default', ['test', 'dist', 'build-customizer']);

  // task for building customizer
  grunt.registerTask('build-customizer', 'Add scripts/less files to customizer.', function () {
    var fs = require('fs')

    function getFiles(type) {
      var files = {}
      fs.readdirSync(type)
        .filter(function (path) {
          return new RegExp('\\.' + type + '$').test(path)
        })
        .forEach(function (path) {
          return files[path] = fs.readFileSync(type + '/' + path, 'utf8')
        })
      return 'var __' + type + ' = ' + JSON.stringify(files) + '\n'
    }

    var customize = fs.readFileSync('customize.html', 'utf-8')
    var files = '<!-- generated -->\n<script id="files">\n' + getFiles('js') + getFiles('less') + '<\/script>\n<!-- /generated -->'
    fs.writeFileSync('customize.html', customize.replace(/<!-- generated -->(.|[\n\r])*<!-- \/generated -->/, files))
  });
};
<|endoftext|>


<commit_before>const
  _URL__GRUNT_CONFIG_FILE = './config/grunt.json',
  _URL__NPM_MANIFEST_FILE = './package.json';

var
  _gruntRegisterTasks = require('grunt-register-tasks'),
  _loadGruntTasks = require('load-grunt-tasks'),
  _timeGrunt = require('time-grunt');

module.exports = function ( $grunt ) {

    var

      _$grunt__file = $grunt.file,
      _$grunt__file__readJSON = _$grunt__file.readJSON,

      _plugins = [
          'grunt-browser-sync',
          'grunt-bump',
          'grunt-contrib-*',
          'grunt-easy-nodefy',
          'grunt-exec',
          'grunt-jsdoc',
          'grunt-jsonlint',
          'grunt-modify-json',
          'grunt-string-replace'
        ],

      _config = {
          'browserSync': {
              'bsFiles': {
                  'src': '<%= cfg.PATH__DOCS %>/<%= cfg.GLOB__ANY_FILE__RECURSIVE %>'
                },
              'options': {
                  'port': 8080,
                  'server': '<%= cfg.PATH__DOCS %>',
                  'watchTask': true
                }
            },
          'bump': {
              'options': {
                  'commit': true,
                  'commitFiles': [
                      '<%= cfg.PATH__ROOT %>/<%= cfg.GLOB__MANIFESTS %>'
                    ],
                  'commitMessage': 'bump(version): %VERSION%',
                  'createTag': false,
                  'files': '<%= cfg.PATH__ROOT %>/<%= cfg.GLOB__MANIFESTS %>',
                  'push': true,
                  'pushTo': 'origin',
                  'updateConfigs': [
                      null,
                      'pkg'
                    ]
                }
            },
          'cfg': _$grunt__file__readJSON( _URL__GRUNT_CONFIG_FILE ),
          'clean': {
              'dist': '<%= cfg.PATH__DIST %>',
              'docs': '<%= cfg.PATH__DOCS %>',
              'fwd': [
                  '<%= cfg.PATH__LANG %>',
                  '<%= cfg.PATH__ROOT %>/<%= cfg.GLOB__LANG_JS %>'
                ]
            },
          'copy': {
              'fwd': {
                  'cwd': '<%= cfg.PATH__FWD %>',
                  'dest': '<%= cfg.PATH__ROOT %>',
                  'expand': true,
                  'src': '<%= cfg.GLOB__JS__RECURSIVE %>'
                },
              'src': {
                  'cwd': '<%= cfg.PATH__SRC %>',
                  'dest': '<%= cfg.PATH__DIST__AMD %>',
                  'expand': true,
                  'src': '<%= cfg.GLOB__JS__RECURSIVE %>'
                }
            },
          'exec': {
              'commit': 'git commit -m "release(v<%= pkg.version %>): distribute"',
              'tag': 'git tag -a v<%= pkg.version %> -m "<%= grunt.option(\'tagMessage\') %>"'
            },
          'jasmine': {
              'src': {
                  'options': {
                      'helpers': '<%= cfg.PATH__TESTS__HELPERS %>/<%= cfg.GLOB__JS__RECURSIVE %>',
                      'outfile': '<%= cfg.PATH__TESTS %>/<%= cfg.GLOB__RUNNER_TEMP_HTML %>',
                      'specs': '<%= cfg.PATH__TESTS__SPECS %>/<%= cfg.GLOB__JS__RECURSIVE %>',
                      'template': require('grunt-template-jasmine-requirejs')
                    }
                }
            },
          'jsdoc': {
              'src': {
                  'dest': '<%= cfg.PATH__DOCS %>',
                  'src': '<%= cfg.PATH__SRC %>/<%= cfg.GLOB__JS__RECURSIVE %>'
                }
            },
          'jshint': {
              'options': {
                  'jshintrc': true
                },
              'fwd': '<%= cfg.PATH__FWD %>/<%= cfg.GLOB__JS__RECURSIVE %>',
              'src': '<%= cfg.PATH__SRC %>/<%= cfg.GLOB__JS__RECURSIVE %>',
              'tests': '<%= cfg.PATH__TESTS %>/<%= cfg.GLOB__JS__RECURSIVE %>'
            },
          'jsonlint': {
              'config': [
                  '<%= cfg.PATH__CONFIG %>/<%= cfg.GLOB__JSON__RECURSIVE %>',
                  '<%= cfg.PATH__ROOT %>/<%= cfg.GLOB__JSHINTRC %>'
                ],
              'manifests': '<%= cfg.PATH__ROOT %>/<%= cfg.GLOB__MANIFESTS %>'
            },
          'modify_json': {
              'manifests': {
                  'files': {
                      '<%= cfg.PATH__ROOT %>': '<%= cfg.PATH__ROOT %>/<%= cfg.GLOB__MANIFESTS %>'
                    },
                  'options': {
                      'add': true,
                      'fields': {
                          'private': false
                        }
                    }
                }
            },
          'nodefy': {
              'src': {
                  'cwd': '<%= cfg.PATH__SRC %>',
                  'dest': '<%= cfg.PATH__DIST__CJS %>',
                  'expand': true,
                  'src': '<%= cfg.GLOB__JS__RECURSIVE %>'
                }
            },
          'pkg': _$grunt__file__readJSON( _URL__NPM_MANIFEST_FILE ),
          'string-replace': {
              'src': {
                  'files': [
                      {
                        'cwd': '<%= cfg.PATH__DIST %>',
                        'dest': '<%= cfg.PATH__DIST %>',
                        'expand': true,
                        'src': '<%= cfg.GLOB__INDEX_JS__RECURSIVE %>'
                      }
                    ],
                  'options': {
                      'replacements': [
                          {
                            'pattern': /<%= pkg\.version %>/g,
                            'replacement': '<%= pkg.version %>'
                          }
                        ]
                    }
                }
            },
          'watch': {
              'docs': {
                  'files': '<%= cfg.PATH__DOCS %>/<%= cfg.GLOB__ANY_FILE__RECURSIVE %>'
                },
              'src': {
                  'files': '<%= cfg.PATH__SRC %>/<%= cfg.GLOB__JS__RECURSIVE %>',
                  'tasks': [
                      'jsdoc'
                    ]
                }
            }
        },

      _tasks = {
          'build': [
              'default',
              'clean',
              'copy',
              'nodefy',
              'string-replace'
            ],
          'default': [
              'jsonlint',
              'jshint'
            ],
          'serve': [
              'jsdoc',
              'browserSync',
              'watch'
            ],
          'test': [
              'default',
              'jasmine'
            ]
        };

    _timeGrunt( $grunt ),

    $grunt.initConfig( _config ),

    _loadGruntTasks(
      $grunt,
      {
        pattern: _plugins,
        scope: 'devDependencies'
      }
    ),

    _gruntRegisterTasks(
      $grunt,
      _tasks
    );

  };<commit_msg>chore(grunt): improve build task<commit_after>const
  _URL__GRUNT_CONFIG_FILE = './config/grunt.json',
  _URL__NPM_MANIFEST_FILE = './package.json';

var
  _gruntRegisterTasks = require('grunt-register-tasks'),
  _loadGruntTasks = require('load-grunt-tasks'),
  _timeGrunt = require('time-grunt');

module.exports = function ( $grunt ) {

    var

      _$grunt__file = $grunt.file,
      _$grunt__file__readJSON = _$grunt__file.readJSON,

      _plugins = [
          'grunt-browser-sync',
          'grunt-bump',
          'grunt-contrib-*',
          'grunt-easy-nodefy',
          'grunt-exec',
          'grunt-jsdoc',
          'grunt-jsonlint',
          'grunt-modify-json',
          'grunt-string-replace'
        ],

      _config = {
          'browserSync': {
              'bsFiles': {
                  'src': '<%= cfg.PATH__DOCS %>/<%= cfg.GLOB__ANY_FILE__RECURSIVE %>'
                },
              'options': {
                  'port': 8080,
                  'server': '<%= cfg.PATH__DOCS %>',
                  'watchTask': true
                }
            },
          'bump': {
              'options': {
                  'commit': true,
                  'commitFiles': [
                      '<%= cfg.PATH__ROOT %>/<%= cfg.GLOB__MANIFESTS %>'
                    ],
                  'commitMessage': 'bump(version): %VERSION%',
                  'createTag': false,
                  'files': '<%= cfg.PATH__ROOT %>/<%= cfg.GLOB__MANIFESTS %>',
                  'push': true,
                  'pushTo': 'origin',
                  'updateConfigs': [
                      null,
                      'pkg'
                    ]
                }
            },
          'cfg': _$grunt__file__readJSON( _URL__GRUNT_CONFIG_FILE ),
          'clean': {
              'dist': '<%= cfg.PATH__DIST %>',
              'docs': '<%= cfg.PATH__DOCS %>',
              'fwd': [
                  '<%= cfg.PATH__LANG %>',
                  '<%= cfg.PATH__ROOT %>/<%= cfg.GLOB__LANG_JS %>'
                ],
              'tests': '<%= cfg.PATH__TESTS %>/<%= cfg.GLOB__RUNNER_TEMP_HTML %>'
            },
          'copy': {
              'fwd': {
                  'cwd': '<%= cfg.PATH__FWD %>',
                  'dest': '<%= cfg.PATH__ROOT %>',
                  'expand': true,
                  'src': '<%= cfg.GLOB__JS__RECURSIVE %>'
                },
              'src': {
                  'cwd': '<%= cfg.PATH__SRC %>',
                  'dest': '<%= cfg.PATH__DIST__AMD %>',
                  'expand': true,
                  'src': '<%= cfg.GLOB__JS__RECURSIVE %>'
                }
            },
          'exec': {
              'commit': 'git commit -m "release(v<%= pkg.version %>): distribute"',
              'tag': 'git tag -a v<%= pkg.version %> -m "<%= grunt.option(\'tagMessage\') %>"'
            },
          'jasmine': {
              'src': {
                  'options': {
                      'helpers': '<%= cfg.PATH__TESTS__HELPERS %>/<%= cfg.GLOB__JS__RECURSIVE %>',
                      'outfile': '<%= cfg.PATH__TESTS %>/<%= cfg.GLOB__RUNNER_TEMP_HTML %>',
                      'specs': '<%= cfg.PATH__TESTS__SPECS %>/<%= cfg.GLOB__JS__RECURSIVE %>',
                      'template': require('grunt-template-jasmine-requirejs')
                    }
                }
            },
          'jsdoc': {
              'src': {
                  'dest': '<%= cfg.PATH__DOCS %>',
                  'src': '<%= cfg.PATH__SRC %>/<%= cfg.GLOB__JS__RECURSIVE %>'
                }
            },
          'jshint': {
              'options': {
                  'jshintrc': true
                },
              'fwd': '<%= cfg.PATH__FWD %>/<%= cfg.GLOB__JS__RECURSIVE %>',
              'src': '<%= cfg.PATH__SRC %>/<%= cfg.GLOB__JS__RECURSIVE %>',
              'tests': '<%= cfg.PATH__TESTS %>/<%= cfg.GLOB__JS__RECURSIVE %>'
            },
          'jsonlint': {
              'config': [
                  '<%= cfg.PATH__CONFIG %>/<%= cfg.GLOB__JSON__RECURSIVE %>',
                  '<%= cfg.PATH__ROOT %>/<%= cfg.GLOB__JSHINTRC %>'
                ],
              'manifests': '<%= cfg.PATH__ROOT %>/<%= cfg.GLOB__MANIFESTS %>'
            },
          'modify_json': {
              'manifests': {
                  'files': {
                      '<%= cfg.PATH__ROOT %>': '<%= cfg.PATH__ROOT %>/<%= cfg.GLOB__MANIFESTS %>'
                    },
                  'options': {
                      'add': true,
                      'fields': {
                          'private': false
                        }
                    }
                }
            },
          'nodefy': {
              'src': {
                  'cwd': '<%= cfg.PATH__DIST__AMD %>',
                  'dest': '<%= cfg.PATH__DIST__CJS %>',
                  'expand': true,
                  'src': '<%= cfg.GLOB__JS__RECURSIVE %>'
                }
            },
          'pkg': _$grunt__file__readJSON( _URL__NPM_MANIFEST_FILE ),
          'string-replace': {
              'src': {
                  'files': [
                      {
                        'cwd': '<%= cfg.PATH__DIST %>',
                        'dest': '<%= cfg.PATH__DIST %>',
                        'expand': true,
                        'src': '<%= cfg.GLOB__INDEX_JS__RECURSIVE %>'
                      }
                    ],
                  'options': {
                      'replacements': [
                          {
                            'pattern': /<%= pkg\.version %>/g,
                            'replacement': '<%= pkg.version %>'
                          }
                        ]
                    }
                }
            },
          'watch': {
              'docs': {
                  'files': '<%= cfg.PATH__DOCS %>/<%= cfg.GLOB__ANY_FILE__RECURSIVE %>'
                },
              'src': {
                  'files': '<%= cfg.PATH__SRC %>/<%= cfg.GLOB__JS__RECURSIVE %>',
                  'tasks': [
                      'jsdoc'
                    ]
                }
            }
        },

      _tasks = {
          'build': [
              'clean',
              'copy',
              'nodefy',
              'string-replace'
            ],
          'default': [
              'jsonlint',
              'jshint'
            ],
          'serve': [
              'jsdoc',
              'browserSync',
              'watch'
            ],
          'test': [
              'default',
              'jasmine'
            ]
        };

    _timeGrunt( $grunt ),

    $grunt.initConfig( _config ),

    _loadGruntTasks(
      $grunt,
      {
        pattern: _plugins,
        scope: 'devDependencies'
      }
    ),

    _gruntRegisterTasks(
      $grunt,
      _tasks
    );

  };<|endoftext|>