<commit_before>/** @license MIT License (c) copyright 2010-2013 original author or authors */

/**
 * Licensed under the MIT License at:
 * http://www.opensource.org/licenses/mit-license.php
 *
 * @author: Brian Cavalier
 * @author: John Hann
 */

(function(define) { 'use strict';
define(function() {

	var when, slice;

	when = require('./when');
	slice = Array.prototype.slice;

	return {
		apply: apply,
		call: call,
		lift: lift
	};

	function lift(generator) {
		return function() {
			return apply(generator, arguments);
		}
	}

	function call(generator) {
		return apply(generator, slice.call(arguments, 1));
	}

	function apply(generator, args) {
		var iterator = generator.apply(this, args);

		return next();

		function next(x) {
			return step('next', x);
		}

		function fail(e) {
			return step('throw', e);
		}

		function step(action, x) {
			var result;

			try {
				result = iterator[action](x);
			} catch (e) {
				return when.reject(e);
			}

			return result.done ? result.value : when(result.value, next, fail);
		}
	}
});
}(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(); }));
<commit_msg>Fix jshint warnings<commit_after>/** @license MIT License (c) copyright 2010-2013 original author or authors */

/**
 * Licensed under the MIT License at:
 * http://www.opensource.org/licenses/mit-license.php
 *
 * @author: Brian Cavalier
 * @author: John Hann
 */

(function(define) { 'use strict';
define(function(require) {

	var when, slice;

	when = require('./when');
	slice = Array.prototype.slice;

	return {
		apply: apply,
		call: call,
		lift: lift
	};

	function lift(generator) {
		return function() {
			return apply(generator, arguments);
		};
	}

	function call(generator) {
		return apply(generator, slice.call(arguments, 1));
	}

	function apply(generator, args) {
		/*jshint validthis:true*/
		var iterator = generator.apply(this, args);

		return next();

		function next(x) {
			return step('next', x);
		}

		function fail(e) {
			return step('throw', e);
		}

		function step(action, x) {
			var result;

			try {
				result = iterator[action](x);
			} catch (e) {
				return when.reject(e);
			}

			return result.done ? result.value : when(result.value, next, fail);
		}
	}
});
}(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); }));
<|endoftext|>


<commit_before>'use strict';

const ConsoleList = require(Editor.url('packages://console/panel/list'));
const Manager = require(Editor.url('packages://console/panel/manager'));

Editor.Panel.extend({

    style: `
        @import url('app://bower_components/fontawesome/css/font-awesome.min.css');
        #console {
            display: flex;
            flex-direction: column;
        }
        header {
            display: flex;
            padding: 4px;
            position: relative;
        }
        section {
            flex: 1;
            border: 1px solid black;
            box-shadow: inset 0 0 8px 2px rgba(0,0,0,0.2);
            background: #333;
        }

        ui-checkbox {
            padding: 3px 4px;
        }
        .collapse {
            position: absolute;
            right: 0;
        }

        section {
            overflow-y: scroll;
            position: relative;
        }
        section .item {
            color: #999;
            line-height: 30px;
            padding: 0 10px;
            box-sizing: border-box;
            position: absolute;
            top: 0;
            font-size: 14px;
            width: 100%;
            -webkit-user-select: initial;
            overflow-x: scroll;
        }
        section .item[fold] {
            overflow-x: hidden;
        }
        section .item[texture=light] {
            background-color:#292929;
        }
        section .item[texture=dark] {
            background-color:#222;
        }
        section .item[type=log] {
            color: #999;
        }
        section .item[type=error] {
            color: #DA2121;
        }
        section .item[type=warn] {
            color: #990;
        }
        section .item[type=info] {
            color: #090;
        }
        section .item[type=failed] {
            color: #DA2121;
        }
        section .item[type=success] {
            color: #090;
        }
        section .item i {
            padding: 0 4px;
        }
        section .item i.fold {
            color: #555;
            cursor: pointer;
            padding: 0;
        }
        section .item i.fa-caret-right {
            padding: 0 1px;
        }

        section div .warp {
            display: flex;
        }
        section div .text {
            position: relative;
            flex: 1;
            white-space: nowrap;
            text-overflow: ellipsis;
            padding-right: 2px;
        }
        section div[fold] .text {
            overflow: hidden;
        }
        section div .info {
            margin-left: 45px;
        }
        section div[fold] .info > div {
            display: none;
        }
        section div .info div {
            white-space: nowrap;
            text-overflow: ellipsis;
            line-height: 26px;
            font-size: 13px;
        }
        section div[fold] .info div {
            overflow: hidden;
        }
        section .item[type=error] .info div {
            color: #A73637;
        }
    `,

    template: `

            <ui-button class="red small transparent" v-on:confirm="onClear">

            </ui-button>
            <ui-button id="openLogBtn" class="small transparent" v-on:click="onPopup">

            </ui-button>
            <ui-input v-on:change="onFilterText"></ui-input>
            <ui-checkbox v-on:confirm="onFilterRegex">Regex</ui-checkbox>
            <ui-select v-on:confirm="onFilterType">
                <option value="">All</option>
                <option value="log">Log</option>
                <option value="success">Success</option>
                <option value="failed">Failed</option>
                <option value="info">Info</option>
                <option value="warn">Warn</option>
                <option value="error">Error</option>
            </ui-select>
            <ui-checkbox class="collapse" v-on:confirm="onCollapse" checked>Collapse</ui-checkbox>

        <console-list v-bind:messages="messages"></console-list>

    `,

    $: {
        console: '#console',
        openLogBtn: '#openLogBtn'
    },

    listeners: {
        'panel-resize' () {
            Manager.update();
        },
        'panel-show' () {
            Manager.update();
        }
    },

    messages: {
        'editor:console-log' (event, message) {
            Manager.addItem({ type: 'log', message: message });
        },

        'editor:console-success' (event, message) {
            Manager.addItem({ type: 'success', message: message });
        },

        'editor:console-failed' (event, message) {
            Manager.addItem({ type: 'failed', message: message });
        },

        'editor:console-info' (event, message) {
            Manager.addItem({ type: 'info', message: message });
        },

        'editor:console-warn' (event, message) {
            Manager.addItem({ type: 'warn', message: message });
        },

        'editor:console-error' (event, message) {
            Manager.addItem({ type: 'error', message: message });
        },

        'editor:console-clear' (event, pattern, useRegex) {
            if (!pattern) {
                return Manager.clear();
            }

            let filter;
            if ( useRegex ) {
                try {
                    filter = new RegExp(pattern);
                } catch ( err ) {
                    filter = new RegExp('');
                }
            } else {
                filter = pattern;
            }

            for (let i = Manager.list.length - 1; i >= 0; i--) {
                let log = Manager.list[i];

                if (useRegex) {
                    if ( filter.exec(log.title) ) {
                        Manager.list.splice(i, 1);
                    }
                }
                else {
                    if ( log.title.indexOf(filter) !== -1 ) {
                        Manager.list.splice(i, 1);
                    }
                }
            }

            Manager.update();

        },

        'console:query-last-error-log' (event) {
            if (!event.reply) {
                return;
            }

            var list = Manager.list;
            var index = list.length - 1;
            while (index >= 0) {
                let item = list[index--];
                if (item.type === 'error' || item.type === 'failed' || item.type === 'warn') {
                    return  event.reply(null, item);
                }
            }

            event.reply(null, undefined);
        }
    },

    ready () {
        var openLogBtn = this.$openLogBtn;
        this._vm = new Vue({
            el: this.$console,
            data: {
                messages: []
            },
            methods: {
                onClear () {
                    Manager.clear();
                    Editor.Ipc.sendToMain('console:clear');
                },
                onPopup () {
                    let rect = openLogBtn.getBoundingClientRect();
                    Editor.Ipc.sendToPackage('console', 'popup-open-log-menu', rect.left, rect.bottom + 5 );
                },
                onFilterType (event) {
                    Manager.setFilterType(event.target.value);
                },
                onCollapse (event) {
                    Manager.setCollapse(event.target.checked);
                },
                onFilterRegex (event) {
                    Manager.setFilterRegex(event.target.value);
                },
                onFilterText (event) {
                    Manager.setFilterText(event.target.value);
                }
            },
            components: {
                'console-list': ConsoleList
            }
        });

        // 将显示的数组设置进Manager
        // manager可以直接修改这个数组，更新数据
        Manager.setRenderCmds(this._vm.messages);

        Editor.Ipc.sendToMain( 'editor:console-query', (err,results) => {
            Manager.addItems(results);
        });
    },

    clear () {
        Manager.clear();
        Editor.Ipc.sendToMain('console:clear');
    }

});
<commit_msg>Detail adjustment<commit_after>'use strict';

const ConsoleList = require(Editor.url('packages://console/panel/list'));
const Manager = require(Editor.url('packages://console/panel/manager'));

