<commit_before>/**
 *    Copyright 2016-today Software Craftmanship Toledo
 *
 * 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.
 */

import { browserHistory } from  'react-router'

import store from   '../stores/store'

const goToResults = ( dispatch ) => {
    let currentState = store.getState()
    if ( currentState.positionAroundMe.errors.length > 0 && currentState.positionAroundMe.busStops.length > 0 ) {
        dispatch( browserHistory.push( '/errors' ) )
    } else {
        dispatch( browserHistory.push( '/results' ) )
    }
}

export default goToResults
<commit_msg>[#37] add goToHome to router app and better behavior in goToResults<commit_after>/**
 *    Copyright 2016-today Software Craftmanship Toledo
 *
 * 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.
 */

import { browserHistory } from  'react-router'

import store from   '../stores/store'

export const goToResults = ( dispatch ) => {
    let currentState = store.getState()
    if ( currentState.positionAroundMe.busStops.length > 0 ) {
        dispatch( browserHistory.push( '/results' ) )
    }
    if ( currentState.positionAroundMe.errors.length > 0 ) {
        dispatch( browserHistory.push( '/errors' ) )
    } else {
        dispatch( browserHistory.push( '/home' ) )
    }
}

export const goToHome = ( dispatch ) => {
    let currentState = store.getState()
    if ( currentState.positionAroundMe.errors.length > 0 ) {
        dispatch( browserHistory.push( '/errors' ) )
    } else {
        dispatch( browserHistory.push( '/home' ) )
    }
}<|endoftext|>


<commit_before>// Routes
import Layout from '@/components/Layout'
import Welcome from '@/components/Welcome'
import Login from '@/components/auth/Login'
import Profile from '@/components/auth/UpdateProfile'
import UpdateProfile from '@/components/auth/UpdateProfile'
import App from '@/components/App'
import NotFound from '@/components/errors/404'
import Firestore from '@/components/Firestore'

import Vue from 'vue'

const routes = [{
    path: '/',
    component: Layout,
    children: [{
            path: '/',
            component: Welcome,
            name: 'Welcome'
        },
        {
            path: '/login',
            component: Login,
            name: 'login'
        },
        {
            path: '/update-profile',
            component: UpdateProfile,
            name: 'Profile Update',
            meta: {
                auth: true
            }
        },
        {
            path: '/realtime-database',
            component: App,
            name: 'Realtime Database',
            meta: {
                auth: true
            }
        },
        {
            path: '/firestore',
            component: Firestore,
            name: 'Cloud Firestore',
            meta: {
                auth: true
            }
        },
        {
            path: '/profile',
            component: Profile,
            name: 'Update Profile',
            meta : {
                auth: true
            }
        },
        {
            path: '*',
            component: NotFound
        }
    ]
}]

export default routes;
<commit_msg>setup routes<commit_after>// Routes
import Layout from '@/components/Layout'
import Welcome from '@/components/Welcome'
import Login from '@/components/auth/Login'
import Profile from '@/components/auth/UpdateProfile'
import App from '@/components/App'
import NotFound from '@/components/errors/404'
import Room from '@/components/Room'

import Vue from 'vue'

const routes = [{
    path: '/',
    component: Layout,
    children: [{
            path: '/',
            component: Welcome,
            name: 'Welcome'
        },
        {
            path: '/login',
            component: Login,
            name: 'login'
        },
        {
            path: '/room',
            component: Room,
            name: 'Cloud Firestore',
            meta: {
                auth: true
            }
        },
        {
            path: '/profile',
            component: Profile,
            name: 'Update Profile',
            meta : {
                auth: true
            }
        },
        {
            path: '*',
            component: NotFound
        }
    ]
}]

export default routes;
<|endoftext|>


<commit_before>const config = require('./config.js')
const path = require('path')

/**
 * Metalsmith plugin.
 * Make global playlists object.
 * Usage:
 * Metalsmith.use(playlists({
 *   collections: ['python', 'scratch']
 * }))
 */
module.exports = function (opts) {
  opts = opts || {}
  opts.collections = opts.collections || []

  return function (files, metalsmith, done) {
    const metadata = metalsmith.metadata()
    metadata.playlists = {}

    // for each collection
    opts.collections.map(collection => {
      // /course\/playlists\/[^\/]+txt$/
      const re = new RegExp([collection, config.playlistFolder,
                            '[^', ']+txt$'].join('\\' + path.sep))
      // [ course/playlists/learn_python.txt, ...]
      const playlists = Object.keys(files).filter(file => {
        return file.search(re) === 0
      })

      metadata.playlists[collection] = []

      for (let file of playlists) {
        const playlist = {}
        playlist.name = playlistName(file)
        playlist.id = playlistId(playlist.name)

        let lessons = files[file].contents.toString('utf8')
        lessons = lessons.match(/[^\r\n]+/g)  // read lines
        playlist.lessons = lessons.map(file => {
          const key = path.join(collection, ...file.split('/'))
          return files[key]
        })

        metadata.playlists[collection].push(playlist)
      }
    })
    done()
  }
}

function playlistName (filename) {
  return path.basename(filename).replace('.txt', '').replace(/_/g, ' ')
}

function playlistId (name) {
  // replace chars in playlist-name, so that it can be used as id or class
  var id = name.replace(/ /g, '_');
  id = id.replace(/[\,\.\-\?]/g, '');
  return id;
}
<commit_msg>playlists: warn if file not found<commit_after>const config = require('./config.js')
const path = require('path')

/**
 * Metalsmith plugin.
 * Make global playlists object.
 * Usage:
 * Metalsmith.use(playlists({
 *   collections: ['python', 'scratch']
 * }))
 */
module.exports = function (opts) {
  opts = opts || {}
  opts.collections = opts.collections || []

  return function (files, metalsmith, done) {
    const metadata = metalsmith.metadata()
    metadata.playlists = {}

    // for each collection
    opts.collections.map(collection => {
      // /course\/playlists\/[^\/]+txt$/
      const re = new RegExp([collection, config.playlistFolder,
                            '[^', ']+txt$'].join('\\' + path.sep))
      // [ course/playlists/learn_python.txt, ...]
      const playlists = Object.keys(files).filter(file => {
        return file.search(re) === 0
      })

      metadata.playlists[collection] = []

      for (let file of playlists) {
        const playlist = {}
        playlist.name = playlistName(file)
        playlist.id = playlistId(playlist.name)

        let lessons = files[file].contents.toString('utf8')
        lessons = lessons.match(/[^\r\n]+/g)  // read lines
        playlist.lessons = lessons.map(file => {
          const key = path.normalize(path.join(collection, ...file.split('/')))
          if (!files[key]) {
            console.warn('playlist: file not found')
            console.warn(key +' in '+ file)
          }
          return files[key]
        })

        metadata.playlists[collection].push(playlist)
      }
    })
    done()
  }
}

function playlistName (filename) {
  return path.basename(filename).replace('.txt', '').replace(/_/g, ' ')
}

function playlistId (name) {
  // replace chars in playlist-name, so that it can be used as id or class
  var id = name.replace(/ /g, '_');
  id = id.replace(/[\,\.\-\?]/g, '');
  return id;
}
<|endoftext|>


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

    WinJS.UI.Pages.define("/demos/files/parent/parent.html", {
        ready: function (element, options) {
            var openPicker = new Windows.Storage.Pickers.FileOpenPicker();
            openPicker.viewMode = Windows.Storage.Pickers.PickerViewMode.thumbnail;
            openPicker.fileTypeFilter.replaceAll([".png", ".jpg", ".jpeg"]);

            q(".parent #open").onclick = function (e) {
                openPicker.pickSingleFileAsync().then(function (file) {
                    var result = q(".parent #result");
                    if (file) {
                        var img = q(".parent #pic");
                        img.src = URL.createObjectURL(file);
                        img.style.display = "block";

                        file.getParentAsync().done(function (parentFolder) {
                            if (parentFolder && parentFolder.name && parentFolder.path)
                                result.innerText = "Parent: " + parentFolder.name + " (" + parentFolder.path + ")";
                            else
                                result.innerText = "Access not granted to parent folder..."
                        },
                            function (error) {
                                result.innerText = error.message || "error in parent script file";
                        });

                    } else {
                        result.innerText = "No file picked";
                    }
                });
            };
        }
    });

})();
<commit_msg>fixed re-entry bug on files demo<commit_after>(function () {
    "use strict";

    WinJS.UI.Pages.define("/demos/files/parent/parent.html", {
        ready: function (element, options) {
            var openPicker = new Windows.Storage.Pickers.FileOpenPicker();
            openPicker.viewMode = Windows.Storage.Pickers.PickerViewMode.thumbnail;
            openPicker.fileTypeFilter.replaceAll([".png", ".jpg", ".jpeg"]);

            element.querySelector(".parent #open").onclick = function (e) {
                openPicker.pickSingleFileAsync().then(function (file) {
                    var result = element.querySelector(".parent #result");
                    if (file) {
                        var img = element.querySelector(".parent #pic");
                        img.src = URL.createObjectURL(file);
                        img.style.display = "block";

                        file.getParentAsync().done(function (parentFolder) {
                            if (parentFolder && parentFolder.name && parentFolder.path)
                                result.innerText = "Parent: " + parentFolder.name + " (" + parentFolder.path + ")";
                            else
                                result.innerText = "Access not granted to parent folder..."
                        },
                            function (error) {
                                result.innerText = error.message || "error in parent script file";
                        });

                    } else {
                        result.innerText = "No file picked";
                    }
                });
            };
        }
    });

})();
<|endoftext|>


