<commit_before>require("ehr/triggers").initScript(this);
var WNPRC = require("wnprc_ehr/WNPRC").WNPRC;

function onInit(event, helper){
    helper.setScriptOptions({
        allowFutureDates: true
    });
    helper.decodeExtraContextProperty('waterInForm');
    helper.decodeExtraContextProperty('clientEncounterDate');

    helper.registerRowProcessor(function (helper, row){
        if (!row)
            return;
        if(!row.Id || !row.volume){
            return;
        }

        var waterInForm = helper.getProperty('waterInForm');
        waterInForm = waterInForm || {};
        waterInForm[row.Id] = waterInForm[row.Id] || [];

        var clientEncounterDate = helper.getProperty('clientEncounterDate');
        clientEncounterDate = clientEncounterDate || {};
        clientEncounterDate[row.Id] = clientEncounterDate [row.Id] || [];

        if (row.objectid){
            LABKEY.ExtAdapter.each(waterInForm[row.Id], function(r){
                if (r.objectid == row.objectid){
                    if(r.volume != row.volume){
                        r.volume = row.volume;
                    }
                    else{
                        return false;
                    }
                }
            }, this)

            LABKEY.ExtAdapter.each(clientEncounterDate[row.Id], function(r){
                if (r.objectid == row.objectid){
                    if(r.date != row.date){
                        r.date = row.date;
                    }
                    else{
                        return false;
                    }
                }
            }, this)
        }
        helper.setProperty('waterInForm',waterInForm);
        helper.setProperty('clientEncounterDate',clientEncounterDate);
    });

}

function onUpsert(helper, scriptErrors, row, oldRow) {

    if (row.date){
        console.log ("row date "+row.date );
        var map = helper.getProperty('clientEncounterDate');
        console.log (map[row.Id]);
        var clientEncounterDate = [];
        if (map && map[row.Id]){
            clientEncounterDate = map[row.Id];

        }
        let errorMessage = WNPRC.Utils.getJavaHelper().checkEncounterTime(row.Id,row.date,clientEncounterDate, 'waterAmount');
        if (errorMessage != null){
            EHR.Server.Utils.addError(scriptErrors,'date',errorMessage,'ERROR');
        }

    }

    if (row.recordSource=="LabWaterForm"){
        /*var today = new Date();
        today.setHours(0,0,0,0);
        var rowDate = new Date (row.date);
        //rowDate.setHours(0,0,0,0);
        if (rowDate.getTime() !== today.getTime()){
            EHR.Server.Utils.addError (scriptErrors,'date','Additional water in this form can only be requested for the same date', 'ERROR');
        }*/
        //row.date = rowDate;
        console.log("value of qcstate waterAmount " + row.qcstate);
        console.log("value of date " + row.date);
        var fixdate = new Date(row.date);
        fixdate.setHours(14);
        fixdate.setMinutes(1);
        row.date = fixdate;
        console.log("value of fixdate " + row.date);
        if (!row.skipWaterRegulationCheck){
            row.qcstate = 10;
            row.QCStateLabel = 'Scheduled'
            console.log("value of qcstate waterAmount after setting 10 " + row.qcstate);

        }

        console.log ("value of assignedTo "+ row.assignedTo)
        if (row.assignedTo == "animalcare" && row.volume && !row.skipWaterRegulationCheck){
            let errorMessage = WNPRC.Utils.getJavaHelper().checkUploadTime(row.id,row.date,row.recordSource,row.assignedTo, 'waterAmount');
            if (errorMessage != null){
                EHR.Server.Utils.addError(scriptErrors,'assignedTo',errorMessage,'INFO');
            }
        }
        if (row.volume && row.waterSource == "regulated" && !row.skipWaterRegulationCheck){
            var map = helper.getProperty('waterInForm');
            var waterInForm = [];
            if (map && map[row.Id]){
                waterInForm = map[row.Id];
            }
            console.log('value of clientWaterVol '+ row.extraContext);
            let jsonArray = WNPRC.Utils.getJavaHelper().checkWaterSchedule(row.id,row.date,row.objectid,row.volume,waterInForm);
            if (jsonArray != null){
                for (var i = 0; i < jsonArray.length; i++ ){
                    let errorObject = JSON.parse(jsonArray[i]);
                    EHR.Server.Utils.addError(scriptErrors,errorObject.field, errorObject.message,errorObject.severity);

                }
            }

        }

    }

}<commit_msg>Remove console logs from waterAmount trigger script<commit_after>require("ehr/triggers").initScript(this);
var WNPRC = require("wnprc_ehr/WNPRC").WNPRC;

function onInit(event, helper){
    helper.setScriptOptions({
        allowFutureDates: true
    });
    helper.decodeExtraContextProperty('waterInForm');
    helper.decodeExtraContextProperty('clientEncounterDate');

    helper.registerRowProcessor(function (helper, row){
        if (!row)
            return;
        if(!row.Id || !row.volume){
            return;
        }

        var waterInForm = helper.getProperty('waterInForm');
        waterInForm = waterInForm || {};
        waterInForm[row.Id] = waterInForm[row.Id] || [];

        var clientEncounterDate = helper.getProperty('clientEncounterDate');
        clientEncounterDate = clientEncounterDate || {};
        clientEncounterDate[row.Id] = clientEncounterDate [row.Id] || [];

        if (row.objectid){
            LABKEY.ExtAdapter.each(waterInForm[row.Id], function(r){
                if (r.objectid == row.objectid){
                    if(r.volume != row.volume){
                        r.volume = row.volume;
                    }
                    else{
                        return false;
                    }
                }
            }, this)

            LABKEY.ExtAdapter.each(clientEncounterDate[row.Id], function(r){
                if (r.objectid == row.objectid){
                    if(r.date != row.date){
                        r.date = row.date;
                    }
                    else{
                        return false;
                    }
                }
            }, this)
        }
        helper.setProperty('waterInForm',waterInForm);
        helper.setProperty('clientEncounterDate',clientEncounterDate);
    });

}

function onUpsert(helper, scriptErrors, row, oldRow) {

    if (row.date){
        //console.log ("row date "+row.date );
        var map = helper.getProperty('clientEncounterDate');
        //console.log (map[row.Id]);
        var clientEncounterDate = [];
        if (map && map[row.Id]){
            clientEncounterDate = map[row.Id];

        }
        let errorMessage = WNPRC.Utils.getJavaHelper().checkEncounterTime(row.Id,row.date,clientEncounterDate, 'waterAmount');
        if (errorMessage != null){
            EHR.Server.Utils.addError(scriptErrors,'date',errorMessage,'ERROR');
        }

    }

    if (row.recordSource=="LabWaterForm"){
        /*var today = new Date();
        today.setHours(0,0,0,0);
        var rowDate = new Date (row.date);
        //rowDate.setHours(0,0,0,0);
        if (rowDate.getTime() !== today.getTime()){
            EHR.Server.Utils.addError (scriptErrors,'date','Additional water in this form can only be requested for the same date', 'ERROR');
        }*/
        //row.date = rowDate;
        //console.log("value of qcstate waterAmount " + row.qcstate);
        //console.log("value of date " + row.date);
        var fixdate = new Date(row.date);
        fixdate.setHours(14);
        fixdate.setMinutes(1);
        row.date = fixdate;
        //console.log("value of fixdate " + row.date);
        if (!row.skipWaterRegulationCheck){
            //TODO: look up the qcstate given the label
            row.qcstate = 10;
            row.QCStateLabel = 'Scheduled'
           //console.log("value of qcstate waterAmount after setting 10 " + row.qcstate);

        }

        //console.log ("value of assignedTo "+ row.assignedTo)
        if (row.assignedTo == "animalcare" && row.volume && !row.skipWaterRegulationCheck){
            let errorMessage = WNPRC.Utils.getJavaHelper().checkUploadTime(row.id,row.date,row.recordSource,row.assignedTo, 'waterAmount');
            if (errorMessage != null){
                EHR.Server.Utils.addError(scriptErrors,'assignedTo',errorMessage,'INFO');
            }
        }
        if (row.volume && row.waterSource == "regulated" && !row.skipWaterRegulationCheck){
            var map = helper.getProperty('waterInForm');
            var waterInForm = [];
            if (map && map[row.Id]){
                waterInForm = map[row.Id];
            }
            //console.log('value of clientWaterVol '+ row.extraContext);
            let jsonArray = WNPRC.Utils.getJavaHelper().checkWaterSchedule(row.id,row.date,row.objectid,row.volume,waterInForm);
            if (jsonArray != null){
                for (var i = 0; i < jsonArray.length; i++ ){
                    let errorObject = JSON.parse(jsonArray[i]);
                    EHR.Server.Utils.addError(scriptErrors,errorObject.field, errorObject.message,errorObject.severity);

                }
            }

        }

    }

}
<|endoftext|>


<commit_before>export { tester };

import * as ValueMax from "../util/ValueMax.js";
import * as AsyncWorker_Proxy_tester from "./AsyncWorker_Proxy_tester.js";

/*
class TestCase {
  constructor( spreadsheetId, range, apiKey ) {
    this.source = source;
    this.skipLineCount = skipLineCount;
    this.result = result;
    this.suspendByteCount = suspendByteCount;
    this.note = note;
  }
}

let testCases = [
  new TestCase( tEncoder.encode(base64EncodedStrings_extra[ 0]), 1, emptyUint8Array, undefined, "Empty. Not enough lines." ),
*/

/**
 * (Note: Their length could be different, but content should be the same.
 * (i.e. the extra elements should all bew undefined))
 */