Editor.Panel.extend({

    style: `
        @import url('app://bower_components/fontawesome/css/font-awesome.min.css');
        #console {
            display: flex;
            flex-direction: column;
        }
        header {
            display: flex;
            padding: 4px;
            position: relative;
        }
        section {
            flex: 1;
            border: 1px solid black;
            box-shadow: inset 0 0 8px 2px rgba(0,0,0,0.2);
            background: #333;
        }

        ui-checkbox {
            padding: 3px 4px;
        }
        .collapse {
            position: absolute;
            right: 0;
        }

        section {
            overflow-y: scroll;
            position: relative;
        }
        section .item {
            color: #999;
            line-height: 30px;
            padding: 0 10px;
            box-sizing: border-box;
            position: absolute;
            top: 0;
            font-size: 14px;
            width: 100%;
            -webkit-user-select: initial;
            overflow-x: scroll;
        }
        section .item[fold] {
            overflow-x: hidden;
        }
        section .item[texture=light] {
            background-color:#292929;
        }
        section .item[texture=dark] {
            background-color:#222;
        }
        section .item[type=log] {
            color: #999;
        }
        section .item[type=error] {
            color: #DA2121;
        }
        section .item[type=warn] {
            color: #990;
        }
        section .item[type=info] {
            color: #090;
        }
        section .item[type=failed] {
            color: #DA2121;
        }
        section .item[type=success] {
            color: #090;
        }
        section .item i {
        }
        section .item i.fold {
            color: #555;
            cursor: pointer;
            padding: 2px;
        }
        section .item i.fa-caret-right {
            padding: 2px 5px 2px 6px;
            margin: 0 -2px;
        }

        section div .warp {
            display: flex;
        }
        section div .text {
            position: relative;
            flex: 1;
            white-space: nowrap;
            text-overflow: ellipsis;
            padding-right: 2px;
        }
        section div[fold] .text {
            overflow: hidden;
        }
        section div .info {
            margin-left: 45px;
        }
        section div[fold] .info > div {
            display: none;
        }
        section div .info div {
            white-space: nowrap;
            text-overflow: ellipsis;
            line-height: 26px;
            font-size: 13px;
        }
        section div[fold] .info div {
            overflow: hidden;
        }
        section .item[type=error] .info div {
            color: #A73637;
        }
    `,

    template: `

            <ui-button class="red small transparent" v-on:confirm="onClear">

            </ui-button>
            <ui-button id="openLogBtn" class="small transparent" v-on:click="onPopup">

            </ui-button>
            <ui-input v-on:change="onFilterText"></ui-input>
            <ui-checkbox v-on:confirm="onFilterRegex">Regex</ui-checkbox>
            <ui-select v-on:confirm="onFilterType">
                <option value="">All</option>
                <option value="log">Log</option>
                <option value="success">Success</option>
                <option value="failed">Failed</option>
                <option value="info">Info</option>
                <option value="warn">Warn</option>
                <option value="error">Error</option>
            </ui-select>
            <ui-checkbox class="collapse" v-on:confirm="onCollapse" checked>Collapse</ui-checkbox>

        <console-list v-bind:messages="messages"></console-list>

    `,

    $: {
        console: '#console',
        openLogBtn: '#openLogBtn'
    },

    listeners: {
        'panel-resize' () {
            Manager.update();
        },
        'panel-show' () {
            Manager.update();
        }
    },

    messages: {
        'editor:console-log' (event, message) {
            Manager.addItem({ type: 'log', message: message });
        },

        'editor:console-success' (event, message) {
            Manager.addItem({ type: 'success', message: message });
        },

        'editor:console-failed' (event, message) {
            Manager.addItem({ type: 'failed', message: message });
        },

        'editor:console-info' (event, message) {
            Manager.addItem({ type: 'info', message: message });
        },

        'editor:console-warn' (event, message) {
            Manager.addItem({ type: 'warn', message: message });
        },

        'editor:console-error' (event, message) {
            Manager.addItem({ type: 'error', message: message });
        },

        'editor:console-clear' (event, pattern, useRegex) {
            if (!pattern) {
                return Manager.clear();
            }

            let filter;
            if ( useRegex ) {
                try {
                    filter = new RegExp(pattern);
                } catch ( err ) {
                    filter = new RegExp('');
                }
            } else {
                filter = pattern;
            }

            for (let i = Manager.list.length - 1; i >= 0; i--) {
                let log = Manager.list[i];

                if (useRegex) {
                    if ( filter.exec(log.title) ) {
                        Manager.list.splice(i, 1);
                    }
                }
                else {
                    if ( log.title.indexOf(filter) !== -1 ) {
                        Manager.list.splice(i, 1);
                    }
                }
            }

            Manager.update();

        },

        'console:query-last-error-log' (event) {
            if (!event.reply) {
                return;
            }

            var list = Manager.list;
            var index = list.length - 1;
            while (index >= 0) {
                let item = list[index--];
                if (item.type === 'error' || item.type === 'failed' || item.type === 'warn') {
                    return  event.reply(null, item);
                }
            }

            event.reply(null, undefined);
        }
    },

    ready () {
        var openLogBtn = this.$openLogBtn;
        this._vm = new Vue({
            el: this.$console,
            data: {
                messages: []
            },
            methods: {
                onClear () {
                    Manager.clear();
                    Editor.Ipc.sendToMain('console:clear');
                },
                onPopup () {
                    let rect = openLogBtn.getBoundingClientRect();
                    Editor.Ipc.sendToPackage('console', 'popup-open-log-menu', rect.left, rect.bottom + 5 );
                },
                onFilterType (event) {
                    Manager.setFilterType(event.target.value);
                },
                onCollapse (event) {
                    Manager.setCollapse(event.target.checked);
                },
                onFilterRegex (event) {
                    Manager.setFilterRegex(event.target.value);
                },
                onFilterText (event) {
                    Manager.setFilterText(event.target.value);
                }
            },
            components: {
                'console-list': ConsoleList
            }
        });

        // 将显示的数组设置进Manager
        // manager可以直接修改这个数组，更新数据
        Manager.setRenderCmds(this._vm.messages);

        Editor.Ipc.sendToMain( 'editor:console-query', (err,results) => {
            Manager.addItems(results);
        });
    },

    clear () {
        Manager.clear();
        Editor.Ipc.sendToMain('console:clear');
    }

});
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2018 Google Inc. All rights reserved.
 *
 * 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.
 */

'use strict';

var testVersion = 'Test-In-Progress';
<commit_msg>- change yts tip branch into 2021<commit_after>/**
 * @license
 * Copyright 2018 Google Inc. All rights reserved.
 *
 * 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.
 */

'use strict';

var testVersion = '2021';
<|endoftext|>


<commit_before>/*
 * get-tweet.js v0.1 by Jimmy King
 * Licensed under The MIT License
 * Issues and feature requests at:
 * https://github.com/jking90/get-tweet
 */

function GetTweet(usrOpts) {
  if (this instanceof GetTweet === false) {
    return new GetTweet(usrOpts);
  }

  this.initVars(usrOpts);
  this.createProcess();
  this.injectScript();
}

GetTweet.noInstances = 0;
GetTweet.instances = {};

// Parse tweets from widget
GetTweet.process = function (data, instance) {
  var fakeAPI = document.createElement('div');
  instance.tweets = [];

  fakeAPI.innerHTML = data.body;

  for (var i = 0; i < instance.options.howMany; i++) {

    var thisTweet = fakeAPI.getElementsByClassName('tweet')[i],
        tweetContent = thisTweet.getElementsByClassName('e-entry-title')[0],
        userInfo = thisTweet.getElementsByClassName('u-url profile')[0];

    var thisTweetObj = {
      html: tweetContent.innerHTML, // HTML from the tweet
      isRT: !!thisTweet.getElementsByClassName('retweet-credit').length, // Boolean indicates whether this is a retweet
      link: thisTweet.getElementsByClassName('permalink')[0].href, // Permalink to tweet
      name: userInfo.getElementsByClassName('full-name')[0].innerText.replace(/^\s+|\s+$/g, ''), // Full name of user
      pic:  userInfo.getElementsByTagName('img')[0].src, // URL for user's profile picture
      text: tweetContent.innerText, // Text from tweet (no links)
      time: Date.parse(thisTweet.getElementsByClassName('permalink')[0].dataset.datetime), // Number of milliseconds since January 1, 1970, 00:00:00 UTC
      user: userInfo.getElementsByClassName('p-nickname')[0].innerText // User's screen name
    };

    instance.tweets.push(thisTweetObj);
  }

  instance.hereYouGo();
};

GetTweet.prototype.initVars = function (usrOpts) {
  var defaults = {
    callbackFn: null,
    howMany: 1,
    widget: null
  };

  this.options = {};

  for (var key in defaults) {
    if (usrOpts.hasOwnProperty(key)) {
      this.options[key] = usrOpts[key];
    } else {
      this.options[key] = defaults[key];
    }
  }

  // Test arguments
  if (typeof this.options.callbackFn !== 'function') {
    console.log('%cYour callback must be a function', 'color: red;');
    return;
  }

  if ((typeof this.options.howMany !== 'number') ||
      (this.options.howMany < 2) || (this.options.howMany > 20)) {
    this.options.howMany = defaults.howMany;
  }

  if (typeof this.options.widget !== 'string') {
    console.log('%cThe widget ID number must be passed as a string.', 'color: red;');
    return;
  }
};

// Create callback for Twitter
GetTweet.prototype.createProcess = function () {
  this.id = 'id_' + GetTweet.noInstances++;
  var self = this;
  GetTweet.instances[this.id] = function (data) {
    GetTweet.process(data, self);
  };
};

// Fetch the timeline from the Twitter widget
GetTweet.prototype.injectScript = function () {
  var script = document.createElement('script');
  script.src = 'http://cdn.syndication.twimg.com/widgets/timelines/' + this.options.widget + '?&lang=en&callback=GetTweet.instances.' + this.id + '&suppress_response_codes=true&rnd=' + Math.random();
  document.getElementsByTagName('head')[0].appendChild(script);

  this.scriptElem = script;
};

// Deliver tweets & trigger callback
GetTweet.prototype.hereYouGo = function () {
  this.tweet = this.tweets[0];
  this.options.callbackFn(this);
};
<commit_msg>JSHint error fixes<commit_after>/*
 * get-tweet.js v0.1 by Jimmy King
 * Licensed under The MIT License
 * Issues and feature requests at:
 * https://github.com/jking90/get-tweet
 */

function GetTweet(usrOpts) {
  if (this instanceof GetTweet === false) {
    return new GetTweet(usrOpts);
  }

  this.initVars(usrOpts);
  this.createProcess();
  this.injectScript();
}

GetTweet.noInstances = 0;
GetTweet.instances = {};

// Parse tweets from widget
GetTweet.process = function (data, instance) {
  var fakeAPI = document.createElement('div');
  instance.tweets = [];

  fakeAPI.innerHTML = data.body;

  for (var i = 0; i < instance.options.howMany; i++) {

    var thisTweet = fakeAPI.getElementsByClassName('tweet')[i],
        tweetContent = thisTweet.getElementsByClassName('e-entry-title')[0],
        userInfo = thisTweet.getElementsByClassName('u-url profile')[0];

    var thisTweetObj = {
      html: tweetContent.innerHTML,
            // HTML from the tweet
      isRT: !!thisTweet.getElementsByClassName('retweet-credit').length,
            // Boolean indicates whether this is a retweet
      link: thisTweet.getElementsByClassName('permalink')[0].href,
            // Permalink to tweet
      name: userInfo.getElementsByClassName('full-name')[0].innerText.replace(/^\s+|\s+$/g, ''),
            // Full name of user
      pic:  userInfo.getElementsByTagName('img')[0].src,
            // URL for user's profile picture
      text: tweetContent.innerText,
            // Text from tweet (no links)
      time: Date.parse(thisTweet.getElementsByClassName('permalink')[0].dataset.datetime),
            // Number of milliseconds since January 1, 1970, 00:00:00 UTC
      user: userInfo.getElementsByClassName('p-nickname')[0].innerText
            // User's screen name
    };

    instance.tweets.push(thisTweetObj);
  }

  instance.hereYouGo();
};

GetTweet.prototype.initVars = function (usrOpts) {
  var defaults = {
    callbackFn: null,
    howMany: 1,
    widget: null
  };

  this.options = {};

  for (var key in defaults) {
    if (usrOpts.hasOwnProperty(key)) {
      this.options[key] = usrOpts[key];
    } else {
      this.options[key] = defaults[key];
    }
  }

  // Test arguments
  if (typeof this.options.callbackFn !== 'function') {
    console.log('%cYour callback must be a function', 'color: red;');
    return;
  }

  if ((typeof this.options.howMany !== 'number') ||
      (this.options.howMany < 2) || (this.options.howMany > 20)) {
    this.options.howMany = defaults.howMany;
  }

  if (typeof this.options.widget !== 'string') {
    console.log('%cThe widget ID number must be passed as a string.', 'color: red;');
    return;
  }
};

// Create callback for Twitter
GetTweet.prototype.createProcess = function () {
  this.id = 'id_' + GetTweet.noInstances++;
  var self = this;
  GetTweet.instances[this.id] = function (data) {
    GetTweet.process(data, self);
  };
};

// Fetch the timeline from the Twitter widget
GetTweet.prototype.injectScript = function () {
  var script = document.createElement('script');
  script.src = 'http://cdn.syndication.twimg.com/widgets/timelines/' + this.options.widget + '?&lang=en&callback=GetTweet.instances.' + this.id + '&suppress_response_codes=true&rnd=' + Math.random();
  document.getElementsByTagName('head')[0].appendChild(script);

  this.scriptElem = script;
};

// Deliver tweets & trigger callback
GetTweet.prototype.hereYouGo = function () {
  this.tweet = this.tweets[0];
  this.options.callbackFn(this);
};
<|endoftext|>