<commit_before>import React from 'react';
import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';
import {Redirect} from 'react-router';
import {getOr} from 'unchanged';
import qs from 'querystring';
import {fetchConfigure, submitConfigure} from '../../actions/configure';
import {Container, Row} from 'reactstrap';
import {ComponentWithError} from '../components/ComponentWithError';
import {Logo} from '../components/Logo';
import {RecentLogins} from './RecentLogins';
import {ConfigureMetadata} from './ConfigureMetadata';
import './Configure.css';

class Configure extends ComponentWithError {
  constructor(props) {
    super(props);

    const params = qs.parse(props.location.search);

    this.state = {
      auth: (params['?auth'] && params['?auth'] === 'true'),
      loaded: false
    };
  }

  async componentDidMount() {
    this._isMounted = true;

    await this.props.fetchConfigure();
    if (this._isMounted) {
      this.setState({
        loaded: true
      });
    }
  }

  componentWillUnmount() {
    this._isMounted = false;
  }

  render() {
    if (this.state.auth) {
      return <Redirect to='/refresh' />
    }
    const metadataUrls = getOr([], 'metadataUrls', this.props);
    return (this.state.loaded) ? (
      <Container>
        <Row>

            <Logo />

              <ConfigureMetadata defaultMetadataUrl={this.props.defaultMetadataUrl} />
              {!!metadataUrls.length && <RecentLogins metadataUrls={metadataUrls} />}

        </Row>
      </Container>
    ) : '';
  }
}

const mapStateToProps = ({configure}) => {
  return {
    ...configure.fetchFailure,
    ...configure.fetchSuccess
  };
};

const mapDispatchToProps = (dispatch) => {
  return {
    fetchConfigure: bindActionCreators(fetchConfigure, dispatch),
    submitConfigure: bindActionCreators(submitConfigure, dispatch)
  };
};

export default connect(mapStateToProps, mapDispatchToProps)(Configure);
<commit_msg>Removed unused reference to action.<commit_after>import React from 'react';
import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';
import {Redirect} from 'react-router';
import {getOr} from 'unchanged';
import qs from 'querystring';
import {fetchConfigure} from '../../actions/configure';
import {Container, Row} from 'reactstrap';
import {ComponentWithError} from '../components/ComponentWithError';
import {Logo} from '../components/Logo';
import {RecentLogins} from './RecentLogins';
import {ConfigureMetadata} from './ConfigureMetadata';
import './Configure.css';

class Configure extends ComponentWithError {
  constructor(props) {
    super(props);

    const params = qs.parse(props.location.search);

    this.state = {
      auth: (params['?auth'] && params['?auth'] === 'true'),
      loaded: false
    };
  }

  async componentDidMount() {
    this._isMounted = true;

    await this.props.fetchConfigure();
    if (this._isMounted) {
      this.setState({
        loaded: true
      });
    }
  }

  componentWillUnmount() {
    this._isMounted = false;
  }

  render() {
    if (this.state.auth) {
      return <Redirect to='/refresh' />
    }
    const metadataUrls = getOr([], 'metadataUrls', this.props);
    return (this.state.loaded) ? (
      <Container>
        <Row>

            <Logo />

              <ConfigureMetadata defaultMetadataUrl={this.props.defaultMetadataUrl} />
              {!!metadataUrls.length && <RecentLogins metadataUrls={metadataUrls} />}

        </Row>
      </Container>
    ) : '';
  }
}

const mapStateToProps = ({configure}) => {
  return {
    ...configure.fetchFailure,
    ...configure.fetchSuccess
  };
};

const mapDispatchToProps = (dispatch) => {
  return {
    fetchConfigure: bindActionCreators(fetchConfigure, dispatch)
  };
};

export default connect(mapStateToProps, mapDispatchToProps)(Configure);
<|endoftext|>


<commit_before>"use strict";
const jsc = require('jsverify');

var runall = async function(actions, state, model) {
    for (var idx = 0 ; idx != actions.length ; ++idx) {
        var ac = actions[idx];
        if (ac.check(model)) {
            if (! await ac.run(state, model)) {
                console.error("Test failed @ step #" + idx + " on task " + ac);
                return false;
            }
        }
    }
    return true;
};

var forAllCommandsHelper = function(arbSeed, arbCommands, warmup, teardown) {
    var testNumber = 0;
    return jsc.forall(arbSeed, arbCommands, async function(seed, commands) {
        var actions = commands.map(c => c.command);
        console.log("#" + (++testNumber) + ": " + actions.join(', '));
        var {state, model} = await warmup(seed);
        var result = await runall(actions, state, model);
        await teardown();
        return result;
    });
};
var forallCommandsSeeded = (arbSeed,
                            arbCommands,
                            warmup = async (seed) => { return {state: {}, model: {}}; },
                            teardown = async () => { return; }) => forAllCommandsHelper(arbSeed, arbCommands, warmup, teardown);

module.exports = {
    forall: (...params) => forallCommandsSeeded.apply(this, [jsc.constant(undefined)].concat(params)),
    forallCommandsSeeded: forallCommandsSeeded
};
<commit_msg>Flag started task during runner<commit_after>"use strict";
const jsc = require('jsverify');

var runall = async function(actions, state, model) {
    for (var idx = 0 ; idx != actions.length ; ++idx) {
        var ac = actions[idx];
        if (ac.check(model)) {
            ac.hasStarted = true;
            if (! await ac.run(state, model)) {
                console.error("Test failed @ step #" + idx + " on task " + ac);
                return false;
            }
        }
    }
    return true;
};

var forAllCommandsHelper = function(arbSeed, arbCommands, warmup, teardown) {
    var testNumber = 0;
    return jsc.forall(arbSeed, arbCommands, async function(seed, commands) {
        var actions = commands.map(c => c.command);
        console.log("#" + (++testNumber) + ": " + actions.join(', '));
        var {state, model} = await warmup(seed);
        var result = await runall(actions, state, model);
        await teardown();
        return result;
    });
};
var forallCommandsSeeded = (arbSeed,
                            arbCommands,
                            warmup = async (seed) => { return {state: {}, model: {}}; },
                            teardown = async () => { return; }) => forAllCommandsHelper(arbSeed, arbCommands, warmup, teardown);

module.exports = {
    forall: (...params) => forallCommandsSeeded.apply(this, [jsc.constant(undefined)].concat(params)),
    forallCommandsSeeded: forallCommandsSeeded
};
<|endoftext|>


<commit_before>/*
 * PollDance JavaScript Library v1.0.0
 * Copyright 2013 Fan Out Networks, Inc.
 * Released under the MIT license (see COPYING file in source distribution)
 */
