<commit_before>var display = null;

var container = document.getElementById( 'canvas-container' );

var renderer = new THREE.WebGLRenderer( { antialias: true, alpha: true } );
renderer.setPixelRatio( window.devicePixelRatio );
container.appendChild( renderer.domElement );

var scene = new THREE.Scene();
//var camera = new THREE.PerspectiveCamera( 75, 1, .01, 100 );
//camera.position.set( 1, 1, 1 );
var camera = new THREE.OrthographicCamera( 1 / - 2, 1 / 2, 1 / 2, 1 / - 2, - 5, 10 );
camera.position.set( 2, 2, 2 );
camera.lookAt( scene.position );

var room = new THREE.Mesh( new THREE.BoxGeometry( 5, 2, 3 ), new THREE.MeshNormalMaterial( { side: THREE.BackSide }) );
room.position.y = 1;
scene.add( room );

var hmd = new THREE.Mesh( new THREE.BoxGeometry( .20, .11, .12 ), new THREE.MeshNormalMaterial() );
scene.add( hmd );

var controls = new THREE.OrbitControls( camera, container );
controls.addEventListener( 'change', render );
controls.target.set( 0, 0, 0 );

var control = new THREE.TransformControls( camera, renderer.domElement );
control.addEventListener( 'change', render );
control.attach( hmd );
control.setSize( .5 );
scene.add( control );

function onWindowResize() {

    var w = container.clientWidth;
    var h = container.clientHeight;

    renderer.setSize( w, h );

    //camera.aspect = w / h;
    //camera.updateProjectionMatrix();

    camera.left = w / - 2;
    camera.right = w / 2;
    camera.top = h / 2;
    camera.bottom = h / - 2;

    camera.updateProjectionMatrix();

    render();

}

window.addEventListener( 'resize', onWindowResize );

function render() {

    var str = 'window.__extHMDResetPose';
    chrome.devtools.inspectedWindow.eval( str, function(result, isException) {
        if( result === true ) {
            hmd.position.set( 0, 0,0 );
            hmd.quaternion.set( 0, 0, 0, 0 );
            var str = 'window.__extHMDResetPose = false;';
            chrome.devtools.inspectedWindow.eval( str );
        }
    } );

    control.update();

    var str = 'window.__extHMDPosition = [' +
        hmd.position.x + ', ' +
        hmd.position.y + ', ' +
        hmd.position.z + '];';
    str += 'window.__extHMDOrientation = [' +
        hmd.quaternion.x + ', ' +
        hmd.quaternion.y + ', ' +
        hmd.quaternion.z + ', ' +
        hmd.quaternion.w + '];';

    chrome.devtools.inspectedWindow.eval( str, function(result, isException) { } );

    renderer.render( scene, camera );
   // requestAnimationFrame( render );

}

window.addEventListener( 'keydown', function ( event ) {

    switch ( event.keyCode ) {

        case 81: // Q
        control.setSpace( control.space === "local" ? "world" : "local" );
        break;

        case 17: // Ctrl
        control.setTranslationSnap( 100 );
        control.setRotationSnap( THREE.Math.degToRad( 15 ) );
        break;

        case 87: // W
        control.setMode( "translate" );
        break;

        case 69: // E
        control.setMode( "rotate" );
        break;

        case 82: // R
        control.setMode( "scale" );
        break;

        case 187:
        case 107: // +, =, num+
        control.setSize( control.size + 0.1 );
        break;

        case 189:
        case 109: // -, _, num-
        control.setSize( Math.max( control.size - 0.1, 0.1 ) );
        break;

    }

});

onWindowResize();
render();

<commit_msg>added invalidation mechanism to prevent unnecessary render calls<commit_after>var display = null;

var container = document.getElementById( 'canvas-container' );

var renderer = new THREE.WebGLRenderer( { antialias: true, alpha: true } );
renderer.setPixelRatio( window.devicePixelRatio );
container.appendChild( renderer.domElement );

var scene = new THREE.Scene();
//var camera = new THREE.PerspectiveCamera( 75, 1, .01, 100 );
//camera.position.set( 1, 1, 1 );
var camera = new THREE.OrthographicCamera( 1 / - 2, 1 / 2, 1 / 2, 1 / - 2, - 5, 10 );
camera.position.set( 2, 2, 2 );
camera.lookAt( scene.position );

var room = new THREE.Mesh( new THREE.BoxGeometry( 5, 2, 3 ), new THREE.MeshNormalMaterial( { side: THREE.BackSide }) );
room.position.y = 1;
scene.add( room );

var hmd = new THREE.Mesh( new THREE.BoxGeometry( .20, .11, .12 ), new THREE.MeshNormalMaterial() );
scene.add( hmd );

var invalidated = true;
function invalidate() {
    invalidated = true;
}

var controls = new THREE.OrbitControls( camera, container );
controls.addEventListener( 'change', invalidate );
controls.target.set( 0, 0, 0 );

var control = new THREE.TransformControls( camera, renderer.domElement );
control.addEventListener( 'change', invalidate );
control.attach( hmd );
control.setSize( .5 );
scene.add( control );

function onWindowResize() {

    var w = container.clientWidth;
    var h = container.clientHeight;

    renderer.setSize( w, h );

    //camera.aspect = w / h;
    //camera.updateProjectionMatrix();

    camera.left = w / - 2;
    camera.right = w / 2;
    camera.top = h / 2;
    camera.bottom = h / - 2;

    camera.updateProjectionMatrix();

    invalidate();

}

window.addEventListener( 'resize', onWindowResize );

function render() {

    var str = 'window.__extHMDResetPose';
    chrome.devtools.inspectedWindow.eval( str, function(result, isException) {
        if( result === true ) {
            invalidate();
            hmd.position.set( 0, 0,0 );
            hmd.quaternion.set( 0, 0, 0, 0 );
            control.detach( hmd );
            control.attach( hmd );
            var str = 'window.__extHMDResetPose = false;';
            chrome.devtools.inspectedWindow.eval( str );
        }
    } );

    if( invalidated ) {

        var str = 'window.__extHMDPosition = [' +
            hmd.position.x + ', ' +
            hmd.position.y + ', ' +
            hmd.position.z + '];';
        str += 'window.__extHMDOrientation = [' +
            hmd.quaternion.x + ', ' +
            hmd.quaternion.y + ', ' +
            hmd.quaternion.z + ', ' +
            hmd.quaternion.w + '];';

        chrome.devtools.inspectedWindow.eval( str );

        renderer.render( scene, camera );
        invalidated = false;
    }

    requestAnimationFrame( render );

}

window.addEventListener( 'keydown', function ( event ) {

    switch ( event.keyCode ) {

        case 81: // Q
        control.setSpace( control.space === "local" ? "world" : "local" );
        break;

        case 17: // Ctrl
        control.setTranslationSnap( 100 );
        control.setRotationSnap( THREE.Math.degToRad( 15 ) );
        break;

        case 87: // W
        control.setMode( "translate" );
        break;

        case 69: // E
        control.setMode( "rotate" );
        break;

        case 82: // R
        control.setMode( "scale" );
        break;

        case 187:
        case 107: // +, =, num+
        control.setSize( control.size + 0.1 );
        break;

        case 189:
        case 109: // -, _, num-
        control.setSize( Math.max( control.size - 0.1, 0.1 ) );
        break;

    }

});

onWindowResize();
render();<|endoftext|>


<commit_before>const renderer = require('ssb-markdown')
const h = require('mutant/h')
const ref = require('ssb-ref')
const nest = require('depnest')

exports.needs = nest({
  'blob.sync.url': 'first',
  'emoji.sync.url': 'first'
})

exports.gives = nest('message.html.markdown')

exports.create = function (api) {
  return nest('message.html.markdown', markdown)

  function markdown (content) {
    if (typeof content === 'string') { content = {text: content} }
    // handle patchwork style mentions.
    var mentions = {}
    if (Array.isArray(content.mentions)) {
      content.mentions.forEach(function (link) {
        if (link.name) mentions['@' + link.name] = link.link
      })
    }

    var md = h('div', {className: 'Markdown'})
    md.innerHTML = renderer.block(content.text, {
      emoji: renderEmoji,
      toUrl: (id) => {
        if (ref.isBlob(id)) return api.blob.sync.url(id)
        return (mentions[id] ? mentions[id] : id)
      },
      imageLink: (id) => id
    })

    return md
  }

  function renderEmoji (emoji) {
    var url = api.emoji.sync.url(emoji)
    if (!url) return ':' + emoji + ':'
    return `
      <img
        src="${encodeURI(url)}"
        alt=":${escape(emoji)}:"
        title=":${escape(emoji)}:"
        class="emoji"
      >
    `
  }
}
<commit_msg>Render custom emoji<commit_after>const renderer = require('ssb-markdown')
const h = require('mutant/h')
const ref = require('ssb-ref')
const nest = require('depnest')

exports.needs = nest({
  'blob.sync.url': 'first',
  'emoji.sync.url': 'first'
})

exports.gives = nest('message.html.markdown')