<commit_before>(function() {
  var φ = 1.618033988749895,
      ρ = 180 / Math.PI;

  var vertices = [
    [1,φ,0], [-1,φ,0], [1,-φ,0], [-1,-φ,0],
    [0,1,φ], [0,-1,φ], [0,1,-φ], [0,-1,-φ],
    [φ,0,1], [-φ,0,1], [φ,0,-1], [-φ,0,-1]
  ];

  var triangles = [
    [0,1,4],  [1,9,4],  [4,9,5],  [5,9,3],  [2,3,7],
    [3,2,5],  [7,10,2], [0,8,10], [0,4,8],  [8,2,10],
    [8,4,5],  [8,5,2],  [1,0,6],  [11,1,6], [3,9,11],
    [6,10,7], [3,11,7], [11,6,7], [6,0,10], [9,1,11]
  ].map(function(triangle) {
    return triangle.map(function(i) {
      return vertices[i];
    });
  });

  d3.geodesic = function(s) {
    return {
      type: "MultiPolygon",
      coordinates: geodesic(Math.round(s)).map(function(triangle) {
        triangle = triangle.map(project);
        triangle.push(triangle[2]);
        return [triangle];
      })
    };
  };

  function geodesic(n) {
    return d3.merge(triangles.map(function(triangle) {
      var i01 = interpolate(triangle[0], triangle[1]),
          i02 = interpolate(triangle[0], triangle[2]),
          triangles = [];

      triangles.push([
        triangle[0],
        i01(1 / n),
        i02(1 / n)
      ]);

      for (var i = 1; i < n; ++i) {
        var i1 = interpolate(i01(i / n), i02(i / n)),
            i2 = interpolate(i01((i + 1) / n), i02((i + 1) / n));
        for (var j = 0; j <= i; ++j) {
          triangles.push([
            i1(j / i),
            i2(j / (i + 1)),
            i2((j + 1) / (i + 1))
          ]);
        }
      }

      return triangles;
    }));
  }

  function interpolate(p0, p1) {
    var x0 = p0[0],
        y0 = p0[1],
        z0 = p0[2],
        x1 = p1[0] - x0,
        y1 = p1[1] - y0,
        z1 = p1[2] - z0;
    return function(t) {
      return [
        x0 + t * x1,
        y0 + t * y1,
        z0 + t * z1
      ];
    };
  }

  function project(p) {
    var x = p[0],
        y = p[1],
        z = p[2];
    return [
      Math.atan2(y, x) * ρ,
      Math.acos(z / Math.sqrt(x * x + y * y + z * z)) * ρ - 90
    ];
  }
})();
<commit_msg>Add d3.geodesic.polygons method.<commit_after>(function() {
  var φ = 1.618033988749895,
      ρ = 180 / Math.PI;

  var vertices = [
    [1,φ,0], [-1,φ,0], [1,-φ,0], [-1,-φ,0],
    [0,1,φ], [0,-1,φ], [0,1,-φ], [0,-1,-φ],
    [φ,0,1], [-φ,0,1], [φ,0,-1], [-φ,0,-1]
  ];

  var triangles = [
    [0,1,4],  [1,9,4],  [4,9,5],  [5,9,3],  [2,3,7],
    [3,2,5],  [7,10,2], [0,8,10], [0,4,8],  [8,2,10],
    [8,4,5],  [8,5,2],  [1,0,6],  [11,1,6], [3,9,11],
    [6,10,7], [3,11,7], [11,6,7], [6,0,10], [9,1,11]
  ].map(function(triangle) {
    return triangle.map(function(i) {
      return vertices[i];
    });
  });

  d3.geodesic = {
    multipolygon: function(n) {
      return {
        type: "MultiPolygon",
        coordinates: geodesic(~~n).map(function(triangle) {
          triangle = triangle.map(project);
          triangle.push(triangle[2]);
          return [triangle];
        })
      };
    },
    polygons: function(n) {
      return geodesic(~~n).map(function(triangle) {
        triangle = triangle.map(project);
        triangle.push(triangle[2]);
        return {type: "Polygon", coordinates: [triangle]};
      });
    }
  };

  function geodesic(n) {
    return d3.merge(triangles.map(function(triangle) {
      var i01 = interpolate(triangle[0], triangle[1]),
          i02 = interpolate(triangle[0], triangle[2]),
          triangles = [];

      triangles.push([
        triangle[0],
        i01(1 / n),
        i02(1 / n)
      ]);

      for (var i = 1; i < n; ++i) {
        var i1 = interpolate(i01(i / n), i02(i / n)),
            i2 = interpolate(i01((i + 1) / n), i02((i + 1) / n));
        for (var j = 0; j <= i; ++j) {
          triangles.push([
            i1(j / i),
            i2(j / (i + 1)),
            i2((j + 1) / (i + 1))
          ]);
        }
        for (var j = 0; j < i; ++j) {
          triangles.push([
            i1(j / i),
            i1((j + 1) / i),
            i2((j + 1) / (i + 1))
          ]);
        }
      }

      return triangles;
    }));
  }

  function interpolate(p0, p1) {
    var x0 = p0[0],
        y0 = p0[1],
        z0 = p0[2],
        x1 = p1[0] - x0,
        y1 = p1[1] - y0,
        z1 = p1[2] - z0;
    return function(t) {
      return [
        x0 + t * x1,
        y0 + t * y1,
        z0 + t * z1
      ];
    };
  }

  function project(p) {
    var x = p[0],
        y = p[1],
        z = p[2];
    return [
      Math.atan2(y, x) * ρ,
      Math.acos(z / Math.sqrt(x * x + y * y + z * z)) * ρ - 90
    ];
  }
})();
<|endoftext|>


<commit_before>'use strict';
var util = require('util');
var yeoman = require('yeoman-generator');
var path = require('path');
var cgUtils = require('../utils.js');
var _ = require('underscore');

_.str = require('underscore.string');
_.mixin(_.str.exports());

var PartialGenerator = module.exports = function PartialGenerator(args, options, config) {

	yeoman.generators.NamedBase.apply(this, arguments);

	try {
		this.appname = require(path.join(process.cwd(), 'package.json')).name;
	} catch (e) {
		this.appname = 'Cant find name from package.json';
	}

};

util.inherits(PartialGenerator, yeoman.generators.NamedBase);

PartialGenerator.prototype.askFor = function askFor() {
	var cb = this.async();

	var prompts = [{
		name: 'route',
		message: 'Enter your route name (i.e. /mypartial/:id).  If you don\'t want a route added for you, leave this empty.'
	}];

	this.prompt(prompts, function (props) {
		this.route = props.route;

		cb();
	}.bind(this));
};

PartialGenerator.prototype.files = function files() {

	this.ctrlname = _.camelize(_.classify(this.name)) + 'Ctrl';

	this.template('partial.js', 'partial/'+this.name+'/'+this.name+'.js');
	this.template('partial.html', 'partial/'+this.name+'/'+this.name+'.html');
	this.template('partial.less', 'partial/'+this.name+'/'+this.name+'.less');
	this.template('spec.js', 'partial/'+this.name+'/'+this.name+'-spec.js');

	cgUtils.addToFile('index.html','<script src="partial/'+this.name+'/'+this.name+'.js"></script>',cgUtils.PARTIAL_JS_MARKER,'  ');
	this.log.writeln(' updating'.green + ' %s','index.html');

	cgUtils.addToFile('css/app.less','@import "../partial/'+this.name+'/'+this.name+'.less";',cgUtils.PARTIAL_LESS_MARKER,'');
	this.log.writeln(' updating'.green + ' %s','app/app.less');

	if (this.route && this.route.length > 0){
		cgUtils.addToFile('js/setup.js','when(\''+this.route+'\',{templateUrl: \'partial/'+this.name+'/'+this.name+'.html\'}).',cgUtils.ROUTE_MARKER,'\t');
		this.log.writeln(' updating'.green + ' %s','js/setup.js');
	}

};
<commit_msg>typofix: app/app.less -> css/app.less<commit_after>'use strict';
var util = require('util');
var yeoman = require('yeoman-generator');
var path = require('path');
var cgUtils = require('../utils.js');
var _ = require('underscore');

_.str = require('underscore.string');
_.mixin(_.str.exports());

var PartialGenerator = module.exports = function PartialGenerator(args, options, config) {

	yeoman.generators.NamedBase.apply(this, arguments);

	try {
		this.appname = require(path.join(process.cwd(), 'package.json')).name;
	} catch (e) {
		this.appname = 'Cant find name from package.json';
	}

};

util.inherits(PartialGenerator, yeoman.generators.NamedBase);

PartialGenerator.prototype.askFor = function askFor() {
	var cb = this.async();

	var prompts = [{
		name: 'route',
		message: 'Enter your route name (i.e. /mypartial/:id).  If you don\'t want a route added for you, leave this empty.'
	}];

	this.prompt(prompts, function (props) {
		this.route = props.route;

		cb();
	}.bind(this));
};

PartialGenerator.prototype.files = function files() {

	this.ctrlname = _.camelize(_.classify(this.name)) + 'Ctrl';

	this.template('partial.js', 'partial/'+this.name+'/'+this.name+'.js');
	this.template('partial.html', 'partial/'+this.name+'/'+this.name+'.html');
	this.template('partial.less', 'partial/'+this.name+'/'+this.name+'.less');
	this.template('spec.js', 'partial/'+this.name+'/'+this.name+'-spec.js');

	cgUtils.addToFile('index.html','<script src="partial/'+this.name+'/'+this.name+'.js"></script>',cgUtils.PARTIAL_JS_MARKER,'  ');
	this.log.writeln(' updating'.green + ' %s','index.html');

	cgUtils.addToFile('css/app.less','@import "../partial/'+this.name+'/'+this.name+'.less";',cgUtils.PARTIAL_LESS_MARKER,'');
	this.log.writeln(' updating'.green + ' %s','css/app.less');

	if (this.route && this.route.length > 0){
		cgUtils.addToFile('js/setup.js','when(\''+this.route+'\',{templateUrl: \'partial/'+this.name+'/'+this.name+'.html\'}).',cgUtils.ROUTE_MARKER,'\t');
		this.log.writeln(' updating'.green + ' %s','js/setup.js');
	}

};
<|endoftext|>


<commit_before>let seed;
let system;

function setup() {
  createCanvas(windowWidth, windowHeight-35);
  P5JsSettings.init();

  system = new System();
  frameRate(1);
  system.tick();

}

function draw(){
  system.tick();
  system.draw();
}
<commit_msg>p5js/water-cycle - Explicitly set the pixelDensity to 1<commit_after>let seed;
let system;

function setup() {
  pixelDensity(1);
  createCanvas(windowWidth, windowHeight-35);
  P5JsSettings.init();

  system = new System();
  frameRate(1);
  system.tick();

}

function draw(){
  system.tick();
  system.draw();
}
<|endoftext|>


<commit_before>var NOTSET = {};