(function () {
/** @define {boolean} */ var DEBUG = true;
"use strict";
(function (window, undefined) {

    var NAMESPACE = "PollDance";
    var TIMEOUT = 60000;
    var emptyMethod = function(){};

    var log;
    if (DEBUG) {
        // don't break if there's no console
        if (typeof (window.console) === "undefined") {
            window.console = { log: emptyMethod, dir: emptyMethod };
        }
        log = function(output) { window.console.log(output); };
    } else {
        log = emptyMethod;
    }

    var copyArray = function(array) {
        var args = Array.prototype.slice.call(arguments, 1);
        return Array.prototype.slice.apply(array, args);
    };

    var indexOfItemInArray = function(array, item) {
        for (var i = 0, length = array.length; i < length; i++) {
            if (array[i] === item) {
                return i;
            }
        }
        return -1;
    };
    var removeFromArray = function (array, item) {
        var again = true;
        while (again) {
            var index = indexOfItemInArray(array, item);
            if (index != -1) {
                array.splice(index, 1);
            } else {
                again = false;
            }
        }
    };

    var jsonCallbacks = {
        id: 0,
        requests: {},
        getJsonpCallback: function (id) {
            var cb;
            var requests = this.requests;
            if (id in this.requests) {
                cb = function (result) { requests[id]._jsonp_callback(result); };
            } else {
                log("no callback with id " + id);
                cb = emptyMethod;
            }
            return cb;
        },
        addJsonpCallback: function (id, obj) {
            this.requests[id] = obj;
        },
        removeJsonpCallback: function (id) {
            delete this.requests[id];
        },
        newCallbackInfo: function () {
            var callbackInfo = {
                id: "cb-" + this.id,
                scriptId: "pd-jsonp-script-" + this.id
            };
            this.id++;
            return callbackInfo;
        }
    };

    var corsAvailable = "withCredentials" in new window.XMLHttpRequest();

    var sameOrigin = function(url) {
        var loc = window.location;
        var a = window.document.createElement('a');
        a.href = url;
        return !a.hostname || (a.hostname == loc.hostname && a.port == loc.port && a.protocol == loc.protocol);
    };

    var Events = function () {
        this._events = {};
    };
    Events.prototype._getHandlersForType = function (type) {
        if (!(type in this._events)) {
            this._events[type] = [];
        }
        return this._events[type];
    };
    Events.prototype.on = function (type, handler) {
        var handlers = this._getHandlersForType(type);
        handlers.push(handler);
    };
    Events.prototype.off = function (type) {
        if (arguments.length > 1) {
            var handler = arguments[1];
            var handlers = this._getHandlersForType(type);
            removeFromArray(handlers, handler);
        } else {
            delete this._events[type];
        }
    };
    Events.prototype.trigger = function (type, obj) {
        var args = copyArray(arguments, 2);
        var handlers = copyArray(this._getHandlersForType(type));
        for (var i = 0, n = handlers.length; i < n; i++) {
            var handler = handlers[i];
            handler.apply(obj, args);
        }
    };

    var errorTypes = {
        "TransportError": 0,
        "TimeoutError": 1
    };

    var transportTypes = {
        "Auto": 0,
        "Xhr": 1,
        "Jsonp": 2
    };

    // PollDance.Request has callback members:
    // on('finished', int code, object result, object headers)
    // on('error', int reason)

    var Request = function () {
        if (!(this instanceof Request)) {
            throw new Error("Constructor called as a function");
        }

        this._events = new Events();
        this._tries = 0;
        this._delayNext = false;
        this._retryTime = 0;
        this._timer = null;
        this._callbackInfo = null;

        this._xhr = null;
        this._method = null;
        this._url = null;
        this._headers = null;
        this._body = null;

        this.transport = transportTypes.Auto;
        this.rawResponse = false;
        this.maxTries = 1;
        this.maxDelay = 1000;

        if (arguments.length > 0) {
            var config = arguments[0];
            if ("transport" in config) {
                this.transport = config.transport;
            }
            if ("rawResponse" in config) {
                this.rawResponse = config.rawResponse;
            }
            if ("maxTries" in config) {
                this.maxTries = config.maxTries;
            }
            if ("maxDelay" in config) {
                this.maxDelay = config.maxDelay;
            }
        }
    };
    Request.prototype.start = function (method, url, headers, body) {
        var self = this;

        self._tries = 0;

        var delaytime;
        if (self._delayNext) {
            self._delayNext = false;
            delaytime = Math.floor(Math.random() * self.maxDelay);
            log("PD: polling again in " + delaytime + "ms");
        } else {
            delaytime = 0; // always queue the call, to prevent browser "busy"
        }

        self._method = method;
        self._url = url;
        self._headers = headers;
        self._body = body;

        self._timer = window.setTimeout(function () { self._connect(); }, delaytime);
    };
    Request.prototype.retry = function () {
        this._retry();
    };
    Request.prototype._connect = function () {
        var self = this;
        self._timer = window.setTimeout(function () { self._timeout(); }, TIMEOUT);

        self._tries++;

        if (self.transport == transportTypes.Auto) {
            if (corsAvailable || sameOrigin(self._url)) {
                self.transport = transportTypes.Xhr;
            } else {
                self.transport = transportTypes.Jsonp;
            }
        }

        if (self.transport == transportTypes.Xhr) {

            self._xhr = new window.XMLHttpRequest();
            self._xhr.onreadystatechange = function () { self._xhr_readystatechange(); };
            self._xhr.open(self._method, self._url, true);

            for (var key in self._headers) {
                if (self._headers.hasOwnProperty(key)) {
                    self._xhr.setRequestHeader(key, self._headers[key]);
                }
            }

            self._xhr.send(self._body);

            log("PD: xhr " + self._url + " " + self._body);

        } else { // Jsonp

            this._callbackInfo = jsonCallbacks.newCallbackInfo();

            var paramList = [];

            paramList.push("_callback=" + encodeURIComponent("window['" + NAMESPACE + "']._getJsonpCallback(\"" + this._callbackInfo.id + "\")"));
            if (self._method != "GET") {
                paramList.push("_method=" + encodeURIComponent(self._method));
            }
            if (self._headers) {
                paramList.push("_headers=" + encodeURIComponent(JSON.stringify(self._headers)));
            }
            if (self._body) {
                paramList.push("_body=" + encodeURIComponent(self._body));
            }
            var params = paramList.join("&");

            var src;
            if (self._url.indexOf("?") != -1) {
                src = self._url + "&" + params;
            } else {
                src = self._url + "?" + params;
            }

            log("PD: json-p " + this._callbackInfo.id + " " + src);
            this._addJsonpCallback(this._callbackInfo, src);
        }
    };
    Request.prototype.abort = function () {
        window.clearTimeout(this._timer);
        this._timer = null;
        this._cancelreq();
    };
    Request.prototype.on = function (type, handler) {
        this._events.on(type, handler);
    };
    Request.prototype.off = function (type) {
        var args = copyArray(arguments, 1).unshift(type);
        this._events.off.apply(this._events, args);
    };
    Request.prototype._addJsonpCallback = function (callbackInfo, src) {
        jsonCallbacks.addJsonpCallback(callbackInfo.id, this);

        var script = window.document.createElement("script");
        script.type = "text/javascript";
        script.id = callbackInfo.scriptId;
        script.src = src;

        var head = window.document.getElementsByTagName("head")[0];
        head.appendChild(script);
    };
    Request.prototype._removeJsonpCallback = function (callbackInfo) {
        jsonCallbacks.removeJsonpCallback(callbackInfo.id, this);

        var script = window.document.getElementById(callbackInfo.scriptId);
        script.parentNode.removeChild(script);
    };
    Request.prototype._cancelreq = function () {
        if (this.transport == transportTypes.Xhr) {
            this._xhr.onreadystatechange = emptyMethod;
            this._xhr.abort();
            this._xhr = null;
        } else { // Jsonp
            log("PD: json-p " + this._callbackInfo.id + " cancel");
            this._removeJsonpCallback(this._callbackInfo);
            this._callbackInfo = null;
        }
    };
    Request.prototype._xhr_readystatechange = function () {
        var xhr = this._xhr;
        if (xhr != null && xhr.readyState === 4) {
            this._xhr = null;

            window.clearTimeout(this._timer);
            this._timer = null;

            if ((!xhr.status || (xhr.status >= 500 && xhr.status < 600)) &&
                (this.maxTries == -1 || this._tries < this.maxTries)) {
                this._retry();
            } else {
                if (xhr.status) {
                    // TODO: xhr.getAllResponseHeaders()
                    this._handle_response(xhr.status, xhr.statusText, {}, xhr.responseText);
                } else {
                    this._error(errorTypes.TransportError);
                }
            }
        }
    };
    Request.prototype._jsonp_callback = function (result) {
        log("PD: json-p " + this._callbackInfo.id + " finished");

        window.clearTimeout(this._timer);
        this._timer = null;

        this._removeJsonpCallback(this._callbackInfo);
        this._callbackInfo = null;

        var headers = ("headers" in result) ? result.headers : {};
        this._handle_response(result.code, result.status, headers, result.body);
    };
    Request.prototype._handle_response = function (code, status, headers, body) {
        var result;
        if (this.rawResponse) {
            result = body;
        } else {
            try {
                result = JSON.parse(body);
            } catch (e) {
                result = body;
            }
        }
        this._finished(code, result, headers);
    };
    Request.prototype._timeout = function () {
        this._timer = null;
        this._cancelreq();

        if (this.maxTries == -1 || this._tries < this.maxTries) {
            this._retry();
        } else {
            this._error(errorTypes.TimeoutError);
        }
    };
    Request.prototype._retry = function () {
        if (this._tries === 1) {
            this._retryTime = 1;
        } else if (this._tries < 8) {
            this._retryTime = this._retryTime * 2;
        }

        var delaytime = this._retryTime * 1000;
        delaytime += Math.floor(Math.random() * this.maxDelay);
        log("PD: trying again in " + delaytime + "ms");

        var self = this;
        self._timer = window.setTimeout(function () { self._connect(); }, delaytime);
    };
    Request.prototype._finished = function (code, result, headers) {
        this._delayNext = true;
        this._events.trigger('finished', this, code, result, headers);
    };
    Request.prototype._error = function (reason) {
        this._delayNext = true;
        this._events.trigger('error', this, reason);
    };

    var exports = {
        Request: Request,
        TransportTypes: transportTypes,
        ErrorTypes: errorTypes,
        _getJsonpCallback: function (id) {
            return jsonCallbacks.getJsonpCallback(id);
        }
    };
    window[NAMESPACE] = window[NAMESPACE] || exports;

})(window);
})();
<commit_msg>remove debug define, parse response json-p headers<commit_after>/*
 * PollDance JavaScript Library v1.0.0
 * Copyright 2013 Fan Out Networks, Inc.
 * Released under the MIT license (see COPYING file in source distribution)
 */