function array2d_compare_EQ( lhs, rhs ) {

  let max_i = Math.max( lhs.length, rhs.length );
  for ( let i = 0; i < max_i; ++i ) {
    let array1d_lhs = lhs[ i ];
    let array1d_rhs = rhs[ i ];

    let max_j = Math.max( array1d_lhs.length, array1d_rhs.length );
    for ( let j = 0; j < max_j; ++j ) {
      if ( array1d_lhs[ j ] != array1d_rhs[ j ] )
        return false;
    }
  }

  return true;
}

/**
 *
 * @param {ValueMax.Percentage.Aggregate} progressParent
 *   Some new progressToAdvance will be created and added to progressParent. The
 * created progressToAdvance will be increased when every time advanced. The
 * progressParent.root_get() will be returned when every time yield.
 *
 */
async function* tester( progressParent ) {
  console.log( "AsyncWorker testing..." );

  const valueCountTotal = 100;

  let progressRoot = progressParent.root_get();

  let progressBoostAll = progressParent.child_add(
    ValueMax.Percentage.Concrete.Pool.get_or_create_by( valueCountTotal ) );

  let progressNonBoostAll = progressParent.child_add(
    ValueMax.Percentage.Concrete.Pool.get_or_create_by( valueCountTotal ) );

  let progressBoostNonBoostInterleave = progressParent.child_add(
    ValueMax.Percentage.Concrete.Pool.get_or_create_by( valueCountTotal ) );

  // All boost.
  {
    let workerProxy = AsyncWorker_Proxy_tester.Pool.get_or_create_by();

    const workerId = 1;
    const intervalMilliseconds = 100;
    const valueBegin = 0;
    const valueCountPerBoost = valueCountTotal;

    let initWorkerPromise = workerProxy.initWorker_async( workerId );
    let initWorkerOk = await initWorkerPromise;

    let numberResulter = workerProxy.number_sequence_asyncGenerator(
      intervalMilliseconds,
      valueBegin, valueCountTotal, valueCountPerBoost );

    let numberResulterNext;
    do {
      numberResulterNext = await numberResulter.next();
      let { done, value } = numberResulterNext;

//!!! ...unfinished... (2022/09/12) check value

      progressBoostAll.value_advance();
      yield progressRoot;

    } while ( !done );

    workerProxy.disposeResources_and_recycleToPool();
    workerProxy = null;
   }

//!!! ...unfinished... (2022/09/12) check value

  let tester1 = GSheets.UrlComposer.Pool.get_or_create_by( spreadsheetId, range );
  let fetcher1 = tester1.fetcher_JSON_ColumnMajorArrayArray( progress1 );
  let result1 = yield* fetcher1;

  // With API key.
  let tester2 = GSheets.UrlComposer.Pool.get_or_create_by( spreadsheetId, range, apiKey );
  let fetcher2 = tester2.fetcher_JSON_ColumnMajorArrayArray( progress2 );
  let result2 = yield* fetcher2;

  // Compare results: should the same.
  if ( !array2d_compare_EQ( result1, result2 ) )
    throw Error( `${result1} != ${result2}` );

  // Test change range.
  {
    let newRange = result1[ 0 ][ 0 ];
    tester1.range_set( newRange );
    let fetcher11 = tester1.fetcher_JSON_ColumnMajorArrayArray( progress11 );
    let result11 = yield* fetcher11;

    tester2.range_set( newRange );
    let fetcher21 = tester2.fetcher_JSON_ColumnMajorArrayArray( progress21 );
    let result21 = yield* fetcher21;

    if ( !array2d_compare_EQ( result11, result21 ) )
      throw Error( `${result11} != ${result21}` );
  }

  tester2.disposeResources_and_recycleToPool();
  tester2 = null;

  tester1.disposeResources_and_recycleToPool();
  tester1 = null;

  console.log( "AsyncWorker download testing... Done." );
}
<commit_msg>Improve comments,<commit_after>export { tester };

import * as ValueMax from "../util/ValueMax.js";
import * as AsyncWorker_Proxy_tester from "./AsyncWorker_Proxy_tester.js";

/*
class TestCase {
  constructor( spreadsheetId, range, apiKey ) {
    this.source = source;
    this.skipLineCount = skipLineCount;
    this.result = result;
    this.suspendByteCount = suspendByteCount;
    this.note = note;
  }
}

let testCases = [
  new TestCase( tEncoder.encode(base64EncodedStrings_extra[ 0]), 1, emptyUint8Array, undefined, "Empty. Not enough lines." ),
*/

/**
 * (Note: Their length could be different, but content should be the same.
 * (i.e. the extra elements should all bew undefined))
 */
function array2d_compare_EQ( lhs, rhs ) {

  let max_i = Math.max( lhs.length, rhs.length );
  for ( let i = 0; i < max_i; ++i ) {
    let array1d_lhs = lhs[ i ];
    let array1d_rhs = rhs[ i ];

    let max_j = Math.max( array1d_lhs.length, array1d_rhs.length );
    for ( let j = 0; j < max_j; ++j ) {
      if ( array1d_lhs[ j ] != array1d_rhs[ j ] )
        return false;
    }
  }

  return true;
}

/**
 *
 * @param {ValueMax.Percentage.Aggregate} progressParent
 *   Some new progressToAdvance will be created and added to progressParent. The
 * created progressToAdvance will be increased when every time advanced. The
 * progressParent.root_get() will be returned when every time yield.
 *
 */
async function* tester( progressParent ) {
  console.log( "AsyncWorker testing..." );

  const valueCountTotal = 100;

  let progressRoot = progressParent.root_get();

  let progressBoostAll = progressParent.child_add(
    ValueMax.Percentage.Concrete.Pool.get_or_create_by( valueCountTotal ) );

  let progressNonBoostAll = progressParent.child_add(
    ValueMax.Percentage.Concrete.Pool.get_or_create_by( valueCountTotal ) );

  let progressBoostNonBoostInterleave = progressParent.child_add(
    ValueMax.Percentage.Concrete.Pool.get_or_create_by( valueCountTotal ) );

  // All boost.
  {
    let workerProxy = AsyncWorker_Proxy_tester.Pool.get_or_create_by();

    const workerId = 1;
    const intervalMilliseconds = 100;
    const valueBegin = 0;
    const valueCountPerBoost = valueCountTotal;

    let initWorkerPromise = workerProxy.initWorker_async( workerId );
    let initWorkerOk = await initWorkerPromise;

    let numberResulter = workerProxy.number_sequence_asyncGenerator(
      intervalMilliseconds,
      valueBegin, valueCountTotal, valueCountPerBoost );

    let numberResulterNext;
    do {
      numberResulterNext = await numberResulter.next();
      let { done, value } = numberResulterNext;

//!!! ...unfinished... (2022/09/12) check value

      progressBoostAll.value_advance();
      yield progressRoot;

    } while ( !done );

//!!! ...unfinished... (2022/09/12) check value

//!!! ...unfinished... (2022/09/12) check processing queue removed.

    workerProxy.disposeResources_and_recycleToPool();
    workerProxy = null;
   }

//!!! ...unfinished... (2022/09/12) check value

  let tester1 = GSheets.UrlComposer.Pool.get_or_create_by( spreadsheetId, range );
  let fetcher1 = tester1.fetcher_JSON_ColumnMajorArrayArray( progress1 );
  let result1 = yield* fetcher1;

  // With API key.
  let tester2 = GSheets.UrlComposer.Pool.get_or_create_by( spreadsheetId, range, apiKey );
  let fetcher2 = tester2.fetcher_JSON_ColumnMajorArrayArray( progress2 );
  let result2 = yield* fetcher2;

  // Compare results: should the same.
  if ( !array2d_compare_EQ( result1, result2 ) )
    throw Error( `${result1} != ${result2}` );

  // Test change range.
  {
    let newRange = result1[ 0 ][ 0 ];
    tester1.range_set( newRange );
    let fetcher11 = tester1.fetcher_JSON_ColumnMajorArrayArray( progress11 );
    let result11 = yield* fetcher11;

    tester2.range_set( newRange );
    let fetcher21 = tester2.fetcher_JSON_ColumnMajorArrayArray( progress21 );
    let result21 = yield* fetcher21;

    if ( !array2d_compare_EQ( result11, result21 ) )
      throw Error( `${result11} != ${result21}` );
  }

  tester2.disposeResources_and_recycleToPool();
  tester2 = null;

  tester1.disposeResources_and_recycleToPool();
  tester1 = null;

  console.log( "AsyncWorker download testing... Done." );
}
<|endoftext|>


<commit_before>"use strict";
module.exports = function(app)
{
    var mongoose = app.openbiz.mongoose;
    var features = {{MODEL_FEATURES}};
    var defaults = {{MODEL_META_DEFAULTS}};
    var schema = new mongoose.Schema(
    app.openbiz.MetadataParser.call(app.openbiz,__filename.replace(/\.js$/i,'.json'),features,defaults),
    {
        collection: '{{MODEL_COLLECTION}}'
    });

    schema.features = features;
    {% for(var i=0;i<MODEL_ACTION_STATICS.length;i++){ var FUNCTION = MODEL_ACTION_STATICS[i]; %}
    //Auto generated function
    schema.statics.{{FUNCTION.name}}: function({{FUNCTION.parameters}}){
        {{FUNCTION.function}}
    };
    {% } %}
    {% for(var i=0;i<MODEL_ACTION_METHODS.length;i++){ var FUNCTION = MODEL_ACTION_METHODS[i]; %}
    //Auto generated function
    schema.methods.{{FUNCTION.name}}: function({{FUNCTION.parameters}}){
        {{FUNCTION.function}}
    };
    {% } %}
    return app.openbiz.db.model('{{APP_NAME}}.{{MODULE_NAME}}.{{MODEL_NAME}}', schema);
}<commit_msg>update<commit_after>"use strict";
module.exports = function(app)
{
    var mongoose = app.openbiz.mongoose;
    var features = {{MODEL_FEATURES}};
    var defaults = {{MODEL_META_DEFAULTS}};
    var schemaMeta = app.openbiz.ModelService.applyMetadata.call(app.openbiz,
        app.openbiz.MetadataParser.call(app.openbiz,__filename.replace(/\.js$/i,'.json'))
        ,features,defaults)
    var schema = new mongoose.Schema(schemaMeta,{
        collection: '{{MODEL_COLLECTION}}'
    });

    schema.features = features;
    {% for(var i=0;i<MODEL_ACTION_STATICS.length;i++){ var FUNCTION = MODEL_ACTION_STATICS[i]; %}
    //Auto generated function
    schema.statics.{{FUNCTION.name}}: function({{FUNCTION.parameters}}){
        {{FUNCTION.function}}
    };
    {% } %}
    {% for(var i=0;i<MODEL_ACTION_METHODS.length;i++){ var FUNCTION = MODEL_ACTION_METHODS[i]; %}
    //Auto generated function
    schema.methods.{{FUNCTION.name}}: function({{FUNCTION.parameters}}){
        {{FUNCTION.function}}
    };
    {% } %}
    return app.openbiz.db.model('{{APP_NAME}}.{{MODULE_NAME}}.{{MODEL_NAME}}', schema);
}<|endoftext|>