exports.create = function (api) {
  return nest('message.html.markdown', markdown)

  function markdown (content) {
    if (typeof content === 'string') { content = {text: content} }
    // handle patchwork style mentions and custom emoji.
    var mentions = {}
    var emojiMentions = {}
    if (Array.isArray(content.mentions)) {
      content.mentions.forEach(function (link) {
        if (link && link.name && link.link) {
          if (link.emoji) emojiMentions[link.name] = link.link
          else mentions['@' + link.name] = link.link
        }
      })
    }

    var md = h('div', {className: 'Markdown'})
    md.innerHTML = renderer.block(content.text, {
      emoji: (emoji) => {
        var url = emojiMentions[emoji]
          ? api.blob.sync.url(emojiMentions[emoji])
          : api.emoji.sync.url(emoji)
        return renderEmoji(emoji, url)
      },
      toUrl: (id) => {
        if (ref.isBlob(id)) return api.blob.sync.url(id)
        return mentions[id] || id
      },
      imageLink: (id) => id
    })

    return md
  }

  function renderEmoji (emoji, url) {
    if (!url) return ':' + emoji + ':'
    return `
      <img
        src="${encodeURI(url)}"
        alt=":${escape(emoji)}:"
        title=":${escape(emoji)}:"
        class="emoji"
      >
    `
  }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2012, Yahoo! Inc.  All rights reserved.
 * Copyrights licensed under the New BSD License.
 * See the accompanying LICENSE file for terms.
 */

/*jslint anon:true, nomen:true, node:true*/
/*global YUI*/

/**
 * @module ResourceStoreAddon
 */

/**
 * RS addon that computes AC addon dependencies at startup to be attached
 * at runtime.
 *
 * @class RSAddonDispatchHelper
 * @extension ResourceStore.server
 */
YUI.add('addon-rs-dispatch-helper', function (Y, NAME) {

    'use strict';

    var libpath = require('path');

    function RSAddonDispatchHelper() {
        RSAddonDispatchHelper.superclass.constructor.apply(this, arguments);
    }

    RSAddonDispatchHelper.NS = 'dispatch-helper';

    Y.extend(RSAddonDispatchHelper, Y.Plugin.Base, {

        initializer: function (config) {
            this.acAddons = {}; // env: poslKey: mojit: details
            this.onHostEvent('mojitResourcesResolved', this.onMojitResourcesResolved, this);
            this.onHostEvent('getMojitTypeDetails', this.onGetMojitTypeDetails, this);
        },

        /**
         * This is called when the ResourceStore fires this event.
         * It augments the mojit type details with the precomputed YUI module
         * dependencies.
         * @method onGetMojitTypeDetails
         * @param {object} evt The fired event.
         * @return {nothing}
         */
        onGetMojitTypeDetails: function (evt) {
            var dest = evt.mojit,
                env = evt.args.env,
                ctx = evt.args.ctx,
                posl = evt.args.posl,
                poslKey = JSON.stringify(posl),
                mojitType = evt.args.mojitType;
            dest.acAddons = {};
            if (this.acAddons[env] && this.acAddons[env][poslKey] && this.acAddons[env][poslKey][mojitType]) {
                dest.acAddons = this.acAddons[env][poslKey][mojitType];
            }
        },

        /**
         * This is called when the ResourceStore fires this event.
         * It precomputes the YUI module dependencies, to be used later during
         * onGetMojitTypeDetails.
         * @method onMojitResourcesResolved
         * @param {object} evt The fired event
         * @return {nothing}
         */
        onMojitResourcesResolved: function (evt) {
            var store = this.get('host'),
                env = evt.env,
                posl = evt.posl,
                poslKey = JSON.stringify(posl),
                mojitType = evt.mojit,
                r,
                res,
                ress = evt.ress,
                controllerYuiName,
                modules = {},
                required = {},
                sorted,
                yuiName,
                addonName,
                acAddonNames = {};   // YUI module: addon name

            if (!evt.ress) {
                return;
            }

            if ('shared' === mojitType) {
                return;
            }

            for (r = 0; r < ress.length; r += 1) {
                res = ress[r];
                if (!res.yui || !res.yui.name) {
                    continue;
                }
                if ('controller' === res.type) {
                    controllerYuiName = res.yui.name;
                    modules[res.yui.name] = this.get('host').yui._makeYUIModuleConfig(env, res);
                }
                if ('addon' === res.type && 'ac' === res.subtype) {
                    modules[res.yui.name] = this.get('host').yui._makeYUIModuleConfig(env, res);
                    acAddonNames[res.yui.name] = libpath.basename(res.name);
                }
            }

            if (!controllerYuiName) {
                // It's not an error if a mojit is missing a controller, since
                // some mojits only run on the server side (or only on the
                // client side).
                return;
            }

            // setting up the proper namespace for the cache.
            this.acAddons[env] = this.acAddons[env] || {};
            this.acAddons[env][poslKey] = this.acAddons[env][poslKey] || {};
            // TODO: should we worry if this.acAddons[env][poslKey][mojitType] is set
            //       at this point? It should never happen.
            this.acAddons[env][poslKey][mojitType] = [];

            required[controllerYuiName] = true;
            // the language doesn't matter for this
            sorted = store.yui._precomputeYUIDependencies('en', env, mojitType, modules, required);
            for (yuiName in sorted.paths) {
                if (sorted.paths.hasOwnProperty(yuiName)) {
                    addonName = acAddonNames[yuiName];
                    if (addonName) {
                        this.acAddons[env][poslKey][mojitType].push(addonName);
                    }
                }
            }
        }

    });

    Y.namespace('mojito.addons.rs')['dispatch-helper'] = RSAddonDispatchHelper;

}, '0.0.1', { requires: [
    'addon-rs-yui',
    'plugin',
    'oop'
]});
<commit_msg>adding a BIG comment for the hack<commit_after>/*
 * Copyright (c) 2012, Yahoo! Inc.  All rights reserved.
 * Copyrights licensed under the New BSD License.
 * See the accompanying LICENSE file for terms.
 */

/*jslint anon:true, nomen:true, node:true*/
/*global YUI*/

/**
 * @module ResourceStoreAddon
 */

/**
 * RS addon that computes AC addon dependencies at startup to be attached
 * at runtime.
 *
 * @class RSAddonDispatchHelper
 * @extension ResourceStore.server
 */
YUI.add('addon-rs-dispatch-helper', function (Y, NAME) {

    'use strict';

    var libpath = require('path');

    function RSAddonDispatchHelper() {
        RSAddonDispatchHelper.superclass.constructor.apply(this, arguments);
    }

    RSAddonDispatchHelper.NS = 'dispatch-helper';

    Y.extend(RSAddonDispatchHelper, Y.Plugin.Base, {

        initializer: function (config) {
            this.acAddons = {}; // env: poslKey: mojit: details
            this.onHostEvent('mojitResourcesResolved', this.onMojitResourcesResolved, this);
            this.onHostEvent('getMojitTypeDetails', this.onGetMojitTypeDetails, this);
        },

        /**
         * This is called when the ResourceStore fires this event.
         * It augments the mojit type details with the precomputed YUI module
         * dependencies.
         * @method onGetMojitTypeDetails
         * @param {object} evt The fired event.
         * @return {nothing}
         */
        onGetMojitTypeDetails: function (evt) {
            var dest = evt.mojit,
                env = evt.args.env,
                ctx = evt.args.ctx,
                posl = evt.args.posl,
                poslKey = JSON.stringify(posl),
                mojitType = evt.args.mojitType;
            dest.acAddons = {};
            if (this.acAddons[env] && this.acAddons[env][poslKey] && this.acAddons[env][poslKey][mojitType]) {
                dest.acAddons = this.acAddons[env][poslKey][mojitType];
            }
        },

        /**
         * This is called when the ResourceStore fires this event.
         * It precomputes the YUI module dependencies, to be used later during
         * onGetMojitTypeDetails.
         * @method onMojitResourcesResolved
         * @param {object} evt The fired event
         * @return {nothing}
         */
        onMojitResourcesResolved: function (evt) {
            var store = this.get('host'),
                env = evt.env,
                posl = evt.posl,
                poslKey = JSON.stringify(posl),
                mojitType = evt.mojit,
                r,
                res,
                ress = evt.ress,
                controllerYuiName,
                modules = {},
                required = {},
                sorted,
                yuiName,
                addonName,
                acAddonNames = {};   // YUI module: addon name

            if (!evt.ress) {
                return;
            }

            if ('shared' === mojitType) {
                return;
            }

            for (r = 0; r < ress.length; r += 1) {
                res = ress[r];
                if (!res.yui || !res.yui.name) {
                    continue;
                }
                if ('controller' === res.type) {
                    controllerYuiName = res.yui.name;
                    modules[res.yui.name] = this.get('host').yui._makeYUIModuleConfig(env, res);
                }
                if ('addon' === res.type && 'ac' === res.subtype) {
                    modules[res.yui.name] = this.get('host').yui._makeYUIModuleConfig(env, res);
                    // HACK/TODO: we are assuming the name of the filename will be
                    // the same as the addon namespace. This is a bold assumption
                    // and we will do the right thing eventually.
                    acAddonNames[res.yui.name] = libpath.basename(res.name);
                }
            }

            if (!controllerYuiName) {
                // It's not an error if a mojit is missing a controller, since
                // some mojits only run on the server side (or only on the
                // client side).
                return;
            }

            // setting up the proper namespace for the cache.
            this.acAddons[env] = this.acAddons[env] || {};
            this.acAddons[env][poslKey] = this.acAddons[env][poslKey] || {};
            // TODO: should we worry if this.acAddons[env][poslKey][mojitType] is set
            //       at this point? It should never happen.
            this.acAddons[env][poslKey][mojitType] = [];

            required[controllerYuiName] = true;
            // the language doesn't matter for this
            sorted = store.yui._precomputeYUIDependencies('en', env, mojitType, modules, required);
            for (yuiName in sorted.paths) {
                if (sorted.paths.hasOwnProperty(yuiName)) {
                    addonName = acAddonNames[yuiName];
                    if (addonName) {
                        this.acAddons[env][poslKey][mojitType].push(addonName);
                    }
                }
            }
        }

    });

    Y.namespace('mojito.addons.rs')['dispatch-helper'] = RSAddonDispatchHelper;

}, '0.0.1', { requires: [
    'addon-rs-yui',
    'plugin',
    'oop'
]});
<|endoftext|>


<commit_before>"use strict";
let map;

var init = function(options) {
	map = setupMap(options);
}

var commands = function(bot, options, action) {
	const message = action.message;
	const words = message.split(" ");

	let args = words.slice(); // copy words
	args.splice(0, 1); // remove command
	args = args.join(" ");

	const target = args.split(/[ ,]/g).filter(Boolean).join(", ");
	const url = map.get(words[0]);
	if (url) {
		bot.say(action.target, (target ? target + ": " + url : url));
	}
};

function setupMap(options) {
	const temp = new Map();
	temp.set(options.commandPrefix + "css", "https://github.com/thelounge/lounge/wiki/CSS-Modifications");
	temp.set(options.commandPrefix + "wiki", "https://github.com/thelounge/lounge/wiki/");
	temp.set(options.commandPrefix + "docs", "https://thelounge.github.io/docs/");
	temp.set(options.commandPrefix + "releases", "https://github.com/thelounge/lounge/release");
	return temp;
}

module.exports = {init, commands};
<commit_msg>Use function to fix lint<commit_after>"use strict";
let map;

function init(options) {
	map = setupMap(options);
}

function commands(bot, options, action) {
	const message = action.message;
	const words = message.split(" ");

	let args = words.slice(); // copy words
	args.splice(0, 1); // remove command
	args = args.join(" ");

	const target = args.split(/[ ,]/g).filter(Boolean).join(", ");
	const url = map.get(words[0]);
	if (url) {
		bot.say(action.target, (target ? target + ": " + url : url));
	}
}

function setupMap(options) {
	const temp = new Map();
	temp.set(options.commandPrefix + "css", "https://github.com/thelounge/lounge/wiki/CSS-Modifications");
	temp.set(options.commandPrefix + "wiki", "https://github.com/thelounge/lounge/wiki/");
	temp.set(options.commandPrefix + "docs", "https://thelounge.github.io/docs/");
	temp.set(options.commandPrefix + "releases", "https://github.com/thelounge/lounge/release");
	return temp;
}

module.exports = {init, commands};
<|endoftext|>


<commit_before>(function ($) {
    "use strict";

    $.extend({

        prototype: {
            each: function () {
                var
                    self = this,
                    i,
                    callback,
                    obj;

                // resolve args
                if (typeof arguments[0] === "function") {
                    callback = arguments[0];
                    obj = self;
                } else if (arguments[0] instanceof Object &&
                    arguments[1]) {
                    obj = arguments[0];
                    callback = arguments[1];
                }

                for (i in obj) {
                    if (obj.hasOwnProperty(i) && !isNaN(parseInt(i, 10))) {
                        callback(obj[i], i);
                    } else {
                        break;
                    }
                }
            }

        }

    });

})(esPhinx);
<commit_msg>remove iterators<commit_after><|endoftext|>


<commit_before>Videbligo.directive('lastmodification', ['MetadataService', '$compile', function(MetadataService, $compile) {

    return {
        restrict: 'AE',
        templateUrl: 'lastmodification_widget/lastmodification.html',
        scope: {},
        link: function(scope, element, attrs) {
            scope.groupLastMod = {};
            scope.dimLastMod = {};
            scope.triggerInProgress = false;

            scope.init = function(){
                scope.data = MetadataService.getData();
                scope.dimLastMod = scope.data.dimension(function(d){
                    var date = d3.time.month(new Date(d.metadata_modified));
                    return date;
                });

                scope.groupLastMod = scope.dimLastMod.group();
                var last = new Date(scope.dimLastMod.top(1)[0].metadata_modified);
                var first = new Date(scope.dimLastMod.bottom(1)[0].metadata_modified);

                dc.constants.EVENT_DELAY = 100;

                var chart = dc.barChart('#last-modification-chart');

                var yMax = d3.max(scope.groupLastMod.all(), function(d) { return d.value; });
                chart.width(600)
                    .height(200)
                    .margins({top: 0, right: 50, bottom: 20, left: 40})
                    .dimension(scope.dimLastMod)
                    .group(scope.groupLastMod)
                    .elasticY(true)
                    .centerBar(true)
                    .gap(1)
                    .transitionDuration(1000)
                    .x(d3.time.scale().domain([first, last]))
                    .round(d3.time.month.round)
                    .xUnits(d3.time.months);

                chart.on("filtered", function(chart, filter){//SUPER MEGA HACKY, besserer weg muss her
                    //if(!scope.triggerInProgress){
                    //    scope.triggerInProgress = true;
                    //    setTimeout(function(){
                    //        scope.triggerInProgress = false;
                    //    }, 1000);
                    //}
                    //console.log('whoooop whooop');
                    //console.log(filter);
                    //MetadataService.triggerUpdate();
                });

                chart.render();
                scope.chart = chart;

                scope.lastModMouseUp = function() {
                    console.log('mouseup');
                    MetadataService.triggerUpdate();
                };

            }

            scope.$on('filterChanged', function() {
                scope.chart.render();
            });

            MetadataService.registerWidget(scope.init);
        }
    };
}]);
<commit_msg>added debouncer<commit_after>Videbligo.directive('lastmodification', ['MetadataService', '$compile', function(MetadataService, $compile) {

    return {
        restrict: 'AE',
        templateUrl: 'lastmodification_widget/lastmodification.html',
        scope: {},
        link: function(scope, element, attrs) {
            scope.groupLastMod = {};
            scope.dimLastMod = {};
            scope.triggerInProgress = false;

            scope.init = function(){
                scope.data = MetadataService.getData();
                scope.dimLastMod = scope.data.dimension(function(d){
                    var date = d3.time.month(new Date(d.metadata_modified));
                    return date;
                });

                scope.groupLastMod = scope.dimLastMod.group();
                var last = new Date(scope.dimLastMod.top(1)[0].metadata_modified);
                var first = new Date(scope.dimLastMod.bottom(1)[0].metadata_modified);

                var yMax = d3.max(scope.groupLastMod.all(), function(d) { return d.value; });
                var chart = dc.barChart('#last-modification-chart');

                scope.debounceTriggerUpdate = debounce(function () {
                    console.log("executing");
                    MetadataService.triggerUpdate();
                }, 500);

                chart.width(600)
                    .height(200)
                    .margins({top: 0, right: 50, bottom: 20, left: 40})
                    .dimension(scope.dimLastMod)
                    .group(scope.groupLastMod)
                    .elasticY(true)
                    .centerBar(true)
                    .gap(1)
                    .transitionDuration(1000)
                    .x(d3.time.scale().domain([first, last]))
                    .round(d3.time.month.round)
                    .xUnits(d3.time.months);

                chart.on("filtered", function(chart, filter){
                    console.log("debouncing");
                    scope.debounceTriggerUpdate();
                });

                $compile(angular.element("#last-modification-chart"))(scope);
                chart.render();
                scope.chart = chart;
            }

            scope.$on('filterChanged', function() {
                scope.chart.render();
            });

            MetadataService.registerWidget(scope.init);
        }
    };
}]);

function debounce(func, wait, immediate) {
    var timeout;
    return function() {
        var context = this, args = arguments;
        var later = function() {
            timeout = null;
            if (!immediate) func.apply(context, args);
        };
        var callNow = immediate && !timeout;
        clearTimeout(timeout);
        timeout = setTimeout(later, wait);
        if (callNow) func.apply(context, args);
    };
}
<|endoftext|>


<commit_before>function Tessel(tessel) {
	this.tessel = tessel;
	this.modules = {};
	this.wifi = null;
	this.onWifiConnectedCallbacks = [];
	this.wifiReconnecting = false;
	this.externalLogger = null;
}

Tessel.prototype.log = function(message) {
	message += " [" + new Date() + "]";
	if (this.externalLogger) {
		this.externalLogger.log(message);
	} else {
		console.log(message);
	}
	return this;
};

Tessel.prototype.workflow = function(wf) {
	var self = this;

	function blinkStatus(blinkInfo) {
		(function doBlinkStatus() {
			self.tessel.led[0].toggle();
			if (++blinkInfo.index < blinkInfo.total) {
				setTimeout(doBlinkStatus, blinkInfo.interval);
			} else {
				self.tessel.led[0].output(0);
			}
		})();
	}

	function blinkWF(blinkInfo) {
		(function doBlinkWF() {
			self.tessel.led[1].toggle();
			if (++blinkInfo.index < blinkInfo.total) {
				setTimeout(doBlinkWF, blinkInfo.interval);
			} else {
				self.tessel.led[1].output(0);
			}
		})();
	}

	function createBlinkInfo(info, err, id) {
		var blinkCount = 1,
			blinkInterval = 300;
		if (err) {
			blinkCount = 20;
		}
		return {
			index: 0,
			total: blinkCount,
			interval: blinkInterval,
			id: id
		};
	}

	if (wf && self.tessel) {
		wf.on('statusStart', function() {
			self.tessel.led[0].output(1);
		});
		wf.on('statusComplete', function(info, err) {
			var blinkInfo = createBlinkInfo(info, err, 'status');
			blinkStatus(blinkInfo);
			if (!err && self.modules.relay) {
				if (info.relayChannelOneOn === true) {
					self.modules.relay.turnOn(1);
				} else {
					self.modules.relay.turnOff(1);
				}
				if (info.relayChannelTwoOn === true) {
					self.modules.relay.turnOn(2);
				} else {
					self.modules.relay.turnOff(2);
				}
			}
		});
		wf.on('workflowStart', function() {
			self.tessel.led[1].output(1);
		});
		wf.on('workflowComplete', function(info, err) {
			var blinkInfo = createBlinkInfo(info, err, 'workflow');
			blinkWF(blinkInfo);
		});
	}
	return this;
};

Tessel.prototype.wifi = function(wifi) {
	var self = this;
	this.wifi = wifi;
	wifi.on('connect', function() {
		self.log("I got connected");
		self.onWifiConnectedCallbacks.forEach(function(item) {
			item();
		});
		self.onWifiConnectedCallbacks = [];
	});

	(function reconnectWifi() {
		if(self.wifi.isConneted()) {
			// Recheck in 1 minute
			console.log("Wifi is connected, will check in a minute.");
			setTimeout(reconnectWifi, 60*1000);
		} else if(self.wifi.isBusy()) {
			// Reconnection may be happening, recheck in 10 seconds
			console.log("Wifi is busy, will check in 10 seconds.");
			setTimeout(reconnectWifi, 10*1000);
		} else {
			// Reconnect and give 30 seconds before retrying
			self.wifi.reset();
			console.log("Wifi is reconnecting, will check in 30 seconds.");
			setTimeout(reconnectWifi, 30*1000);
		}
	})();

	/*
	function reconnectWifi() {
		if (!self.wifiReconnecting) {
			self.wifiReconnecting = true;
			setTimeout(function reset() {
				wifi.reset();
				setTimeout(function resetCheck() {
					if (wifi.isConnected()) {
						self.wifiReconnecting = false;
					} else {
						if (wifi.isBusy()) {
							setTimeout(resetCheck, 2000);
						} else {
							reset();
						}
					}
				}, 2000);
			}, 500);
		}
	}

	wifi.on('disconnect', function() {
		self.log("I got disconnected");
		reconnectWifi();
	});

	wifi.on('error', function() {
		self.log("I got errored");
		reconnectWifi();
	});
	*/
	return this;
};

Tessel.prototype.relay = function(module) {
	this.modules.relay = module;
	return this;
};

Tessel.prototype.climate = function(module) {
	this.modules.climate = module;
	return this;
};

Tessel.prototype.ambient = function(module) {
	this.modules.ambient = module;
	this.resetAmbientStats();
	return this;
};

Tessel.prototype.stopAmbientStats = function() {
	if (this.modules.ambientStatsInterval) {
		clearInterval(this.modules.ambientStatsInterval);
	}
};

Tessel.prototype.resetAmbientStats = function() {
	var self = this;
	var maxValue = Number.MAX_VALUE || 9999999999999999;
	this.modules.ambientStats = {
		light: [],
		sound: []
	};

	this.modules.ambientStatsInterval = setInterval(function() {
		self.modules.ambient.getLightLevel(function(err, ldata) {
			self.modules.ambientStats.light.push(ldata);
			self.modules.ambient.getSoundLevel(function(err, sdata) {
				self.modules.ambientStats.sound.push(sdata);
			});
		});
	}, 500);
	return this;
};

Tessel.prototype.readClimate = function(data, done) {
	data = data || {};
	var self = this;
	if (self.modules.climate) {
		self.modules.climate.readTemperature('f', function(err, temp) {
			data.temperature = temp.toFixed(4);
			self.modules.climate.readHumidity(function(err, humid) {
				data.humidity = humid.toFixed(4);
				done(data);
			});
		});
	} else {
		done(data);
	}
	return this;
};

Tessel.prototype.readAmbient = function(data, done) {
	data = data || {};
	var self = this;
	if (self.modules.ambient) {
		self.stopAmbientStats();
		self.modules.ambient.getSoundLevel(function(err, sound) {
			self.modules.ambientStats.sound.push(sound);
			self.modules.ambient.getLightLevel(function(err, light) {
				self.modules.ambientStats.light.push(light);
				data.light = self.modules.ambientStats.light
				data.sound = self.modules.ambientStats.sound;
				self.resetAmbientStats();
				done(data);
			});
		});
	} else {
		done(data);
	}
	return this;
};

Tessel.prototype.runWifiRequiredTask = function(task) {
	if (this.wifi) {
		if (this.wifi.isConnected()) {
			task();
		} else {
			this.onWifiConnectedCallbacks.push(task);
		}
	} else {
		task();
	}
};

Tessel.prototype.read = function(data, done) {
	data = data || {};
	var self = this;
	self.runWifiRequiredTask(function() {
		self.readClimate(data, function() {
			self.readAmbient(data, function() {
				done(data);
			});
		});
	});
	return this;
};

module.exports = function(api, config) {
	api.tessel = function(tessel) {
		return new Tessel(tessel);
	};
};<commit_msg>Fixed wifi interval check<commit_after>function Tessel(tessel) {
	this.tessel = tessel;
	this.modules = {};
	this.wifi = null;
	this.onWifiConnectedCallbacks = [];
	this.wifiReconnecting = false;
	this.externalLogger = null;
}

Tessel.prototype.log = function(message) {
	message += " [" + new Date() + "]";
	if (this.externalLogger) {
		this.externalLogger.log(message);
	} else {
		console.log(message);
	}
	return this;
};

Tessel.prototype.workflow = function(wf) {
	var self = this;

	function blinkStatus(blinkInfo) {
		(function doBlinkStatus() {
			self.tessel.led[0].toggle();
			if (++blinkInfo.index < blinkInfo.total) {
				setTimeout(doBlinkStatus, blinkInfo.interval);
			} else {
				self.tessel.led[0].output(0);
			}
		})();
	}

	function blinkWF(blinkInfo) {
		(function doBlinkWF() {
			self.tessel.led[1].toggle();
			if (++blinkInfo.index < blinkInfo.total) {
				setTimeout(doBlinkWF, blinkInfo.interval);
			} else {
				self.tessel.led[1].output(0);
			}
		})();
	}

	function createBlinkInfo(info, err, id) {
		var blinkCount = 1,
			blinkInterval = 300;
		if (err) {
			blinkCount = 20;
		}
		return {
			index: 0,
			total: blinkCount,
			interval: blinkInterval,
			id: id
		};
	}

	if (wf && self.tessel) {
		wf.on('statusStart', function() {
			self.tessel.led[0].output(1);
		});
		wf.on('statusComplete', function(info, err) {
			var blinkInfo = createBlinkInfo(info, err, 'status');
			blinkStatus(blinkInfo);
			if (!err && self.modules.relay) {
				if (info.relayChannelOneOn === true) {
					self.modules.relay.turnOn(1);
				} else {
					self.modules.relay.turnOff(1);
				}
				if (info.relayChannelTwoOn === true) {
					self.modules.relay.turnOn(2);
				} else {
					self.modules.relay.turnOff(2);
				}
			}
		});
		wf.on('workflowStart', function() {
			self.tessel.led[1].output(1);
		});
		wf.on('workflowComplete', function(info, err) {
			var blinkInfo = createBlinkInfo(info, err, 'workflow');
			blinkWF(blinkInfo);
		});
	}
	return this;
};

Tessel.prototype.wifi = function(wifi) {
	var self = this;
	self.wifi = wifi;
	wifi.on('connect', function() {
		self.log("I got connected");
		self.onWifiConnectedCallbacks.forEach(function(item) {
			item();
		});
		self.onWifiConnectedCallbacks = [];
	});

	(function(wifi) {
		function reconnectWifi() {
			if(wifi.isConneted()) {
				// Recheck in 1 minute
				console.log("Wifi is connected, will check in a minute.");
				setTimeout(reconnectWifi, 60*1000);
			} else if(wifi.isBusy()) {
				// Reconnection may be happening, recheck in 10 seconds
				console.log("Wifi is busy, will check in 10 seconds.");
				setTimeout(reconnectWifi, 10*1000);
			} else {
				// Reconnect and give 30 seconds before retrying
				wifi.reset();
				console.log("Wifi is reconnecting, will check in 30 seconds.");
				setTimeout(reconnectWifi, 30*1000);
			}
		}
	})(wifi);

	/*
	function reconnectWifi() {
		if (!self.wifiReconnecting) {
			self.wifiReconnecting = true;
			setTimeout(function reset() {
				wifi.reset();
				setTimeout(function resetCheck() {
					if (wifi.isConnected()) {
						self.wifiReconnecting = false;
					} else {
						if (wifi.isBusy()) {
							setTimeout(resetCheck, 2000);
						} else {
							reset();
						}
					}
				}, 2000);
			}, 500);
		}
	}

	wifi.on('disconnect', function() {
		self.log("I got disconnected");
		reconnectWifi();
	});

	wifi.on('error', function() {
		self.log("I got errored");
		reconnectWifi();
	});
	*/
	return this;
};

Tessel.prototype.relay = function(module) {
	this.modules.relay = module;
	return this;
};

Tessel.prototype.climate = function(module) {
	this.modules.climate = module;
	return this;
};

Tessel.prototype.ambient = function(module) {
	this.modules.ambient = module;
	this.resetAmbientStats();
	return this;
};

Tessel.prototype.stopAmbientStats = function() {
	if (this.modules.ambientStatsInterval) {
		clearInterval(this.modules.ambientStatsInterval);
	}
};

Tessel.prototype.resetAmbientStats = function() {
	var self = this;
	var maxValue = Number.MAX_VALUE || 9999999999999999;
	this.modules.ambientStats = {
		light: [],
		sound: []
	};

	this.modules.ambientStatsInterval = setInterval(function() {
		self.modules.ambient.getLightLevel(function(err, ldata) {
			self.modules.ambientStats.light.push(ldata);
			self.modules.ambient.getSoundLevel(function(err, sdata) {
				self.modules.ambientStats.sound.push(sdata);
			});
		});
	}, 500);
	return this;
};

Tessel.prototype.readClimate = function(data, done) {
	data = data || {};
	var self = this;
	if (self.modules.climate) {
		self.modules.climate.readTemperature('f', function(err, temp) {
			data.temperature = temp.toFixed(4);
			self.modules.climate.readHumidity(function(err, humid) {
				data.humidity = humid.toFixed(4);
				done(data);
			});
		});
	} else {
		done(data);
	}
	return this;
};

Tessel.prototype.readAmbient = function(data, done) {
	data = data || {};
	var self = this;
	if (self.modules.ambient) {
		self.stopAmbientStats();
		self.modules.ambient.getSoundLevel(function(err, sound) {
			self.modules.ambientStats.sound.push(sound);
			self.modules.ambient.getLightLevel(function(err, light) {
				self.modules.ambientStats.light.push(light);
				data.light = self.modules.ambientStats.light;
				data.sound = self.modules.ambientStats.sound;
				self.resetAmbientStats();
				done(data);
			});
		});
	} else {
		done(data);
	}
	return this;
};

Tessel.prototype.runWifiRequiredTask = function(task) {
	if (this.wifi) {
		if (this.wifi.isConnected()) {
			task();
		} else {
			this.onWifiConnectedCallbacks.push(task);
		}
	} else {
		task();
	}
};

Tessel.prototype.read = function(data, done) {
	data = data || {};
	var self = this;
	self.runWifiRequiredTask(function() {
		self.readClimate(data, function() {
			self.readAmbient(data, function() {
				done(data);
			});
		});
	});
	return this;
};

module.exports = function(api, config) {
	api.tessel = function(tessel) {
		return new Tessel(tessel);
	};
};<|endoftext|>


<commit_before>var deps = [
require('utils'),
require('storage_manager'),
require('device_manager'),
require('parser'),
require('selector_manager'),
require('modal_dialog'),
require('code_manager'),
require('panels'),
require('rich_text_editor'),
require('style_manager'),
require('asset_manager'),
require('css_composer'),
require('dom_components'),
require('canvas'),
require('commands'),
require('block_manager'),
require('trait_manager'),
];

var Backbone = require('backbone');
var UndoManager = require('backbone-undo');
var key = require('keymaster');
var timedInterval;

module.exports = Backbone.Model.extend({

  defaults: {
    clipboard: null,
    designerMode: false,
    selectedComponent: null,
    previousModel: null,
    changesCount:  0,
    storables: [],
    toLoad: [],
    opened: {},
    device: '',
  },

  initialize(c) {
    this.config = c;
    this.set('Config', c);

    if(c.el && c.fromElement)
      this.config.components = c.el.innerHTML;

    // Load modules
    deps.forEach(function(name){
      this.loadModule(name);
    }, this);

    // Call modules with onLoad callback
    this.get('toLoad').forEach(M => {
      M.onLoad();
    });

    this.loadOnStart();
    this.initUndoManager();

    this.on('change:selectedComponent', this.componentSelected, this);
    this.on('change:changesCount', this.updateBeforeUnload, this);
  },

  /**
   * Load on start if it was requested
   * @private
   */
  loadOnStart() {
    const sm = this.get('StorageManager');

    if (sm && sm.getConfig().autoload) {
      this.load();
    }
  },

  /**
   * Set the alert before unload in case it's requested
   * and there are unsaved changes
   */
  updateBeforeUnload() {
    var changes = this.get('changesCount');

    if (this.config.noticeOnUnload && changes) {
      window.onbeforeunload = e => 1;
    } else {
      window.onbeforeunload = null;
    }
  },

  /**
   * Load generic module
   * @param {String} moduleName Module name
   * @return {this}
   */
  loadModule(moduleName) {
    var c = this.config;
    var M = new moduleName();
    var name = M.name.charAt(0).toLowerCase() + M.name.slice(1);
    var cfg = c[name] || c[M.name] || {};
    cfg.pStylePrefix = c.pStylePrefix || '';

    // Check if module is storable
    var sm = this.get('StorageManager');
    if(M.storageKey && M.store && M.load && sm){
      cfg.stm = sm;
      var storables = this.get('storables');
      storables.push(M);
      this.set('storables', storables);
    }
    cfg.em = this;
    M.init(Object.create(cfg));

    // Bind the module to the editor model if public
    if(!M.private)
      this.set(M.name, M);

    if(M.onLoad)
      this.get('toLoad').push(M);

    return this;
  },

  /**
   * Initialize editor model and set editor instance
   * @param {Editor} editor Editor instance
   * @return {this}
   * @private
   */
  init(editor) {
    this.set('Editor', editor);
  },

  /**
   * Listen for new rules
   * @param {Object} collection
   * @private
   */
  listenRules(collection) {
    this.stopListening(collection, 'add remove', this.listenRule);
    this.listenTo(collection, 'add remove', this.listenRule);
    collection.each(function(model){
      this.listenRule(model);
    }, this);
  },

  /**
   * Listen for rule changes
   * @param {Object} model
   * @private
   */
  listenRule(model) {
    this.stopListening(model, 'change:style', this.componentsUpdated);
    this.listenTo(model, 'change:style', this.componentsUpdated);
  },

  /**
   * Triggered when something in components is changed
   * @param  {Object}  model
   * @param  {Mixed}    val  Value
   * @param  {Object}  opt  Options
   * @private
   * */
  componentsUpdated(model, val, opt) {
    timedInterval && clearInterval(timedInterval);
    timedInterval = setTimeout(() => {
      var count = this.get('changesCount') + 1;
      var avoidStore = opt ? opt.avoidStore : 0;
      var stm = this.get('StorageManager');
      this.set('changesCount', count);

      if (!stm.isAutosave() || count < stm.getStepsBeforeSave()) {
        return;
      }

      if (!avoidStore) {
        this.store();
      }
    }, 0);
  },

  /**
   * Initialize Undo manager
   * @private
   * */
  initUndoManager() {
    if(this.um)
      return;
    var cmp = this.get('DomComponents');
    if(cmp && this.config.undoManager){
      var that = this;
      this.um = new UndoManager({
          register: [cmp.getComponents(), this.get('CssComposer').getAll()],
          track: true
      });
      this.UndoManager = this.um;
      this.set('UndoManager', this.um);
      key('⌘+z, ctrl+z', () => {
        that.um.undo(true);
        that.trigger('component:update');
      });
      key('⌘+shift+z, ctrl+shift+z', () => {
        that.um.redo(true);
        that.trigger('component:update');
      });

      UndoManager.removeUndoType("change");
      var beforeCache;
      UndoManager.addUndoType("change:style", {
        "on": function (model, value, opts) {
          var opt = opts || {};
          if(!beforeCache){
            beforeCache = model.previousAttributes();
          }
          if (opt && opt.avoidStore) {
            return;
          } else {
            var obj = {
                "object": model,
                "before": beforeCache,
                "after": model.toJSON()
            };
            beforeCache = null;
            return obj;
          }
        },
        "undo": function (model, bf, af, opt) {
          model.set(bf);
          // Update also inputs inside Style Manager
          that.trigger('change:selectedComponent');
        },
        "redo": function (model, bf, af, opt) {
          model.set(af);
          // Update also inputs inside Style Manager
          that.trigger('change:selectedComponent');
        }
      });
    }
  },

  /**
   * Callback on component selection
   * @param   {Object}   Model
   * @param   {Mixed}   New value
   * @param   {Object}   Options
   * @private
   * */
  componentSelected(model, val, options) {
    if(!this.get('selectedComponent'))
      this.trigger('deselect-comp');
    else
      this.trigger('select-comp',[model,val,options]);
  },

  /**
   * Triggered when components are updated
   * @param  {Object}  model
   * @param  {Mixed}    val  Value
   * @param  {Object}  opt  Options
   * @private
   * */
  updateComponents(model, val, opt) {
    var comps  = model.get('components'),
        classes  = model.get('classes'),
        avSt  = opt ? opt.avoidStore : 0;

    // Observe component with Undo Manager
    if(this.um)
      this.um.register(comps);

    // Call stopListening for not creating nested listeners
    this.stopListening(comps, 'add', this.updateComponents);
    this.stopListening(comps, 'remove', this.rmComponents);
    this.listenTo(comps, 'add', this.updateComponents);
    this.listenTo(comps, 'remove', this.rmComponents);

    this.stopListening(classes, 'add remove', this.componentsUpdated);
    this.listenTo(classes, 'add remove', this.componentsUpdated);

    var evn = 'change:style change:content';
    this.stopListening(model, evn, this.componentsUpdated);
    this.listenTo(model, evn, this.componentsUpdated);

    if(!avSt)
      this.componentsUpdated();
  },

  /**
   * Init stuff like storage for already existing elements
   * @param {Object}  model
   * @private
   */
  initChildrenComp(model) {
      var comps  = model.get('components');
      this.updateComponents(model, null, { avoidStore : 1 });
      comps.each(function(md) {
          this.initChildrenComp(md);
          if(this.um)
            this.um.register(md);
      }, this);
  },

  /**
   * Triggered when some component is removed updated
   * @param  {Object}  model
   * @param  {Mixed}    val  Value
   * @param  {Object}  opt  Options
   * @private
   * */
  rmComponents(model, val, opt) {
    var avSt  = opt ? opt.avoidStore : 0;

    if(!avSt)
      this.componentsUpdated();
  },

  /**
   * Returns model of the selected component
   * @return {Component|null}
   * @private
   */
  getSelected() {
    return this.get('selectedComponent');
  },

  /**
   * Set components inside editor's canvas. This method overrides actual components
   * @param {Object|string} components HTML string or components model
   * @return {this}
   * @private
   */
  setComponents(components) {
    return this.get('DomComponents').setComponents(components);
  },

  /**
   * Returns components model from the editor's canvas
   * @return {Components}
   * @private
   */
  getComponents() {
    var cmp = this.get('DomComponents');
    var cm = this.get('CodeManager');

    if(!cmp || !cm)
      return;

    var wrp  = cmp.getComponents();
    return cm.getCode(wrp, 'json');
  },

  /**
   * Set style inside editor's canvas. This method overrides actual style
   * @param {Object|string} style CSS string or style model
   * @return {this}
   * @private
   */
  setStyle(style) {
    var rules = this.get('CssComposer').getAll();
    for(var i = 0, len = rules.length; i < len; i++)
      rules.pop();
    rules.add(style);
    return this;
  },

  /**
   * Returns rules/style model from the editor's canvas
   * @return {Rules}
   * @private
   */
  getStyle() {
    return this.get('CssComposer').getAll();
  },

  /**
   * Returns HTML built inside canvas
   * @return {string} HTML string
   * @private
   */
  getHtml() {
    var js = this.config.jsInHtml ? this.getJs() : '';
    var wrp  = this.get('DomComponents').getComponent();
    var html = this.get('CodeManager').getCode(wrp, 'html');
    html += js ? '<script>'+ js +'</script>' : '';
    return html;
  },

  /**
   * Returns CSS built inside canvas
   * @return {string} CSS string
   * @private
   */
  getCss() {
    var cssc = this.get('CssComposer');
    var wrp = this.get('DomComponents').getComponent();
    var protCss = this.config.protectedCss;

    return protCss + this.get('CodeManager').getCode(wrp, 'css', cssc);
  },

  /**
   * Returns JS of all components
   * @return {string} JS string
   * @private
   */
  getJs() {
    var wrp = this.get('DomComponents').getWrapper();
    return this.get('CodeManager').getCode(wrp, 'js').trim();
  },

  /**
   * Store data to the current storage
   * @param {Function} clb Callback function
   * @return {Object} Stored data
   * @private
   */
  store(clb) {
    var sm = this.get('StorageManager');
    var store = {};
    if(!sm)
      return;

    // Fetch what to store
    this.get('storables').forEach(m => {
      var obj = m.store(1);
      for(var el in obj)
        store[el] = obj[el];
    });

    sm.store(store, () => {
      clb && clb();
      this.set('changesCount', 0);
      this.trigger('storage:store', store);
    });

    return store;
  },

  /**
   * Load data from the current storage
   * @param {Function} clb Callback function
   * @return {Object} Loaded data
   * @private
   */
  load(clb) {
    var result = this.getCacheLoad(1, clb);
    this.get('storables').forEach(m => {
      m.load(result);
    });
    return result;
  },

  /**
   * Returns cached load
   * @param {Boolean} force Force to reload
   * @param {Function} clb Callback function
   * @return {Object}
   * @private
   */
  getCacheLoad(force, clb) {
    var f = force ? 1 : 0;
    if(this.cacheLoad && !f)
      return this.cacheLoad;
    var sm = this.get('StorageManager');
    var load = [];

    if(!sm)
      return {};

    this.get('storables').forEach(m => {
      var key = m.storageKey;
      key = typeof key === 'function' ? key() : key;
      var keys = key instanceof Array ? key : [key];
      keys.forEach(k => {
        load.push(k);
      });
    });

    this.cacheLoad = sm.load(load, (loaded) => {
      clb && clb(loaded);
      this.trigger('storage:load', loaded);
    });
    return this.cacheLoad;
  },

  /**
   * Returns device model by name
   * @return {Device|null}
   */
  getDeviceModel() {
    var name = this.get('device');
    return this.get('DeviceManager').get(name);
  },

  /**
   * Run default command if setted
   * @private
   */
  runDefault() {
    var command = this.get('Commands').get(this.config.defaultCommand);
    if(!command || this.defaultRunning)
      return;
    command.stop(this, this);
    command.run(this, this);
    this.defaultRunning = 1;
  },

  /**
   * Stop default command
   * @private
   */
  stopDefault() {
    var command = this.get('Commands').get(this.config.defaultCommand);
    if(!command)
      return;
    command.stop(this, this);
    this.defaultRunning = 0;
  },

  /**
   * Update canvas dimensions and refresh data useful for tools positioning
   * @private
   */
  refreshCanvas() {
    this.set('canvasOffset', this.get('Canvas').getOffset());
  },

  /**
   * Clear all selected stuf inside the window, sometimes is useful to call before
   * doing some dragging opearation
   * @param {Window} win If not passed the current one will be used
   * @private
   */
  clearSelection(win) {
    var w = win || window;
    w.getSelection().removeAllRanges();
  },

});
<commit_msg>update store when changing component attributes<commit_after>var deps = [
require('utils'),
require('storage_manager'),
require('device_manager'),
require('parser'),
require('selector_manager'),
require('modal_dialog'),
require('code_manager'),
require('panels'),
require('rich_text_editor'),
require('style_manager'),
require('asset_manager'),
require('css_composer'),
require('dom_components'),
require('canvas'),
require('commands'),
require('block_manager'),
require('trait_manager'),
];

var Backbone = require('backbone');
var UndoManager = require('backbone-undo');
var key = require('keymaster');
var timedInterval;

module.exports = Backbone.Model.extend({

  defaults: {
    clipboard: null,
    designerMode: false,
    selectedComponent: null,
    previousModel: null,
    changesCount:  0,
    storables: [],
    toLoad: [],
    opened: {},
    device: '',
  },

  initialize(c) {
    this.config = c;
    this.set('Config', c);

    if(c.el && c.fromElement)
      this.config.components = c.el.innerHTML;

    // Load modules
    deps.forEach(function(name){
      this.loadModule(name);
    }, this);

    // Call modules with onLoad callback
    this.get('toLoad').forEach(M => {
      M.onLoad();
    });

    this.loadOnStart();
    this.initUndoManager();

    this.on('change:selectedComponent', this.componentSelected, this);
    this.on('change:changesCount', this.updateBeforeUnload, this);
  },

  /**
   * Load on start if it was requested
   * @private
   */
  loadOnStart() {
    const sm = this.get('StorageManager');

    if (sm && sm.getConfig().autoload) {
      this.load();
    }
  },

  /**
   * Set the alert before unload in case it's requested
   * and there are unsaved changes
   */
  updateBeforeUnload() {
    var changes = this.get('changesCount');

    if (this.config.noticeOnUnload && changes) {
      window.onbeforeunload = e => 1;
    } else {
      window.onbeforeunload = null;
    }
  },

  /**
   * Load generic module
   * @param {String} moduleName Module name
   * @return {this}
   */
  loadModule(moduleName) {
    var c = this.config;
    var M = new moduleName();
    var name = M.name.charAt(0).toLowerCase() + M.name.slice(1);
    var cfg = c[name] || c[M.name] || {};
    cfg.pStylePrefix = c.pStylePrefix || '';

    // Check if module is storable
    var sm = this.get('StorageManager');
    if(M.storageKey && M.store && M.load && sm){
      cfg.stm = sm;
      var storables = this.get('storables');
      storables.push(M);
      this.set('storables', storables);
    }
    cfg.em = this;
    M.init(Object.create(cfg));

    // Bind the module to the editor model if public
    if(!M.private)
      this.set(M.name, M);

    if(M.onLoad)
      this.get('toLoad').push(M);

    return this;
  },

  /**
   * Initialize editor model and set editor instance
   * @param {Editor} editor Editor instance
   * @return {this}
   * @private
   */
  init(editor) {
    this.set('Editor', editor);
  },

  /**
   * Listen for new rules
   * @param {Object} collection
   * @private
   */
  listenRules(collection) {
    this.stopListening(collection, 'add remove', this.listenRule);
    this.listenTo(collection, 'add remove', this.listenRule);
    collection.each(function(model){
      this.listenRule(model);
    }, this);
  },

  /**
   * Listen for rule changes
   * @param {Object} model
   * @private
   */
  listenRule(model) {
    this.stopListening(model, 'change:style', this.componentsUpdated);
    this.listenTo(model, 'change:style', this.componentsUpdated);
  },

  /**
   * Triggered when something in components is changed
   * @param  {Object}  model
   * @param  {Mixed}    val  Value
   * @param  {Object}  opt  Options
   * @private
   * */
  componentsUpdated(model, val, opt) {
    timedInterval && clearInterval(timedInterval);
    timedInterval = setTimeout(() => {
      var count = this.get('changesCount') + 1;
      var avoidStore = opt ? opt.avoidStore : 0;
      var stm = this.get('StorageManager');
      this.set('changesCount', count);

      if (!stm.isAutosave() || count < stm.getStepsBeforeSave()) {
        return;
      }

      if (!avoidStore) {
        this.store();
      }
    }, 0);
  },

  /**
   * Initialize Undo manager
   * @private
   * */
  initUndoManager() {
    if(this.um)
      return;
    var cmp = this.get('DomComponents');
    if(cmp && this.config.undoManager){
      var that = this;
      this.um = new UndoManager({
          register: [cmp.getComponents(), this.get('CssComposer').getAll()],
          track: true
      });
      this.UndoManager = this.um;
      this.set('UndoManager', this.um);
      key('⌘+z, ctrl+z', () => {
        that.um.undo(true);
        that.trigger('component:update');
      });
      key('⌘+shift+z, ctrl+shift+z', () => {
        that.um.redo(true);
        that.trigger('component:update');
      });

      UndoManager.removeUndoType("change");
      var beforeCache;
      UndoManager.addUndoType("change:style", {
        "on": function (model, value, opts) {
          var opt = opts || {};
          if(!beforeCache){
            beforeCache = model.previousAttributes();
          }
          if (opt && opt.avoidStore) {
            return;
          } else {
            var obj = {
                "object": model,
                "before": beforeCache,
                "after": model.toJSON()
            };
            beforeCache = null;
            return obj;
          }
        },
        "undo": function (model, bf, af, opt) {
          model.set(bf);
          // Update also inputs inside Style Manager
          that.trigger('change:selectedComponent');
        },
        "redo": function (model, bf, af, opt) {
          model.set(af);
          // Update also inputs inside Style Manager
          that.trigger('change:selectedComponent');
        }
      });
    }
  },

  /**
   * Callback on component selection
   * @param   {Object}   Model
   * @param   {Mixed}   New value
   * @param   {Object}   Options
   * @private
   * */
  componentSelected(model, val, options) {
    if(!this.get('selectedComponent'))
      this.trigger('deselect-comp');
    else
      this.trigger('select-comp',[model,val,options]);
  },

  /**
   * Triggered when components are updated
   * @param  {Object}  model
   * @param  {Mixed}    val  Value
   * @param  {Object}  opt  Options
   * @private
   * */
  updateComponents(model, val, opt) {
    var comps  = model.get('components'),
        classes  = model.get('classes'),
        avSt  = opt ? opt.avoidStore : 0;

    // Observe component with Undo Manager
    if(this.um)
      this.um.register(comps);

    // Call stopListening for not creating nested listeners
    this.stopListening(comps, 'add', this.updateComponents);
    this.stopListening(comps, 'remove', this.rmComponents);
    this.listenTo(comps, 'add', this.updateComponents);
    this.listenTo(comps, 'remove', this.rmComponents);

    this.stopListening(classes, 'add remove', this.componentsUpdated);
    this.listenTo(classes, 'add remove', this.componentsUpdated);

    var evn = 'change:style change:content change:attributes';
    this.stopListening(model, evn, this.componentsUpdated);
    this.listenTo(model, evn, this.componentsUpdated);

    if(!avSt)
      this.componentsUpdated();
  },

  /**
   * Init stuff like storage for already existing elements
   * @param {Object}  model
   * @private
   */
  initChildrenComp(model) {
      var comps  = model.get('components');
      this.updateComponents(model, null, { avoidStore : 1 });
      comps.each(function(md) {
          this.initChildrenComp(md);
          if(this.um)
            this.um.register(md);
      }, this);
  },

  /**
   * Triggered when some component is removed updated
   * @param  {Object}  model
   * @param  {Mixed}    val  Value
   * @param  {Object}  opt  Options
   * @private
   * */
  rmComponents(model, val, opt) {
    var avSt  = opt ? opt.avoidStore : 0;

    if(!avSt)
      this.componentsUpdated();
  },

  /**
   * Returns model of the selected component
   * @return {Component|null}
   * @private
   */
  getSelected() {
    return this.get('selectedComponent');
  },

  /**
   * Set components inside editor's canvas. This method overrides actual components
   * @param {Object|string} components HTML string or components model
   * @return {this}
   * @private
   */
  setComponents(components) {
    return this.get('DomComponents').setComponents(components);
  },

  /**
   * Returns components model from the editor's canvas
   * @return {Components}
   * @private
   */
  getComponents() {
    var cmp = this.get('DomComponents');
    var cm = this.get('CodeManager');

    if(!cmp || !cm)
      return;

    var wrp  = cmp.getComponents();
    return cm.getCode(wrp, 'json');
  },

  /**
   * Set style inside editor's canvas. This method overrides actual style
   * @param {Object|string} style CSS string or style model
   * @return {this}
   * @private
   */
  setStyle(style) {
    var rules = this.get('CssComposer').getAll();
    for(var i = 0, len = rules.length; i < len; i++)
      rules.pop();
    rules.add(style);
    return this;
  },

  /**
   * Returns rules/style model from the editor's canvas
   * @return {Rules}
   * @private
   */
  getStyle() {
    return this.get('CssComposer').getAll();
  },

  /**
   * Returns HTML built inside canvas
   * @return {string} HTML string
   * @private
   */
  getHtml() {
    var js = this.config.jsInHtml ? this.getJs() : '';
    var wrp  = this.get('DomComponents').getComponent();
    var html = this.get('CodeManager').getCode(wrp, 'html');
    html += js ? '<script>'+ js +'</script>' : '';
    return html;
  },

  /**
   * Returns CSS built inside canvas
   * @return {string} CSS string
   * @private
   */
  getCss() {
    var cssc = this.get('CssComposer');
    var wrp = this.get('DomComponents').getComponent();
    var protCss = this.config.protectedCss;

    return protCss + this.get('CodeManager').getCode(wrp, 'css', cssc);
  },

  /**
   * Returns JS of all components
   * @return {string} JS string
   * @private
   */
  getJs() {
    var wrp = this.get('DomComponents').getWrapper();
    return this.get('CodeManager').getCode(wrp, 'js').trim();
  },

  /**
   * Store data to the current storage
   * @param {Function} clb Callback function
   * @return {Object} Stored data
   * @private
   */
  store(clb) {
    var sm = this.get('StorageManager');
    var store = {};
    if(!sm)
      return;

    // Fetch what to store
    this.get('storables').forEach(m => {
      var obj = m.store(1);
      for(var el in obj)
        store[el] = obj[el];
    });

    sm.store(store, () => {
      clb && clb();
      this.set('changesCount', 0);
      this.trigger('storage:store', store);
    });

    return store;
  },

  /**
   * Load data from the current storage
   * @param {Function} clb Callback function
   * @return {Object} Loaded data
   * @private
   */
  load(clb) {
    var result = this.getCacheLoad(1, clb);
    this.get('storables').forEach(m => {
      m.load(result);
    });
    return result;
  },

  /**
   * Returns cached load
   * @param {Boolean} force Force to reload
   * @param {Function} clb Callback function
   * @return {Object}
   * @private
   */
  getCacheLoad(force, clb) {
    var f = force ? 1 : 0;
    if(this.cacheLoad && !f)
      return this.cacheLoad;
    var sm = this.get('StorageManager');
    var load = [];

    if(!sm)
      return {};

    this.get('storables').forEach(m => {
      var key = m.storageKey;
      key = typeof key === 'function' ? key() : key;
      var keys = key instanceof Array ? key : [key];
      keys.forEach(k => {
        load.push(k);
      });
    });

    this.cacheLoad = sm.load(load, (loaded) => {
      clb && clb(loaded);
      this.trigger('storage:load', loaded);
    });
    return this.cacheLoad;
  },

  /**
   * Returns device model by name
   * @return {Device|null}
   */
  getDeviceModel() {
    var name = this.get('device');
    return this.get('DeviceManager').get(name);
  },

  /**
   * Run default command if setted
   * @private
   */
  runDefault() {
    var command = this.get('Commands').get(this.config.defaultCommand);
    if(!command || this.defaultRunning)
      return;
    command.stop(this, this);
    command.run(this, this);
    this.defaultRunning = 1;
  },

  /**
   * Stop default command
   * @private
   */
  stopDefault() {
    var command = this.get('Commands').get(this.config.defaultCommand);
    if(!command)
      return;
    command.stop(this, this);
    this.defaultRunning = 0;
  },

  /**
   * Update canvas dimensions and refresh data useful for tools positioning
   * @private
   */
  refreshCanvas() {
    this.set('canvasOffset', this.get('Canvas').getOffset());
  },

  /**
   * Clear all selected stuf inside the window, sometimes is useful to call before
   * doing some dragging opearation
   * @param {Window} win If not passed the current one will be used
   * @private
   */
  clearSelection(win) {
    var w = win || window;
    w.getSelection().removeAllRanges();
  },

});
<|endoftext|>


<commit_before>// Copyright 2008 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
//       copyright notice, this list of conditions and the following
//       disclaimer in the documentation and/or other materials provided
//       with the distribution.
//     * Neither the name of Google Inc. nor the names of its
//       contributors may be used to endorse or promote products derived
//       from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// Flags: --allow-natives-syntax

function makeArguments() {
  var result = [ ];
  result.push(17);
  result.push(-31);
  result.push(new Array(100));
  result.push(new Array(100003));
  result.push(Number.MIN_VALUE);
  result.push("whoops");
  result.push("x");
  result.push({"x": 1, "y": 2});
  var slowCaseObj = {"a": 3, "b": 4, "c": 5};
  delete slowCaseObj.c;
  result.push(slowCaseObj);
  result.push(function () { return 8; });
  return result;
}

var kArgObjects = makeArguments().length;

function makeFunction(name, argc) {
  var args = [];
  for (var i = 0; i < argc; i++)
    args.push("x" + i);
  var argsStr = args.join(", ");
  return new Function(args.join(", "), "return %" + name + "(" + argsStr + ");");
}

function testArgumentCount(name) {
  for (var i = 0; i < 10; i++) {
    var func = makeFunction(name, i);
    var args = [ ];
    for (var j = 0; j < i; j++)
      args.push(0);
    try {
      func.apply(void 0, args);
    } catch (e) {
      // we don't care what happens as long as we don't crash
    }
  }
}

function testArgumentTypes(name, argc) {
  var type = 0;
  var hasMore = true;
  var func = makeFunction(name, argc);
  while (hasMore) {
    var argPool = makeArguments();
    var current = type;
    var hasMore = false;
    var argList = [ ];
    for (var i = 0; i < argc; i++) {
      var index = current % kArgObjects;
      current = (current / kArgObjects) << 0;
      if (index != (kArgObjects - 1))
        hasMore = true;
      argList.push(argPool[index]);
    }
    try {
      func.apply(void 0, argList);
    } catch (e) {
      // we don't care what happens as long as we don't crash
    }
    type++;
  }
}

var knownProblems = {
  "Abort": true,

  // These functions use pseudo-stack-pointers and are not robust
  // to unexpected integer values.
  "DebugEvaluate": true,

  // These functions do nontrivial error checking in recursive calls,
  // which means that we have to propagate errors back.
  "SetFunctionBreakPoint": true,
  "SetScriptBreakPoint": true,
  "ChangeBreakOnException": true,
  "PrepareStep": true,

  // Too slow.
  "DebugReferencedBy": true,

  // Calling disable/enable access checks may interfere with the
  // the rest of the tests.
  "DisableAccessChecks": true,
  "EnableAccessChecks": true,

  // These functions should not be callable as runtime functions.
  "NewContext": true,
  "NewArgumentsFast": true,
  "PushContext": true,
  "LazyCompile": true,
  "CreateObjectLiteralBoilerplate": true,
  "CloneLiteralBoilerplate": true,
  "CloneShallowLiteralBoilerplate": true,
  "CreateArrayLiteralBoilerplate": true,
  "IS_VAR": true,
  "ResolvePossiblyDirectEval": true,
  "Log": true,

  "CollectStackTrace": true
};

var currentlyUncallable = {
  // We need to find a way to test this without breaking the system.
  "SystemBreak": true
};

function testNatives() {
  var allNatives = %ListNatives();
  for (var i = 0; i < allNatives.length; i++) {
    var nativeInfo = allNatives[i];
    var name = nativeInfo[0];
    if (name in knownProblems || name in currentlyUncallable)
      continue;
    print(name);
    var argc = nativeInfo[1];
    testArgumentCount(name);
    testArgumentTypes(name, argc);
  }
}

testNatives();
<commit_msg>The runtime function DeclareGlobals is not called from JavaScript. Add it to the exclusions list in the fuzz-natives test.<commit_after>// Copyright 2008 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
//       copyright notice, this list of conditions and the following
//       disclaimer in the documentation and/or other materials provided
//       with the distribution.
//     * Neither the name of Google Inc. nor the names of its
//       contributors may be used to endorse or promote products derived
//       from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// Flags: --allow-natives-syntax

function makeArguments() {
  var result = [ ];
  result.push(17);
  result.push(-31);
  result.push(new Array(100));
  result.push(new Array(100003));
  result.push(Number.MIN_VALUE);
  result.push("whoops");
  result.push("x");
  result.push({"x": 1, "y": 2});
  var slowCaseObj = {"a": 3, "b": 4, "c": 5};
  delete slowCaseObj.c;
  result.push(slowCaseObj);
  result.push(function () { return 8; });
  return result;
}

var kArgObjects = makeArguments().length;

function makeFunction(name, argc) {
  var args = [];
  for (var i = 0; i < argc; i++)
    args.push("x" + i);
  var argsStr = args.join(", ");
  return new Function(args.join(", "), "return %" + name + "(" + argsStr + ");");
}

function testArgumentCount(name) {
  for (var i = 0; i < 10; i++) {
    var func = makeFunction(name, i);
    var args = [ ];
    for (var j = 0; j < i; j++)
      args.push(0);
    try {
      func.apply(void 0, args);
    } catch (e) {
      // we don't care what happens as long as we don't crash
    }
  }
}

function testArgumentTypes(name, argc) {
  var type = 0;
  var hasMore = true;
  var func = makeFunction(name, argc);
  while (hasMore) {
    var argPool = makeArguments();
    var current = type;
    var hasMore = false;
    var argList = [ ];
    for (var i = 0; i < argc; i++) {
      var index = current % kArgObjects;
      current = (current / kArgObjects) << 0;
      if (index != (kArgObjects - 1))
        hasMore = true;
      argList.push(argPool[index]);
    }
    try {
      func.apply(void 0, argList);
    } catch (e) {
      // we don't care what happens as long as we don't crash
    }
    type++;
  }
}

var knownProblems = {
  "Abort": true,

  // These functions use pseudo-stack-pointers and are not robust
  // to unexpected integer values.
  "DebugEvaluate": true,

  // These functions do nontrivial error checking in recursive calls,
  // which means that we have to propagate errors back.
  "SetFunctionBreakPoint": true,
  "SetScriptBreakPoint": true,
  "ChangeBreakOnException": true,
  "PrepareStep": true,

  // Too slow.
  "DebugReferencedBy": true,

  // Calling disable/enable access checks may interfere with the
  // the rest of the tests.
  "DisableAccessChecks": true,
  "EnableAccessChecks": true,

  // These functions should not be callable as runtime functions.
  "NewContext": true,
  "NewArgumentsFast": true,
  "PushContext": true,
  "LazyCompile": true,
  "CreateObjectLiteralBoilerplate": true,
  "CloneLiteralBoilerplate": true,
  "CloneShallowLiteralBoilerplate": true,
  "CreateArrayLiteralBoilerplate": true,
  "IS_VAR": true,
  "ResolvePossiblyDirectEval": true,
  "Log": true,
  "DeclareGlobals": true,

  "CollectStackTrace": true
};

var currentlyUncallable = {
  // We need to find a way to test this without breaking the system.
  "SystemBreak": true
};

function testNatives() {
  var allNatives = %ListNatives();
  for (var i = 0; i < allNatives.length; i++) {
    var nativeInfo = allNatives[i];
    var name = nativeInfo[0];
    if (name in knownProblems || name in currentlyUncallable)
      continue;
    print(name);
    var argc = nativeInfo[1];
    testArgumentCount(name);
    testArgumentTypes(name, argc);
  }
}

testNatives();
<|endoftext|>


<commit_before>/**
 * Imports
 */

// import IndeterminateProgress from '../components/IndeterminateProgress'
import ModalMessage from 'components/ModalMessage'
import ShowcaseView from 'components/ShowcaseView'
import {Block, Icon, Text, Image} from 'vdux-ui'
import {component, element} from 'vdux'
import Card from 'components/Card'
import palette from 'utils/palette'
import reduce from '@f/reduce'
import fire from 'vdux-fire'
import map from '@f/map'

/**
 * <Featured Feed/>
 */

export default fire((props) => ({
  coursesVal: '/courses',
  recent: {
    // ref: '/users/JmQFPY4ZgkNa17hvhlfXHoUvo3d2/games',
    ref: '/games',
    updates: [
      {method: 'orderByChild', value: 'creatorID'},
      {method: 'equalTo', value: 'kvkXjds5fRh0jliRNfji3LTFMbI3'},
      {method: 'limitToLast', value: 3}
    ]
  }
}))(component({
  render ({props, context, state}) {
    const {coursesVal, project, recent} = props
    const {value, loading} = coursesVal

    if (loading || recent.loading) return

    const courses = map((course, key) => (
      {...course, color: palette[Object.keys(value).indexOf(key)].value}
    ), value)

    const recents = map((recent, i) => (
      {...recent, color: palette[(i + 6)].value}
    ), recent.value.reverse())

    if (project) {
      return <ModalMessage
        fullscreen
        headerColor='#666'
        bgColor='#fafafa'
        header={courses[project].title}
        dismiss={context.setUrl('/featured')}
        noFooter
        body={<ShowcaseView
          color={courses[project].color}
          playlists={courses[project].playlists} />} />
    }

    return (
      <Block m='0 auto' w='980px'>
        <Text fs='l'>
          COURSES
        </Text>
        <Text display='block' mt='0.5em' fontWeight='200' fs='m'>
          Use these courses to get started in PixelBots.
        </Text>
        <Block wide>
          <Block py='2em' flexWrap='wrap' align='space-between start'>
            {reduce(reduceToCards, [], courses)}
          </Block>
        </Block>
        <Text fs='l'>
          RECENT
        </Text>
        <Text display='block' mt='0.5em' fontWeight='200' fs='m'>
          Check out some recently added challenges!
        </Text>
        <Block wide>
          <Block py='2em' flexWrap='wrap' align='space-between start'>
            {map((recent => <FeaturedCard ref={`/games/${recent.key}`} feature={recent} />), recents)}
          </Block>
        </Block>
      </Block>
    )
  }
}))

function reduceToCards (arr, feature, key) {
  return arr.concat(
    <FeaturedCard feature={feature} ref={`/featured/${key}`} />
  )
}

const FeaturedCard = component({
  render ({props, context}) {
    const {ref, feature} = props
    const {title, playlists, imageUrl, description, color} = feature
    const {setUrl} = context
    const w = 310

    return (
      <Card
        w={w}
        h='auto'
        my='10px'
        minHeight='200px'
        cursor='pointer'
        hoverProps={{boxShadow: 'rgba(0, 0, 0, 0.2) 0px 3px 2px 0px'}}
        onClick={setUrl(ref)}
        cardTitle={title}
        cardFooter={
          <Block fs='xs' align='start center'>
            {
              playlists && [
                <Icon fs='m' name='collections' />,
                <Text ml='6px'>{playlists.length} playlists</Text>
              ]
            }
            {
              imageUrl &&
                <Block align='center center' pt='l'>
                  <Image src={imageUrl} w={100} border='1px solid divider' />
                </Block>
            }
          </Block>
        }
        borderRadius={3}
        headerColor={color}>
        <Text>{description || 'No description'}</Text>
      </Card>
    )
  }
})

<commit_msg>load home recent seperately<commit_after>/**
 * Imports
 */

// import IndeterminateProgress from '../components/IndeterminateProgress'
import ModalMessage from 'components/ModalMessage'
import ShowcaseView from 'components/ShowcaseView'
import {Block, Icon, Text, Image} from 'vdux-ui'
import {component, element} from 'vdux'
import Card from 'components/Card'
import palette from 'utils/palette'
import reduce from '@f/reduce'
import fire from 'vdux-fire'
import map from '@f/map'

/**
 * <Featured Feed/>
 */

export default fire((props) => ({
  coursesVal: '/courses'
}))(component({
  render ({props, context, state}) {
    const {coursesVal, project} = props
    const {value, loading} = coursesVal

    if (loading) return

    const courses = map((course, key) => (
      {...course, color: palette[Object.keys(value).indexOf(key)].value}
    ), value)

    if (project) {
      return <ModalMessage
        fullscreen
        headerColor='#666'
        bgColor='#fafafa'
        header={courses[project].title}
        dismiss={context.setUrl('/featured')}
        noFooter
        body={<ShowcaseView
          color={courses[project].color}
          playlists={courses[project].playlists} />} />
    }

    return (
      <Block m='0 auto' w='980px'>
        <Text fs='l'>
          COURSES
        </Text>
        <Text display='block' mt='0.5em' fontWeight='200' fs='m'>
          Use these courses to get started in PixelBots.
        </Text>
        <Block wide>
          <Block py='2em' flexWrap='wrap' align='space-between start'>
            {reduce(reduceToCards, [], courses)}
          </Block>
        </Block>
        <Text fs='l'>
          RECENT
        </Text>
        <Text display='block' mt='0.5em' fontWeight='200' fs='m'>
          Check out some recently added challenges!
        </Text>
        <Block wide>
          <RecentCards />
        </Block>
      </Block>
    )
  }
}))

function reduceToCards (arr, feature, key) {
  return arr.concat(
    <FeaturedCard feature={feature} ref={`/featured/${key}`} />
  )
}

const RecentCards = fire((props) => ({
  recent: {
    // ref: '/users/JmQFPY4ZgkNa17hvhlfXHoUvo3d2/games',
    ref: '/games',
    updates: [
      {method: 'orderByChild', value: 'creatorID'},
      {method: 'equalTo', value: 'kvkXjds5fRh0jliRNfji3LTFMbI3'},
      {method: 'limitToLast', value: 3}
    ]
  }
}))(component({
  render ({props}) {
    const {recent} = props
    const {value, loading} = recent

    if (loading) return

    console.log(value)
    const recents = map((recent, i) => (
      {...recent, color: palette[(i + 6)].value}
    ), value.reverse())

    return (
      <Block py='2em' flexWrap='wrap' align='space-between start'>
        {
          map((recent => <FeaturedCard ref={`/games/${recent.key}`} feature={recent} />), recents)
        }
      </Block>
    )
  }
}))

const FeaturedCard = component({
  render ({props, context}) {
    const {ref, feature} = props
    const {title, playlists, imageUrl, description, color} = feature
    const {setUrl} = context
    const w = 310

    return (
      <Card
        w={w}
        h='auto'
        my='10px'
        minHeight='200px'
        cursor='pointer'
        hoverProps={{boxShadow: 'rgba(0, 0, 0, 0.2) 0px 3px 2px 0px'}}
        onClick={setUrl(ref)}
        cardTitle={title}
        cardFooter={
          <Block fs='xs' align='start center'>
            {
              playlists && [
                <Icon fs='m' name='collections' />,
                <Text ml='6px'>{playlists.length} playlists</Text>
              ]
            }
            {
              imageUrl &&
                <Block align='center center' pt='l'>
                  <Image src={imageUrl} w={100} border='1px solid divider' />
                </Block>
            }
          </Block>
        }
        borderRadius={3}
        headerColor={color}>
        <Text>{description || 'No description'}</Text>
      </Card>
    )
  }
})

<|endoftext|>