(function () {
"use strict";
var DEBUG = true;
(function (window, undefined) {

    var NAMESPACE = "PollDance";
    var TIMEOUT = 60000;
    var emptyMethod = function(){};

    var log;
    if (DEBUG) {
        // don't break if there's no console
        if (typeof (window.console) === "undefined") {
            window.console = { log: emptyMethod, dir: emptyMethod };
        }
        log = function(output) { window.console.log(output); };
    } else {
        log = emptyMethod;
    }

    var copyArray = function(array) {
        var args = Array.prototype.slice.call(arguments, 1);
        return Array.prototype.slice.apply(array, args);
    };

    var indexOfItemInArray = function(array, item) {
        for (var i = 0, length = array.length; i < length; i++) {
            if (array[i] === item) {
                return i;
            }
        }
        return -1;
    };
    var removeFromArray = function (array, item) {
        var again = true;
        while (again) {
            var index = indexOfItemInArray(array, item);
            if (index != -1) {
                array.splice(index, 1);
            } else {
                again = false;
            }
        }
    };

    var parseResponseHeaders = function(headerStr) {
        var headers = {};
        if (!headerStr) {
            return headers;
        }
        var headerPairs = headerStr.split('\u000d\u000a');
        for (var i = 0; i < headerPairs.length; i++) {
            var headerPair = headerPairs[i];
            var index = headerPair.indexOf('\u003a\u0020');
            if (index > 0) {
                var key = headerPair.substring(0, index);
                var val = headerPair.substring(index + 2);
                headers[key] = val;
            }
        }
        return headers;
    };

    var jsonCallbacks = {
        id: 0,
        requests: {},
        getJsonpCallback: function (id) {
            var cb;
            var requests = this.requests;
            if (id in this.requests) {
                cb = function (result) { requests[id]._jsonp_callback(result); };
            } else {
                log("no callback with id " + id);
                cb = emptyMethod;
            }
            return cb;
        },
        addJsonpCallback: function (id, obj) {
            this.requests[id] = obj;
        },
        removeJsonpCallback: function (id) {
            delete this.requests[id];
        },
        newCallbackInfo: function () {
            var callbackInfo = {
                id: "cb-" + this.id,
                scriptId: "pd-jsonp-script-" + this.id
            };
            this.id++;
            return callbackInfo;
        }
    };

    var corsAvailable = "withCredentials" in new window.XMLHttpRequest();

    var sameOrigin = function(url) {
        var loc = window.location;
        var a = window.document.createElement('a');
        a.href = url;
        return !a.hostname || (a.hostname == loc.hostname && a.port == loc.port && a.protocol == loc.protocol);
    };

    var Events = function () {
        this._events = {};
    };
    Events.prototype._getHandlersForType = function (type) {
        if (!(type in this._events)) {
            this._events[type] = [];
        }
        return this._events[type];
    };
    Events.prototype.on = function (type, handler) {
        var handlers = this._getHandlersForType(type);
        handlers.push(handler);
    };
    Events.prototype.off = function (type) {
        if (arguments.length > 1) {
            var handler = arguments[1];
            var handlers = this._getHandlersForType(type);
            removeFromArray(handlers, handler);
        } else {
            delete this._events[type];
        }
    };
    Events.prototype.trigger = function (type, obj) {
        var args = copyArray(arguments, 2);
        var handlers = copyArray(this._getHandlersForType(type));
        for (var i = 0, n = handlers.length; i < n; i++) {
            var handler = handlers[i];
            handler.apply(obj, args);
        }
    };

    var errorTypes = {
        "TransportError": 0,
        "TimeoutError": 1
    };

    var transportTypes = {
        "Auto": 0,
        "Xhr": 1,
        "Jsonp": 2
    };

    // PollDance.Request has callback members:
    // on('finished', int code, object result, object headers)
    // on('error', int reason)

    var Request = function () {
        if (!(this instanceof Request)) {
            throw new Error("Constructor called as a function");
        }

        this._events = new Events();
        this._tries = 0;
        this._delayNext = false;
        this._retryTime = 0;
        this._timer = null;
        this._callbackInfo = null;

        this._xhr = null;
        this._method = null;
        this._url = null;
        this._headers = null;
        this._body = null;

        this.transport = transportTypes.Auto;
        this.rawResponse = false;
        this.maxTries = 1;
        this.maxDelay = 1000;

        if (arguments.length > 0) {
            var config = arguments[0];
            if ("transport" in config) {
                this.transport = config.transport;
            }
            if ("rawResponse" in config) {
                this.rawResponse = config.rawResponse;
            }
            if ("maxTries" in config) {
                this.maxTries = config.maxTries;
            }
            if ("maxDelay" in config) {
                this.maxDelay = config.maxDelay;
            }
        }
    };
    Request.prototype.start = function (method, url, headers, body) {
        var self = this;

        self._tries = 0;

        var delaytime;
        if (self._delayNext) {
            self._delayNext = false;
            delaytime = Math.floor(Math.random() * self.maxDelay);
            log("PD: polling again in " + delaytime + "ms");
        } else {
            delaytime = 0; // always queue the call, to prevent browser "busy"
        }

        self._method = method;
        self._url = url;
        self._headers = headers;
        self._body = body;

        self._timer = window.setTimeout(function () { self._connect(); }, delaytime);
    };
    Request.prototype.retry = function () {
        this._retry();
    };
    Request.prototype._connect = function () {
        var self = this;
        self._timer = window.setTimeout(function () { self._timeout(); }, TIMEOUT);

        self._tries++;

        if (self.transport == transportTypes.Auto) {
            if (corsAvailable || sameOrigin(self._url)) {
                self.transport = transportTypes.Xhr;
            } else {
                self.transport = transportTypes.Jsonp;
            }
        }

        if (self.transport == transportTypes.Xhr) {

            self._xhr = new window.XMLHttpRequest();
            self._xhr.onreadystatechange = function () { self._xhr_readystatechange(); };
            self._xhr.open(self._method, self._url, true);

            for (var key in self._headers) {
                if (self._headers.hasOwnProperty(key)) {
                    self._xhr.setRequestHeader(key, self._headers[key]);
                }
            }

            self._xhr.send(self._body);

            log("PD: xhr " + self._url + " " + self._body);

        } else { // Jsonp

            this._callbackInfo = jsonCallbacks.newCallbackInfo();

            var paramList = [];

            paramList.push("_callback=" + encodeURIComponent("window['" + NAMESPACE + "']._getJsonpCallback(\"" + this._callbackInfo.id + "\")"));
            if (self._method != "GET") {
                paramList.push("_method=" + encodeURIComponent(self._method));
            }
            if (self._headers) {
                paramList.push("_headers=" + encodeURIComponent(JSON.stringify(self._headers)));
            }
            if (self._body) {
                paramList.push("_body=" + encodeURIComponent(self._body));
            }
            var params = paramList.join("&");

            var src;
            if (self._url.indexOf("?") != -1) {
                src = self._url + "&" + params;
            } else {
                src = self._url + "?" + params;
            }

            log("PD: json-p " + this._callbackInfo.id + " " + src);
            this._addJsonpCallback(this._callbackInfo, src);
        }
    };
    Request.prototype.abort = function () {
        window.clearTimeout(this._timer);
        this._timer = null;
        this._cancelreq();
    };
    Request.prototype.on = function (type, handler) {
        this._events.on(type, handler);
    };
    Request.prototype.off = function (type) {
        var args = copyArray(arguments, 1).unshift(type);
        this._events.off.apply(this._events, args);
    };
    Request.prototype._addJsonpCallback = function (callbackInfo, src) {
        jsonCallbacks.addJsonpCallback(callbackInfo.id, this);

        var script = window.document.createElement("script");
        script.type = "text/javascript";
        script.id = callbackInfo.scriptId;
        script.src = src;

        var head = window.document.getElementsByTagName("head")[0];
        head.appendChild(script);
    };
    Request.prototype._removeJsonpCallback = function (callbackInfo) {
        jsonCallbacks.removeJsonpCallback(callbackInfo.id, this);

        var script = window.document.getElementById(callbackInfo.scriptId);
        script.parentNode.removeChild(script);
    };
    Request.prototype._cancelreq = function () {
        if (this.transport == transportTypes.Xhr) {
            this._xhr.onreadystatechange = emptyMethod;
            this._xhr.abort();
            this._xhr = null;
        } else { // Jsonp
            log("PD: json-p " + this._callbackInfo.id + " cancel");
            this._removeJsonpCallback(this._callbackInfo);
            this._callbackInfo = null;
        }
    };
    Request.prototype._xhr_readystatechange = function () {
        var xhr = this._xhr;
        if (xhr != null && xhr.readyState === 4) {
            this._xhr = null;

            window.clearTimeout(this._timer);
            this._timer = null;

            if ((!xhr.status || (xhr.status >= 500 && xhr.status < 600)) &&
                (this.maxTries == -1 || this._tries < this.maxTries)) {
                this._retry();
            } else {
                if (xhr.status) {
                    var headersStr = xhr.getAllResponseHeaders();
                    var headers = parseResponseHeaders(headersStr);
                    this._handle_response(xhr.status, xhr.statusText, headers, xhr.responseText);
                } else {
                    this._error(errorTypes.TransportError);
                }
            }
        }
    };
    Request.prototype._jsonp_callback = function (result) {
        log("PD: json-p " + this._callbackInfo.id + " finished");

        window.clearTimeout(this._timer);
        this._timer = null;

        this._removeJsonpCallback(this._callbackInfo);
        this._callbackInfo = null;

        var headers = ("headers" in result) ? result.headers : {};
        this._handle_response(result.code, result.status, headers, result.body);
    };
    Request.prototype._handle_response = function (code, status, headers, body) {
        var result;
        if (this.rawResponse) {
            result = body;
        } else {
            try {
                result = JSON.parse(body);
            } catch (e) {
                result = body;
            }
        }
        this._finished(code, result, headers);
    };
    Request.prototype._timeout = function () {
        this._timer = null;
        this._cancelreq();

        if (this.maxTries == -1 || this._tries < this.maxTries) {
            this._retry();
        } else {
            this._error(errorTypes.TimeoutError);
        }
    };
    Request.prototype._retry = function () {
        if (this._tries === 1) {
            this._retryTime = 1;
        } else if (this._tries < 8) {
            this._retryTime = this._retryTime * 2;
        }

        var delaytime = this._retryTime * 1000;
        delaytime += Math.floor(Math.random() * this.maxDelay);
        log("PD: trying again in " + delaytime + "ms");

        var self = this;
        self._timer = window.setTimeout(function () { self._connect(); }, delaytime);
    };
    Request.prototype._finished = function (code, result, headers) {
        this._delayNext = true;
        this._events.trigger('finished', this, code, result, headers);
    };
    Request.prototype._error = function (reason) {
        this._delayNext = true;
        this._events.trigger('error', this, reason);
    };

    var exports = {
        Request: Request,
        TransportTypes: transportTypes,
        ErrorTypes: errorTypes,
        _getJsonpCallback: function (id) {
            return jsonCallbacks.getJsonpCallback(id);
        }
    };
    window[NAMESPACE] = window[NAMESPACE] || exports;

})(window);
})();
<|endoftext|>