ReactiveObj = function (initialValue, options) {
  var self = this;
  self._obj = typeof initialValue === 'object' ? initialValue : {};
  self._deps = {children: {}, deps: {}};
  self._willInvalidate = [];
  self._willCleanDeps = [];

  if (!options) return;
  if (typeof options.transform === 'function')
    self._transform = options.transform;
};
_.extend(ReactiveObj.prototype, {

  _matchKeyPath: function (keyPath) {
    if (typeof keyPath === 'string') keyPath = [keyPath];
    else if (typeof keyPath === 'undefined') keyPath = [];
    else if (!(keyPath instanceof Array)) throw new Error('Invalid keypath');

    return keyPath;
  },

  _visitPath: function (node, keyPath, visitor) {
    for (var i=0, l=keyPath.length, s=node, lastS=null; i<l; i+=1) {
      if (typeof s === 'object' && keyPath[i] in s) {
        lastS = s;
        s = s[keyPath[i]];
      }
      else break;
    }
    if (i === l || !keyPath.length)
      return typeof visitor !== 'function' ? s : visitor({
        node: lastS,
        value: s,
        key: keyPath[i - 1]
      });

    return NOTSET;
  },

  // Shallow clone an object with new value at the path
  _copyOnWrite: function (node, path, value) {
    var prevNode = node;
    var newNode = {};
    var currentNode = newNode;
    var currentKey, currentValue;

    for (var i=0, l=path.length-1; i<=l; i+=1) {
      currentKey = path[i];
      if (i === l) currentValue = value;
      else {
        if (prevNode[currentKey] instanceof Array) currentValue = [];
        else currentValue = {};
      }

      if (prevNode) _.extend(currentNode, _.omit(prevNode, currentKey));

      currentNode[currentKey] = currentValue;
      currentNode = currentNode[currentKey];
      if (prevNode) prevNode = prevNode[currentKey];
    }

    return newNode;
  },

  _addDep: function (opt) {
    var self = this;
    var currentNode = self._deps;
    var nextNode;

    if (!opt.path.length) self._addDepToNode(self._deps, opt);

    for (var i=0, l=opt.path.length-1; i<=l; i+=1) {
      nextNode = currentNode.children[opt.path[i]] =
        currentNode.children[opt.path[i]] ||
        {children: {}, deps: {}};

      if (i === l) self._addDepToNode(nextNode, opt);

      currentNode = nextNode;
    }
  },

  _addDepToNode: function (node, opt) {
    node.deps[opt.id] = {
      comp: opt.comp,
      lastVal: opt.lastVal
    };
  },

  _removeDep: function (opt) {
    var self = this;
    var currentNode = self._deps;
    var nextNode;

    if (!opt.path.length) self._removeDepFromNode(self._deps, opt);

    for (var i=0, l=opt.path.length-1; i<=l; i+=1) {
      if (!currentNode) break;
      nextNode = currentNode.children[opt.path[i]];

      if (i === l) self._removeDepFromNode(nextNode, opt);

      currentNode = nextNode;
    }
  },

  _removeDepFromNode: function (node, opt) {
    var self = this;
    if (!node.deps[opt.id]) return;

    delete node.deps[opt.id];

    if (self._willCleanDeps.length === 0) {
      Tracker.afterFlush(function () {
        self._cleanDeps();
      });
    }
    self._willCleanDeps.push(opt.path);
  },

  _cleanDeps: function () {
    var self = this;
    var cleanPaths = _.chain(self._willCleanDeps)
    .uniq(function (v) {
      return JSON.stringify(v);
    })
    .sortBy(function (v) { return -1 * v.length; })
    .each(function (path) {
      var currentNode = self._deps;
      var nextNode;

      for (var i=0, l=path.length-1; i<=l; i+=1) {
        if (!currentNode || !currentNode.children) return;

        nextNode = currentNode.children[path[i]];
        if(i === l) {
          if (!_.size(nextNode.children) && !_.size(nextNode.deps))
            delete currentNode.children[path[i]];
        }
        currentNode = nextNode;
      }
    })
    .value();

    // Reset
    self._willCleanDeps = [];
  },

  get: function (keyPath, valueIfNotSet) {
    var self = this;
    var computation, id, value;
    keyPath = self._matchKeyPath(keyPath);

    value = self._visitPath(self._obj, keyPath);

    if (Tracker.active) {
      computation = Tracker.currentComputation;
      id = computation._id;
      self._addDep({
        id: id,
        path: keyPath,
        comp: computation,
        lastVal: value
      });
      Tracker.currentComputation.onInvalidate(function () {
        self._removeDep({path: keyPath, id: id});
      });
    }

    if (value === NOTSET) return valueIfNotSet;
    return self._transform ? self._transform(value) : value;
  },

  set: function (keyPath, value) {
    var self = this;
    var newState, noop;
    if (arguments.length < 2) throw new Error("No value to set");
    keyPath = self._matchKeyPath(keyPath);

    // Replace root node
    if (!keyPath.length) newState = value;

    // If value assigned is the same as the old value, it is a noop
    noop = self._visitPath(self._obj, keyPath, function (context) {
      if (context.value === value) return true;
    });
    if (noop === true) return self;

    // Replace state
    self._obj = newState || self._copyOnWrite(self._obj, keyPath, value);

    self.invalidate(keyPath);

    return self;
  },

  update: function (keyPath, valIfNotSet, updater) {
    var self = this;
    var useNotSetVal = true;
    var write = {};
    var oldVal, newVal;
    keyPath = self._matchKeyPath(keyPath);
    if (arguments.length < 2) throw new Error('Insufficient arguments');
    else if (arguments.length === 2) {
      updater = valIfNotSet;
      useNotSetVal = false;
    }
    if (typeof updater !== 'function')
      throw new Error('Invalid or missing updater function');

    oldVal = self._visitPath(self._obj, keyPath);
    if (oldVal === NOTSET) {
      if (useNotSetVal) write.value = valIfNotSet;
    }
    else {
      newVal = updater(self._transform ? self._transform(oldVal) : oldVal);
      if (oldVal !== newVal) write.value = newVal;
    }

    if ('value' in write) {
      self._obj = self._copyOnWrite(self._obj, keyPath, write.value);
      self.invalidate(keyPath);
    }

    return self;
  },

  invalidate: function (keyPath) {
    var self = this;

    // Calls invalidate later if not already
    if (self._willInvalidate.length === 0) {
      Tracker.afterFlush(function () {
        self._processInvalidations();
      });
    }

    if (typeof keyPath === 'string') keyPath = [keyPath];
    else if (!(keyPath instanceof Array)) keyPath = [];
    self._willInvalidate.push(keyPath);
  },

  forceInvalidate: function (keyPath, options) {
    var self = this;
    var path, lastNode;
    keyPath = self._matchKeyPath(keyPath);
    path = self._keyPathToDepPath(keyPath);
    options = options || {};

    self._visitPath(self._deps, path, function (context) {
      self._resetDeps(context.node.deps, options.allTypes);
      lastNode = context.node;
    });

    if (lastNode)
      self._traverse(lastNode, function (nodeDes) {
        self._resetDeps(nodeDes.node.deps, options.allTypes);
        return nodeDes.node.children;
      });

    self.invalidate(keyPath);
  },

  _resetDeps: function (deps, allTypes) {
    var depKeys = _.keys(deps);

    for (var i=0, l=depKeys.length, d; i<l; i+=1) {
      d = deps[depKeys[i]];
      if (allTypes) delete d.lastVal;
      else if (d.lastVal instanceof Object) delete d.lastVal;
    };
  },

  _makePathTree: function (pathArr) {
    return _.chain(pathArr)
    .sortBy(function (keyPath) { return keyPath.length; })
    .reduce(function (tree, keyPath) {
      var currentPath = tree;
      if (tree === true) return tree;

      if (keyPath.length === 0) return tree = true;

      for (var i=0, l=keyPath.length - 1, v; i<=l; i+=1) {
        v = currentPath[keyPath[i]];

        if (v === true) return tree;

        if (i === l) currentPath[keyPath[i]] = true;
        else if (!v) currentPath[keyPath[i]] = {};

        currentPath = currentPath[keyPath[i]];
      }

      return tree;
    }, {})
    .value();
  },

  _traverse: function (tree, callback) {
    var queue = [];
    var next = {parent: null, node: tree, path: []};
    var nextNodes;

    while (next) {
      nextNodes = callback(next);
      if (typeof nextNodes === 'object') {
        _.each(nextNodes, function(node, k) {
          if (!node) return;
          queue.push({parent: next, node: node, path: next.path.concat(k)});
        });
      }
      next = queue.shift();
    }
  },

  _processInvalidations: function () {
    var self = this;
    var invalidTree;
    if (self._willInvalidate.length === 0) return;

    // Populate invalidation tree
    invalidTree = self._makePathTree(self._willInvalidate);

    self._invalidateTree(invalidTree);

    // Reset
    self._willInvalidate = [];
  },

  _invalidateTree: function (invalidTree) {
    var self = this;
    self._traverse(invalidTree, function (nodeDes) {
      self._invalidateComputation(
        nodeDes.path,
        nodeDes.node === true ? true : undefined
      );
      return nodeDes.node;
    });
  },

  _keyPathToDepPath: function (keyPath) {
    var path = ['children'];
    for (var i=0, l=keyPath.length; i<l; i+=1) {
      path.push(keyPath[i], 'children');
    }
    return path;
  },

  _invalidateComputation: function (keyPath, invalidateChildren) {
    var self = this;
    var path = self._keyPathToDepPath(keyPath);
    var lastNode;

    self._visitPath(self._deps, path, function (context) {
      self._invalidatePathDeps(keyPath, context.node.deps);
      lastNode = context.node;
    });

    if (lastNode && invalidateChildren)
      self._traverse(lastNode, function (nodeDes) {
        if (nodeDes.path.length) {
          var path = keyPath.concat(nodeDes.path);
          self._invalidatePathDeps(path, nodeDes.node.deps);
        }
        return nodeDes.node.children;
      });
  },

  _invalidatePathDeps: function (keyPath, deps) {
    var self = this;
    var depKeys = _.keys(deps);
    var val = self._visitPath(self._obj, keyPath);
    if (val === NOTSET) val = undefined;

    for (var i=0, l=depKeys.length, d; i<l; i+=1) {
      d = deps[depKeys[i]];
      if (!('lastVal' in d) || val !== d.lastVal) d.comp.invalidate();
    };
  }
});
<commit_msg>Add noChildren option to forceInvalidate method<commit_after>var NOTSET = {};