<commit_before>/* Copyright © 2015 PointSource, LLC. All rights reserved. */

var _ = require('lodash'),
    request = require('request'),
    jwt = require('jsonwebtoken'),
    base64 = require('base64url'),
    getPem = require('rsa-pem-from-mod-exp');

var _discovery = null, _certs, _pems = {};
var _cfg = null;

module.exports.init = function (app, logger, config, auth, callback) {

    var cfg = config.get('google-jwt');
    _cfg = cfg;
    if (cfg.clientId) {

        logger.warn('Using experimental google-jwt auth');

        //get the discovery data, which we need to look up certificates
        request.get('https://accounts.google.com/.well-known/openid-configuration', function (err, resp, body) {
            if (err) {
                return callback(err);
            }

            if (resp.statusCode !== 200) {
                return callback(new Error('Could not access google discovery service.'));
            }

            _discovery = JSON.parse(body);

            //Download the certificates
            request.get(_discovery.jwks_uri, function (err, resp, body) {
                if (err) {
                    return callback(err);
                }

                if (resp.statusCode !== 200) {
                    return callback(new Error('Could not access google certs.'));
                }

                _certs = JSON.parse(body);

                //convert the jwks to pem certificates
                _certs.keys.forEach(function (key) {
                    _pems[key.kid] = getPem(key.n, key.e);
                });
                callback();
            });
        });
    } else {
        callback(); //nothing to do
    }

}

module.exports.authenticate = function (req, res, next) {
    var bearerToken = req.headers["authorization"];
    if (bearerToken) {
        var bearer = bearerToken.split(' ')[1];

        //we need to decode just the header of the jwt so that we can figure out the kid
        var parts = bearer.split('.');
        try {
            var header = JSON.parse(base64.decode(parts[0]));
            var kid = header.kid;

            //with the kid, we can look up the corresponding pem
            var pem = _pems[kid];

            //for some reason, the iss can be either accounts.google.com or https://accounts.google.com
            //let's go ahead and use the one from the token itself
            var payload = JSON.parse(base64.decode(parts[1]));
            var iss = _discovery.issuer;
            if (payload.iss === 'accounts.google.com') {
                iss = 'accounts.google.com';
            }

            jwt.verify(bearer, pem, {
                issuer: iss,
                algorithms: _discovery.id_token_signing_alg_values_supported,
                audience: _cfg.clientId
            }, function (err, decoded) {
                //console.log(decoded)
                if (err) {
                    return res.status(401).send(err.message);
                }
                req.user = {
                    email: decoded.email,
                    id: decoded.sub
                };
                next();
            });
        } catch (err) {
            //invalid token
            res.sendStatus(401);
        }
    } else {
        res.sendStatus(401);
    }
}
<commit_msg>Improve validation of Bearer token for JWT<commit_after>/* Copyright © 2015 PointSource, LLC. All rights reserved. */

var _ = require('lodash'),
    request = require('request'),
    jwt = require('jsonwebtoken'),
    base64 = require('base64url'),
    getPem = require('rsa-pem-from-mod-exp');

var _discovery = null, _certs, _pems = {};
var _cfg = null;

module.exports.init = function (app, logger, config, auth, callback) {

    var cfg = config.get('google-jwt');
    _cfg = cfg;
    if (cfg.clientId) {

        logger.warn('Using experimental google-jwt auth');

        //get the discovery data, which we need to look up certificates
        request.get('https://accounts.google.com/.well-known/openid-configuration', function (err, resp, body) {
            if (err) {
                return callback(err);
            }

            if (resp.statusCode !== 200) {
                return callback(new Error('Could not access google discovery service.'));
            }

            _discovery = JSON.parse(body);

            //Download the certificates
            request.get(_discovery.jwks_uri, function (err, resp, body) {
                if (err) {
                    return callback(err);
                }

                if (resp.statusCode !== 200) {
                    return callback(new Error('Could not access google certs.'));
                }

                _certs = JSON.parse(body);

                //convert the jwks to pem certificates
                _certs.keys.forEach(function (key) {
                    _pems[key.kid] = getPem(key.n, key.e);
                });
                callback();
            });
        });
    } else {
        callback(); //nothing to do
    }

}

//either return token from the Bearer, Bearer <token>, or false if malformed
function extractToken(token) {
    var regex = /^Bearer\s(\S+)$/i;
    var result = regex.exec(token);
    return result ? result[1] : false;
}

module.exports.authenticate = function (req, res, next) {
    var bearerToken = req.headers["authorization"];
    if (bearerToken) {

        var bearer = extractToken(bearerToken);
        if (!bearer) {
            return res.sendStatus(400);  //bad request, malformed beared
        }

        var bearer = bearerToken.split(' ')[1];

        //we need to decode just the header of the jwt so that we can figure out the kid
        //TODO: Validate that bearer token is well formed before trying to split
        var parts = bearer.split('.');
        try {
            var header = JSON.parse(base64.decode(parts[0]));
            var kid = header.kid;

            //with the kid, we can look up the corresponding pem
            var pem = _pems[kid];

            //for some reason, the iss can be either accounts.google.com or https://accounts.google.com
            //let's go ahead and use the one from the token itself
            var payload = JSON.parse(base64.decode(parts[1]));
            var iss = _discovery.issuer;
            if (payload.iss === 'accounts.google.com') {
                iss = 'accounts.google.com';
            }

            jwt.verify(bearer, pem, {
                issuer: iss,
                algorithms: _discovery.id_token_signing_alg_values_supported,
                audience: _cfg.clientId
            }, function (err, decoded) {
                //console.log(decoded)
                if (err) {
                    return res.status(401).send(err.message);
                }
                req.user = {
                    email: decoded.email,
                    id: decoded.sub
                };
                next();
            });
        } catch (err) {
            //invalid token
            res.sendStatus(401);
        }
    } else {
        res.sendStatus(401);
    }
}
<|endoftext|>


<commit_before>/* eslint no-unused-expressions: 0 */
/* global sinon */

import { Collection } from "src/index";