<commit_before>import Client from './client';

export {
  Client
};
<commit_msg>export default client<commit_after>import Client from './client';

export default {
  Client
};
<|endoftext|>


<commit_before>'use strict';

import React, {
  Component,
  Text,
  View
} from 'react-native';

class Camera extends Component {

  constructor() {
    super();
    this.state = {
    };
  }

  render() {
    return(
      <View>
        <Text>Camera</Text>
      </View>
    );
  }
}

module.exports = Camera;
<commit_msg>Camera for real<commit_after>'use strict';

import React, {
  Component,
  Text,
  View,
  StyleSheet,
  ToolbarAndroid,
  Image,
  style
} from 'react-native';
var ImagePickerManager = require('NativeModules').ImagePickerManager;

class Camera extends Component {
  constructor() {
    super();
    this.state = {
      avatarSource: null
    };
  }
  onPress() {
    alert('Hi');
  }
  openCamera()
  {
    ImagePickerManager.showImagePicker(options, (response) => {
      console.log('Response = ', response);

      if (response.didCancel) {
        console.log('User cancelled image picker');
      } else if (response.error) {
        console.log('ImagePickerManager Error: ', response.error);
      } else {
        // You can display the image using either data:
        const source = {uri: 'data:image/jpeg;base64,' + response.data, isStatic: true};

        this.setState({
          avatarSource: source
        });
      }
    });
  }

  render() {
    return(
      <View>
      <ToolbarAndroid
        title='Create a Post'
        style={styles.toolbar}
        actions={[{title: 'Next', show: 'always'}] }
        onActionSelected={this.onPress.bind(this)} />
        <ToolbarAndroid
        style={styles.toolbar}
        actions = {[{title: 'Camera', show: 'always'}]}
        onActionSelected = {this.openCamera.bind(this)} />
        <Image source={this.state.avatarSource} style={styles.uploadAvatar} />
      </View>
    );
  }
}
var styles = StyleSheet.create({
  toolbar: {
    height: 56,
    backgroundColor: '#4682b4',
  },
  uploadAvatar: {
    height: 370,
    width: 370,
  }
});

var options = {
  title: 'Select Avatar', // specify null or empty string to remove the title
  cancelButtonTitle: 'Cancel',
  takePhotoButtonTitle: 'Take Photo...', // specify null or empty string to remove this button
  chooseFromLibraryButtonTitle: 'Choose from Library...', // specify null or empty string to remove this button
  cameraType: 'back', // 'front' or 'back'
  mediaType: 'photo', // 'photo' or 'video'
  videoQuality: 'high', // 'low', 'medium', or 'high'
  durationLimit: 10, // video recording max time in seconds
  maxWidth: 370, // photos only
  maxHeight: 370, // photos only
  aspectX: 2, // android only - aspectX:aspectY, the cropping image's ratio of width to height
  aspectY: 1, // android only - aspectX:aspectY, the cropping image's ratio of width to height
  quality: 1, // 0 to 1, photos only
  angle: 0, // android only, photos only
  allowsEditing: false, // Built in functionality to resize, reposition the image after selection
  noData: false, // photos only - disables the base64 `data` field from being generated (greatly improves performance on large photos)
};

module.exports = Camera;
<|endoftext|>


<commit_before>// Package of defining Vegalite Specification's json schema

var schema = module.exports = {},
  util = require('../util');

schema.util = require('./schemautil');

schema.marktype = {
  type: 'string',
  enum: ['point', 'bar', 'line', 'area', 'circle', 'square', 'text']
};

schema.aggr = {
  type: 'string',
  enum: ['avg', 'sum', 'min', 'max', 'count'],
  supportedEnums: {
    Q: ['avg', 'sum', 'min', 'max', 'count'],
    O: [],
    T: ['avg', 'min', 'max'],
    '': ['count']
  },
  supportedTypes: {'Q': true, 'O': true, 'T': true, '': true}
};

schema.band = {
  type: 'object',
  properties: {
    size: {
      type: 'integer',
      minimum: 0
    },
    padding: {
      type: 'integer',
      minimum: 0,
      default: 1
    }
  }
};

schema.timefns = ['month', 'year', 'dayofweek', 'date', 'hour', 'minute', 'second'];

schema.fn = {
  type: 'string',
  enum: schema.timefns,
  supportedTypes: {'T': true}
};

//TODO(kanitw): add other type of function here

schema.scale_type = {
  type: 'string',
  enum: ['linear', 'log', 'pow', 'sqrt', 'quantile'],
  default: 'linear',
  supportedTypes: {'Q': true}
};

schema.field = {
  type: 'object',
  properties: {
    name: {
      type: 'string'
    }
  }
};

var clone = util.duplicate;
var merge = schema.util.merge;

var typicalField = merge(clone(schema.field), {
  type: 'object',
  properties: {
    type: {
      type: 'string',
      enum: ['O', 'Q', 'T']
    },
    bin: {
      type: 'boolean',
      default: false,
      supportedTypes: {'Q': true} // TODO: add 'O' after finishing #81
    },
    aggr: schema.aggr,
    fn: schema.fn,
    scale: {
      type: 'object',
      properties: {
        type: schema.scale_type,
        reverse: {
          type: 'boolean',
          default: false,
          supportedTypes: {'Q': true, 'O': true, 'T': true}
        },
        zero: {
          type: 'boolean',
          description: 'Include zero',
          supportedTypes: {'Q': true}
        },
        nice: {
          type: 'string',
          enum: ['second', 'minute', 'hour', 'day', 'week', 'month', 'year'],
          supportedTypes: {'T': true}
        }
      }
    }
  }
});

var onlyOrdinalField = merge(clone(schema.field), {
  type: 'object',
  properties: {
    type: {
      type: 'string',
      enum: ['O','Q'] // ordinal-only field supports Q when bin is applied
    },
    bin: {
      type: 'boolean',
      default: false,
      supportedTypes: {'Q': true} // TODO: add 'O' after finishing #81
    },
    aggr: {
      type: 'string',
      enum: ['count'],
      supportedTypes: {'O': true}
    }
  }
});

var axisMixin = {
  type: 'object',
  properties: {
    axis: {
      type: 'object',
      properties: {
        grid: {
          type: 'boolean',
          default: true,
          description: 'A flag indicate if gridlines should be created in addition to ticks.'
        },
        title: {
          type: 'boolean',
          default: true,
          description: 'A title for the axis.'
        },
        titleAlign: {
          type: 'string',
          enum: ['left', 'right', 'center']
        },
        titleOffset: {
          type: 'integer',
          description: 'A title offset value for the axis.'
        },
        format: {
          type: 'string',
          description: 'The formatting pattern for axis labels.'
        }
      }
    }
  }
};

var bandMixin = {
  type: 'object',
  properties: {
    band: schema.band
  }
};

var legendMixin = {
  type: 'object',
  properties: {
    legend: {
      type: 'boolean',
      default: true
    }
  }
};

var textMixin = {
  type: 'object',
  properties: {
    text: {
      type: 'object',
      properties: {
        text: {
          type: 'object',
          properties: {
            align: {
              type: 'string',
              default: 'left'
            },
            baseline: {
              type: 'string',
              default: 'middle'
            },
            margin: {
              type: 'integer',
              default: 4,
              minimum: 0
            }
          }
        },
        font: {
          type: 'object',
          properties: {
            weight: {
              type: 'string',
              enum: ['normal', 'bold'],
              default: 'normal'
            },
            size: {
              type: 'integer',
              default: 10,
              minimum: 0
            },
            family: {
              type: 'string',
              default: 'Helvetica Neue'
            },
            style: {
              type: 'string',
              default: 'normal',
              enum: ['normal', 'italic']
            }
          }
        }
      }
    }
  }
};

var sizeMixin = {
  type: 'object',
  properties: {
    value: {
      type: 'integer',
      default: 30,
      minimum: 0
    }
  }
};

var colorMixin = {
  type: 'object',
  properties: {
    value: {
      type: 'string',
      role: 'color',
      default: 'steelblue'
    },
    scale: {
      type: 'object',
      properties: {
        range: {
          type: ['string', 'array']
        }
      }
    }
  }
};

var alphaMixin = {
  type: 'object',
  properties: {
    value: {
      type: 'number',
      default: undefined,  // auto
      minimum: 0,
      maximum: 1
    }
  }
};

var shapeMixin = {
  type: 'object',
  properties: {
    value: {
      type: 'string',
      enum: ['circle', 'square', 'cross', 'diamond', 'triangle-up', 'triangle-down'],
      default: 'circle'
    }
  }
};

var rowMixin = {
  properties: {
    height: {
      type: 'number',
      minimum: 0,
      default: 150
    },
    padding: {
      type: 'number',
      minimum: 0,
      maximum: 1,
      default: 0.1
    }
  }
};