ReactiveObj = function (initialValue, options) {
  var self = this;
  self._obj = typeof initialValue === 'object' ? initialValue : {};
  self._deps = {children: {}, deps: {}};
  self._willInvalidate = [];
  self._willCleanDeps = [];

  if (!options) return;
  if (typeof options.transform === 'function')
    self._transform = options.transform;
};
_.extend(ReactiveObj.prototype, {

  _matchKeyPath: function (keyPath) {
    if (typeof keyPath === 'string') keyPath = [keyPath];
    else if (typeof keyPath === 'undefined') keyPath = [];
    else if (!(keyPath instanceof Array)) throw new Error('Invalid keypath');

    return keyPath;
  },

  _visitPath: function (node, keyPath, visitor) {
    for (var i=0, l=keyPath.length, s=node, lastS=null; i<l; i+=1) {
      if (typeof s === 'object' && keyPath[i] in s) {
        lastS = s;
        s = s[keyPath[i]];
      }
      else break;
    }
    if (i === l || !keyPath.length)
      return typeof visitor !== 'function' ? s : visitor({
        node: lastS,
        value: s,
        key: keyPath[i - 1]
      });

    return NOTSET;
  },

  // Shallow clone an object with new value at the path
  _copyOnWrite: function (node, path, value) {
    var prevNode = node;
    var newNode = {};
    var currentNode = newNode;
    var currentKey, currentValue;

    for (var i=0, l=path.length-1; i<=l; i+=1) {
      currentKey = path[i];
      if (i === l) currentValue = value;
      else {
        if (prevNode[currentKey] instanceof Array) currentValue = [];
        else currentValue = {};
      }

      if (prevNode) _.extend(currentNode, _.omit(prevNode, currentKey));

      currentNode[currentKey] = currentValue;
      currentNode = currentNode[currentKey];
      if (prevNode) prevNode = prevNode[currentKey];
    }

    return newNode;
  },

  _addDep: function (opt) {
    var self = this;
    var currentNode = self._deps;
    var nextNode;

    if (!opt.path.length) self._addDepToNode(self._deps, opt);

    for (var i=0, l=opt.path.length-1; i<=l; i+=1) {
      nextNode = currentNode.children[opt.path[i]] =
        currentNode.children[opt.path[i]] ||
        {children: {}, deps: {}};

      if (i === l) self._addDepToNode(nextNode, opt);

      currentNode = nextNode;
    }
  },

  _addDepToNode: function (node, opt) {
    node.deps[opt.id] = {
      comp: opt.comp,
      lastVal: opt.lastVal
    };
  },

  _removeDep: function (opt) {
    var self = this;
    var currentNode = self._deps;
    var nextNode;

    if (!opt.path.length) self._removeDepFromNode(self._deps, opt);

    for (var i=0, l=opt.path.length-1; i<=l; i+=1) {
      if (!currentNode) break;
      nextNode = currentNode.children[opt.path[i]];

      if (i === l) self._removeDepFromNode(nextNode, opt);

      currentNode = nextNode;
    }
  },

  _removeDepFromNode: function (node, opt) {
    var self = this;
    if (!node.deps[opt.id]) return;

    delete node.deps[opt.id];

    if (self._willCleanDeps.length === 0) {
      Tracker.afterFlush(function () {
        self._cleanDeps();
      });
    }
    self._willCleanDeps.push(opt.path);
  },

  _cleanDeps: function () {
    var self = this;
    var cleanPaths = _.chain(self._willCleanDeps)
    .uniq(function (v) {
      return JSON.stringify(v);
    })
    .sortBy(function (v) { return -1 * v.length; })
    .each(function (path) {
      var currentNode = self._deps;
      var nextNode;

      for (var i=0, l=path.length-1; i<=l; i+=1) {
        if (!currentNode || !currentNode.children) return;

        nextNode = currentNode.children[path[i]];
        if(i === l) {
          if (!_.size(nextNode.children) && !_.size(nextNode.deps))
            delete currentNode.children[path[i]];
        }
        currentNode = nextNode;
      }
    })
    .value();

    // Reset
    self._willCleanDeps = [];
  },

  get: function (keyPath, valueIfNotSet) {
    var self = this;
    var computation, id, value;
    keyPath = self._matchKeyPath(keyPath);

    value = self._visitPath(self._obj, keyPath);

    if (Tracker.active) {
      computation = Tracker.currentComputation;
      id = computation._id;
      self._addDep({
        id: id,
        path: keyPath,
        comp: computation,
        lastVal: value
      });
      Tracker.currentComputation.onInvalidate(function () {
        self._removeDep({path: keyPath, id: id});
      });
    }

    if (value === NOTSET) return valueIfNotSet;
    return self._transform ? self._transform(value) : value;
  },

  set: function (keyPath, value) {
    var self = this;
    var newState, noop;
    if (arguments.length < 2) throw new Error("No value to set");
    keyPath = self._matchKeyPath(keyPath);

    // Replace root node
    if (!keyPath.length) newState = value;

    // If value assigned is the same as the old value, it is a noop
    noop = self._visitPath(self._obj, keyPath, function (context) {
      if (context.value === value) return true;
    });
    if (noop === true) return self;

    // Replace state
    self._obj = newState || self._copyOnWrite(self._obj, keyPath, value);

    self.invalidate(keyPath);

    return self;
  },

  update: function (keyPath, valIfNotSet, updater) {
    var self = this;
    var useNotSetVal = true;
    var write = {};
    var oldVal, newVal;
    keyPath = self._matchKeyPath(keyPath);
    if (arguments.length < 2) throw new Error('Insufficient arguments');
    else if (arguments.length === 2) {
      updater = valIfNotSet;
      useNotSetVal = false;
    }
    if (typeof updater !== 'function')
      throw new Error('Invalid or missing updater function');

    oldVal = self._visitPath(self._obj, keyPath);
    if (oldVal === NOTSET) {
      if (useNotSetVal) write.value = valIfNotSet;
    }
    else {
      newVal = updater(self._transform ? self._transform(oldVal) : oldVal);
      if (oldVal !== newVal) write.value = newVal;
    }

    if ('value' in write) {
      self._obj = self._copyOnWrite(self._obj, keyPath, write.value);
      self.invalidate(keyPath);
    }

    return self;
  },

  invalidate: function (keyPath) {
    var self = this;

    // Calls invalidate later if not already
    if (self._willInvalidate.length === 0) {
      Tracker.afterFlush(function () {
        self._processInvalidations();
      });
    }

    if (typeof keyPath === 'string') keyPath = [keyPath];
    else if (!(keyPath instanceof Array)) keyPath = [];
    self._willInvalidate.push(keyPath);
  },

  forceInvalidate: function (keyPath, options) {
    var self = this;
    var path, lastNode;
    keyPath = self._matchKeyPath(keyPath);
    path = self._keyPathToDepPath(keyPath);
    options = options || {};
    _.defaults(options, {
      allType: false,
      noChildren: false
    });

    self._visitPath(self._deps, path, function (context) {
      self._resetDeps(context.node.deps, options.allTypes);
      lastNode = context.node;
    });

    if (!options.noChildren && lastNode)
      self._traverse(lastNode, function (nodeDes) {
        self._resetDeps(nodeDes.node.deps, options.allTypes);
        return nodeDes.node.children;
      });

    self.invalidate(keyPath);
  },

  _resetDeps: function (deps, allTypes) {
    var depKeys = _.keys(deps);

    for (var i=0, l=depKeys.length, d; i<l; i+=1) {
      d = deps[depKeys[i]];
      if (allTypes) delete d.lastVal;
      else if (d.lastVal instanceof Object) delete d.lastVal;
    };
  },

  _makePathTree: function (pathArr) {
    return _.chain(pathArr)
    .sortBy(function (keyPath) { return keyPath.length; })
    .reduce(function (tree, keyPath) {
      var currentPath = tree;
      if (tree === true) return tree;

      if (keyPath.length === 0) return tree = true;

      for (var i=0, l=keyPath.length - 1, v; i<=l; i+=1) {
        v = currentPath[keyPath[i]];

        if (v === true) return tree;

        if (i === l) currentPath[keyPath[i]] = true;
        else if (!v) currentPath[keyPath[i]] = {};

        currentPath = currentPath[keyPath[i]];
      }

      return tree;
    }, {})
    .value();
  },

  _traverse: function (tree, callback) {
    var queue = [];
    var next = {parent: null, node: tree, path: []};
    var nextNodes;

    while (next) {
      nextNodes = callback(next);
      if (typeof nextNodes === 'object') {
        _.each(nextNodes, function(node, k) {
          if (!node) return;
          queue.push({parent: next, node: node, path: next.path.concat(k)});
        });
      }
      next = queue.shift();
    }
  },

  _processInvalidations: function () {
    var self = this;
    var invalidTree;
    if (self._willInvalidate.length === 0) return;

    // Populate invalidation tree
    invalidTree = self._makePathTree(self._willInvalidate);

    self._invalidateTree(invalidTree);

    // Reset
    self._willInvalidate = [];
  },

  _invalidateTree: function (invalidTree) {
    var self = this;
    self._traverse(invalidTree, function (nodeDes) {
      self._invalidateComputation(
        nodeDes.path,
        nodeDes.node === true ? true : undefined
      );
      return nodeDes.node;
    });
  },

  _keyPathToDepPath: function (keyPath) {
    var path = ['children'];
    for (var i=0, l=keyPath.length; i<l; i+=1) {
      path.push(keyPath[i], 'children');
    }
    return path;
  },

  _invalidateComputation: function (keyPath, invalidateChildren) {
    var self = this;
    var path = self._keyPathToDepPath(keyPath);
    var lastNode;

    self._visitPath(self._deps, path, function (context) {
      self._invalidatePathDeps(keyPath, context.node.deps);
      lastNode = context.node;
    });

    if (lastNode && invalidateChildren)
      self._traverse(lastNode, function (nodeDes) {
        if (nodeDes.path.length) {
          var path = keyPath.concat(nodeDes.path);
          self._invalidatePathDeps(path, nodeDes.node.deps);
        }
        return nodeDes.node.children;
      });
  },

  _invalidatePathDeps: function (keyPath, deps) {
    var self = this;
    var depKeys = _.keys(deps);
    var val = self._visitPath(self._obj, keyPath);
    if (val === NOTSET) val = undefined;

    for (var i=0, l=depKeys.length, d; i<l; i+=1) {
      d = deps[depKeys[i]];
      if (!('lastVal' in d) || val !== d.lastVal) d.comp.invalidate();
    };
  }
});
<|endoftext|>


<commit_before>
// An AttributeHandler object is responsible for updating a particular attribute
// of a particular element.  AttributeHandler subclasses implement
// browser-specific logic for dealing with particular attributes across
// different browsers.
//
// To define a new type of AttributeHandler, use
// `var FooHandler = AttributeHandler.extend({ update: function ... })`
// where the `update` function takes arguments `(element, oldValue, value)`.
// The `element` argument is always the same between calls to `update` on
// the same instance.  `oldValue` and `value` are each either `null` or
// a Unicode string of the type that might be passed to the value argument
// of `setAttribute` (i.e. not an HTML string with character references).
// When an AttributeHandler is installed, an initial call to `update` is
// always made with `oldValue = null`.  The `update` method can access
// `this.name` if the AttributeHandler class is a generic one that applies
// to multiple attribute names.
//
// AttributeHandlers can store custom properties on `this`, as long as they
// don't use the names `element`, `name`, `value`, and `oldValue`.
//
// AttributeHandlers can't influence how attributes appear in rendered HTML,
// only how they are updated after materialization as DOM.

AttributeHandler = function (name, value) {
  this.name = name;
  this.value = value;
};

AttributeHandler.prototype.update = function (element, oldValue, value) {
  if (value === null) {
    if (oldValue !== null)
      element.removeAttribute(this.name);
  } else {
    element.setAttribute(this.name, value);
  }
};

AttributeHandler.extend = function (options) {
  var curType = this;
  var subType = function AttributeHandlerSubtype(/*arguments*/) {
    AttributeHandler.apply(this, arguments);
  };
  subType.prototype = new curType;
  subType.extend = curType.extend;
  if (options)
    _.extend(subType.prototype, options);
  return subType;
};

/// Apply the diff between the attributes of "oldValue" and "value" to "element."
//
// Each subclass must implement a parseValue method which takes a string
// as an input and returns a dict of attributes. The keys of the dict
// are unique identifiers (ie. css properties in the case of styles), and the
// values are the entire attribute which will be injected into the element.
//
// Extended below to support classes, SVG elements and styles.