describe("collections", () => {

  describe("isNonEmptyArray", () => {

    it("returns false for undefined argument", () => {
      expect(Collection.isNonEmptyArray()).to.equal(false);
    });

    it("returns false for empty array", () => {
      expect(Collection.isNonEmptyArray([])).to.equal(false);
    });

    it("returns true for non-empty array", () => {
      expect(Collection.isNonEmptyArray(["hello"])).to.equal(true);
    });
  });

  describe("containsStrings", () => {

    it("handles empty argument", () => {
      expect(Collection.containsStrings()).to.equal(false);
    });

    it("handles empty array", () => {
      expect(Collection.containsStrings([])).to.equal(false);
    });

    it("returns false for collections of non-strings", () => {
      expect(Collection.containsStrings([0, 1])).to.equal(false);
      expect(Collection.containsStrings([undefined, null, NaN])).to.equal(false);
      expect(Collection.containsStrings([{}, { a: "foo" }])).to.equal(false);
    });

    it("returns false for collections with strings", () => {
      expect(Collection.containsStrings(["hello"])).to.equal(true);
      expect(Collection.containsStrings(["hello", "there"])).to.equal(true);
      expect(Collection.containsStrings([0, "hello", {}, null])).to.equal(true);
    });
  });

  describe("containsOnlyStrings", () => {

    it("handles empty argument", () => {
      expect(Collection.containsOnlyStrings()).to.equal(false);
    });

    it("handles empty array", () => {
      expect(Collection.containsOnlyStrings([])).to.equal(false);
    });

    it("returns false for collections of non-strings", () => {
      expect(Collection.containsOnlyStrings([0, 1])).to.equal(false);
      expect(Collection.containsOnlyStrings([undefined, null, NaN])).to.equal(false);
      expect(Collection.containsOnlyStrings([{}, { a: "foo" }])).to.equal(false);
    });

    it("returns false for collections with some strings", () => {
      expect(Collection.containsOnlyStrings(["hello", 0])).to.equal(false);
      expect(Collection.containsOnlyStrings(["hello", ["not me"]])).to.equal(false);
      expect(Collection.containsOnlyStrings([0, "hello", {}, null])).to.equal(false);
    });

    it("returns true for collections with only strings", () => {
      expect(Collection.containsOnlyStrings(["hello"])).to.equal(true);
      expect(Collection.containsOnlyStrings(["hello", "there"])).to.equal(true);
    });
  });

  describe("isArrayOfArrays", () => {

    it("handles empty argument", () => {
      expect(Collection.isArrayOfArrays()).to.equal(false);
    });

    it("handles empty array", () => {
      expect(Collection.isArrayOfArrays([])).to.equal(false);
    });

    it("returns false for collections of non-arrays", () => {
      expect(Collection.isArrayOfArrays([1])).to.equal(false);
      expect(Collection.isArrayOfArrays([{}])).to.equal(false);
      expect(Collection.isArrayOfArrays(["a"])).to.equal(false);
    });

    it("returns false for mixed collections", () => {
      expect(Collection.isArrayOfArrays([[], 1, {}])).to.equal(false);
      expect(Collection.isArrayOfArrays([1, [], {}])).to.equal(false);
      expect(Collection.isArrayOfArrays([1, {}, []])).to.equal(false);
    });

    it("returns true for collections of arrays", () => {
      expect(Collection.isArrayOfArrays([ [] ])).to.equal(true);
      expect(Collection.isArrayOfArrays([ [{}] ])).to.equal(true);
      expect(Collection.isArrayOfArrays([ [ [] ] ])).to.equal(true);
      expect(Collection.isArrayOfArrays([ [], [] ])).to.equal(true);
    });
  });

  describe("removeUndefined", () => {

    it("handles empty array", () => {
      expect(Collection.removeUndefined([])).to.eql([]);
    });

    it("does not filter non-undefineds", () => {
      const testArray = [0, 1, "a", {}, false, null, NaN];
      expect(Collection.removeUndefined(testArray)).to.eql(testArray);
    });

    it("filters out undefineds", () => {
      const testArray = [undefined, 0, undefined, {}, false, null, NaN, undefined];
      const expectedArray = [0, {}, false, null, NaN];
      expect(Collection.removeUndefined(testArray)).to.eql(expectedArray);
    });
  });

  describe("getMaxValue", () => {

    it("returns a date if array contains dates", () => {
      const array = [new Date(2016, 3, 6), new Date(2017, 5, 3), 10];
      expect(Collection.getMaxValue(array)).to.eql(new Date(2017, 5, 3));
    });

    it("returns a number if array does not contain dates", () => {
      const array = [3, 8, 10];
      expect(Collection.getMaxValue(array)).to.eql(10);
    });

    it("allows values to be concated and returns the appropriate number", () => {
      const array = [3, 8, 10];
      expect(Collection.getMaxValue(array, 1, 20)).to.eql(20);
    });
  });

  describe("getMinValue", () => {

    it("returns a date if array contains dates", () => {
      const array = [new Date(2016, 3, 6), new Date(2017, 5, 3), new Date(2015, 11, 4)];
      expect(Collection.getMinValue(array)).to.eql(new Date(2015, 11, 4));
    });

    it("returns a number if array does not contain dates", () => {
      const array = [3, 8, 10];
      expect(Collection.getMinValue(array)).to.eql(3);
    });

    it("allows values to be concated and returns the appropriate number", () => {
      const array = [3, 8, 10];
      expect(Collection.getMinValue(array, 1, 20)).to.eql(1);
    });
  });

  describe("allSetsEqual", () => {

    it("returns true when all sets are equal", () => {
      const comparisons = [
        [1, 1],
        ["wow", "wow"],
        [{ stuff: 43 }, { stuff: 43 }]
      ];

      expect(Collection.allSetsEqual(comparisons)).to.eql(true);
    });

    it("returns false when not all sets are equal", () => {
      const comparisons = [
        [1, 1],
        ["wow", "wow"],
        [{ stuff: 1 }, { stuff: 43 }]
      ];

      expect(Collection.allSetsEqual(comparisons)).to.eql(false);
    });
  });

  describe("areVictoryPropsEqual", () => {
    let sandbox;
    beforeEach(() => {
      sandbox = sinon.sandbox.create();
      sandbox.spy(Collection, "checkEquality");
    });
    afterEach(() => {
      sandbox.restore();
    });

    it("returns early when nested collections are strictly equal", () => {
      const a = { test: { nested: "a" } };
      const b = a;
      expect(Collection.areVictoryPropsEqual(a, b)).to.equal(true);
      expect(Collection.checkEquality).calledOnce.and.returned(true);
    });

    it("returns early when nested collections are not the same length", () => {
      const a = { test: { nested: "a" }, test2: { nested: "b" } };
      const b = { test: { nested: "a" } };
      expect(Collection.areVictoryPropsEqual(a, b)).to.equal(false);
      expect(Collection.checkEquality).calledOnce.and.returned(false);
    });

    it("returns early if values are not the same type", () => {
      const a = { test: { nested: "a" } };
      const b = { test: () => "a" };
      expect(Collection.areVictoryPropsEqual(a, b)).to.equal(false);
      expect(Collection.checkEquality).calledOnce.and.returned(false);
    });

    it("returns early when nested elements are empty", () => {
      const a = { a: [] };
      const b = { a: [] };
      expect(Collection.areVictoryPropsEqual(a, b)).to.equal(true);
      expect(Collection.checkEquality).calledOnce.and.returned(true);
    });

    it("returns true if values are functions", () => {
      const a = { test: () => "a" };
      const b = { test: () => "a" };
      expect(Collection.areVictoryPropsEqual(a, b)).to.equal(true);
    });

    it("recursively checks equality for nested collections", () => {
      const a = { test: { nested: "a" }, test2: { nested: "a" } };
      const b = { test: { nested: "a" }, test2: { nested: "a" } };
      expect(Collection.areVictoryPropsEqual(a, b)).to.equal(true);
      expect(Collection.checkEquality).calledThrice;
    });

    it("does not recursively check date objects", () => {
      const a = { test: new Date(), test2: new Date() };
      const b = { test: new Date(), test2: new Date() };
      expect(Collection.areVictoryPropsEqual(a, b)).to.equal(true);
      expect(Collection.checkEquality).calledOnce.and.returned(true);
    });

    it("returns equal for equivalent date objects", () => {
      const a = { test: new Date(2010, 1, 1) };
      const b = { test: new Date("Mon Feb 01 2010 00:00:00 GMT-0800 (PST)") };
      expect(Collection.areVictoryPropsEqual(a, b)).to.equal(true);
    });

  });
});
<commit_msg>use exact dates<commit_after>/* eslint no-unused-expressions: 0 */
/* global sinon */

import { Collection } from "src/index";