var colMixin = {
  properties: {
    width: {
      type: 'number',
      minimum: 0,
      default: 150
    },
    padding: {
      type: 'number',
      minimum: 0,
      maximum: 1,
      default: 0.1
    }
  }
};

var requiredNameType = {
  required: ['name', 'type']
};

var x = merge(merge(merge(clone(typicalField), axisMixin), bandMixin), requiredNameType);
var y = clone(x);

var facet = merge(clone(onlyOrdinalField), requiredNameType);
var row = merge(clone(facet), rowMixin);
var col = merge(clone(facet), colMixin);

var size = merge(merge(clone(typicalField), legendMixin), sizeMixin);
var color = merge(merge(clone(typicalField), legendMixin), colorMixin);
var alpha = merge(clone(typicalField), alphaMixin);
var shape = merge(merge(clone(onlyOrdinalField), legendMixin), shapeMixin);

var text = merge(clone(typicalField), textMixin);

var filter = {
  type: 'array',
  items: {
    type: 'object',
    properties: {
      operands: {
        type: 'array',
        items: {
          type: ['string', 'boolean', 'integer', 'number']
        }
      },
      operator: {
        type: 'string',
        enum: ['>', '>=', '=', '!=', '<', '<=', 'notNull']
      }
    }
  }
};

var cfg = {
  type: 'object',
  properties: {
    // template
    width: {
      type: 'integer',
      default: undefined
    },
    height: {
      type: 'integer',
      default: undefined
    },
    viewport: {
      type: 'array',
      items: {
        type: ['integer']
      },
      default: undefined
    },
    //binning
    maxbins: {
      type: 'integer',
      default: 15,
      minimum: 2
    },

    // single plot
    singleHeight: {
      // will be overwritten by bandWidth * (cardinality + padding)
      type: 'integer',
      default: 200,
      minimum: 0
    },
    singleWidth: {
      // will be overwritten by bandWidth * (cardinality + padding)
      type: 'integer',
      default: 200,
      minimum: 0
    },
    // band size
    largeBandSize: {
      type: 'integer',
      default: 19,
      minimum: 0
    },
    smallBandSize: {
      //small multiples or single plot with high cardinality
      type: 'integer',
      default: 12,
      minimum: 0
    },
    largeBandMaxCardinality: {
      type: 'integer',
      default: 10
    },
    // small multiples
    cellPadding: {
      type: 'number',
      default: 0.1
    },
    cellBackgroundColor: {
      type: 'string',
      role: 'color',
      default: '#fdfdfd'
    },
    textCellWidth: {
      type: 'integer',
      default: 90,
      minimum: 0
    },

    // marks
    strokeWidth: {
      type: 'integer',
      default: 2,
      minimum: 0
    },

    // scales
    timeScaleLabelLength: {
      type: 'integer',
      default: 3,
      minimum: 0
    },
    // other
    characterWidth: {
      type: 'integer',
      default: 6
    },

    // data source
    dataFormatType: {
      type: 'string',
      enum: ['json', 'csv'],
      default: 'json'
    },
    useVegaServer: {
      type: 'boolean',
      default: false
    },
    dataUrl: {
      type: 'string',
      default: undefined
    },
    vegaServerTable: {
      type: 'string',
      default: undefined
    },
    vegaServerUrl: {
      type: 'string',
      default: 'http://localhost:3001'
    }
  }
};

/** @type Object Schema of a vegalite specification */
schema.schema = {
  $schema: 'http://json-schema.org/draft-04/schema#',
  Description: 'Schema for vegalite specification',
  type: 'object',
  required: ['marktype', 'enc', 'cfg'],
  properties: {
    marktype: schema.marktype,
    enc: {
      type: 'object',
      properties: {
        x: x,
        y: y,
        row: row,
        col: col,
        size: size,
        color: color,
        alpha: alpha,
        shape: shape,
        text: text
      }
    },
    filter: filter,
    cfg: cfg
  }
};

/** Instantiate a verbose vl spec from the schema */
schema.instantiate = function() {
  return schema.util.instantiate(schema.schema);
};
<commit_msg>Revert "Enable grid by default"<commit_after>// Package of defining Vegalite Specification's json schema

var schema = module.exports = {},
  util = require('../util');

schema.util = require('./schemautil');

schema.marktype = {
  type: 'string',
  enum: ['point', 'bar', 'line', 'area', 'circle', 'square', 'text']
};

schema.aggr = {
  type: 'string',
  enum: ['avg', 'sum', 'min', 'max', 'count'],
  supportedEnums: {
    Q: ['avg', 'sum', 'min', 'max', 'count'],
    O: [],
    T: ['avg', 'min', 'max'],
    '': ['count']
  },
  supportedTypes: {'Q': true, 'O': true, 'T': true, '': true}
};

schema.band = {
  type: 'object',
  properties: {
    size: {
      type: 'integer',
      minimum: 0
    },
    padding: {
      type: 'integer',
      minimum: 0,
      default: 1
    }
  }
};

schema.timefns = ['month', 'year', 'dayofweek', 'date', 'hour', 'minute', 'second'];

schema.fn = {
  type: 'string',
  enum: schema.timefns,
  supportedTypes: {'T': true}
};

//TODO(kanitw): add other type of function here

schema.scale_type = {
  type: 'string',
  enum: ['linear', 'log', 'pow', 'sqrt', 'quantile'],
  default: 'linear',
  supportedTypes: {'Q': true}
};

schema.field = {
  type: 'object',
  properties: {
    name: {
      type: 'string'
    }
  }
};

var clone = util.duplicate;
var merge = schema.util.merge;

var typicalField = merge(clone(schema.field), {
  type: 'object',
  properties: {
    type: {
      type: 'string',
      enum: ['O', 'Q', 'T']
    },
    bin: {
      type: 'boolean',
      default: false,
      supportedTypes: {'Q': true} // TODO: add 'O' after finishing #81
    },
    aggr: schema.aggr,
    fn: schema.fn,
    scale: {
      type: 'object',
      properties: {
        type: schema.scale_type,
        reverse: {
          type: 'boolean',
          default: false,
          supportedTypes: {'Q': true, 'O': true, 'T': true}
        },
        zero: {
          type: 'boolean',
          description: 'Include zero',
          supportedTypes: {'Q': true}
        },
        nice: {
          type: 'string',
          enum: ['second', 'minute', 'hour', 'day', 'week', 'month', 'year'],
          supportedTypes: {'T': true}
        }
      }
    }
  }
});

var onlyOrdinalField = merge(clone(schema.field), {
  type: 'object',
  properties: {
    type: {
      type: 'string',
      enum: ['O','Q'] // ordinal-only field supports Q when bin is applied
    },
    bin: {
      type: 'boolean',
      default: false,
      supportedTypes: {'Q': true} // TODO: add 'O' after finishing #81
    },
    aggr: {
      type: 'string',
      enum: ['count'],
      supportedTypes: {'O': true}
    }
  }
});

var axisMixin = {
  type: 'object',
  properties: {
    axis: {
      type: 'object',
      properties: {
        grid: {
          type: 'boolean',
          default: false,
          description: 'A flag indicate if gridlines should be created in addition to ticks.'
        },
        title: {
          type: 'boolean',
          default: true,
          description: 'A title for the axis.'
        },
        titleAlign: {
          type: 'string',
          enum: ['left', 'right', 'center']
        },
        titleOffset: {
          type: 'integer',
          description: 'A title offset value for the axis.'
        },
        format: {
          type: 'string',
          description: 'The formatting pattern for axis labels.'
        }
      }
    }
  }
};

var bandMixin = {
  type: 'object',
  properties: {
    band: schema.band
  }
};

var legendMixin = {
  type: 'object',
  properties: {
    legend: {
      type: 'boolean',
      default: true
    }
  }
};

var textMixin = {
  type: 'object',
  properties: {
    text: {
      type: 'object',
      properties: {
        text: {
          type: 'object',
          properties: {
            align: {
              type: 'string',
              default: 'left'
            },
            baseline: {
              type: 'string',
              default: 'middle'
            },
            margin: {
              type: 'integer',
              default: 4,
              minimum: 0
            }
          }
        },
        font: {
          type: 'object',
          properties: {
            weight: {
              type: 'string',
              enum: ['normal', 'bold'],
              default: 'normal'
            },
            size: {
              type: 'integer',
              default: 10,
              minimum: 0
            },
            family: {
              type: 'string',
              default: 'Helvetica Neue'
            },
            style: {
              type: 'string',
              default: 'normal',
              enum: ['normal', 'italic']
            }
          }
        }
      }
    }
  }
};

var sizeMixin = {
  type: 'object',
  properties: {
    value: {
      type: 'integer',
      default: 30,
      minimum: 0
    }
  }
};

var colorMixin = {
  type: 'object',
  properties: {
    value: {
      type: 'string',
      role: 'color',
      default: 'steelblue'
    },
    scale: {
      type: 'object',
      properties: {
        range: {
          type: ['string', 'array']
        }
      }
    }
  }
};

var alphaMixin = {
  type: 'object',
  properties: {
    value: {
      type: 'number',
      default: undefined,  // auto
      minimum: 0,
      maximum: 1
    }
  }
};

var shapeMixin = {
  type: 'object',
  properties: {
    value: {
      type: 'string',
      enum: ['circle', 'square', 'cross', 'diamond', 'triangle-up', 'triangle-down'],
      default: 'circle'
    }
  }
};