var DiffingAttributeHandler = AttributeHandler.extend({
  update: function (element, oldValue, value) {
    if (!this.getCurrentValue || !this.setValue || !this.parseValue)
      throw new Error("Missing methods in subclass of 'DiffingAttributeHandler'");

    var oldAttrsMap = oldValue ? this.parseValue(oldValue) : {};
    var newAttrsMap = value ? this.parseValue(value) : {};

    // the current attributes on the element, which we will mutate.

    var attrString = this.getCurrentValue(element);
    var attrsMap = attrString ? this.parseValue(attrString) : {};

    _.each(_.keys(oldAttrsMap), function (t) {
      if (! (t in newAttrsMap))
        delete attrsMap[t];
    });

    _.each(_.keys(newAttrsMap), function (t) {
      attrsMap[t] = newAttrsMap[t];
    });

    this.setValue(element, _.values(attrsMap).join(' '));
  }
});

var ClassHandler = DiffingAttributeHandler.extend({
  // @param rawValue {String}
  getCurrentValue: function (element) {
    return element.className;
  },
  setValue: function (element, className) {
    element.className = className;
  },
  parseValue: function (attrString) {
    var tokens = {};

    _.each(attrString.split(' '), function(token) {
      if (token)
        tokens[token] = token;
    });
    return tokens;
  }
});

var SVGClassHandler = ClassHandler.extend({
  getCurrentValue: function (element) {
    return element.className.baseVal;
  },
  setValue: function (element, className) {
    element.setAttribute('class', className);
  }
});