describe("collections", () => {

  describe("isNonEmptyArray", () => {

    it("returns false for undefined argument", () => {
      expect(Collection.isNonEmptyArray()).to.equal(false);
    });

    it("returns false for empty array", () => {
      expect(Collection.isNonEmptyArray([])).to.equal(false);
    });

    it("returns true for non-empty array", () => {
      expect(Collection.isNonEmptyArray(["hello"])).to.equal(true);
    });
  });

  describe("containsStrings", () => {

    it("handles empty argument", () => {
      expect(Collection.containsStrings()).to.equal(false);
    });

    it("handles empty array", () => {
      expect(Collection.containsStrings([])).to.equal(false);
    });

    it("returns false for collections of non-strings", () => {
      expect(Collection.containsStrings([0, 1])).to.equal(false);
      expect(Collection.containsStrings([undefined, null, NaN])).to.equal(false);
      expect(Collection.containsStrings([{}, { a: "foo" }])).to.equal(false);
    });

    it("returns false for collections with strings", () => {
      expect(Collection.containsStrings(["hello"])).to.equal(true);
      expect(Collection.containsStrings(["hello", "there"])).to.equal(true);
      expect(Collection.containsStrings([0, "hello", {}, null])).to.equal(true);
    });
  });

  describe("containsOnlyStrings", () => {

    it("handles empty argument", () => {
      expect(Collection.containsOnlyStrings()).to.equal(false);
    });

    it("handles empty array", () => {
      expect(Collection.containsOnlyStrings([])).to.equal(false);
    });

    it("returns false for collections of non-strings", () => {
      expect(Collection.containsOnlyStrings([0, 1])).to.equal(false);
      expect(Collection.containsOnlyStrings([undefined, null, NaN])).to.equal(false);
      expect(Collection.containsOnlyStrings([{}, { a: "foo" }])).to.equal(false);
    });

    it("returns false for collections with some strings", () => {
      expect(Collection.containsOnlyStrings(["hello", 0])).to.equal(false);
      expect(Collection.containsOnlyStrings(["hello", ["not me"]])).to.equal(false);
      expect(Collection.containsOnlyStrings([0, "hello", {}, null])).to.equal(false);
    });

    it("returns true for collections with only strings", () => {
      expect(Collection.containsOnlyStrings(["hello"])).to.equal(true);
      expect(Collection.containsOnlyStrings(["hello", "there"])).to.equal(true);
    });
  });

  describe("isArrayOfArrays", () => {

    it("handles empty argument", () => {
      expect(Collection.isArrayOfArrays()).to.equal(false);
    });

    it("handles empty array", () => {
      expect(Collection.isArrayOfArrays([])).to.equal(false);
    });

    it("returns false for collections of non-arrays", () => {
      expect(Collection.isArrayOfArrays([1])).to.equal(false);
      expect(Collection.isArrayOfArrays([{}])).to.equal(false);
      expect(Collection.isArrayOfArrays(["a"])).to.equal(false);
    });

    it("returns false for mixed collections", () => {
      expect(Collection.isArrayOfArrays([[], 1, {}])).to.equal(false);
      expect(Collection.isArrayOfArrays([1, [], {}])).to.equal(false);
      expect(Collection.isArrayOfArrays([1, {}, []])).to.equal(false);
    });

    it("returns true for collections of arrays", () => {
      expect(Collection.isArrayOfArrays([ [] ])).to.equal(true);
      expect(Collection.isArrayOfArrays([ [{}] ])).to.equal(true);
      expect(Collection.isArrayOfArrays([ [ [] ] ])).to.equal(true);
      expect(Collection.isArrayOfArrays([ [], [] ])).to.equal(true);
    });
  });

  describe("removeUndefined", () => {

    it("handles empty array", () => {
      expect(Collection.removeUndefined([])).to.eql([]);
    });

    it("does not filter non-undefineds", () => {
      const testArray = [0, 1, "a", {}, false, null, NaN];
      expect(Collection.removeUndefined(testArray)).to.eql(testArray);
    });

    it("filters out undefineds", () => {
      const testArray = [undefined, 0, undefined, {}, false, null, NaN, undefined];
      const expectedArray = [0, {}, false, null, NaN];
      expect(Collection.removeUndefined(testArray)).to.eql(expectedArray);
    });
  });

  describe("getMaxValue", () => {

    it("returns a date if array contains dates", () => {
      const array = [new Date(2016, 3, 6), new Date(2017, 5, 3), 10];
      expect(Collection.getMaxValue(array)).to.eql(new Date(2017, 5, 3));
    });

    it("returns a number if array does not contain dates", () => {
      const array = [3, 8, 10];
      expect(Collection.getMaxValue(array)).to.eql(10);
    });

    it("allows values to be concated and returns the appropriate number", () => {
      const array = [3, 8, 10];
      expect(Collection.getMaxValue(array, 1, 20)).to.eql(20);
    });
  });

  describe("getMinValue", () => {

    it("returns a date if array contains dates", () => {
      const array = [new Date(2016, 3, 6), new Date(2017, 5, 3), new Date(2015, 11, 4)];
      expect(Collection.getMinValue(array)).to.eql(new Date(2015, 11, 4));
    });

    it("returns a number if array does not contain dates", () => {
      const array = [3, 8, 10];
      expect(Collection.getMinValue(array)).to.eql(3);
    });

    it("allows values to be concated and returns the appropriate number", () => {
      const array = [3, 8, 10];
      expect(Collection.getMinValue(array, 1, 20)).to.eql(1);
    });
  });

  describe("allSetsEqual", () => {

    it("returns true when all sets are equal", () => {
      const comparisons = [
        [1, 1],
        ["wow", "wow"],
        [{ stuff: 43 }, { stuff: 43 }]
      ];

      expect(Collection.allSetsEqual(comparisons)).to.eql(true);
    });

    it("returns false when not all sets are equal", () => {
      const comparisons = [
        [1, 1],
        ["wow", "wow"],
        [{ stuff: 1 }, { stuff: 43 }]
      ];

      expect(Collection.allSetsEqual(comparisons)).to.eql(false);
    });
  });

  describe("areVictoryPropsEqual", () => {
    let sandbox;
    beforeEach(() => {
      sandbox = sinon.sandbox.create();
      sandbox.spy(Collection, "checkEquality");
    });
    afterEach(() => {
      sandbox.restore();
    });

    it("returns early when nested collections are strictly equal", () => {
      const a = { test: { nested: "a" } };
      const b = a;
      expect(Collection.areVictoryPropsEqual(a, b)).to.equal(true);
      expect(Collection.checkEquality).calledOnce.and.returned(true);
    });

    it("returns early when nested collections are not the same length", () => {
      const a = { test: { nested: "a" }, test2: { nested: "b" } };
      const b = { test: { nested: "a" } };
      expect(Collection.areVictoryPropsEqual(a, b)).to.equal(false);
      expect(Collection.checkEquality).calledOnce.and.returned(false);
    });

    it("returns early if values are not the same type", () => {
      const a = { test: { nested: "a" } };
      const b = { test: () => "a" };
      expect(Collection.areVictoryPropsEqual(a, b)).to.equal(false);
      expect(Collection.checkEquality).calledOnce.and.returned(false);
    });

    it("returns early when nested elements are empty", () => {
      const a = { a: [] };
      const b = { a: [] };
      expect(Collection.areVictoryPropsEqual(a, b)).to.equal(true);
      expect(Collection.checkEquality).calledOnce.and.returned(true);
    });

    it("returns true if values are functions", () => {
      const a = { test: () => "a" };
      const b = { test: () => "a" };
      expect(Collection.areVictoryPropsEqual(a, b)).to.equal(true);
    });

    it("recursively checks equality for nested collections", () => {
      const a = { test: { nested: "a" }, test2: { nested: "a" } };
      const b = { test: { nested: "a" }, test2: { nested: "a" } };
      expect(Collection.areVictoryPropsEqual(a, b)).to.equal(true);
      expect(Collection.checkEquality).calledThrice;
    });

    it("does not recursively check date objects", () => {
      const a = { test: new Date(2010, 2, 1), test2: new Date(2010, 1, 1) };
      const b = { test: new Date(2010, 2, 1), test2: new Date(2010, 1, 1) };
      expect(Collection.areVictoryPropsEqual(a, b)).to.equal(true);
      expect(Collection.checkEquality).calledOnce.and.returned(true);
    });

    it("returns equal for equivalent date objects", () => {
      const a = { test: new Date(2010, 1, 1) };
      const b = { test: new Date("Mon Feb 01 2010 00:00:00 GMT-0800 (PST)") };
      expect(Collection.areVictoryPropsEqual(a, b)).to.equal(true);
    });

  });
});
<|endoftext|>


<commit_before>/* global console */

function parsePostData(query) {
  var result = {};
  query.split("&").forEach(function(part) {
    var item = part.split("=");
    result[item[0]] = decodeURIComponent(item[1]);
  });
  return result;
}

function json(code, obj) {
  if (typeof code === "object") {
    obj = code;
    code = 200;
  }
  return [code, {"Content-Type": "application/json"}, JSON.stringify(obj)];
}

export default function() {
  var server = new Pretender(function() {
    this.post('/session', function(request) {
      var data = parsePostData(request.requestBody);

      if (data.password === 'correct') {
        return json({username: 'eviltrout'});
      }
      return json(400, {error: 'invalid login'});
    });

    this.get('/users/hp.json', function() {
      return json({"value":"32faff1b1ef1ac3","challenge":"61a3de0ccf086fb9604b76e884d75801"});
    });

    this.get('/users/check_username', function(request) {
      if (request.queryParams.username === 'taken') {
        return json({available: false, suggestion: 'nottaken'});
      }
      return json({available: true});
    });

    this.post('/users', function(request) {
      return json({success: true});
    });
  });

  server.unhandledRequest = function(verb, path) {
    console.error('Unhandled request in test environment: ' + path + ' (' + verb + ')');
  };

  return server;
}
<commit_msg>Return a CSRF in case it's requested<commit_after>/* global console */

function parsePostData(query) {
  var result = {};
  query.split("&").forEach(function(part) {
    var item = part.split("=");
    result[item[0]] = decodeURIComponent(item[1]);
  });
  return result;
}

function json(code, obj) {
  if (typeof code === "object") {
    obj = code;
    code = 200;
  }
  return [code, {"Content-Type": "application/json"}, JSON.stringify(obj)];
}

export default function() {
  var server = new Pretender(function() {
    this.post('/session', function(request) {
      var data = parsePostData(request.requestBody);

      if (data.password === 'correct') {
        return json({username: 'eviltrout'});
      }
      return json(400, {error: 'invalid login'});
    });

    this.get('/users/hp.json', function() {
      return json({"value":"32faff1b1ef1ac3","challenge":"61a3de0ccf086fb9604b76e884d75801"});
    });

    this.get('/session/csrf', function() {
      return json({"csrf":"mgk906YLagHo2gOgM1ddYjAN4hQolBdJCqlY6jYzAYs="});
    });

    this.get('/users/check_username', function(request) {
      if (request.queryParams.username === 'taken') {
        return json({available: false, suggestion: 'nottaken'});
      }
      return json({available: true});
    });

    this.post('/users', function(request) {
      return json({success: true});
    });
  });

  server.unhandledRequest = function(verb, path) {
    console.error('Unhandled request in test environment: ' + path + ' (' + verb + ')');
  };

  return server;
}
<|endoftext|>