var rowMixin = {
  properties: {
    height: {
      type: 'number',
      minimum: 0,
      default: 150
    },
    padding: {
      type: 'number',
      minimum: 0,
      maximum: 1,
      default: 0.1
    }
  }
};

var colMixin = {
  properties: {
    width: {
      type: 'number',
      minimum: 0,
      default: 150
    },
    padding: {
      type: 'number',
      minimum: 0,
      maximum: 1,
      default: 0.1
    }
  }
};

var requiredNameType = {
  required: ['name', 'type']
};

var x = merge(merge(merge(clone(typicalField), axisMixin), bandMixin), requiredNameType);
var y = clone(x);

var facet = merge(clone(onlyOrdinalField), requiredNameType);
var row = merge(clone(facet), rowMixin);
var col = merge(clone(facet), colMixin);

var size = merge(merge(clone(typicalField), legendMixin), sizeMixin);
var color = merge(merge(clone(typicalField), legendMixin), colorMixin);
var alpha = merge(clone(typicalField), alphaMixin);
var shape = merge(merge(clone(onlyOrdinalField), legendMixin), shapeMixin);

var text = merge(clone(typicalField), textMixin);

var filter = {
  type: 'array',
  items: {
    type: 'object',
    properties: {
      operands: {
        type: 'array',
        items: {
          type: ['string', 'boolean', 'integer', 'number']
        }
      },
      operator: {
        type: 'string',
        enum: ['>', '>=', '=', '!=', '<', '<=', 'notNull']
      }
    }
  }
};

var cfg = {
  type: 'object',
  properties: {
    // template
    width: {
      type: 'integer',
      default: undefined
    },
    height: {
      type: 'integer',
      default: undefined
    },
    viewport: {
      type: 'array',
      items: {
        type: ['integer']
      },
      default: undefined
    },
    //binning
    maxbins: {
      type: 'integer',
      default: 15,
      minimum: 2
    },

    // single plot
    singleHeight: {
      // will be overwritten by bandWidth * (cardinality + padding)
      type: 'integer',
      default: 200,
      minimum: 0
    },
    singleWidth: {
      // will be overwritten by bandWidth * (cardinality + padding)
      type: 'integer',
      default: 200,
      minimum: 0
    },
    // band size
    largeBandSize: {
      type: 'integer',
      default: 19,
      minimum: 0
    },
    smallBandSize: {
      //small multiples or single plot with high cardinality
      type: 'integer',
      default: 12,
      minimum: 0
    },
    largeBandMaxCardinality: {
      type: 'integer',
      default: 10
    },
    // small multiples
    cellPadding: {
      type: 'number',
      default: 0.1
    },
    cellBackgroundColor: {
      type: 'string',
      role: 'color',
      default: '#fdfdfd'
    },
    textCellWidth: {
      type: 'integer',
      default: 90,
      minimum: 0
    },

    // marks
    strokeWidth: {
      type: 'integer',
      default: 2,
      minimum: 0
    },

    // scales
    timeScaleLabelLength: {
      type: 'integer',
      default: 3,
      minimum: 0
    },
    // other
    characterWidth: {
      type: 'integer',
      default: 6
    },

    // data source
    dataFormatType: {
      type: 'string',
      enum: ['json', 'csv'],
      default: 'json'
    },
    useVegaServer: {
      type: 'boolean',
      default: false
    },
    dataUrl: {
      type: 'string',
      default: undefined
    },
    vegaServerTable: {
      type: 'string',
      default: undefined
    },
    vegaServerUrl: {
      type: 'string',
      default: 'http://localhost:3001'
    }
  }
};

/** @type Object Schema of a vegalite specification */
schema.schema = {
  $schema: 'http://json-schema.org/draft-04/schema#',
  Description: 'Schema for vegalite specification',
  type: 'object',
  required: ['marktype', 'enc', 'cfg'],
  properties: {
    marktype: schema.marktype,
    enc: {
      type: 'object',
      properties: {
        x: x,
        y: y,
        row: row,
        col: col,
        size: size,
        color: color,
        alpha: alpha,
        shape: shape,
        text: text
      }
    },
    filter: filter,
    cfg: cfg
  }
};

/** Instantiate a verbose vl spec from the schema */
schema.instantiate = function() {
  return schema.util.instantiate(schema.schema);
};
<|endoftext|>


<commit_before>import * as THREE from "three";
import WindowResize from "three-window-resize";
import random from "lodash.random";
import sample from "lodash.sample";
import each from "promise-each";
import FontCache from "./font-cache";
import ModelCache from "./model-cache";
import SoundCache from "./sound-cache";

const appEl = document.querySelector(".app");
const loadingEl = appEl.querySelector(".loading");
const color = new THREE.Color(getComputedStyle(appEl).getPropertyValue("color"));
const material = new THREE.MeshToonMaterial({ color });
const fieldOfView = 55;
const drawDistance = 1000;
const gridSize = 10000;
const gridDivisions = 140;
const fontFilenames = ["Righteous_Regular.json"];
const modelFilenames = Array.from({ length: 4 }, (_, index) => `${index + 1}.obj`);
const soundFilenames = Array.from({ length: 26 }, (_, index) => `${index + 1}.ogg`);
const fontCache = new FontCache("fonts");
const modelCache = new ModelCache("models");
const soundCache = new SoundCache("sounds");

let renderer, camera, scene, description, title, gridTop, gridBottom, spotlight, models, sounds;

init().then(render);

function init() {
  return Promise
  .resolve()
  .then(() => (
    Promise.resolve(fontFilenames).then(each((fontFilename, index) => {
      loadingEl.innerHTML = `Loading font ${index + 1}/${fontFilenames.length}...`;
      return fontCache.set(fontFilename);
    }))
  )).then(() => (
    Promise.resolve(modelFilenames).then(each((modelFilename, index) => {
      loadingEl.innerHTML = `Loading model ${index + 1}/${modelFilenames.length}...`;
      return modelCache.set(modelFilename);
    }))
  )).then(() => (
    Promise.resolve(soundFilenames).then(each((soundFilename, index) => {
      loadingEl.innerHTML = `Loading sound ${index + 1}/${soundFilenames.length}...`;
      return soundCache.set(soundFilename);
    }))
  )).then(() => {
    loadingEl.remove();

    renderer = new THREE.WebGLRenderer({ alpha: true, antialias: true });
    renderer.setSize(window.innerWidth, window.innerHeight);
    appEl.appendChild(renderer.domElement);

    camera = new THREE.PerspectiveCamera(fieldOfView, window.innerWidth / window.innerHeight, 1, drawDistance);
    camera.position.x = 0;
    camera.position.y = 0;
    camera.position.z = drawDistance;

    WindowResize(renderer, camera); // Automatically handle window resize events.

    scene = new THREE.Scene();

    let font = fontCache.get("Righteous_Regular.json");
    description = new THREE.Mesh(new THREE.TextGeometry("SLEEP, STUDY, AND RELAX WITH THE SOUND OF SYNTHESIZERS!", { font, size: 35, height: 1 }));
    description.material = Object.assign(material.clone(), { transparent: true });
    description.geometry.computeBoundingBox(); // Compute bounding box so that text can be centered.
    description.position.x = description.geometry.boundingBox.min.x - description.geometry.boundingBox.max.x / 2;
    description.position.x -= 2; // FIXME: Text doesn't center properly; a bug in FontLoader?
    description.position.y = description.geometry.boundingBox.min.y - description.geometry.boundingBox.max.y / 2;
    description.position.z = camera.position.z + 250;
    scene.add(description);

    title = new THREE.Mesh(new THREE.TextGeometry("SYNTH MOOD", { font, size: 110, height: 1 }));
    title.material = material;
    title.geometry.computeBoundingBox(); // Compute bounding box so that text can be centered.
    title.position.x = title.geometry.boundingBox.min.x - title.geometry.boundingBox.max.x / 2;
    title.position.x -= 6; // FIXME: Text doesn't center properly; a bug in FontLoader?
    title.position.y = title.geometry.boundingBox.min.y - title.geometry.boundingBox.max.y / 2;
    title.position.z = camera.position.z + 1250;
    scene.add(title);

    gridTop = new THREE.GridHelper(gridSize, gridDivisions);
    gridTop.position.x = 0;
    gridTop.position.y = 125;
    gridTop.position.z = 0;
    gridTop.material = material;
    scene.add(gridTop);

    gridBottom = new THREE.GridHelper(gridSize, gridDivisions);
    gridBottom.position.x = 0;
    gridBottom.position.y = -125;
    gridBottom.position.z = 0;
    gridBottom.material = material;
    scene.add(gridBottom);

    spotlight = new THREE.SpotLight();
    spotlight.position.x = 0;
    spotlight.position.y = 0;
    spotlight.position.z = -700;
    spotlight.distance = drawDistance + Math.abs(spotlight.position.z) - 100;
    spotlight.intensity = 2;
    spotlight.decay = 0.7;
    spotlight.color = color;
    spotlight.target = camera;
    scene.add(spotlight);

    models = [];
    sounds = [];
  });
}