var StyleHandler = DiffingAttributeHandler.extend({
  getCurrentValue: function (element) {
    return element.getAttribute('style');
  },
  setValue: function (element, style) {
    if (style === '') {
      element.removeAttribute('style');
    } else {
      element.setAttribute('style', style);
    }
  },

  // Parse a string to produce a map from property to attribute string.
  //
  // Example:
  // "color:red; foo:12px" produces a token {color: "color:red", foo:"foo:12px"}
  parseValue: function (attrString) {
    var tokens = {};

    // Regex for parsing a css attribute declaration, taken from css-parse:
    // https://github.com/reworkcss/css-parse/blob/7cef3658d0bba872cde05a85339034b187cb3397/index.js#L219
    var regex = /(\*?[-#\/\*\\\w]+(?:\[[0-9a-z_-]+\])?)\s*:\s*(?:\'(?:\\\'|.)*?\'|"(?:\\"|.)*?"|\([^\)]*?\)|[^};])+[;\s]*/g;
    var match = regex.exec(attrString);
    while (match) {
      // match[0] = entire matching string
      // match[1] = css property
      // Prefix the token to prevent conflicts with existing properties.

      // XXX No `String.trim` on Safari 4. Swap out $.trim if we want to
      // remove strong dep on jquery.
      tokens[' ' + match[1]] = match[0].trim ?
        match[0].trim() : $.trim(match[0]);

      match = regex.exec(attrString);
    }

    return tokens;
  }
});

var BooleanHandler = AttributeHandler.extend({
  update: function (element, oldValue, value) {
    var name = this.name;
    if (value == null) {
      if (oldValue != null)
        element[name] = false;
    } else {
      element[name] = true;
    }
  }
});

var ValueHandler = AttributeHandler.extend({
  update: function (element, oldValue, value) {
    element.value = value;
  }
});

// attributes of the type 'xlink:something' should be set using
// the correct namespace in order to work
var XlinkHandler = AttributeHandler.extend({
  update: function(element, oldValue, value) {
    var NS = 'http://www.w3.org/1999/xlink';
    if (value === null) {
      if (oldValue !== null)
        element.removeAttributeNS(NS, this.name);
    } else {
      element.setAttributeNS(NS, this.name, this.value);
    }
  }
});

// cross-browser version of `instanceof SVGElement`
var isSVGElement = function (elem) {
  return 'ownerSVGElement' in elem;
};

var isUrlAttribute = function (tagName, attrName) {
  // Compiled from http://www.w3.org/TR/REC-html40/index/attributes.html
  // and
  // http://www.w3.org/html/wg/drafts/html/master/index.html#attributes-1
  var urlAttrs = {
    FORM: ['action'],
    BODY: ['background'],
    BLOCKQUOTE: ['cite'],
    Q: ['cite'],
    DEL: ['cite'],
    INS: ['cite'],
    OBJECT: ['classid', 'codebase', 'data', 'usemap'],
    APPLET: ['codebase'],
    A: ['href'],
    AREA: ['href'],
    LINK: ['href'],
    BASE: ['href'],
    IMG: ['longdesc', 'src', 'usemap'],
    FRAME: ['longdesc', 'src'],
    IFRAME: ['longdesc', 'src'],
    HEAD: ['profile'],
    SCRIPT: ['src'],
    INPUT: ['src', 'usemap', 'formaction'],
    BUTTON: ['formaction'],
    BASE: ['href'],
    MENUITEM: ['icon'],
    HTML: ['manifest'],
    VIDEO: ['poster']
  };

  if (attrName === 'itemid') {
    return true;
  }

  var urlAttrNames = urlAttrs[tagName] || [];
  return _.contains(urlAttrNames, attrName);
};

// To get the protocol for a URL, we let the browser normalize it for
// us, by setting it as the href for an anchor tag and then reading out
// the 'protocol' property.
if (Meteor.isClient) {
  var anchorForNormalization = document.createElement('A');
}

var getUrlProtocol = function (url) {
  if (Meteor.isClient) {
    anchorForNormalization.href = url;
    return (anchorForNormalization.protocol || "").toLowerCase();
  } else {
    throw new Error('getUrlProtocol not implemented on the server');
  }
};

// UrlHandler is an attribute handler for all HTML attributes that take
// URL values. It disallows javascript: URLs, unless
// UI._allowJavascriptUrls() has been called. To detect javascript:
// urls, we set the attribute on a dummy anchor element and then read
// out the 'protocol' property of the attribute.
var origUpdate = AttributeHandler.prototype.update;
var UrlHandler = AttributeHandler.extend({
  update: function (element, oldValue, value) {
    var self = this;
    var args = arguments;

    if (UI._javascriptUrlsAllowed()) {
      origUpdate.apply(self, args);
    } else {
      var isJavascriptProtocol = (getUrlProtocol(value) === "javascript:");
      if (isJavascriptProtocol) {
        Meteor._debug("URLs that use the 'javascript:' protocol are not " +
                      "allowed in URL attribute values. " +
                      "Call UI._allowJavascriptUrls() " +
                      "to enable them.");
        origUpdate.apply(self, [element, oldValue, null]);
      } else {
        origUpdate.apply(self, args);
      }
    }
  }
});

// XXX make it possible for users to register attribute handlers!
makeAttributeHandler = function (elem, name, value) {
  // generally, use setAttribute but certain attributes need to be set
  // by directly setting a JavaScript property on the DOM element.
  if (name === 'class') {
    if (isSVGElement(elem)) {
      return new SVGClassHandler(name, value);
    } else {
      return new ClassHandler(name, value);
    }
  } else if (name === 'style') {
    return new StyleHandler(name, value);
  } else if ((elem.tagName === 'OPTION' && name === 'selected') ||
             (elem.tagName === 'INPUT' && name === 'checked')) {
    return new BooleanHandler(name, value);
  } else if ((elem.tagName === 'TEXTAREA' || elem.tagName === 'INPUT')
             && name === 'value') {
    // internally, TEXTAREAs tracks their value in the 'value'
    // attribute just like INPUTs.
    return new ValueHandler(name, value);
  } else if (name.substring(0,6) === 'xlink:') {
    return new XlinkHandler(name.substring(6), value);
  } else if (isUrlAttribute(elem.tagName, name)) {
    return new UrlHandler(name, value);
  } else {
    return new AttributeHandler(name, value);
  }

  // XXX will need one for 'style' on IE, though modern browsers
  // seem to handle setAttribute ok.
};

ElementAttributesUpdater = function (elem) {
  this.elem = elem;
  this.handlers = {};
};

// Update attributes on `elem` to the dictionary `attrs`, whose
// values are strings.
ElementAttributesUpdater.prototype.update = function(newAttrs) {
  var elem = this.elem;
  var handlers = this.handlers;

  for (var k in handlers) {
    if (! _.has(newAttrs, k)) {
      // remove attributes (and handlers) for attribute names
      // that don't exist as keys of `newAttrs` and so won't
      // be visited when traversing it.  (Attributes that
      // exist in the `newAttrs` object but are `null`
      // are handled later.)
      var handler = handlers[k];
      var oldValue = handler.value;
      handler.value = null;
      handler.update(elem, oldValue, null);
      delete handlers[k];
    }
  }

  for (var k in newAttrs) {
    var handler = null;
    var oldValue;
    var value = newAttrs[k];
    if (! _.has(handlers, k)) {
      if (value !== null) {
        // make new handler
        handler = makeAttributeHandler(elem, k, value);
        handlers[k] = handler;
        oldValue = null;
      }
    } else {
      handler = handlers[k];
      oldValue = handler.value;
    }
    if (oldValue !== value) {
      handler.value = value;
      handler.update(elem, oldValue, value);
      if (value === null)
        delete handlers[k];
    }
  }
};
<commit_msg>Blaze: Don't update input elements if their value doesn't need updating<commit_after>
// An AttributeHandler object is responsible for updating a particular attribute
// of a particular element.  AttributeHandler subclasses implement
// browser-specific logic for dealing with particular attributes across
// different browsers.
//
// To define a new type of AttributeHandler, use
// `var FooHandler = AttributeHandler.extend({ update: function ... })`
// where the `update` function takes arguments `(element, oldValue, value)`.
// The `element` argument is always the same between calls to `update` on
// the same instance.  `oldValue` and `value` are each either `null` or
// a Unicode string of the type that might be passed to the value argument
// of `setAttribute` (i.e. not an HTML string with character references).
// When an AttributeHandler is installed, an initial call to `update` is
// always made with `oldValue = null`.  The `update` method can access
// `this.name` if the AttributeHandler class is a generic one that applies
// to multiple attribute names.
//
// AttributeHandlers can store custom properties on `this`, as long as they
// don't use the names `element`, `name`, `value`, and `oldValue`.
//
// AttributeHandlers can't influence how attributes appear in rendered HTML,
// only how they are updated after materialization as DOM.

AttributeHandler = function (name, value) {
  this.name = name;
  this.value = value;
};

AttributeHandler.prototype.update = function (element, oldValue, value) {
  if (value === null) {
    if (oldValue !== null)
      element.removeAttribute(this.name);
  } else {
    element.setAttribute(this.name, value);
  }
};

AttributeHandler.extend = function (options) {
  var curType = this;
  var subType = function AttributeHandlerSubtype(/*arguments*/) {
    AttributeHandler.apply(this, arguments);
  };
  subType.prototype = new curType;
  subType.extend = curType.extend;
  if (options)
    _.extend(subType.prototype, options);
  return subType;
};

/// Apply the diff between the attributes of "oldValue" and "value" to "element."
//
// Each subclass must implement a parseValue method which takes a string
// as an input and returns a dict of attributes. The keys of the dict
// are unique identifiers (ie. css properties in the case of styles), and the
// values are the entire attribute which will be injected into the element.
//
// Extended below to support classes, SVG elements and styles.

var DiffingAttributeHandler = AttributeHandler.extend({
  update: function (element, oldValue, value) {
    if (!this.getCurrentValue || !this.setValue || !this.parseValue)
      throw new Error("Missing methods in subclass of 'DiffingAttributeHandler'");

    var oldAttrsMap = oldValue ? this.parseValue(oldValue) : {};
    var newAttrsMap = value ? this.parseValue(value) : {};

    // the current attributes on the element, which we will mutate.

    var attrString = this.getCurrentValue(element);
    var attrsMap = attrString ? this.parseValue(attrString) : {};

    _.each(_.keys(oldAttrsMap), function (t) {
      if (! (t in newAttrsMap))
        delete attrsMap[t];
    });

    _.each(_.keys(newAttrsMap), function (t) {
      attrsMap[t] = newAttrsMap[t];
    });

    this.setValue(element, _.values(attrsMap).join(' '));
  }
});

var ClassHandler = DiffingAttributeHandler.extend({
  // @param rawValue {String}
  getCurrentValue: function (element) {
    return element.className;
  },
  setValue: function (element, className) {
    element.className = className;
  },
  parseValue: function (attrString) {
    var tokens = {};

    _.each(attrString.split(' '), function(token) {
      if (token)
        tokens[token] = token;
    });
    return tokens;
  }
});

var SVGClassHandler = ClassHandler.extend({
  getCurrentValue: function (element) {
    return element.className.baseVal;
  },
  setValue: function (element, className) {
    element.setAttribute('class', className);
  }
});

var StyleHandler = DiffingAttributeHandler.extend({
  getCurrentValue: function (element) {
    return element.getAttribute('style');
  },
  setValue: function (element, style) {
    if (style === '') {
      element.removeAttribute('style');
    } else {
      element.setAttribute('style', style);
    }
  },

  // Parse a string to produce a map from property to attribute string.
  //
  // Example:
  // "color:red; foo:12px" produces a token {color: "color:red", foo:"foo:12px"}
  parseValue: function (attrString) {
    var tokens = {};

    // Regex for parsing a css attribute declaration, taken from css-parse:
    // https://github.com/reworkcss/css-parse/blob/7cef3658d0bba872cde05a85339034b187cb3397/index.js#L219
    var regex = /(\*?[-#\/\*\\\w]+(?:\[[0-9a-z_-]+\])?)\s*:\s*(?:\'(?:\\\'|.)*?\'|"(?:\\"|.)*?"|\([^\)]*?\)|[^};])+[;\s]*/g;
    var match = regex.exec(attrString);
    while (match) {
      // match[0] = entire matching string
      // match[1] = css property
      // Prefix the token to prevent conflicts with existing properties.

      // XXX No `String.trim` on Safari 4. Swap out $.trim if we want to
      // remove strong dep on jquery.
      tokens[' ' + match[1]] = match[0].trim ?
        match[0].trim() : $.trim(match[0]);

      match = regex.exec(attrString);
    }

    return tokens;
  }
});

var BooleanHandler = AttributeHandler.extend({
  update: function (element, oldValue, value) {
    var name = this.name;
    if (value == null) {
      if (oldValue != null)
        element[name] = false;
    } else {
      element[name] = true;
    }
  }
});

var ValueHandler = AttributeHandler.extend({
  update: function (element, oldValue, value) {
    if (value !== element.value)
      element.value = value;
  }
});

// attributes of the type 'xlink:something' should be set using
// the correct namespace in order to work
var XlinkHandler = AttributeHandler.extend({
  update: function(element, oldValue, value) {
    var NS = 'http://www.w3.org/1999/xlink';
    if (value === null) {
      if (oldValue !== null)
        element.removeAttributeNS(NS, this.name);
    } else {
      element.setAttributeNS(NS, this.name, this.value);
    }
  }
});

// cross-browser version of `instanceof SVGElement`
var isSVGElement = function (elem) {
  return 'ownerSVGElement' in elem;
};

var isUrlAttribute = function (tagName, attrName) {
  // Compiled from http://www.w3.org/TR/REC-html40/index/attributes.html
  // and
  // http://www.w3.org/html/wg/drafts/html/master/index.html#attributes-1
  var urlAttrs = {
    FORM: ['action'],
    BODY: ['background'],
    BLOCKQUOTE: ['cite'],
    Q: ['cite'],
    DEL: ['cite'],
    INS: ['cite'],
    OBJECT: ['classid', 'codebase', 'data', 'usemap'],
    APPLET: ['codebase'],
    A: ['href'],
    AREA: ['href'],
    LINK: ['href'],
    BASE: ['href'],
    IMG: ['longdesc', 'src', 'usemap'],
    FRAME: ['longdesc', 'src'],
    IFRAME: ['longdesc', 'src'],
    HEAD: ['profile'],
    SCRIPT: ['src'],
    INPUT: ['src', 'usemap', 'formaction'],
    BUTTON: ['formaction'],
    BASE: ['href'],
    MENUITEM: ['icon'],
    HTML: ['manifest'],
    VIDEO: ['poster']
  };

  if (attrName === 'itemid') {
    return true;
  }

  var urlAttrNames = urlAttrs[tagName] || [];
  return _.contains(urlAttrNames, attrName);
};

// To get the protocol for a URL, we let the browser normalize it for
// us, by setting it as the href for an anchor tag and then reading out
// the 'protocol' property.
if (Meteor.isClient) {
  var anchorForNormalization = document.createElement('A');
}

var getUrlProtocol = function (url) {
  if (Meteor.isClient) {
    anchorForNormalization.href = url;
    return (anchorForNormalization.protocol || "").toLowerCase();
  } else {
    throw new Error('getUrlProtocol not implemented on the server');
  }
};

// UrlHandler is an attribute handler for all HTML attributes that take
// URL values. It disallows javascript: URLs, unless
// UI._allowJavascriptUrls() has been called. To detect javascript:
// urls, we set the attribute on a dummy anchor element and then read
// out the 'protocol' property of the attribute.
var origUpdate = AttributeHandler.prototype.update;
var UrlHandler = AttributeHandler.extend({
  update: function (element, oldValue, value) {
    var self = this;
    var args = arguments;

    if (UI._javascriptUrlsAllowed()) {
      origUpdate.apply(self, args);
    } else {
      var isJavascriptProtocol = (getUrlProtocol(value) === "javascript:");
      if (isJavascriptProtocol) {
        Meteor._debug("URLs that use the 'javascript:' protocol are not " +
                      "allowed in URL attribute values. " +
                      "Call UI._allowJavascriptUrls() " +
                      "to enable them.");
        origUpdate.apply(self, [element, oldValue, null]);
      } else {
        origUpdate.apply(self, args);
      }
    }
  }
});

// XXX make it possible for users to register attribute handlers!
makeAttributeHandler = function (elem, name, value) {
  // generally, use setAttribute but certain attributes need to be set
  // by directly setting a JavaScript property on the DOM element.
  if (name === 'class') {
    if (isSVGElement(elem)) {
      return new SVGClassHandler(name, value);
    } else {
      return new ClassHandler(name, value);
    }
  } else if (name === 'style') {
    return new StyleHandler(name, value);
  } else if ((elem.tagName === 'OPTION' && name === 'selected') ||
             (elem.tagName === 'INPUT' && name === 'checked')) {
    return new BooleanHandler(name, value);
  } else if ((elem.tagName === 'TEXTAREA' || elem.tagName === 'INPUT')
             && name === 'value') {
    // internally, TEXTAREAs tracks their value in the 'value'
    // attribute just like INPUTs.
    return new ValueHandler(name, value);
  } else if (name.substring(0,6) === 'xlink:') {
    return new XlinkHandler(name.substring(6), value);
  } else if (isUrlAttribute(elem.tagName, name)) {
    return new UrlHandler(name, value);
  } else {
    return new AttributeHandler(name, value);
  }

  // XXX will need one for 'style' on IE, though modern browsers
  // seem to handle setAttribute ok.
};

ElementAttributesUpdater = function (elem) {
  this.elem = elem;
  this.handlers = {};
};

// Update attributes on `elem` to the dictionary `attrs`, whose
// values are strings.
ElementAttributesUpdater.prototype.update = function(newAttrs) {
  var elem = this.elem;
  var handlers = this.handlers;

  for (var k in handlers) {
    if (! _.has(newAttrs, k)) {
      // remove attributes (and handlers) for attribute names
      // that don't exist as keys of `newAttrs` and so won't
      // be visited when traversing it.  (Attributes that
      // exist in the `newAttrs` object but are `null`
      // are handled later.)
      var handler = handlers[k];
      var oldValue = handler.value;
      handler.value = null;
      handler.update(elem, oldValue, null);
      delete handlers[k];
    }
  }

  for (var k in newAttrs) {
    var handler = null;
    var oldValue;
    var value = newAttrs[k];
    if (! _.has(handlers, k)) {
      if (value !== null) {
        // make new handler
        handler = makeAttributeHandler(elem, k, value);
        handlers[k] = handler;
        oldValue = null;
      }
    } else {
      handler = handlers[k];
      oldValue = handler.value;
    }
    if (oldValue !== value) {
      handler.value = value;
      handler.update(elem, oldValue, value);
      if (value === null)
        delete handlers[k];
    }
  }
};
<|endoftext|>


<commit_before>Facts = {};

var serverFactsCollection = 'meteor_Facts_server';

if (Meteor.isServer) {
  // By default, we publish facts to no user if autopublish is off, and to all
  // users if autopublish is on.
  var userIdFilter = function (userId) {
    return !!Package.autopublish;
  };

  // XXX make this take effect at runtime too?
  Facts.setUserIdFilter = function (filter) {
    userIdFilter = filter;
  };

  // XXX Use a minimongo collection instead and hook up an observeChanges
  // directly to a publish.
  var factsByPackage = {};
  var activeSubscriptions = [];

  Facts.incrementServerFact = function (pkg, fact, increment) {
    if (!_.has(factsByPackage, pkg)) {
      factsByPackage[pkg] = {};
      factsByPackage[pkg][fact] = increment;
      _.each(activeSubscriptions, function (sub) {
        sub.added(serverFactsCollection, pkg, factsByPackage[pkg]);
      });
      return;
    }

    var packageFacts = factsByPackage[pkg];
    if (!_.has(packageFacts, fact))
      factsByPackage[pkg][fact] = 0;
    factsByPackage[pkg][fact] += increment;
    var changedField = {};
    changedField[fact] = factsByPackage[pkg][fact];
    _.each(activeSubscriptions, function (sub) {
      sub.changed(serverFactsCollection, pkg, changedField);
    });
  };

  // Deferred, because we have an unordered dependency on livedata.
  // XXX is this safe? could somebody try to connect before Meteor.publish is
  // called?
  Meteor.defer(function () {
    // XXX Also publish facts-by-package.
    Meteor.publish("meteor_facts", function () {
      var sub = this;
      if (!userIdFilter(this.userId)) {
        sub.ready();
        return;
      }
      activeSubscriptions.push(sub);
      _.each(factsByPackage, function (facts, pkg) {
        sub.added(serverFactsCollection, pkg, facts);
      });
      sub.onStop(function () {
        activeSubscriptions = _.without(activeSubscriptions, sub);
      });
      sub.ready();
    }, {is_auto: true});
  });
} else {
  Facts.server = new Meteor.Collection(serverFactsCollection);

  Template.serverFacts.factsByPackage = function () {
    return Facts.server.find();
  };
  Template.serverFacts.facts = function () {
    var factArray = [];
    _.each(this, function (value, name) {
      if (name !== '_id')
        factArray.push({name: name, value: value});
    });
    return factArray;
  };

  // Subscribe when the template is first made, and unsubscribe when it
  // is removed. If for some reason puts two copies of the template on
  // the screen at once, we'll subscribe twice. Meh.
  Template.serverFacts.created = function () {
    this._stopHandle = Meteor.subscribe("meteor_facts");
  };
  Template.serverFacts.destroyed = function () {
    if (this._stopHandle) {
      this._stopHandle.stop();
      this._stopHandle = null;
    }
  };
}
<commit_msg>Make factsByPackage data available to the server environment<commit_after>Facts = {};

var serverFactsCollection = 'meteor_Facts_server';

if (Meteor.isServer) {
  // By default, we publish facts to no user if autopublish is off, and to all
  // users if autopublish is on.
  var userIdFilter = function (userId) {
    return !!Package.autopublish;
  };

  // XXX make this take effect at runtime too?
  Facts.setUserIdFilter = function (filter) {
    userIdFilter = filter;
  };

  // XXX Use a minimongo collection instead and hook up an observeChanges
  // directly to a publish.
  var factsByPackage = {};
  var activeSubscriptions = [];

  // Make factsByPackage data available to the server environment
  Facts._factsByPackage = factsByPackage;

  Facts.incrementServerFact = function (pkg, fact, increment) {
    if (!_.has(factsByPackage, pkg)) {
      factsByPackage[pkg] = {};
      factsByPackage[pkg][fact] = increment;
      _.each(activeSubscriptions, function (sub) {
        sub.added(serverFactsCollection, pkg, factsByPackage[pkg]);
      });
      return;
    }

    var packageFacts = factsByPackage[pkg];
    if (!_.has(packageFacts, fact))
      factsByPackage[pkg][fact] = 0;
    factsByPackage[pkg][fact] += increment;
    var changedField = {};
    changedField[fact] = factsByPackage[pkg][fact];
    _.each(activeSubscriptions, function (sub) {
      sub.changed(serverFactsCollection, pkg, changedField);
    });
  };

  // Deferred, because we have an unordered dependency on livedata.
  // XXX is this safe? could somebody try to connect before Meteor.publish is
  // called?
  Meteor.defer(function () {
    // XXX Also publish facts-by-package.
    Meteor.publish("meteor_facts", function () {
      var sub = this;
      if (!userIdFilter(this.userId)) {
        sub.ready();
        return;
      }
      activeSubscriptions.push(sub);
      _.each(factsByPackage, function (facts, pkg) {
        sub.added(serverFactsCollection, pkg, facts);
      });
      sub.onStop(function () {
        activeSubscriptions = _.without(activeSubscriptions, sub);
      });
      sub.ready();
    }, {is_auto: true});
  });
} else {
  Facts.server = new Meteor.Collection(serverFactsCollection);

  Template.serverFacts.factsByPackage = function () {
    return Facts.server.find();
  };
  Template.serverFacts.facts = function () {
    var factArray = [];
    _.each(this, function (value, name) {
      if (name !== '_id')
        factArray.push({name: name, value: value});
    });
    return factArray;
  };

  // Subscribe when the template is first made, and unsubscribe when it
  // is removed. If for some reason puts two copies of the template on
  // the screen at once, we'll subscribe twice. Meh.
  Template.serverFacts.created = function () {
    this._stopHandle = Meteor.subscribe("meteor_facts");
  };
  Template.serverFacts.destroyed = function () {
    if (this._stopHandle) {
      this._stopHandle.stop();
      this._stopHandle = null;
    }
  };
}
<|endoftext|>


<commit_before>const express = require("express");
const setTimeout =  require("timers").setTimeout;
const roslib = require("roslib");
const http = require("http");
const url = require('url');
const ipware = require('ipware');
const bodyParser = require("body-parser");
const app = express();
const ipw = ipware();

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
app.post("/rp", (req, res) => {
    const request_from = ((ipw.get_ip(req).clientIp).split(":")).pop();
    const local_ip = req.headers.host.split(":")[0]
    if(request_from != local_ip){
        res.json({
            "message":"This host has no authority to access this server"
        });
        return;
    }

    const remote_url = req.body.url;
    const room_name = req.body.room;
    const command = req.body.command;

    let req_service = "";
    let req_service_type = "";
    if(command == "robot_task"){
        req_service = req.body.service;
        req_service_type = req.body.service_type;
    }

    const ros_remote = new roslib.Ros({
        url: "ws://" + remote_url + ":9090"
    });
    ros_remote.on('connection', () => {
        console.log('Connected to websocket server');
    });

    ros_remote.on('error', error =>{
        console.log('Erro connecting to websocket server: ', error);
    });

    ros_remote.on('close', () => {
        console.log("Connection to websocket server was closed");
    });

    const get_id = new roslib.Service({
        ros: ros_remote,
        name: "get_id",
        serviceType: "tms_nw_api/get_id"
    });

    let get_id_req = new roslib.ServiceRequest({
        url: "http://" + local_ip
    });

    get_id.callService(get_id_req, id_res => {
        console.log(id_res);
        let anc_list = id_res.task_announce.split("$");
        let announce = "";
        let room_flag = 0;
        for(let anc in anc_list){
            if(anc_list[anc] == "object"){
                announce += id_res.object_announce;
            }else if(anc_list[anc] == "robot"){
                announce += id_res.robot_announce;
            }else if(anc_list[anc] == "place"){
                announce += id_res.place_announce;
            }else if(anc_list[anc] == "user"){
                announce += id_res.user_announce;
            }else{
                announce += anc_list[anc];
                if(room_flag == 0){
                    room_flag += 1;
                }
                else if(room_flag == 1 && (command == "search_object" || command == "robot_task")){
                    announce += room_name + "の";
                    room_flag = 2;
                }
            }
        }
        console.log(announce);

        if(command =="robot_task"){
            const remote_task = new roslib.Service({
                ros: ros_remote,
                name: req_service,
                serviceType: req_service_type
            });

            const remote_req = new roslib.ServiceRequest({
                "task_id": id_res.task_id,
                "robot_id": id_res.robot_id,
                "object_id":id_res.object_id,
                "user_id": id_res.user_id,
                "place_id": id_res.place_id,
                "priority": 0
            });

            remote_task.callService(remote_req, service_res =>{
                console.log(service_res);
            })

        }
        res.json = ({
            "message":"OK",
            "announce":announce
        });
        return res;

});
    });

app.listen(5000);<commit_msg>Fix the problem: HTTP response doesn't return<commit_after>const express = require("express");
const setTimeout =  require("timers").setTimeout;
const roslib = require("roslib");
const http = require("http");
const url = require('url');
const ipware = require('ipware');
const bodyParser = require("body-parser");
const app = express();
const ipw = ipware();

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
app.post("/rp", (req, res) => {
    const request_from = ((ipw.get_ip(req).clientIp).split(":")).pop();
    const local_ip = req.headers.host.split(":")[0]
    if(request_from != local_ip){
        res.json({
            "message":"This host has no authority to access this server"
        });
        return;
    }

    const remote_url = req.body.url;
    const room_name = req.body.room;
    const command = req.body.command;

    let req_service = "";
    let req_service_type = "";
    if(command == "robot_task"){
        req_service = req.body.service;
        req_service_type = req.body.service_type;
    }

    const ros_remote = new roslib.Ros({
        url: "ws://" + remote_url + ":9090"
    });
    ros_remote.on('connection', () => {
        console.log('Connected to websocket server');
    });

    ros_remote.on('error', error =>{
        console.log('Erro connecting to websocket server: ', error);
    });

    ros_remote.on('close', () => {
        console.log("Connection to websocket server was closed");
    });

    const get_id = new roslib.Service({
        ros: ros_remote,
        name: "get_id",
        serviceType: "tms_nw_api/get_id"
    });

    let get_id_req = new roslib.ServiceRequest({
        url: "http://" + local_ip
    });

    get_id.callService(get_id_req, id_res => {
        console.log(id_res);
        let anc_list = id_res.task_announce.split("$");
        let announce = "";
        let room_flag = 0;
        for(let anc in anc_list){
            if(anc_list[anc] == "object"){
                announce += id_res.object_announce;
            }else if(anc_list[anc] == "robot"){
                announce += id_res.robot_announce;
            }else if(anc_list[anc] == "place"){
                announce += id_res.place_announce;
            }else if(anc_list[anc] == "user"){
                announce += id_res.user_announce;
            }else{
                announce += anc_list[anc];
                if(room_flag == 0){
                    room_flag += 1;
                }
                else if(room_flag == 1 && (command == "search_object" || command == "robot_task")){
                    announce += room_name + "の";
                    room_flag = 2;
                }
            }
        }
        console.log(announce);

        if(command =="robot_task"){
            const remote_task = new roslib.Service({
                ros: ros_remote,
                name: req_service,
                serviceType: req_service_type
            });

            const remote_req = new roslib.ServiceRequest({
                "task_id": id_res.task_id,
                "robot_id": id_res.robot_id,
                "object_id":id_res.object_id,
                "user_id": id_res.user_id,
                "place_id": id_res.place_id,
                "priority": 0
            });

            remote_task.callService(remote_req, service_res =>{
                console.log(service_res);
            })

        }
        /*
        res.json = ({
            "message":"OK",
            "announce":announce
        });
        */
        res.status(200).json({
            "message":"OK",
            "announce":announce
        });
        return;

});
    });

app.listen(5000);<|endoftext|>


<commit_before>const browsers = ['Firefox'];

if (!process.env.CI) {
    browsers.push('Chrome');
    switch (process.platform) {
        case 'darwin':
            browsers.push('Safari');
            break;
        case 'win32':
            browsers.push('IE');
            browsers.push('Edge');
            break;
    }
}

module.exports = (config) => {
    config.set({
        basePath: '../',
        frameworks: ['mocha', 'chai'],
        files: [
            'dist/browser-id3-writer.min.js',
            'test/common.js',
            'test/browser.js',
            {
                pattern: 'test/assets/song.mp3',
                included: false,
                served: true
            }
        ],
        reporters: ['dots'],
        browsers: browsers,
        singleRun: true
    });
};
<commit_msg>Change karma log lvl to WARN<commit_after>const browsers = ['Firefox'];

if (!process.env.CI) {
    browsers.push('Chrome');
    switch (process.platform) {
        case 'darwin':
            browsers.push('Safari');
            break;
        case 'win32':
            browsers.push('IE');
            browsers.push('Edge');
            break;
    }
}

module.exports = (config) => {
    config.set({
        basePath: '../',
        frameworks: ['mocha', 'chai'],
        files: [
            'dist/browser-id3-writer.min.js',
            'test/common.js',
            'test/browser.js',
            {
                pattern: 'test/assets/song.mp3',
                included: false,
                served: true
            }
        ],
        reporters: ['dots'],
        browsers: browsers,
        singleRun: true,
        logLevel: config.LOG_WARN
    });
};
<|endoftext|>