<commit_before>/*global require,CodeMirror,JSHINT*/
require({
        baseUrl: '../../Source',
        packages: [{
            name: 'dojo',
            location: '../ThirdParty/dojo-release-1.7.2-src/dojo'
        }, {
            name: 'dijit',
            location: '../ThirdParty/dojo-release-1.7.2-src/dijit'
        }, {
            name: 'dojox',
            location: '../ThirdParty/dojo-release-1.7.2-src/dojox'
        }, {
            name: 'Sandcastle',
            location: '../Apps/Sandcastle'
        }]
    }, [
        'Widgets/Dojo/CesiumViewerWidget',
        'dojo/parser',
        'dojo/dom',
        'dojo/dom-class',
        'dojo/dom-construct',
        'dojo/io-query',
        'dojo/_base/fx',
        'dojo/_base/window',
        'dojo/_base/xhr',
        'dijit/registry',
        'dijit/layout/ContentPane',
        'dijit/form/Button',
        'dijit/form/DropDownButton',
        'dijit/form/ToggleButton',
        'dijit/form/DropDownButton',
        'dijit/form/TextBox',
        'dijit/TooltipDialog',
        'dijit/Menu',
        'dijit/MenuBar',
        'dijit/PopupMenuBarItem',
        'dijit/MenuItem',
        'dijit/layout/BorderContainer',
        'dijit/layout/TabContainer',
        'dijit/Toolbar',
        'dijit/ToolbarSeparator',
        'Sandcastle/LinkButton',
        'dojo/domReady!'],
    function (
            CesiumViewerWidget,
            parser,
            dom,
            domClass,
            domConstruct,
            ioQuery,
            fx,
            win,
            xhr,
            registry,
            ContentPane
    ) {
        "use strict";
        parser.parse();
        window.CesiumViewerWidget = CesiumViewerWidget; // for autocomplete.
        fx.fadeOut({ node: 'loading', onEnd: function () {
            domConstruct.destroy('loading');
        }}).play();

        var logOutput = document.getElementById('logOutput');
        function appendConsole(className, message) {
            var ele = document.createElement('span');
            ele.className = className;
            ele.textContent = message + "\n";
            logOutput.appendChild(ele);
            logOutput.parentNode.scrollTop = logOutput.clientHeight + 8 - logOutput.parentNode.clientHeight;
        }

        // NOTE: BlobBuilder will eventually be deprecated and replaced with a direct constructor on Blob itself.
        // https://developer.mozilla.org/en/DOM/Blob
        var BlobBuilder = BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder;
        var getURL = window.URL || window.webkitURL || window;
        if (typeof BlobBuilder === 'undefined') {
            registry.byId('buttonSaveAs').set('disabled', true);
        }

        var jsEditor;
        var htmlEditor;
        var suggestButton = registry.byId('buttonSuggest');
        var docTimer;
        var docTabs = {};
        var cesiumContainer = registry.byId('cesiumContainer');
        var docNode = dom.byId('docPopup');
        var docMessage = dom.byId('docPopupMessage');
        var local = { 'docTypes': [],  'headers': ""};
        var errorLines = [];
        var highlightLines = [];
        var hintGlobals = [
            'require',
            'document',
            'window',
            'console',
            'Sandcastle'
        ];
        var hintOptions = {
            predef: hintGlobals,
            // These are copied from the Eclipse jsHint plugin options on the Cesium project itself.
            // They should be kept in sync with that list of options.
            bitwise : false,
            curly : true,
            eqeqeq : true,
            forin : true,
            immed : false,
            latedef : true,
            newcap : true,
            noarg : true,
            noempty : false,
            nonew : true,
            plusplus : false,
            regexp : false,
            undef : true,
            strict : true,
            trailing : false,
            asi : false,
            boss : false,
            debug : false,
            eqnull : false,
            es5 : false,
            esnext : false,
            evil : false,
            expr : false,
            funcscope : false,
            globalstrict : false,
            iterator : false,
            lastsemic : false,
            laxbreak : false,
            laxcomma : false,
            loopfunc : false,
            multistr : false,
            onecase : false,
            proto : false,
            regexdash : false,
            scripturl : false,
            smarttabs : false,
            shadow : false,
            sub : false,
            supernew : false,
            validthis : false,
            browser : true
        };
        var hintTimer;

        xhr.get({
            url: '../../Build/Documentation/types.txt',
            handleAs: 'json',
            error: function(error) {
                // Quiet for now, because the console will be cleared soon after this.
                // We'll let the user know about this error further down.
            }
        }).then(function (value) {
            local.docTypes = value;
        });

        xhr.get({
            url: 'templates/bucket.html',
            handleAs: 'text'
        }).then(function (value) {
            var pos = value.indexOf('', pos);
            local.headers = value.substring(0, pos + 1) + '\n';
        });

        function highlightRun(light) {
            if (light) {
                domClass.add(registry.byId('buttonRun').domNode, 'highlightToolbarButton');
            } else {
                domClass.remove(registry.byId('buttonRun').domNode, 'highlightToolbarButton');
            }
        }

        function highlightSaveAs(light) {
            if (light) {
                domClass.add(registry.byId('buttonSaveAs').domNode, 'highlightToolbarButton');
            } else {
                domClass.remove(registry.byId('buttonSaveAs').domNode, 'highlightToolbarButton');
            }
        }

        function openDocTab(title, link) {
            if (typeof docTabs[title] === 'undefined') {
                docTabs[title] = new ContentPane({
                    title: title,
                    focused: true,
                    content: '',
                    closable: true,
                    onClose: function () {
                        docTabs[this.title] = undefined;
                        // Return true to close the tab.
                        return true;
                    }
                }).placeAt(cesiumContainer);
                // After the iframe loads, re-scroll to selected field.
                docTabs[title].domNode.childNodes[0].onload = function () {
                    this.onload = function () {};
                    this.src = link;
                };
                cesiumContainer.selectChild(docTabs[title]);
            } else {
                // Tab already exists, but maybe not visible.  FireFox needs the tab to
                // be revealed before a re-scroll can happen.  Chrome works either way.
                cesiumContainer.selectChild(docTabs[title]);
                docTabs[title].domNode.childNodes[0].src = link;
            }
        }

        function showDocPopup () {
            var selectedText = jsEditor.getSelection();

            var onDocClick = function () {
                openDocTab(this.textContent, this.href);
                return false;
            };

            if (selectedText && selectedText in local.docTypes && typeof local.docTypes[selectedText].push === 'function') {
                var member, ele, i, len = local.docTypes[selectedText].length;
                docMessage.innerHTML = '';
                for (i = 0; i < len; ++i) {
                    member = local.docTypes[selectedText][i];
                    ele = document.createElement('a');
                    ele.target = "_blank";
                    ele.textContent = member.replace('.html', '').replace('module-', '').replace('#', '.');
                    ele.href = '../../Build/Documentation/' + member;
                    ele.onclick = onDocClick;
                    docMessage.appendChild(ele);
                }
                jsEditor.addWidget(jsEditor.getCursor(true), docNode);
                docNode.style.top = (parseInt(docNode.style.top, 10) - 5) + 'px';
            }
        }

        function onCursorActivity() {
            docNode.style.left = "-999px";
            if (typeof docTimer !== 'undefined') {
                window.clearTimeout(docTimer);
            }
            docTimer = window.setTimeout(showDocPopup, 500);
        }

        var bucketFrame = document.getElementById('bucketFrame');
        var bucketPane = registry.byId('bucketPane');

        var abbrDiv = document.createElement('div');
        var abbrEle = document.createElement('abbr');
        abbrEle.textContent = '%N%';
        abbrDiv.appendChild(abbrEle);

        function makeLineLabel(msg) {
            abbrEle.title = msg;
            return abbrDiv.innerHTML;
        }

        function clearAllErrors() {
            var line, hint, hints, i, len;
            hintTimer = undefined;
            while (errorLines.length > 0) {
                line = errorLines.pop();
                jsEditor.setLineClass(line, null);
                jsEditor.clearMarker(line);
            }
            if (!JSHINT(jsEditor.getValue(), hintOptions)) {
                hints = JSHINT.errors;
                len = hints.length;
                for (i = 0; i < len; ++i) {
                    hint = hints[i];
                    if ((hint !== null) && (typeof hint.reason !== 'undefined') && (hint.line > 0)) {
                        line = jsEditor.setMarker(hint.line - 1, makeLineLabel(hint.reason), "hintMarker");
                        jsEditor.setLineClass(line, "hintLine");
                        errorLines.push(line);
                    }
                }
            }
        }

        function scheduleHint() {
            if (typeof hintTimer !== 'undefined') {
                window.clearTimeout(hintTimer);
            }
            hintTimer = setTimeout(clearAllErrors, 550);
            highlightRun(true);
        }

        function highlightLine(lineNum) {
            var line;
            while (highlightLines.length > 0) {
                line = highlightLines.pop();
                jsEditor.setLineClass(line, null);
                jsEditor.clearMarker(line);
            }
            if (lineNum > 0) {
                line = jsEditor.setMarker(lineNum - 1, makeLineLabel('hover'), "highlightMarker");
                jsEditor.setLineClass(line, "highlightLine");
                highlightLines.push(line);

                // Scroll to bring the highlighted line into view.
                jsEditor.setCursor(lineNum);
                jsEditor.setSelection({line: lineNum - 2, ch:0}, {line: lineNum - 2, ch: 0});
                jsEditor.focus();
                jsEditor.setSelection({line: lineNum, ch: 0}, {line: lineNum, ch: 0});
            }
        }

        CodeMirror.commands.runCesium = function(cm) {
            clearAllErrors();
            highlightRun(false);
            cesiumContainer.selectChild(bucketPane);
            bucketFrame.contentWindow.location.reload();
        };

        CodeMirror.commands.autocomplete = function(cm) {
            CodeMirror.simpleHint(cm, CodeMirror.cesiumHint);
        };

        jsEditor = CodeMirror.fromTextArea(document.getElementById("code"), {
            mode: "javascript",
            lineNumbers: true,
            matchBrackets: true,
            indentUnit: 4,
            onCursorActivity: onCursorActivity,
            onChange: scheduleHint,
            extraKeys: {
                "Ctrl-Space": "autocomplete",
                "F9": "runCesium",
                "Tab": "indentMore",
                "Shift-Tab": "indentLess"
            }
        });

        htmlEditor = CodeMirror.fromTextArea(document.getElementById("htmlBody"), {
            mode: "text/html",
            lineNumbers: true,
            matchBrackets: true,
            indentUnit: 4,
            extraKeys: {
                "F9": "runCesium",
                "Tab": "indentMore",
                "Shift-Tab": "indentLess"
            }
        });

        function loadFromGallery(link) {
            xhr.get({
                url: 'gallery/' + link,
                handleAs: 'text',
                error: function(error) {
                    appendConsole('consoleError', error);
                }
            }).then(function (value) {
                var pos = value.indexOf('', pos);
                var body = value.substring(pos + 2);
                pos = body.indexOf('');
                if ((pos <= 0) || (pos2 <= pos)) {
                    var ele = document.createElement('span');
                    ele.className = 'consoleError';
                    ele.textContent = 'Error reading source file: ' + link + '\n';
                    appendConsole(ele);
                } else {
                    var script = body.substring(pos + 38, pos2 - 1);
                    while (script.charAt(0) < 32) {
                        script = script.substring(1);
                    }
                    jsEditor.setValue(script);
                    htmlEditor.setValue(body.substring(0, pos - 1));
                    CodeMirror.commands.runCesium(jsEditor);
                }
            });
        }

        var queryObject = {};
        if (window.location.search) {
            queryObject = ioQuery.queryToObject(window.location.search.substring(1));
        }

        window.addEventListener('message', function (e) {
            var line;
            // The iframe (bucket.html) sends this message on load.
            // This triggers the code to be injected into the iframe.
            if (e.data === 'reload') {
                logOutput.innerHTML = "";
                if (typeof queryObject.src !== 'undefined') {
                    // This happens once on Sandcastle page load, the blank bucket.html triggers a load
                    // of the selected demo code from the gallery, followed by a Run (F9) equivalent.
                    loadFromGallery(queryObject.src);
                    queryObject.src = undefined;
                } else {
                    // This happens after a Run (F9) reloads bucket.html, to inject the editor code
                    // into the iframe, causing the demo to run there.
                    var bucketDoc = bucketFrame.contentDocument;
                    var bodyEle = bucketDoc.createElement('div');
                    bodyEle.innerHTML = htmlEditor.getValue();
                    bucketDoc.body.appendChild(bodyEle);
                    var jsEle = bucketDoc.createElement('script');
                    jsEle.type = 'text/javascript';
                    jsEle.textContent = jsEditor.getValue();
                    bucketDoc.body.appendChild(jsEle);
                    if (local.docTypes.length === 0) {
                        appendConsole('consoleError', "Documentation not available.  Please run the 'release' build script to generate Cesium documentation.");
                    }
                }
            } else if (typeof e.data.log !== 'undefined') {
                // Console log messages from the iframe display in Sandcastle.
                appendConsole('consoleLog', e.data.log);
            } else if (typeof e.data.error !== 'undefined') {
                // Console error messages from the iframe display in Sandcastle
                appendConsole('consoleError', e.data.error);
                if (typeof e.data.lineNumber !== 'undefined') {
                    line = jsEditor.setMarker(e.data.lineNumber - 1, makeLineLabel(e.data.rawErrorMsg), "errorMarker");
                    jsEditor.setLineClass(line, "errorLine");
                    errorLines.push(line);
                }
            } else if (typeof e.data.highlight !== 'undefined') {
                // Hovering objects in the embedded Cesium window.
                highlightLine(e.data.highlight);
            }
        }, true);

        registry.byId('jsContainer').on('show', function () {
            suggestButton.set('disabled', false);
            jsEditor.refresh();
        });

        registry.byId('htmlContainer').on('show', function () {
            suggestButton.set('disabled', true);
            htmlEditor.refresh();
        });

        // Clicking the 'Run' button simply reloads the iframe.
        registry.byId('buttonRun').on('click', function () {
            CodeMirror.commands.runCesium(jsEditor);
        });

        registry.byId('buttonSuggest').on('click', function () {
            CodeMirror.commands.autocomplete(jsEditor);
        });

        registry.byId('dropDownSaveAs').on('show', function () {
            var html = local.headers + htmlEditor.getValue() +
                '\n\n\n\n';

            var octetBB = new BlobBuilder();
            octetBB.append(html);
            var octetBlob = octetBB.getBlob("application/octet-stream");
            var octetBlobURL = getURL.createObjectURL(octetBlob);
            dom.byId('saveAsFile').href = octetBlobURL;

            var baseHref = window.location.href, pos = baseHref.lastIndexOf('/');
            baseHref = baseHref.substring(0, pos) + '/gallery/';
            html = html.replace('', '\n    <base href="' + baseHref + '">');
            var htmlBB = new BlobBuilder();
            htmlBB.append(html);
            var htmlBlob = htmlBB.getBlob("text/html;charset=utf-8");
            var htmlBlobURL = getURL.createObjectURL(htmlBlob);
            dom.byId('saveAsNewWindow').href = htmlBlobURL;
        });

        registry.byId('buttonThumbnail').on('change', function (newValue) {
            if (newValue) {
                domClass.add('bucketFrame', 'makeThumbnail');
            } else {
                domClass.remove('bucketFrame', 'makeThumbnail');
            }
        });
    });