function render() {
  // Queue up the next render.
  setTimeout(render, 16);

  // Move grids closer to the camera.
  // To make grids appear "infinite", reset their position once they have travelled one grid row of distance.
  gridTop.position.z += gridTop.position.z < gridSize / gridDivisions ? 1 : -gridTop.position.z;
  gridBottom.position.z += gridBottom.position.z < gridSize / gridDivisions ? 1 : -gridBottom.position.z;

  if (description.position.z > 0) {
    // Move description away from the camera until it reaches its resting position.
    description.position.z = Math.max(description.position.z - 5, 0);
  } else if (title.position.z > 0) {
    // Move title away from the camera until it reaches its resting position.
    title.position.z = Math.max(title.position.z - 5, 0);

    // Fade-out description once title enters the picture.
    if (title.position.z < camera.position.z) {
      description.material.opacity -= 0.008;
    }
  } else {
    // Move models closer to the camera.
    // Destroy models once they have travelled past the camera.
    models.forEach(model => {
      if (model.position.z < camera.position.z) {
        model.position.z += 4;
      } else {
        models.shift();
        scene.remove(model);
      }
    });

    // Spawn a new model?
    let lastModel = models[models.length - 1];
    if (!lastModel || lastModel.position.z > title.position.z + 60) {
      let model = sample(Array.from(modelCache.values())).clone();
      model.position.x = lastModel && lastModel.position.y === gridBottom.position.y ? -lastModel.position.x : random(title.position.x, title.position.x + title.geometry.boundingBox.max.x - title.geometry.boundingBox.min.x);
      model.position.y = lastModel && lastModel.position.y === gridBottom.position.y ? gridTop.position.y : gridBottom.position.y;
      model.position.z = title.position.z;
      model.scale.x = model.scale.y = model.scale.z = 15;
      model.children.filter(child => child instanceof THREE.Mesh).forEach(mesh => Object.assign(mesh, { material }));
      models.push(model);
      scene.add(model);
    }

    // Spawn a new sound?
    let lastSound = sounds[sounds.length - 1];
    if (!lastSound || lastSound.position > lastSound.duration * 0.65) {
      let sound = sample(Array.from(soundCache.values()).filter(sound => !sounds.includes(sound)));
      sound.repeats = random(0, 4);
      sound.onPosition(sound.duration * 0.95, () => {
        if (sound.repeats > 0) {
          sound.repeats--;
          sound.setPosition(0);
        }
      });
      sound.play({ onfinish: ::sounds.shift, volume: 20 });
      sounds.push(sound);
    }
  }

  // Render the scene!
  renderer.render(scene, camera);
}

// Google Analytics.
if (process.env.NODE_ENV === "production") {
  (function(i,s,o,g,r,a,m){i["GoogleAnalyticsObject"]=r;i[r]=i[r]||function(){
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
  })(window,document,"script","https://www.google-analytics.com/analytics.js","ga");
  ga("create", "UA-24505142-6", "auto");
  ga("send", "pageview");
}
<commit_msg>Remove animated description<commit_after>import * as THREE from "three";
import WindowResize from "three-window-resize";
import random from "lodash.random";
import sample from "lodash.sample";
import each from "promise-each";
import FontCache from "./font-cache";
import ModelCache from "./model-cache";
import SoundCache from "./sound-cache";

const appEl = document.querySelector(".app");
const loadingEl = appEl.querySelector(".loading");
const color = new THREE.Color(getComputedStyle(appEl).getPropertyValue("color"));
const material = new THREE.MeshToonMaterial({ color });
const fieldOfView = 55;
const drawDistance = 1000;
const gridSize = 10000;
const gridDivisions = 140;
const fontFilenames = ["Righteous_Regular.json"];
const modelFilenames = Array.from({ length: 4 }, (_, index) => `${index + 1}.obj`);
const soundFilenames = Array.from({ length: 26 }, (_, index) => `${index + 1}.ogg`);
const fontCache = new FontCache("fonts");
const modelCache = new ModelCache("models");
const soundCache = new SoundCache("sounds");

let renderer, camera, scene, title, gridTop, gridBottom, spotlight, models, sounds;

init().then(render);

function init() {
  return Promise
  .resolve()
  .then(() => (
    Promise.resolve(fontFilenames).then(each((fontFilename, index) => {
      loadingEl.innerHTML = `Loading font ${index + 1}/${fontFilenames.length}...`;
      return fontCache.set(fontFilename);
    }))
  )).then(() => (
    Promise.resolve(modelFilenames).then(each((modelFilename, index) => {
      loadingEl.innerHTML = `Loading model ${index + 1}/${modelFilenames.length}...`;
      return modelCache.set(modelFilename);
    }))
  )).then(() => (
    Promise.resolve(soundFilenames).then(each((soundFilename, index) => {
      loadingEl.innerHTML = `Loading sound ${index + 1}/${soundFilenames.length}...`;
      return soundCache.set(soundFilename);
    }))
  )).then(() => {
    loadingEl.remove();

    renderer = new THREE.WebGLRenderer({ alpha: true, antialias: true });
    renderer.setSize(window.innerWidth, window.innerHeight);
    appEl.appendChild(renderer.domElement);

    camera = new THREE.PerspectiveCamera(fieldOfView, window.innerWidth / window.innerHeight, 1, drawDistance);
    camera.position.x = 0;
    camera.position.y = 0;
    camera.position.z = drawDistance;

    WindowResize(renderer, camera); // Automatically handle window resize events.

    scene = new THREE.Scene();

    let font = fontCache.get("Righteous_Regular.json");

    title = new THREE.Mesh(new THREE.TextGeometry("SYNTH MOOD", { font, size: 110, height: 1 }));
    title.material = material;
    title.geometry.computeBoundingBox(); // Compute bounding box so that text can be centered.
    title.position.x = title.geometry.boundingBox.min.x - title.geometry.boundingBox.max.x / 2;
    title.position.x -= 6; // FIXME: Text doesn't center properly; a bug in FontLoader?
    title.position.y = title.geometry.boundingBox.min.y - title.geometry.boundingBox.max.y / 2;
    title.position.z = camera.position.z + 250;
    scene.add(title);

    gridTop = new THREE.GridHelper(gridSize, gridDivisions);
    gridTop.position.x = 0;
    gridTop.position.y = 125;
    gridTop.position.z = 0;
    gridTop.material = material;
    scene.add(gridTop);

    gridBottom = new THREE.GridHelper(gridSize, gridDivisions);
    gridBottom.position.x = 0;
    gridBottom.position.y = -125;
    gridBottom.position.z = 0;
    gridBottom.material = material;
    scene.add(gridBottom);

    spotlight = new THREE.SpotLight();
    spotlight.position.x = 0;
    spotlight.position.y = 0;
    spotlight.position.z = -700;
    spotlight.distance = drawDistance + Math.abs(spotlight.position.z) - 100;
    spotlight.intensity = 2;
    spotlight.decay = 0.7;
    spotlight.color = color;
    spotlight.target = camera;
    scene.add(spotlight);

    models = [];
    sounds = [];
  });
}

function render() {
  // Queue up the next render.
  setTimeout(render, 16);

  // Move grids closer to the camera.
  // To make grids appear "infinite", reset their position once they have travelled one grid row of distance.
  gridTop.position.z += gridTop.position.z < gridSize / gridDivisions ? 1 : -gridTop.position.z;
  gridBottom.position.z += gridBottom.position.z < gridSize / gridDivisions ? 1 : -gridBottom.position.z;

  if (title.position.z > 0) {
    // Move title away from the camera until it reaches its resting position.
    title.position.z = Math.max(title.position.z - 5, 0);
  } else {
    // Move models closer to the camera.
    // Destroy models once they have travelled past the camera.
    models.forEach(model => {
      if (model.position.z < camera.position.z) {
        model.position.z += 4;
      } else {
        models.shift();
        scene.remove(model);
      }
    });

    // Spawn a new model?
    let lastModel = models[models.length - 1];
    if (!lastModel || lastModel.position.z > title.position.z + 60) {
      let model = sample(Array.from(modelCache.values())).clone();
      model.position.x = lastModel && lastModel.position.y === gridBottom.position.y ? -lastModel.position.x : random(title.position.x, title.position.x + title.geometry.boundingBox.max.x - title.geometry.boundingBox.min.x);
      model.position.y = lastModel && lastModel.position.y === gridBottom.position.y ? gridTop.position.y : gridBottom.position.y;
      model.position.z = title.position.z;
      model.scale.x = model.scale.y = model.scale.z = 15;
      model.children.filter(child => child instanceof THREE.Mesh).forEach(mesh => Object.assign(mesh, { material }));
      models.push(model);
      scene.add(model);
    }

    // Spawn a new sound?
    let lastSound = sounds[sounds.length - 1];
    if (!lastSound || lastSound.position > lastSound.duration * 0.65) {
      let sound = sample(Array.from(soundCache.values()).filter(sound => !sounds.includes(sound)));
      sound.repeats = random(0, 4);
      sound.onPosition(sound.duration * 0.95, () => {
        if (sound.repeats > 0) {
          sound.repeats--;
          sound.setPosition(0);
        }
      });
      sound.play({ onfinish: ::sounds.shift, volume: 20 });
      sounds.push(sound);
    }
  }

  // Render the scene!
  renderer.render(scene, camera);
}

// Google Analytics.
if (process.env.NODE_ENV === "production") {
  (function(i,s,o,g,r,a,m){i["GoogleAnalyticsObject"]=r;i[r]=i[r]||function(){
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
  })(window,document,"script","https://www.google-analytics.com/analytics.js","ga");
  ga("create", "UA-24505142-6", "auto");
  ga("send", "pageview");
}
<|endoftext|>