<commit_msg>Sandcastle - Change line highlight message now that there are demos that allow the user to read it.<commit_after>/*global require,CodeMirror,JSHINT*/
require({
        baseUrl: '../../Source',
        packages: [{
            name: 'dojo',
            location: '../ThirdParty/dojo-release-1.7.2-src/dojo'
        }, {
            name: 'dijit',
            location: '../ThirdParty/dojo-release-1.7.2-src/dijit'
        }, {
            name: 'dojox',
            location: '../ThirdParty/dojo-release-1.7.2-src/dojox'
        }, {
            name: 'Sandcastle',
            location: '../Apps/Sandcastle'
        }]
    }, [
        'Widgets/Dojo/CesiumViewerWidget',
        'dojo/parser',
        'dojo/dom',
        'dojo/dom-class',
        'dojo/dom-construct',
        'dojo/io-query',
        'dojo/_base/fx',
        'dojo/_base/window',
        'dojo/_base/xhr',
        'dijit/registry',
        'dijit/layout/ContentPane',
        'dijit/form/Button',
        'dijit/form/DropDownButton',
        'dijit/form/ToggleButton',
        'dijit/form/DropDownButton',
        'dijit/form/TextBox',
        'dijit/TooltipDialog',
        'dijit/Menu',
        'dijit/MenuBar',
        'dijit/PopupMenuBarItem',
        'dijit/MenuItem',
        'dijit/layout/BorderContainer',
        'dijit/layout/TabContainer',
        'dijit/Toolbar',
        'dijit/ToolbarSeparator',
        'Sandcastle/LinkButton',
        'dojo/domReady!'],
    function (
            CesiumViewerWidget,
            parser,
            dom,
            domClass,
            domConstruct,
            ioQuery,
            fx,
            win,
            xhr,
            registry,
            ContentPane
    ) {
        "use strict";
        parser.parse();
        window.CesiumViewerWidget = CesiumViewerWidget; // for autocomplete.
        fx.fadeOut({ node: 'loading', onEnd: function () {
            domConstruct.destroy('loading');
        }}).play();

        var logOutput = document.getElementById('logOutput');
        function appendConsole(className, message) {
            var ele = document.createElement('span');
            ele.className = className;
            ele.textContent = message + "\n";
            logOutput.appendChild(ele);
            logOutput.parentNode.scrollTop = logOutput.clientHeight + 8 - logOutput.parentNode.clientHeight;
        }

        // NOTE: BlobBuilder will eventually be deprecated and replaced with a direct constructor on Blob itself.
        // https://developer.mozilla.org/en/DOM/Blob
        var BlobBuilder = BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder;
        var getURL = window.URL || window.webkitURL || window;
        if (typeof BlobBuilder === 'undefined') {
            registry.byId('buttonSaveAs').set('disabled', true);
        }

        var jsEditor;
        var htmlEditor;
        var suggestButton = registry.byId('buttonSuggest');
        var docTimer;
        var docTabs = {};
        var cesiumContainer = registry.byId('cesiumContainer');
        var docNode = dom.byId('docPopup');
        var docMessage = dom.byId('docPopupMessage');
        var local = { 'docTypes': [],  'headers': ""};
        var errorLines = [];
        var highlightLines = [];
        var hintGlobals = [
            'require',
            'document',
            'window',
            'console',
            'Sandcastle'
        ];
        var hintOptions = {
            predef: hintGlobals,
            // These are copied from the Eclipse jsHint plugin options on the Cesium project itself.
            // They should be kept in sync with that list of options.
            bitwise : false,
            curly : true,
            eqeqeq : true,
            forin : true,
            immed : false,
            latedef : true,
            newcap : true,
            noarg : true,
            noempty : false,
            nonew : true,
            plusplus : false,
            regexp : false,
            undef : true,
            strict : true,
            trailing : false,
            asi : false,
            boss : false,
            debug : false,
            eqnull : false,
            es5 : false,
            esnext : false,
            evil : false,
            expr : false,
            funcscope : false,
            globalstrict : false,
            iterator : false,
            lastsemic : false,
            laxbreak : false,
            laxcomma : false,
            loopfunc : false,
            multistr : false,
            onecase : false,
            proto : false,
            regexdash : false,
            scripturl : false,
            smarttabs : false,
            shadow : false,
            sub : false,
            supernew : false,
            validthis : false,
            browser : true
        };
        var hintTimer;

        xhr.get({
            url: '../../Build/Documentation/types.txt',
            handleAs: 'json',
            error: function(error) {
                // Quiet for now, because the console will be cleared soon after this.
                // We'll let the user know about this error further down.
            }
        }).then(function (value) {
            local.docTypes = value;
        });

        xhr.get({
            url: 'templates/bucket.html',
            handleAs: 'text'
        }).then(function (value) {
            var pos = value.indexOf('', pos);
            local.headers = value.substring(0, pos + 1) + '\n';
        });

        function highlightRun(light) {
            if (light) {
                domClass.add(registry.byId('buttonRun').domNode, 'highlightToolbarButton');
            } else {
                domClass.remove(registry.byId('buttonRun').domNode, 'highlightToolbarButton');
            }
        }

        function highlightSaveAs(light) {
            if (light) {
                domClass.add(registry.byId('buttonSaveAs').domNode, 'highlightToolbarButton');
            } else {
                domClass.remove(registry.byId('buttonSaveAs').domNode, 'highlightToolbarButton');
            }
        }

        function openDocTab(title, link) {
            if (typeof docTabs[title] === 'undefined') {
                docTabs[title] = new ContentPane({
                    title: title,
                    focused: true,
                    content: '',
                    closable: true,
                    onClose: function () {
                        docTabs[this.title] = undefined;
                        // Return true to close the tab.
                        return true;
                    }
                }).placeAt(cesiumContainer);
                // After the iframe loads, re-scroll to selected field.
                docTabs[title].domNode.childNodes[0].onload = function () {
                    this.onload = function () {};
                    this.src = link;
                };
                cesiumContainer.selectChild(docTabs[title]);
            } else {
                // Tab already exists, but maybe not visible.  FireFox needs the tab to
                // be revealed before a re-scroll can happen.  Chrome works either way.
                cesiumContainer.selectChild(docTabs[title]);
                docTabs[title].domNode.childNodes[0].src = link;
            }
        }

        function showDocPopup () {
            var selectedText = jsEditor.getSelection();

            var onDocClick = function () {
                openDocTab(this.textContent, this.href);
                return false;
            };

            if (selectedText && selectedText in local.docTypes && typeof local.docTypes[selectedText].push === 'function') {
                var member, ele, i, len = local.docTypes[selectedText].length;
                docMessage.innerHTML = '';
                for (i = 0; i < len; ++i) {
                    member = local.docTypes[selectedText][i];
                    ele = document.createElement('a');
                    ele.target = "_blank";
                    ele.textContent = member.replace('.html', '').replace('module-', '').replace('#', '.');
                    ele.href = '../../Build/Documentation/' + member;
                    ele.onclick = onDocClick;
                    docMessage.appendChild(ele);
                }
                jsEditor.addWidget(jsEditor.getCursor(true), docNode);
                docNode.style.top = (parseInt(docNode.style.top, 10) - 5) + 'px';
            }
        }

        function onCursorActivity() {
            docNode.style.left = "-999px";
            if (typeof docTimer !== 'undefined') {
                window.clearTimeout(docTimer);
            }
            docTimer = window.setTimeout(showDocPopup, 500);
        }

        var bucketFrame = document.getElementById('bucketFrame');
        var bucketPane = registry.byId('bucketPane');

        var abbrDiv = document.createElement('div');
        var abbrEle = document.createElement('abbr');
        abbrEle.textContent = '%N%';
        abbrDiv.appendChild(abbrEle);

        function makeLineLabel(msg) {
            abbrEle.title = msg;
            return abbrDiv.innerHTML;
        }

        function clearAllErrors() {
            var line, hint, hints, i, len;
            hintTimer = undefined;
            while (errorLines.length > 0) {
                line = errorLines.pop();
                jsEditor.setLineClass(line, null);
                jsEditor.clearMarker(line);
            }
            if (!JSHINT(jsEditor.getValue(), hintOptions)) {
                hints = JSHINT.errors;
                len = hints.length;
                for (i = 0; i < len; ++i) {
                    hint = hints[i];
                    if ((hint !== null) && (typeof hint.reason !== 'undefined') && (hint.line > 0)) {
                        line = jsEditor.setMarker(hint.line - 1, makeLineLabel(hint.reason), "hintMarker");
                        jsEditor.setLineClass(line, "hintLine");
                        errorLines.push(line);
                    }
                }
            }
        }

        function scheduleHint() {
            if (typeof hintTimer !== 'undefined') {
                window.clearTimeout(hintTimer);
            }
            hintTimer = setTimeout(clearAllErrors, 550);
            highlightRun(true);
        }

        function highlightLine(lineNum) {
            var line;
            while (highlightLines.length > 0) {
                line = highlightLines.pop();
                jsEditor.setLineClass(line, null);
                jsEditor.clearMarker(line);
            }
            if (lineNum > 0) {
                line = jsEditor.setMarker(lineNum - 1, makeLineLabel('highlighted by demo'), "highlightMarker");
                jsEditor.setLineClass(line, "highlightLine");
                highlightLines.push(line);

                // Scroll to bring the highlighted line into view.
                jsEditor.setCursor(lineNum);
                jsEditor.setSelection({line: lineNum - 2, ch:0}, {line: lineNum - 2, ch: 0});
                jsEditor.focus();
                jsEditor.setSelection({line: lineNum, ch: 0}, {line: lineNum, ch: 0});
            }
        }

        CodeMirror.commands.runCesium = function(cm) {
            clearAllErrors();
            highlightRun(false);
            cesiumContainer.selectChild(bucketPane);
            bucketFrame.contentWindow.location.reload();
        };

        CodeMirror.commands.autocomplete = function(cm) {
            CodeMirror.simpleHint(cm, CodeMirror.cesiumHint);
        };

        jsEditor = CodeMirror.fromTextArea(document.getElementById("code"), {
            mode: "javascript",
            lineNumbers: true,
            matchBrackets: true,
            indentUnit: 4,
            onCursorActivity: onCursorActivity,
            onChange: scheduleHint,
            extraKeys: {
                "Ctrl-Space": "autocomplete",
                "F9": "runCesium",
                "Tab": "indentMore",
                "Shift-Tab": "indentLess"
            }
        });

        htmlEditor = CodeMirror.fromTextArea(document.getElementById("htmlBody"), {
            mode: "text/html",
            lineNumbers: true,
            matchBrackets: true,
            indentUnit: 4,
            extraKeys: {
                "F9": "runCesium",
                "Tab": "indentMore",
                "Shift-Tab": "indentLess"
            }
        });

        function loadFromGallery(link) {
            xhr.get({
                url: 'gallery/' + link,
                handleAs: 'text',
                error: function(error) {
                    appendConsole('consoleError', error);
                }
            }).then(function (value) {
                var pos = value.indexOf('', pos);
                var body = value.substring(pos + 2);
                pos = body.indexOf('');
                if ((pos <= 0) || (pos2 <= pos)) {
                    var ele = document.createElement('span');
                    ele.className = 'consoleError';
                    ele.textContent = 'Error reading source file: ' + link + '\n';
                    appendConsole(ele);
                } else {
                    var script = body.substring(pos + 38, pos2 - 1);
                    while (script.charAt(0) < 32) {
                        script = script.substring(1);
                    }
                    jsEditor.setValue(script);
                    htmlEditor.setValue(body.substring(0, pos - 1));
                    CodeMirror.commands.runCesium(jsEditor);
                }
            });
        }

        var queryObject = {};
        if (window.location.search) {
            queryObject = ioQuery.queryToObject(window.location.search.substring(1));
        }

        window.addEventListener('message', function (e) {
            var line;
            // The iframe (bucket.html) sends this message on load.
            // This triggers the code to be injected into the iframe.
            if (e.data === 'reload') {
                logOutput.innerHTML = "";
                if (typeof queryObject.src !== 'undefined') {
                    // This happens once on Sandcastle page load, the blank bucket.html triggers a load
                    // of the selected demo code from the gallery, followed by a Run (F9) equivalent.
                    loadFromGallery(queryObject.src);
                    queryObject.src = undefined;
                } else {
                    // This happens after a Run (F9) reloads bucket.html, to inject the editor code
                    // into the iframe, causing the demo to run there.
                    var bucketDoc = bucketFrame.contentDocument;
                    var bodyEle = bucketDoc.createElement('div');
                    bodyEle.innerHTML = htmlEditor.getValue();
                    bucketDoc.body.appendChild(bodyEle);
                    var jsEle = bucketDoc.createElement('script');
                    jsEle.type = 'text/javascript';
                    jsEle.textContent = jsEditor.getValue();
                    bucketDoc.body.appendChild(jsEle);
                    if (local.docTypes.length === 0) {
                        appendConsole('consoleError', "Documentation not available.  Please run the 'release' build script to generate Cesium documentation.");
                    }
                }
            } else if (typeof e.data.log !== 'undefined') {
                // Console log messages from the iframe display in Sandcastle.
                appendConsole('consoleLog', e.data.log);
            } else if (typeof e.data.error !== 'undefined') {
                // Console error messages from the iframe display in Sandcastle
                appendConsole('consoleError', e.data.error);
                if (typeof e.data.lineNumber !== 'undefined') {
                    line = jsEditor.setMarker(e.data.lineNumber - 1, makeLineLabel(e.data.rawErrorMsg), "errorMarker");
                    jsEditor.setLineClass(line, "errorLine");
                    errorLines.push(line);
                }
            } else if (typeof e.data.highlight !== 'undefined') {
                // Hovering objects in the embedded Cesium window.
                highlightLine(e.data.highlight);
            }
        }, true);

        registry.byId('jsContainer').on('show', function () {
            suggestButton.set('disabled', false);
            jsEditor.refresh();
        });

        registry.byId('htmlContainer').on('show', function () {
            suggestButton.set('disabled', true);
            htmlEditor.refresh();
        });

        // Clicking the 'Run' button simply reloads the iframe.
        registry.byId('buttonRun').on('click', function () {
            CodeMirror.commands.runCesium(jsEditor);
        });

        registry.byId('buttonSuggest').on('click', function () {
            CodeMirror.commands.autocomplete(jsEditor);
        });

        registry.byId('dropDownSaveAs').on('show', function () {
            var html = local.headers + htmlEditor.getValue() +
                '\n\n\n\n';

            var octetBB = new BlobBuilder();
            octetBB.append(html);
            var octetBlob = octetBB.getBlob("application/octet-stream");
            var octetBlobURL = getURL.createObjectURL(octetBlob);
            dom.byId('saveAsFile').href = octetBlobURL;

            var baseHref = window.location.href, pos = baseHref.lastIndexOf('/');
            baseHref = baseHref.substring(0, pos) + '/gallery/';
            html = html.replace('', '\n    <base href="' + baseHref + '">');
            var htmlBB = new BlobBuilder();
            htmlBB.append(html);
            var htmlBlob = htmlBB.getBlob("text/html;charset=utf-8");
            var htmlBlobURL = getURL.createObjectURL(htmlBlob);
            dom.byId('saveAsNewWindow').href = htmlBlobURL;
        });

        registry.byId('buttonThumbnail').on('change', function (newValue) {
            if (newValue) {
                domClass.add('bucketFrame', 'makeThumbnail');
            } else {
                domClass.remove('bucketFrame', 'makeThumbnail');
            }
        });
    });
<|endoftext|>