<commit_before>/////////////////////////////////////////////////////////////////////
//// cron jobs for updating/fetching data
/////////////////////////////////////////////////////////////////////

const CronJob = require('cron').CronJob;
const blockchainApi = require('./../lib/blockchain-info-api');
const BitcoinValue = require('./../model/BitcoinValue.js');
const BitcoinValueHourlyAvg = require('./../model/BitcoinValueHourlyAvg.js');
const BitcoinValueDailyAvg = require('./../model/BitcoinValueDailyAvg.js');
const BitcoinValueMonthlyAvg = require('./../model/BitcoinValueMonthlyAvg.js');
const tools = require('./../lib/tools');

var mongoCallback = function(error, data) {
  if(error)
    console.log(error);
  // else
  //   console.log(data);
}

var updateHourlyAvgValue = function(error, data) {
    // current timestamp in UTC
    var UTCtimestamp = parseInt(new Date().getTime() / 1000);
    // current rouned hour timestamp in UTC
    var roundHourUTCtimestamp = UTCtimestamp - (UTCtimestamp % 3600);

    // get all values for from start of current hour up to now
    // if it's 14:30, then get values between 14:00 and 14:30
    BitcoinValue.find({
        timestamp: {
            $gte: roundHourUTCtimestamp,
            $lte: UTCtimestamp
        }
    }, function(error, data) {
        // error check
        if(error) {
          console.log(error);
          return false;
        }

        var hourAvg = tools.getDataAverage(data, 'value');

        // skip update if avarage is null
        if (hourAvg === null) return;

        // check if there is an hourly avg value with this timestamp
        // update/create accordingly
        BitcoinValueHourlyAvg.update({
            timestamp: roundHourUTCtimestamp
        },
        { value: hourAvg},
        function (err, raw) {
            if(err) {
              console.log(err);
            }

            // if not matching object exist,
            // then create new with these values
            if (raw.n == 0) {
                BitcoinValueHourlyAvg.create({
                    value: hourAvg,
                    timestamp: roundHourUTCtimestamp
                }, mongoCallback);
            }
        });
    });
}

// cron job every 15 minutes
// var job1 = new CronJob('00 */5 * * * *', function() {
var job1 = new CronJob('00 00,15,30,45 * * * *', function() {
    blockchainApi.fetchCurrentPrice(function (body) {
        BitcoinValue.create({
            value: body.USD.last,
            timestamp: tools.getCurrentTimestamp()
        }, updateHourlyAvgValue);
    });
}, null, true, 'UTC');

// // cron job every hour at :05 minutes
// // calc and write avg bitcoin value for previous hour
// var job2 = new CronJob('00 05 * * * *', function() {
//     // current timestamp in UTC
//     var UTCtimestamp = parseInt(new Date().getTime() / 1000);
//     // current rouned hour timestamp in UTC
//     var roundHourUTCtimestamp = UTCtimestamp - (UTCtimestamp % 3600);
//     // previous rouned hour timestamp in UTC
//     var prevHourUTCtimestamp = roundHourUTCtimestamp - 3600;
//
//     // get all values for past hour
//     // if it's 14:05, then get values between 13:00 and 14:00 (UTC)
//     BitcoinValue.find({
//         timestamp: {
//             $gte: prevHourUTCtimestamp,
//             $lte: roundHourUTCtimestamp
//         }
//     }, function(error, data) {
//         // error check
//         if(error) {
//           console.log(error);
//           return false;
//         }
//
//         var hourAvg = tools.getDataAverage(data, 'value');
//
//         // skip update if avarage is null
//         if (hourAvg === null) return;
//
//         // write hourly avg value to db
//         BitcoinValueHourlyAvg.create({
//             value: hourAvg,
//             timestamp: prevHourUTCtimestamp
//         }, mongoCallback);
//     });
//
// }, null, true, 'UTC');

// cron job every hour at :59 minutes
// calc and write avg bitcoin value for current day up to this moment
var job3 = new CronJob('00 59 * * * *', function() {

    // // proceed only if it's 0 Hours UTC (12 AM)
    // if (new Date().getUTCHours() != 0) {
    //     return;
    // }

    // current timestamp in UTC
    var UTCtimestamp = parseInt(new Date().getTime() / 1000);
    // current rouned day timestamp in UTC
    var roundDayUTCtimestamp = UTCtimestamp - (UTCtimestamp % (24 * 3600));

    // // previous rouned day timestamp in UTC
    // var prevDayUTCtimestamp = roundDayUTCtimestamp - (24 * 3600);

    // get all hourly average values for past day
    // and calc the average value
    BitcoinValueHourlyAvg.find({
        timestamp: {
            $gte: roundDayUTCtimestamp,
            $lte: UTCtimestamp
        }
    }, function(error, data) {
        // error check
        if(error) {
          console.log(error);
          return false;
        }

        var dailyAvg = tools.getDataAverage(data, 'value');

        // skip update if avarage is null
        if (dailyAvg === null) return;

        // check if there is a daily avg value with this timestamp
        // update/create accordingly
        BitcoinValueDailyAvg.update({
            timestamp: roundDayUTCtimestamp
        },
        { value: dailyAvg},
        function (err, raw) {
            if(err) {
              console.log(err);
            }

            // if not matching object exist,
            // then create new with these values
            if (raw.n == 0) {
                BitcoinValueDailyAvg.create({
                    value: dailyAvg,
                    timestamp: roundDayUTCtimestamp
                }, mongoCallback);
            }
        });
    });

}, null, true, 'UTC');

// cron job every day at 23:55 minutes
// calc and write avg bitcoin value for current month up to this moment
var job4 = new CronJob('00 55 23 * * *', function() {
    // get current year and month
    // build monthly string like '2017-07-01' and convert it to timestamp
    var year = new Date().getUTCFullYear();
    var monthString = tools.monthIntToString(new Date().getUTCMonth());
    var monthlyTimestamp = new Date(
        year + '-' + monthString + '-01'
    ).getTime() / 1000;

    // get all daily average values for past month
    BitcoinValueDailyAvg.find({
        timestamp: {
            $gte: monthlyTimestamp,
        }
    }, function(error, data) {
        // error check
        if(error) {
          console.log(error);
          return false;
        }

        var monthlyAvg = tools.getDataAverage(data, 'value');

        // skip update if avarage is null
        if (monthlyAvg === null) return;

        // check if there is a monthly avg value with this timestamp
        // update/create accordingly
        BitcoinValueMonthlyAvg.update({
            timestamp: monthlyTimestamp
        },
        { value: monthlyAvg},
        function (error, raw) {
            if(error) {
              console.log(error);
              return false;
            }

            // if not matching object exist,
            // then create new with these values
            if (raw.n == 0) {
                BitcoinValueMonthlyAvg.create({
                    value: monthlyAvg,
                    timestamp: monthlyTimestamp
                }, mongoCallback);
            }
        });
    });

}, null, true, 'UTC');

// exports
module.exports = {
    fetchCurrentValue: job1,
    // updateHourlyValue: job2,
    updateDailyValue: job3,
    updateMonthlyValue: job4
};
<commit_msg>Temp enable of cronjob2<commit_after>/////////////////////////////////////////////////////////////////////
//// cron jobs for updating/fetching data
/////////////////////////////////////////////////////////////////////

const CronJob = require('cron').CronJob;
const blockchainApi = require('./../lib/blockchain-info-api');
const BitcoinValue = require('./../model/BitcoinValue.js');
const BitcoinValueHourlyAvg = require('./../model/BitcoinValueHourlyAvg.js');
const BitcoinValueDailyAvg = require('./../model/BitcoinValueDailyAvg.js');
const BitcoinValueMonthlyAvg = require('./../model/BitcoinValueMonthlyAvg.js');
const tools = require('./../lib/tools');

var mongoCallback = function(error, data) {
  if(error)
    console.log(error);
  // else
  //   console.log(data);
}

var updateHourlyAvgValue = function(error, data) {
    // current timestamp in UTC
    var UTCtimestamp = parseInt(new Date().getTime() / 1000);
    // current rouned hour timestamp in UTC
    var roundHourUTCtimestamp = UTCtimestamp - (UTCtimestamp % 3600);

    // get all values for from start of current hour up to now
    // if it's 14:30, then get values between 14:00 and 14:30
    BitcoinValue.find({
        timestamp: {
            $gte: roundHourUTCtimestamp,
            $lte: UTCtimestamp
        }
    }, function(error, data) {
        // error check
        if(error) {
          console.log(error);
          return false;
        }

        var hourAvg = tools.getDataAverage(data, 'value');

        // skip update if avarage is null
        if (hourAvg === null) return;

        // check if there is an hourly avg value with this timestamp
        // update/create accordingly
        BitcoinValueHourlyAvg.update({
            timestamp: roundHourUTCtimestamp
        },
        { value: hourAvg},
        function (err, raw) {
            if(err) {
              console.log(err);
            }

            // if not matching object exist,
            // then create new with these values
            if (raw.n == 0) {
                BitcoinValueHourlyAvg.create({
                    value: hourAvg,
                    timestamp: roundHourUTCtimestamp
                }, mongoCallback);
            }
        });
    });
}

// cron job every 15 minutes
// var job1 = new CronJob('00 */5 * * * *', function() {
var job1 = new CronJob('00 00,15,30,45 * * * *', function() {
    blockchainApi.fetchCurrentPrice(function (body) {
        BitcoinValue.create({
            value: body.USD.last,
            timestamp: tools.getCurrentTimestamp()
        }, updateHourlyAvgValue);
    });
}, null, true, 'UTC');

// cron job every hour at :05 minutes
// calc and write avg bitcoin value for previous hour
var job2 = new CronJob('00 05 * * * *', function() {
    // current timestamp in UTC
    var UTCtimestamp = parseInt(new Date().getTime() / 1000);
    // current rouned hour timestamp in UTC
    var roundHourUTCtimestamp = UTCtimestamp - (UTCtimestamp % 3600);
    // previous rouned hour timestamp in UTC
    var prevHourUTCtimestamp = roundHourUTCtimestamp - 3600;

    // get all values for past hour
    // if it's 14:05, then get values between 13:00 and 14:00 (UTC)
    BitcoinValue.find({
        timestamp: {
            $gte: prevHourUTCtimestamp,
            $lte: roundHourUTCtimestamp
        }
    }, function(error, data) {
        // error check
        if(error) {
          console.log(error);
          return false;
        }

        var hourAvg = tools.getDataAverage(data, 'value');

        // skip update if avarage is null
        if (hourAvg === null) return;

        // write hourly avg value to db
        BitcoinValueHourlyAvg.create({
            value: hourAvg,
            timestamp: prevHourUTCtimestamp
        }, mongoCallback);
    });

}, null, true, 'UTC');

// cron job every hour at :59 minutes
// calc and write avg bitcoin value for current day up to this moment
var job3 = new CronJob('00 59 * * * *', function() {

    // // proceed only if it's 0 Hours UTC (12 AM)
    // if (new Date().getUTCHours() != 0) {
    //     return;
    // }

    // current timestamp in UTC
    var UTCtimestamp = parseInt(new Date().getTime() / 1000);
    // current rouned day timestamp in UTC
    var roundDayUTCtimestamp = UTCtimestamp - (UTCtimestamp % (24 * 3600));

    // // previous rouned day timestamp in UTC
    // var prevDayUTCtimestamp = roundDayUTCtimestamp - (24 * 3600);

    // get all hourly average values for past day
    // and calc the average value
    BitcoinValueHourlyAvg.find({
        timestamp: {
            $gte: roundDayUTCtimestamp,
            $lte: UTCtimestamp
        }
    }, function(error, data) {
        // error check
        if(error) {
          console.log(error);
          return false;
        }

        var dailyAvg = tools.getDataAverage(data, 'value');

        // skip update if avarage is null
        if (dailyAvg === null) return;

        // check if there is a daily avg value with this timestamp
        // update/create accordingly
        BitcoinValueDailyAvg.update({
            timestamp: roundDayUTCtimestamp
        },
        { value: dailyAvg},
        function (err, raw) {
            if(err) {
              console.log(err);
            }

            // if not matching object exist,
            // then create new with these values
            if (raw.n == 0) {
                BitcoinValueDailyAvg.create({
                    value: dailyAvg,
                    timestamp: roundDayUTCtimestamp
                }, mongoCallback);
            }
        });
    });

}, null, true, 'UTC');

// cron job every day at 23:55 minutes
// calc and write avg bitcoin value for current month up to this moment
var job4 = new CronJob('00 55 23 * * *', function() {
    // get current year and month
    // build monthly string like '2017-07-01' and convert it to timestamp
    var year = new Date().getUTCFullYear();
    var monthString = tools.monthIntToString(new Date().getUTCMonth());
    var monthlyTimestamp = new Date(
        year + '-' + monthString + '-01'
    ).getTime() / 1000;

    // get all daily average values for past month
    BitcoinValueDailyAvg.find({
        timestamp: {
            $gte: monthlyTimestamp,
        }
    }, function(error, data) {
        // error check
        if(error) {
          console.log(error);
          return false;
        }

        var monthlyAvg = tools.getDataAverage(data, 'value');

        // skip update if avarage is null
        if (monthlyAvg === null) return;

        // check if there is a monthly avg value with this timestamp
        // update/create accordingly
        BitcoinValueMonthlyAvg.update({
            timestamp: monthlyTimestamp
        },
        { value: monthlyAvg},
        function (error, raw) {
            if(error) {
              console.log(error);
              return false;
            }

            // if not matching object exist,
            // then create new with these values
            if (raw.n == 0) {
                BitcoinValueMonthlyAvg.create({
                    value: monthlyAvg,
                    timestamp: monthlyTimestamp
                }, mongoCallback);
            }
        });
    });

}, null, true, 'UTC');

// exports
module.exports = {
    fetchCurrentValue: job1,
    updateHourlyValue: job2,
    updateDailyValue: job3,
    updateMonthlyValue: job4
};
<|endoftext|>


<commit_before>// 初始化
mui.init();

// 所有的方法都放到这里
mui.plusReady(function(){
	initDb();
	initDoneList();
});

// 初始化数据库
function initDb(){
	db = qiao.h.db();
	qiao.h.update(db, 'drop table t_plan_day_done');
	qiao.h.update(db, 'create table if not exists t_plan_day_done (id unique, plan_title, plan_content)');
}

// 初始化待办事项
function initDoneList(){
	var $ul = $('#donelist').empty();
	qiao.h.query(db, 'select * from t_plan_day_done order by id desc', function(res){
		for (i = 0; i < res.rows.length; i++) {
			$ul.append(genLi(res.rows.item(i)));
		}

		showList($ul);
	});
}
function genLi(data){
	return '
' + data.plan_title + '
';
}
function showList(ul){
	if(ul.find('li').size() > 0 &&  ul.is(':hidden')) ul.show();
}<commit_msg>webview方式趋近完成<commit_after>// 初始化
mui.init();

// 所有的方法都放到这里
mui.plusReady(function(){
	initDb();
	initDoneList();
});

// 初始化数据库
function initDb(){
	db = qiao.h.db();
//	qiao.h.update(db, 'drop table t_plan_day_done');
	qiao.h.update(db, 'create table if not exists t_plan_day_done (id unique, plan_title, plan_content)');
}

// 初始化待办事项
function initDoneList(){
	var $ul = $('#donelist').empty();
	qiao.h.query(db, 'select * from t_plan_day_done order by id desc', function(res){
		for (i = 0; i < res.rows.length; i++) {
			$ul.append(genLi(res.rows.item(i)));
		}

		showList($ul);
	});
}
function genLi(data){
	return '
' + data.plan_title + '
';
}
function showList(ul){
	if(ul.find('li').size() > 0 &&  ul.is(':hidden')) ul.show();
}<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

const bindingGraph = (function() {
  /**
   * A dictionary that maps a node's name to its identifier.
   * @type {Map<string, number>}
   */
  const nodesToNumbers = new Map();

  /**
   * A data structure DataSet
   * that contains all the nodes from the shown subgraph.
   */
  const nodes = new vis.DataSet();

  /**
   * A data structure DataSet
   * that contains all the edges from the shown subgraph.
   */
  const edges = new vis.DataSet();

  /**
   * Constructs a simple name from the full node name.
   *
   * @example from com.google.List[com.google.Beach] it will construct List[Beach].
   * @param {string} node a full name of the node
   */
  function getSimpleName(node) {
    const firstIndex = node.indexOf('[');

    if (firstIndex === -1) {
      const components = node.split('.');
      return components[components.length - 1];
    }

    const container = node.substring(0, firstIndex).split('.').slice(-1);
    const content = getSimpleName(node.substring(firstIndex + 1, node.lastIndexOf(']')));
    return `${container}[${content}]`;
  }

  /**
   * Associates given node with an identifier, if the node was not represented in the graph.
   *
   * @param {string} node a node to be added if it doesn't exist
   * @return {number} an identifier of a given node
   */
  function addNode(node) {
    if (!nodesToNumbers.has(node)) {
      nodesToNumbers.set(node, nodesToNumbers.size);
    }

    const id = nodesToNumbers.get(node);
    if (nodes.get(id) === null) {
      // Since angle brackets have a special meaning in html, we replace them with square brackets.
      const fullName = node.replace(/</g, "[").replace(/>/g, "]");
      const simpleName = getSimpleName(fullName);
      nodes.add({id: id, label: simpleName, title: fullName});
    }
    return id;
  }

  /**
   * Tries to remove the given node from a subgraph.
   *
   *
The operation is considered successful only if the given node does not connect
   * to any other node in the graph.
   *
   * @param {number} nodeId an identifier of a node to be removed
   */
  function tryToRemoveNode(nodeId) {
    if (getAllEdges(nodeId).length === 0) {
      nodes.remove(nodeId);
    }
  }

  /**
   * Retrieves all edges where the start or destination nodes are equal to the given one.
   *
   * @param {number} nodeId an identifier of the given node
   */
  function getAllEdges(nodeId) {
    return edges.get({
      filter: function (edge) {
        return (edge.from === nodeId || edge.to === nodeId);
      }
    });
  }

  /**
   * Retrieves all edges where the start node is the specified one.
   *
   * @param {number} nodeId an identifier of the given node
   */
  function getAllDeps(nodeId) {
    return edges.get({
      filter: function (edge) {
        return (edge.from === nodeId);
      }
    });
  }

  /**
   * Removes an edge from a subgraph, and if the destination node
   * becomes isolated, then removes it as well.
   *
   * @param edge an edge which will be removed
   */
  function removeEdge(edge) {
    edges.remove(edge);

    tryToRemoveNode(edge.to);
  }

  /**
   * Adds an edge from the source node to the target.
   *
   * @param {string} source the first node of the given edge
   * @param {string} target the second node of the given edge
   */
  function addEdge(source, target, style) {
    const sourceId = addNode(source);
    const targetId = addNode(target);

    edges.add({from: sourceId, to: targetId});
  }

  return {
    /**
     * Removes all edges with the given start node from the subgraph.
     *
     * @param {string} node a source node which dependencies will be removed
     */
    deleteDeps: function (node) {
      // Retrieves all edges having a start node with value `node`.
      const edgesToBeRemoved = getAllDeps(nodesToNumbers.get(node));

      for (let edge of edgesToBeRemoved) {
        removeEdge(edge);
      }
    },

    /**
     * Takes a string representing a path where two adjacent nodes are connected by an edge,
     * and adds all these edges to the subgraph.
     *
     *
Given path is separated with ' -> ' arrow.
     *
     * @param {string} path a valid string representing a path with at least two nodes
     */
    addPath: function (path) {
      const nodesInPath = path.split( ' -> ');
      for (let index = 0; index + 1 < nodesInPath.length; ++index) {
        addEdge(nodesInPath[index], nodesInPath[index + 1]);
      }
    },

    /**
     * Adds all source node's dependencies to the subgraph.
     * @param {string} source
     * @param {string[]} deps
     */
    addDeps: function (source, deps) {
      for (const childNode of deps) {
        addEdge(source, childNode);
      }
    },

    /**
     * Clears all data from the graph.
     */
    clear: function () {
      nodesToNumbers.clear();
      nodes.clear();
      edges.clear();
    },

    /**
     * Returns a DataSet
     * with all edges from the subgraph.
     *
     * @return {vis.DataSet}
     */
    getEdges: function () {
      return edges;
    },

    /**
     * Returns a DataSet
     * with all nodes from the subgraph.
     *
     * @return {vis.DataSet}
     */
    getNodes: function () {
      return nodes;
    },

    /**
     * Draws the entire graph and sets events listeners.
     */
    draw: function() {
      const container = document.getElementById('binding-graph');
      const data = {
        nodes: nodes,
        edges: edges
      };

      const options = {};
      const network = new vis.Network(container, data, options);
    }
  };
})();
<commit_msg>Replaced `let` with `const` in several for loops<commit_after>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

const bindingGraph = (function() {
  /**
   * A dictionary that maps a node's name to its identifier.
   * @type {Map<string, number>}
   */
  const nodesToNumbers = new Map();

  /**
   * A data structure DataSet
   * that contains all the nodes from the shown subgraph.
   */
  const nodes = new vis.DataSet();

  /**
   * A data structure DataSet
   * that contains all the edges from the shown subgraph.
   */
  const edges = new vis.DataSet();

  /**
   * Constructs a simple name from the full node name.
   *
   * @example from com.google.List[com.google.Beach] it will construct List[Beach].
   * @param {string} node a full name of the node
   */
  function getSimpleName(node) {
    const firstIndex = node.indexOf('[');

    if (firstIndex === -1) {
      const components = node.split('.');
      return components[components.length - 1];
    }

    const container = node.substring(0, firstIndex).split('.').slice(-1);
    const content = getSimpleName(node.substring(firstIndex + 1, node.lastIndexOf(']')));
    return `${container}[${content}]`;
  }

  /**
   * Associates given node with an identifier, if the node was not represented in the graph.
   *
   * @param {string} node a node to be added if it doesn't exist
   * @return {number} an identifier of a given node
   */
  function addNode(node) {
    if (!nodesToNumbers.has(node)) {
      nodesToNumbers.set(node, nodesToNumbers.size);
    }

    const id = nodesToNumbers.get(node);
    if (nodes.get(id) === null) {
      // Since angle brackets have a special meaning in html, we replace them with square brackets.
      const fullName = node.replace(/</g, "[").replace(/>/g, "]");
      const simpleName = getSimpleName(fullName);
      nodes.add({id: id, label: simpleName, title: fullName});
    }
    return id;
  }

  /**
   * Tries to remove the given node from a subgraph.
   *
   *
The operation is considered successful only if the given node does not connect
   * to any other node in the graph.
   *
   * @param {number} nodeId an identifier of a node to be removed
   */
  function tryToRemoveNode(nodeId) {
    if (getAllEdges(nodeId).length === 0) {
      nodes.remove(nodeId);
    }
  }

  /**
   * Retrieves all edges where the start or destination nodes are equal to the given one.
   *
   * @param {number} nodeId an identifier of the given node
   */
  function getAllEdges(nodeId) {
    return edges.get({
      filter: function (edge) {
        return (edge.from === nodeId || edge.to === nodeId);
      }
    });
  }

  /**
   * Retrieves all edges where the start node is the specified one.
   *
   * @param {number} nodeId an identifier of the given node
   */
  function getAllDeps(nodeId) {
    return edges.get({
      filter: function (edge) {
        return (edge.from === nodeId);
      }
    });
  }

  /**
   * Removes an edge from a subgraph, and if the destination node
   * becomes isolated, then removes it as well.
   *
   * @param edge an edge which will be removed
   */
  function removeEdge(edge) {
    edges.remove(edge);

    tryToRemoveNode(edge.to);
  }

  /**
   * Adds an edge from the source node to the target.
   *
   * @param {string} source the first node of the given edge
   * @param {string} target the second node of the given edge
   */
  function addEdge(source, target, style) {
    const sourceId = addNode(source);
    const targetId = addNode(target);

    edges.add({from: sourceId, to: targetId});
  }

  return {
    /**
     * Removes all edges with the given start node from the subgraph.
     *
     * @param {string} node a source node which dependencies will be removed
     */
    deleteDeps: function (node) {
      // Retrieves all edges having a start node with value `node`.
      const edgesToBeRemoved = getAllDeps(nodesToNumbers.get(node));

      for (const edge of edgesToBeRemoved) {
        removeEdge(edge);
      }
    },

    /**
     * Takes a string representing a path where two adjacent nodes are connected by an edge,
     * and adds all these edges to the subgraph.
     *
     *
Given path is separated with ' -> ' arrow.
     *
     * @param {string} path a valid string representing a path with at least two nodes
     */
    addPath: function (path) {
      const nodesInPath = path.split( ' -> ');
      for (let index = 0; index + 1 < nodesInPath.length; ++index) {
        addEdge(nodesInPath[index], nodesInPath[index + 1]);
      }
    },

    /**
     * Adds all source node's dependencies to the subgraph.
     * @param {string} source
     * @param {string[]} deps
     */
    addDeps: function (source, deps) {
      for (const childNode of deps) {
        addEdge(source, childNode);
      }
    },

    /**
     * Clears all data from the graph.
     */
    clear: function () {
      nodesToNumbers.clear();
      nodes.clear();
      edges.clear();
    },

    /**
     * Returns a DataSet
     * with all edges from the subgraph.
     *
     * @return {vis.DataSet}
     */
    getEdges: function () {
      return edges;
    },

    /**
     * Returns a DataSet
     * with all nodes from the subgraph.
     *
     * @return {vis.DataSet}
     */
    getNodes: function () {
      return nodes;
    },

    /**
     * Draws the entire graph and sets events listeners.
     */
    draw: function() {
      const container = document.getElementById('binding-graph');
      const data = {
        nodes: nodes,
        edges: edges
      };

      const options = {};
      const network = new vis.Network(container, data, options);
    }
  };
})();
<|endoftext|>


<commit_before>// `client` section processor
//

'use strict';

// stdlib
var fs    = require('fs');
var path  = require('path');

// 3rd-party
var _            = require('lodash');
var ejs          = require('ejs');
var async        = require('async');
var fstools      = require('fs-tools');
var findRequires = require('find-requires');

// internal
var stopwatch         = require('../utils/stopwatch');
var resolveModulePath = require('./utils/resolve_module_path');
var jetson            = require('../../jetson');

////////////////////////////////////////////////////////////////////////////////

var WRAPPER_TEMPLATE_PATH = path.join(__dirname, 'client', 'wrapper.tpl');
var WRAPPER_TEMPLATE = _.template(fs.readFileSync(WRAPPER_TEMPLATE_PATH, 'utf8'));

// Contains full list of bundled modules (files) of the current sandbox.
var vendorModules;
var clientModules;

////////////////////////////////////////////////////////////////////////////////

// Used to detect JavaScript comments at top of a file.
// Allows to find actual code start.
var HEADER_COMMENT_PATTERN = new RegExp(
  '^(?:\\s*' +
    '(' +
      '(?:\/[*](?:\\s*|.+?)*?[*]\/)' + '|' +
      '(?:\/\/.*\n?)+' +
    ')*' +
  '\\s*)*', 'm');

// Wraps the given source code string as a module definition for the client.
// Recursively browserifies and embeds all of unbundled dependencies.
function browserifySingle(source, options) {
  var dontWrap     = options.dontWrap    || false
    , apiPath      = options.apiPath     || null
    , embedCache   = options.embedCache  || []
    , result       = []
    , fsPath       = options.fsPath
    , directory    = path.dirname(fsPath)
    , commentMatch = HEADER_COMMENT_PATTERN.exec(source);

  if (!fsPath) {
    throw new Error('Missed required `fsPath` argument.');
  }

  // Embedded modules must be placed *after* Mincer's comment directives.
  if (commentMatch) {
    result.push(source.slice(0, commentMatch[0].length));
    source = source.slice(commentMatch[0].length);
  }

  // Look for:
  // - Requires of "foreign", unbundled modules.
  // - Node package-relative requires. Such as `require("nodeca.core/something")`
  findRequires(source, { raw: true }).forEach(function (match) {
    var resolvedPath, dependencySource;

    // Require path cannot be determinated - skip.
    if (!match.value) {
      return;
    }

    resolvedPath = resolveModulePath(directory, match.value);

    if (!fs.existsSync(resolvedPath)) {
      throw new Error(fsPath + ': cannot require a non-existent module ' +
                      resolvedPath + ' at line ' + match.line);
    }

    if (_.contains(clientModules, resolvedPath)) {
      throw new Error(fsPath + ': require of a client block is prohibited ' +
                      'at line ' + match.line + ' (' + resolvedPath + ')');
    }

    // FIXME: This is not actually safe way to replace require paths, but
    // alternative ways seem be too complicated.
    source = source.replace(match.raw, JSON.stringify(resolvedPath));

    // Embed private local modules. (not described in the bundle config and
    // not embedded yet)
    if (!_.contains(vendorModules, resolvedPath) &&
        !_.contains(embedCache, resolvedPath)) {

      embedCache.push(resolvedPath);
      dependencySource = fs.readFileSync(resolvedPath, 'utf8');

      // Recursively browserify and embed the unbundled module.
      result.push(browserifySingle(dependencySource, {
        fsPath:     resolvedPath
      , embedCache: embedCache
      }));
    }
  });

  if (dontWrap) {
    result.push(source);
  } else {
    result.push(WRAPPER_TEMPLATE({
      name:    fsPath  || null
    , apiPath: apiPath || null
    , source:  source
    }));
  }

  return result.join('\n');
}

// Wraps all of the given files for in-browser use and writes the result into
// the destination filepath. `files` should be an array of Pathname objects
// taken from `client` section of a package.
function browserifyFiles(files, destination) {
  var result      = []
    , embedCache  = [];

  // Write module definitions.
  _.forEach(files, function (pathname) {
    result.push(browserifySingle(pathname.readSync(), {
      fsPath:     pathname.toString()
    , apiPath:    pathname.apiPath
    , embedCache: embedCache
    }));
  });

  // Write the result to the destination.
  fstools.mkdirSync(path.dirname(destination));
  fs.writeFileSync(destination, result.join('\n'), 'utf8');
}

function browserifyMainFile(N, pathname, destination) {
  var result = pathname.readSync();

  if ('.ejs' === pathname.extname) {
    result = ejs.render(result, { N: N, jetson: jetson.serialize });
  }

  result = browserifySingle(result, {
    fsPath:   pathname.toString()
  , dontWrap: true
  });

  // Write the result to the destination.
  fstools.mkdirSync(path.dirname(destination));
  fs.writeFileSync(destination, result, 'utf8');
}

////////////////////////////////////////////////////////////////////////////////

module.exports = function (sandbox, callback) {
  var timer = stopwatch()
    , N = sandbox.N
    , tmpdir = sandbox.tmpdir;

  //
  // Collect flat lists of all `vendor` and `client` files from all packages.
  //

  vendorModules =
    _(sandbox.config.packages)
    .pluck('vendor')
    .map(_.values)
    .flatten()
    .valueOf();

  clientModules =
    _(sandbox.config.packages)
    .pluck('client')
    .compact()
    .pluck('files')
    .flatten()
    .invoke('toString')
    .valueOf();

  //
  // Build client files for each package
  //

  async.forEachSeries(_.keys(sandbox.config.packages), function (pkgName, next) {
    var clientConfig = sandbox.config.packages[pkgName].client
      , resultFile   = path.join(tmpdir, 'client', pkgName + '.js')
      , clientTmpDir = path.join(tmpdir, 'client', pkgName)
      , mainFile     = path.join(clientTmpDir, 'main.js')
      , modulesFile  = path.join(clientTmpDir, 'client.js')
      , targetFile   = null // mainFile if exists; modulesFile otherwise.
      , environment  = sandbox.assets.environment
      , originPaths  = environment.paths // to restore it later
      , timer        = stopwatch();

    if (!clientConfig) {
      next();
      return;
    }

    try {
      browserifyFiles(clientConfig.files, modulesFile);

      if (clientConfig.main) {
        browserifyMainFile(N, clientConfig.main, mainFile);
        targetFile = mainFile;
      } else {
        targetFile = modulesFile;
      }
    } catch (err) {
      next(err);
      return;
    }

    // Prepend path with `modulesFile` to allow use
    //
    //   //= require client
    //
    // in main file
    environment.prependPath(clientTmpDir);

    // When Mincer is asked for a main file, it must be within roots, that
    // Mincer knows about. See: https://github.com/nodeca/mincer/issues/51
    clientConfig.lookup.forEach(function (options) {
      environment.appendPath(options.root);
    });

    // Check that main file is requirable.
    if (!environment.findAsset(targetFile)) {
      // Restore Mincer's paths.
      environment.clearPaths();
      environment.appendPath(originPaths);

      next('Main client file of ' + pkgName + ' not found: ' + targetFile);
      return;
    }

    environment.findAsset(targetFile).compile(function (err, data) {
      if (err) {
        next(err);
        return;
      }

      var source = data.toString();

      // Initialize package modules.
      clientConfig.files.forEach(function (pathname) {
        source += '\nNodecaLoader.require(' + JSON.stringify(pathname.toString()) + ');';
      });

      // The current package is complete.
      fs.writeFile(resultFile, source, 'utf8', function (err) {
        if (err) {
          next(err);
          return;
        }

        // Restore Mincer's paths.
        environment.clearPaths();
        environment.appendPath(originPaths);

        N.logger.debug('Compiled client of %s %s', pkgName, timer.elapsed);
        fstools.remove(clientTmpDir, next);
      });
    });
  }, function (err) {
    N.logger.info('Processed client section %s', timer.elapsed);
    callback(err);
  });
};
<commit_msg>Simplify vendor/client modules collectiors.<commit_after>// `client` section processor
//

'use strict';

// stdlib
var fs    = require('fs');
var path  = require('path');

// 3rd-party
var _            = require('lodash');
var ejs          = require('ejs');
var async        = require('async');
var fstools      = require('fs-tools');
var findRequires = require('find-requires');

// internal
var stopwatch         = require('../utils/stopwatch');
var resolveModulePath = require('./utils/resolve_module_path');
var jetson            = require('../../jetson');

////////////////////////////////////////////////////////////////////////////////

var WRAPPER_TEMPLATE_PATH = path.join(__dirname, 'client', 'wrapper.tpl');
var WRAPPER_TEMPLATE = _.template(fs.readFileSync(WRAPPER_TEMPLATE_PATH, 'utf8'));

// Contains full list of bundled modules (files) of the current sandbox.
var vendorModules;
var clientModules;

////////////////////////////////////////////////////////////////////////////////

// Used to detect JavaScript comments at top of a file.
// Allows to find actual code start.
var HEADER_COMMENT_PATTERN = new RegExp(
  '^(?:\\s*' +
    '(' +
      '(?:\/[*](?:\\s*|.+?)*?[*]\/)' + '|' +
      '(?:\/\/.*\n?)+' +
    ')*' +
  '\\s*)*', 'm');

// Wraps the given source code string as a module definition for the client.
// Recursively browserifies and embeds all of unbundled dependencies.
function browserifySingle(source, options) {
  var dontWrap     = options.dontWrap    || false
    , apiPath      = options.apiPath     || null
    , embedCache   = options.embedCache  || []
    , result       = []
    , fsPath       = options.fsPath
    , directory    = path.dirname(fsPath)
    , commentMatch = HEADER_COMMENT_PATTERN.exec(source);

  if (!fsPath) {
    throw new Error('Missed required `fsPath` argument.');
  }

  // Embedded modules must be placed *after* Mincer's comment directives.
  if (commentMatch) {
    result.push(source.slice(0, commentMatch[0].length));
    source = source.slice(commentMatch[0].length);
  }

  // Look for:
  // - Requires of "foreign", unbundled modules.
  // - Node package-relative requires. Such as `require("nodeca.core/something")`
  findRequires(source, { raw: true }).forEach(function (match) {
    var resolvedPath, dependencySource;

    // Require path cannot be determinated - skip.
    if (!match.value) {
      return;
    }

    resolvedPath = resolveModulePath(directory, match.value);

    if (!fs.existsSync(resolvedPath)) {
      throw new Error(fsPath + ': cannot require a non-existent module ' +
                      resolvedPath + ' at line ' + match.line);
    }

    if (_.contains(clientModules, resolvedPath)) {
      throw new Error(fsPath + ': require of a client block is prohibited ' +
                      'at line ' + match.line + ' (' + resolvedPath + ')');
    }

    // FIXME: This is not actually safe way to replace require paths, but
    // alternative ways seem be too complicated.
    source = source.replace(match.raw, JSON.stringify(resolvedPath));

    // Embed private local modules. (not described in the bundle config and
    // not embedded yet)
    if (!_.contains(vendorModules, resolvedPath) &&
        !_.contains(embedCache, resolvedPath)) {

      embedCache.push(resolvedPath);
      dependencySource = fs.readFileSync(resolvedPath, 'utf8');

      // Recursively browserify and embed the unbundled module.
      result.push(browserifySingle(dependencySource, {
        fsPath:     resolvedPath
      , embedCache: embedCache
      }));
    }
  });

  if (dontWrap) {
    result.push(source);
  } else {
    result.push(WRAPPER_TEMPLATE({
      name:    fsPath  || null
    , apiPath: apiPath || null
    , source:  source
    }));
  }

  return result.join('\n');
}

// Wraps all of the given files for in-browser use and writes the result into
// the destination filepath. `files` should be an array of Pathname objects
// taken from `client` section of a package.
function browserifyFiles(files, destination) {
  var result      = []
    , embedCache  = [];

  // Write module definitions.
  _.forEach(files, function (pathname) {
    result.push(browserifySingle(pathname.readSync(), {
      fsPath:     pathname.toString()
    , apiPath:    pathname.apiPath
    , embedCache: embedCache
    }));
  });

  // Write the result to the destination.
  fstools.mkdirSync(path.dirname(destination));
  fs.writeFileSync(destination, result.join('\n'), 'utf8');
}

function browserifyMainFile(N, pathname, destination) {
  var result = pathname.readSync();

  if ('.ejs' === pathname.extname) {
    result = ejs.render(result, { N: N, jetson: jetson.serialize });
  }

  result = browserifySingle(result, {
    fsPath:   pathname.toString()
  , dontWrap: true
  });

  // Write the result to the destination.
  fstools.mkdirSync(path.dirname(destination));
  fs.writeFileSync(destination, result, 'utf8');
}

////////////////////////////////////////////////////////////////////////////////

module.exports = function (sandbox, callback) {
  var timer = stopwatch()
    , N = sandbox.N
    , tmpdir = sandbox.tmpdir;

  //
  // Collect flat lists of all `vendor` and `client` files from all packages.
  //

  vendorModules = [];
  clientModules = [];

  _.forEach(sandbox.config.packages, function (pkg) {
    vendorModules = vendorModules.concat(_.values(pkg.vendor));
  });

  _.forEach(sandbox.config.packages, function (pkg) {
    if (pkg.client) {
      clientModules = clientModules.concat(_.invoke(pkg.client.files, 'toString'));
    }
  });

  //
  // Build client files for each package
  //

  async.forEachSeries(_.keys(sandbox.config.packages), function (pkgName, next) {
    var clientConfig = sandbox.config.packages[pkgName].client
      , resultFile   = path.join(tmpdir, 'client', pkgName + '.js')
      , clientTmpDir = path.join(tmpdir, 'client', pkgName)
      , mainFile     = path.join(clientTmpDir, 'main.js')
      , modulesFile  = path.join(clientTmpDir, 'client.js')
      , targetFile   = null // mainFile if exists; modulesFile otherwise.
      , environment  = sandbox.assets.environment
      , originPaths  = environment.paths // to restore it later
      , timer        = stopwatch();

    if (!clientConfig) {
      next();
      return;
    }

    try {
      browserifyFiles(clientConfig.files, modulesFile);

      if (clientConfig.main) {
        browserifyMainFile(N, clientConfig.main, mainFile);
        targetFile = mainFile;
      } else {
        targetFile = modulesFile;
      }
    } catch (err) {
      next(err);
      return;
    }

    // Prepend path with `modulesFile` to allow use
    //
    //   //= require client
    //
    // in main file
    environment.prependPath(clientTmpDir);

    // When Mincer is asked for a main file, it must be within roots, that
    // Mincer knows about. See: https://github.com/nodeca/mincer/issues/51
    clientConfig.lookup.forEach(function (options) {
      environment.appendPath(options.root);
    });

    // Check that main file is requirable.
    if (!environment.findAsset(targetFile)) {
      // Restore Mincer's paths.
      environment.clearPaths();
      environment.appendPath(originPaths);

      next('Main client file of ' + pkgName + ' not found: ' + targetFile);
      return;
    }

    environment.findAsset(targetFile).compile(function (err, data) {
      if (err) {
        next(err);
        return;
      }

      var source = data.toString();

      // Initialize package modules.
      clientConfig.files.forEach(function (pathname) {
        source += '\nNodecaLoader.require(' + JSON.stringify(pathname.toString()) + ');';
      });

      // The current package is complete.
      fs.writeFile(resultFile, source, 'utf8', function (err) {
        if (err) {
          next(err);
          return;
        }

        // Restore Mincer's paths.
        environment.clearPaths();
        environment.appendPath(originPaths);

        N.logger.debug('Compiled client of %s %s', pkgName, timer.elapsed);
        fstools.remove(clientTmpDir, next);
      });
    });
  }, function (err) {
    N.logger.info('Processed client section %s', timer.elapsed);
    callback(err);
  });
};
<|endoftext|>


<commit_before>(function () {
  'use strict';
  var _ = require('underscore'),
    R = require('ramda'),
    Repository = require('./repository_with_graph').RepositoryWithGraph,
    Model = require('./model').Model,
    configureStates,
    typeIs,
    determineSuperstate,
    prepareStartState,
    prepareServiceState,
    determinePrefix,
    prependPrefix,
    appendIdPlaceholder,
    isParameterized,
    hasUrlTemplate,
    appendIdPlaceholderForParameterizedState,
    determineUrlTemplate,
    determineUrlTemplateIfNotDetermined,
    prepareEntityState,
    prepareRepositoryState,
    copyInfoFromRepositoryState;

  typeIs = R.curry(function (type, state) {
    return state.type === type;
  });

  determineSuperstate = R.curry(function (states, state) {
    if (state.superstate) {
      state.superstate = states[state.superstate];
    }
  });

  prepareStartState = R.curry(R.func('setAsStart'));
  prepareServiceState = R.curry(R.func('addService'));

  determinePrefix = function (state) {
    var prefix = '/';

    if (state.superstate) {
      // First determine the entire chain
      determineUrlTemplateIfNotDetermined(state.superstate);
      prefix = state.superstate.urlTemplate + '/';
    }

    return prefix;
  };

  prependPrefix = function (state) {
    state.urlTemplate = R.concat(determinePrefix(state), state.name);
    return state;
  };

  appendIdPlaceholder = function(state) {
    state.urlTemplate = R.concat(state.urlTemplate, '/:id');
    return state;
  };

  isParameterized = R.prop('parameterized');
  hasUrlTemplate = R.prop('urlTemplate');
  appendIdPlaceholderForParameterizedState = R.cond(isParameterized, appendIdPlaceholder, R.identity);
  determineUrlTemplate = R.pipe(prependPrefix, appendIdPlaceholderForParameterizedState);
  determineUrlTemplateIfNotDetermined = R.cond(hasUrlTemplate, R.identity, determineUrlTemplate);

  prepareEntityState = R.curry(function (states, entity) {
    var repositoryState = states[entity.options.containedIn];
    entity.repositoryState = repositoryState;
    entity.addModel(Model);
  });

  prepareRepositoryState = R.curry(function (states, repository) {
    var entityState = states[repository.options.contains];
    repository.entityState = entityState;
    repository.model = entityState.model;
    repository.addRepository(Repository);
  });

  copyInfoFromRepositoryState = function (entity) {
    var repositoryState = entity.repositoryState,
      repository = repositoryState.repository;
    entity.collectionName = repositoryState.collectionName;
    entity.collection = repositoryState.collection;
    entity.repository = repositoryState.repository;
    repository.relations = entity.relations;
  };

  configureStates = function (states) {
    var entities = _.filter(states, typeIs('entity')),
      repositories = _.filter(states, typeIs('repository')),
      services = _.filter(states, typeIs('service')),
      starts = _.filter(states, typeIs('start'));

    _.each(states, determineSuperstate(states));
    _.each(states, determineUrlTemplateIfNotDetermined);

    // TODO: Remove DEBUG info
    _.each(states, function (state) {
      require('console').log('State %s: %s', state.name, state.urlTemplate);
    });

    _.each(starts, prepareStartState);
    _.each(services, prepareServiceState);
    _.each(entities, prepareEntityState(states));
    _.each(repositories, prepareRepositoryState(states));
    _.each(entities, copyInfoFromRepositoryState);
  };

  exports.configureStates = configureStates;
}());
<commit_msg>Remove debug info<commit_after>(function () {
  'use strict';
  var _ = require('underscore'),
    R = require('ramda'),
    Repository = require('./repository_with_graph').RepositoryWithGraph,
    Model = require('./model').Model,
    configureStates,
    typeIs,
    determineSuperstate,
    prepareStartState,
    prepareServiceState,
    determinePrefix,
    prependPrefix,
    appendIdPlaceholder,
    isParameterized,
    hasUrlTemplate,
    appendIdPlaceholderForParameterizedState,
    determineUrlTemplate,
    determineUrlTemplateIfNotDetermined,
    prepareEntityState,
    prepareRepositoryState,
    copyInfoFromRepositoryState;

  typeIs = R.curry(function (type, state) {
    return state.type === type;
  });

  determineSuperstate = R.curry(function (states, state) {
    if (state.superstate) {
      state.superstate = states[state.superstate];
    }
  });

  prepareStartState = R.curry(R.func('setAsStart'));
  prepareServiceState = R.curry(R.func('addService'));

  determinePrefix = function (state) {
    var prefix = '/';

    if (state.superstate) {
      // First determine the entire chain
      determineUrlTemplateIfNotDetermined(state.superstate);
      prefix = state.superstate.urlTemplate + '/';
    }

    return prefix;
  };

  prependPrefix = function (state) {
    state.urlTemplate = R.concat(determinePrefix(state), state.name);
    return state;
  };

  appendIdPlaceholder = function(state) {
    state.urlTemplate = R.concat(state.urlTemplate, '/:id');
    return state;
  };

  isParameterized = R.prop('parameterized');
  hasUrlTemplate = R.prop('urlTemplate');
  appendIdPlaceholderForParameterizedState = R.cond(isParameterized, appendIdPlaceholder, R.identity);
  determineUrlTemplate = R.pipe(prependPrefix, appendIdPlaceholderForParameterizedState);
  determineUrlTemplateIfNotDetermined = R.cond(hasUrlTemplate, R.identity, determineUrlTemplate);

  prepareEntityState = R.curry(function (states, entity) {
    var repositoryState = states[entity.options.containedIn];
    entity.repositoryState = repositoryState;
    entity.addModel(Model);
  });

  prepareRepositoryState = R.curry(function (states, repository) {
    var entityState = states[repository.options.contains];
    repository.entityState = entityState;
    repository.model = entityState.model;
    repository.addRepository(Repository);
  });

  copyInfoFromRepositoryState = function (entity) {
    var repositoryState = entity.repositoryState,
      repository = repositoryState.repository;
    entity.collectionName = repositoryState.collectionName;
    entity.collection = repositoryState.collection;
    entity.repository = repositoryState.repository;
    repository.relations = entity.relations;
  };

  configureStates = function (states) {
    var entities = _.filter(states, typeIs('entity')),
      repositories = _.filter(states, typeIs('repository')),
      services = _.filter(states, typeIs('service')),
      starts = _.filter(states, typeIs('start'));

    _.each(states, determineSuperstate(states));
    _.each(states, determineUrlTemplateIfNotDetermined);
    _.each(starts, prepareStartState);
    _.each(services, prepareServiceState);
    _.each(entities, prepareEntityState(states));
    _.each(repositories, prepareRepositoryState(states));
    _.each(entities, copyInfoFromRepositoryState);
  };

  exports.configureStates = configureStates;
}());
<|endoftext|>


<commit_before>/*!
 * Copyright 2014 Apereo Foundation (AF) Licensed under the
 * Educational Community License, Version 2.0 (the "License"); you may
 * not use this file except in compliance with the License. You may
 * obtain a copy of the License at
 *
 *     http://opensource.org/licenses/ECL-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an "AS IS"
 * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing
 * permissions and limitations under the License.
 */

require(['jquery', 'oae.core', 'underscore', 'jquery.history', 'jquery.switchtab'], function($, oae, _) {

    // Variable that will be used to keep track of the current
    // infinite scroll instance
    var infinityScroll = false;

    var $switchtab = null;
    var currSwitchtabId = null;

    /**
     * Get the search query data in the current state
     *
     * @return {Object}     queryData           The query data from the current state
     * @return {String}     queryData.q         The full-text search query
     * @return {String[]}   queryData.types     The resource types for which to search
     * @return {String}     queryData.tenant    The tenant alias in which to search
     */
    var getQueryData = function() {
        var params = oae.api.util.url(History.getState().cleanUrl).param();
        var q = params.q;
        var tenant = params.tenant;
        var types = [];
        if (params.types) {
            types = params.types.split(',');
        }

        var data = {
            'q': params.q,
            'tenant': tenant,
            'types': types
        };

        return data;
    };

    /**
     * Convert the given query data object into a url-encoded querystring string
     *
     * @return {String}     The query string (including the '?'), or an empty string if the data object is empty
     */
    var createQueryString = function(obj) {
        var params = [];
        $.each(obj, function(key, val) {
            params.push(key + '=' + oae.api.util.security().encodeForURL(val));
        });
        return (params.length) ? '?' + params.join('&') : '';
    };

    /**
     * Initialize a new infinite scroll container that lists the search results.
     */
    var renderSearch = function() {
        // Disable the previous infinite scroll
        if (infinityScroll) {
            infinityScroll.kill();
        }

        // Ensure the correct tab class is on the search content container. This CSS class helps
        // the UI hide/show search form controls that are applicable to specied search scope
        var switchtabId = $switchtab.switchtabId();
        if (currSwitchtabId !== switchtabId) {
            currSwitchtabId = switchtabId;
            $('#search-content-container')
                .removeClass('search-my')
                .removeClass('search-all')
                .addClass('search-' + switchtabId);
        }

        var title = ['__MSG__SEARCH__'];
        var queryData = getQueryData();

        // Apply the search value to the search text field
        $('.search-query').val(queryData.q);
        if (queryData.q) {
            title.push(queryData.q);
        }

        // Set the browser title
        oae.api.util.setBrowserTitle(title);

        // Reset the type checkboxes to make sure that none of them stay checked incorrectly
        // when hitting the back and forward buttons
        $('#search-refine-type input[type="checkbox"]').prop('checked', false);

        $.each(queryData.types, function(i, type) {
            $('#search-refine-type input[type="checkbox"][data-type="' + type + '"]').prop('checked', true);
        });

        // Ensure only the selected tenant is chosen, if at all
        $('#search-refine-tenant input[type="checkbox"]').removeAttr('checked');
        if (queryData.tenant) {
            $('#search-refine-tenant input[type="checkbox"][data-tenant="' + queryData.tenant + '"]').prop('checked', true);
        }

        // Hide the 'within tenant' checkbox for private tenants
        if (oae.api.config.getValue('oae-tenants', 'tenantprivacy', 'tenantprivate')) {
            $('#search-refine-tenant').hide();
        }

        var searchParams = {
            'limit': 12,
            'q': queryData.q,
            'resourceTypes': queryData.types,
            'scope': '_' + currSwitchtabId
        };

        if (searchParams.scope === '_my') {
            // "My" search never includes users, and will be harmful if only "user" is selected from
            // the "Everything" tab. Just always filter it out
            searchParams.resourceTypes = _.without(searchParams.resourceTypes, 'user');
        } else if (searchParams.scope === '_all' && queryData.tenant) {
            // If a tenant is specified, we search by the tenant
            searchParams.scope = queryData.tenant;
        }

        // Set up the infinite scroll for the list of search results
        infinityScroll = $('.oae-list').infiniteScroll('/api/search/general', searchParams, '#search-template', {
            'postRenderer': function(data) {
                var nrResults = oae.api.l10n.transformNumber(data.total);
                $('.oae-list-header-badge').text(nrResults).show();
            },
            'emptyListProcessor': function() {
                oae.api.util.template().render($('#search-noresults-template'), {
                    'query': queryData.q
                }, $('.oae-list'));
            }
        });
    };

    /**
     * Initiate a new search based on the current state of the search parameters. This can be re-run
     * whenever search parameters are changed
     */
    var modifySearch = function() {
        // Get the query from the search form
        var query = $.trim($('#search-query').val());

        // Get all of the selected type checkboxes
        var types = [];
        $('#search-refine-type input[type="checkbox"]:checked').each(function() {
            types.push($(this).attr('data-type'));
        });

        var tenant = $('#search-refine-tenant input[type="checkbox"]:checked').attr('data-tenant');
        var path = oae.api.util.url(History.getState().cleanUrl).attr('path');
        var params = {};

        if (query) {
            params.q = query;
        }

        if (types.length > 0) {
            params.types = types.join(',');
        }

        if (tenant) {
            params.tenant = tenant;
        }

        // Append the query string, if any
        path += createQueryString(params);

        History.pushState({}, null, path);

        return false;
    };

    /**
     * Extract the search query and type refinements from the current URL.
     * This will only be executed when the page is loaded.
     */
    var initSearch = function() {
        oae.api.util.template().render($('#search-list-header-template'), null, $('#search-list-header'));
        oae.api.util.template().render($('#search-lhnavigation-template'), null, $('#search-lhnavigation'));

        // We should intelligently detect that if someone goes to /search/<search query>, we should
        // automatically send them to /search/all?q=<search query>
        var state = History.getState();
        var url = oae.api.util.url(History.getState().cleanUrl);
        var path = url.attr('path').split('/');
        var queryString = url.attr('query');

        /*!
         * This is backward compatibility handling for links that are sent to OAE. Previously, a
         * link could be sent to /search/<query> to send a user to the search page with a pre-
         * loaded query. Now those search endpoints look like /search/all/<query> and
         * /search/my/<query>.
         *
         * To transition to this, we look if the query looks like /search/<query> where <query> is
         * not "all" or "my". If so, we rewrite the URL to /search/all/<query>.
         *
         * TODO: Remove after this is released
         */
        var topLevelSearch = path[2] || '';
        if (topLevelSearch !== 'my' && topLevelSearch !== 'all') {
            // The topLevelSearch does not equal "my" or "all", so we make that path portion the `q`
            // parameter and send them to /search/all
            path[2] = 'all';
            if (queryString) {
                queryString += '&';
            }
            queryString += 'q=' + topLevelSearch;
            History.replaceState({}, null, path.join('/') + '?' + queryString);
        } else if (topLevelSearch !== 'all' && oae.data.me.anon) {
            // When the user is anonymous, they can only go to /search/all, so send them there
            // instead with the search query
            path[2] = 'all';
            path = path.join('/');
            if (queryString) {
                path += '?' + queryString;
            }
            History.replaceState({}, null, path);
        }

        // Initialize the switchtab component
        $switchtab = $('#search-scope').switchtab();
    };

    /**
     * Add the different event bindings
     */
    var addBinding = function() {
        // Listen to the form submit event on the search form
        $(document).on('submit', '#search-form', modifySearch);

        // Listen to changes to the checkboxes that refine search options
        $('#search-refine-type').on('change', 'input[type="checkbox"]', modifySearch);

        // Listen to changes to the checkboxes that refine by tenant
        $('#search-refine-tenant').on('change', 'input[type="checkbox"]', modifySearch);

        // Listen to History.js state changes
        $(window).on('statechange', renderSearch);
    };

    initSearch();
    addBinding();
    renderSearch();
});
<commit_msg>Set scope to tenancy when dealing with private tenants<commit_after>/*!
 * Copyright 2014 Apereo Foundation (AF) Licensed under the
 * Educational Community License, Version 2.0 (the "License"); you may
 * not use this file except in compliance with the License. You may
 * obtain a copy of the License at
 *
 *     http://opensource.org/licenses/ECL-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an "AS IS"
 * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing
 * permissions and limitations under the License.
 */

require(['jquery', 'oae.core', 'underscore', 'jquery.history', 'jquery.switchtab'], function($, oae, _) {

    // Variable that will be used to keep track of the current
    // infinite scroll instance
    var infinityScroll = false;

    var $switchtab = null;
    var currSwitchtabId = null;

    /**
     * Get the search query data in the current state
     *
     * @return {Object}     queryData           The query data from the current state
     * @return {String}     queryData.q         The full-text search query
     * @return {String[]}   queryData.types     The resource types for which to search
     * @return {String}     queryData.tenant    The tenant alias in which to search
     */
    var getQueryData = function() {
        var params = oae.api.util.url(History.getState().cleanUrl).param();
        var q = params.q;
        var tenant = params.tenant;
        var types = [];
        if (params.types) {
            types = params.types.split(',');
        }

        var data = {
            'q': params.q,
            'tenant': tenant,
            'types': types
        };

        return data;
    };

    /**
     * Convert the given query data object into a url-encoded querystring string
     *
     * @return {String}     The query string (including the '?'), or an empty string if the data object is empty
     */
    var createQueryString = function(obj) {
        var params = [];
        $.each(obj, function(key, val) {
            params.push(key + '=' + oae.api.util.security().encodeForURL(val));
        });
        return (params.length) ? '?' + params.join('&') : '';
    };

    /**
     * Initialize a new infinite scroll container that lists the search results.
     */
    var renderSearch = function() {
        // Disable the previous infinite scroll
        if (infinityScroll) {
            infinityScroll.kill();
        }

        // Ensure the correct tab class is on the search content container. This CSS class helps
        // the UI hide/show search form controls that are applicable to specied search scope
        var switchtabId = $switchtab.switchtabId();
        if (currSwitchtabId !== switchtabId) {
            currSwitchtabId = switchtabId;
            $('#search-content-container')
                .removeClass('search-my')
                .removeClass('search-all')
                .addClass('search-' + switchtabId);
        }

        var title = ['__MSG__SEARCH__'];
        var queryData = getQueryData();

        // Apply the search value to the search text field
        $('.search-query').val(queryData.q);
        if (queryData.q) {
            title.push(queryData.q);
        }

        // Set the browser title
        oae.api.util.setBrowserTitle(title);

        // Reset the type checkboxes to make sure that none of them stay checked incorrectly
        // when hitting the back and forward buttons
        $('#search-refine-type input[type="checkbox"]').prop('checked', false);

        $.each(queryData.types, function(i, type) {
            $('#search-refine-type input[type="checkbox"][data-type="' + type + '"]').prop('checked', true);
        });

        // Hide the 'within tenant' checkbox for private tenants
        var isPrivate = oae.api.config.getValue('oae-tenants', 'tenantprivacy', 'tenantprivate');
        if (isPrivate) {
            $('#search-refine-tenant').hide();
        } else {
            // Ensure only the selected tenant is chosen, if at all
            $('#search-refine-tenant input[type="checkbox"]').removeAttr('checked');
            if (queryData.tenant) {
                $('#search-refine-tenant input[type="checkbox"][data-tenant="' + queryData.tenant + '"]').prop('checked', true);
            }
        }

        var searchParams = {
            'limit': 12,
            'q': queryData.q,
            'resourceTypes': queryData.types,
            'scope': '_' + currSwitchtabId
        };

        if (searchParams.scope === '_my') {
            // "My" search never includes users, and will be harmful if only "user" is selected from
            // the "Everything" tab. Just always filter it out
            searchParams.resourceTypes = _.without(searchParams.resourceTypes, 'user');
        } else if (searchParams.scope === '_all' && (queryData.tenant || isPrivate)) {
            // If a tenant is specified or the current tenant is private, we search by the tenant
            queryData.tenant = queryData.tenant ? queryData.tenant : $('#search-refine-tenant input[type="checkbox"]').attr('data-tenant');
            searchParams.scope = queryData.tenant;
        }

        // Set up the infinite scroll for the list of search results
        infinityScroll = $('.oae-list').infiniteScroll('/api/search/general', searchParams, '#search-template', {
            'postRenderer': function(data) {
                var nrResults = oae.api.l10n.transformNumber(data.total);
                $('.oae-list-header-badge').text(nrResults).show();
            },
            'emptyListProcessor': function() {
                oae.api.util.template().render($('#search-noresults-template'), {
                    'query': queryData.q
                }, $('.oae-list'));
            }
        });
    };

    /**
     * Initiate a new search based on the current state of the search parameters. This can be re-run
     * whenever search parameters are changed
     */
    var modifySearch = function() {
        // Get the query from the search form
        var query = $.trim($('#search-query').val());

        // Get all of the selected type checkboxes
        var types = [];
        $('#search-refine-type input[type="checkbox"]:checked').each(function() {
            types.push($(this).attr('data-type'));
        });

        var tenant = $('#search-refine-tenant input[type="checkbox"]:checked').attr('data-tenant');
        var path = oae.api.util.url(History.getState().cleanUrl).attr('path');
        var params = {};

        if (query) {
            params.q = query;
        }

        if (types.length > 0) {
            params.types = types.join(',');
        }

        if (tenant) {
            params.tenant = tenant;
        }

        // Append the query string, if any
        path += createQueryString(params);

        History.pushState({}, null, path);

        return false;
    };

    /**
     * Extract the search query and type refinements from the current URL.
     * This will only be executed when the page is loaded.
     */
    var initSearch = function() {
        oae.api.util.template().render($('#search-list-header-template'), null, $('#search-list-header'));
        oae.api.util.template().render($('#search-lhnavigation-template'), null, $('#search-lhnavigation'));

        // We should intelligently detect that if someone goes to /search/<search query>, we should
        // automatically send them to /search/all?q=<search query>
        var state = History.getState();
        var url = oae.api.util.url(History.getState().cleanUrl);
        var path = url.attr('path').split('/');
        var queryString = url.attr('query');

        /*!
         * This is backward compatibility handling for links that are sent to OAE. Previously, a
         * link could be sent to /search/<query> to send a user to the search page with a pre-
         * loaded query. Now those search endpoints look like /search/all/<query> and
         * /search/my/<query>.
         *
         * To transition to this, we look if the query looks like /search/<query> where <query> is
         * not "all" or "my". If so, we rewrite the URL to /search/all/<query>.
         *
         * TODO: Remove after this is released
         */
        var topLevelSearch = path[2] || '';
        if (topLevelSearch !== 'my' && topLevelSearch !== 'all') {
            // The topLevelSearch does not equal "my" or "all", so we make that path portion the `q`
            // parameter and send them to /search/all
            path[2] = 'all';
            if (queryString) {
                queryString += '&';
            }
            queryString += 'q=' + topLevelSearch;
            History.replaceState({}, null, path.join('/') + '?' + queryString);
        } else if (topLevelSearch !== 'all' && oae.data.me.anon) {
            // When the user is anonymous, they can only go to /search/all, so send them there
            // instead with the search query
            path[2] = 'all';
            path = path.join('/');
            if (queryString) {
                path += '?' + queryString;
            }
            History.replaceState({}, null, path);
        }

        // Initialize the switchtab component
        $switchtab = $('#search-scope').switchtab();
    };

    /**
     * Add the different event bindings
     */
    var addBinding = function() {
        // Listen to the form submit event on the search form
        $(document).on('submit', '#search-form', modifySearch);

        // Listen to changes to the checkboxes that refine search options
        $('#search-refine-type').on('change', 'input[type="checkbox"]', modifySearch);

        // Listen to changes to the checkboxes that refine by tenant
        $('#search-refine-tenant').on('change', 'input[type="checkbox"]', modifySearch);

        // Listen to History.js state changes
        $(window).on('statechange', renderSearch);
    };

    initSearch();
    addBinding();
    renderSearch();
});
<|endoftext|>


<commit_before><commit_msg>Hid layers when not used<commit_after><|endoftext|>


<commit_before>goog.provide('ol.renderer.canvas.VectorLayer');

goog.require('goog.asserts');
goog.require('goog.events');
goog.require('goog.functions');
goog.require('ol.ViewHint');
goog.require('ol.extent');
goog.require('ol.feature');
goog.require('ol.layer.Vector');
goog.require('ol.render.canvas.ReplayGroup');
goog.require('ol.renderer.canvas.Layer');
goog.require('ol.renderer.vector');
goog.require('ol.source.Vector');

/**
 * @constructor
 * @extends {ol.renderer.canvas.Layer}
 * @param {ol.renderer.Map} mapRenderer Map renderer.
 * @param {ol.layer.Vector} vectorLayer Vector layer.
 */
ol.renderer.canvas.VectorLayer = function(mapRenderer, vectorLayer) {

  goog.base(this, mapRenderer, vectorLayer);

  /**
   * @private
   * @type {boolean}
   */
  this.dirty_ = false;

  /**
   * @private
   * @type {number}
   */
  this.renderedRevision_ = -1;

  /**
   * @private
   * @type {number}
   */
  this.renderedResolution_ = NaN;

  /**
   * @private
   * @type {ol.Extent}
   */
  this.renderedExtent_ = ol.extent.createEmpty();

  /**
   * @private
   * @type {ol.render.canvas.ReplayGroup}
   */
  this.replayGroup_ = null;

};
goog.inherits(ol.renderer.canvas.VectorLayer, ol.renderer.canvas.Layer);

/**
 * @inheritDoc
 */
ol.renderer.canvas.VectorLayer.prototype.composeFrame =
    function(frameState, layerState, context) {

  var transform = this.getTransform(frameState);

  this.dispatchPreComposeEvent(context, frameState, transform);

  var replayGroup = this.replayGroup_;
  if (!goog.isNull(replayGroup)) {
    var renderGeometryFunction = this.getRenderGeometryFunction_();
    goog.asserts.assert(goog.isFunction(renderGeometryFunction));
    context.globalAlpha = layerState.opacity;
    replayGroup.replay(
        context, frameState.extent, frameState.pixelRatio, transform,
        renderGeometryFunction);
  }

  this.dispatchPostComposeEvent(context, frameState, transform);

};

/**
 * @inheritDoc
 */
ol.renderer.canvas.VectorLayer.prototype.forEachFeatureAtPixel =
    function(coordinate, frameState, callback, thisArg) {
  if (goog.isNull(this.replayGroup_)) {
    return undefined;
  } else {
    var extent = frameState.extent;
    var resolution = frameState.view2DState.resolution;
    var rotation = frameState.view2DState.rotation;
    var layer = this.getLayer();
    var renderGeometryFunction = this.getRenderGeometryFunction_();
    goog.asserts.assert(goog.isFunction(renderGeometryFunction));
    return this.replayGroup_.forEachGeometryAtPixel(extent, resolution,
        rotation, coordinate, renderGeometryFunction,
        /**
         * @param {ol.geom.Geometry} geometry Geometry.
         * @param {Object} data Data.
         * @return {?} Callback result.
         */
        function(geometry, data) {
          var feature = /** @type {ol.Feature} */ (data);
          goog.asserts.assert(goog.isDef(feature));
          return callback.call(thisArg, feature, layer);
        });
  }
};

/**
 * @private
 * @return {function(ol.geom.Geometry): boolean} Render geometry function.
 */
ol.renderer.canvas.VectorLayer.prototype.getRenderGeometryFunction_ =
    function() {
  var vectorLayer = this.getLayer();
  goog.asserts.assertInstanceof(vectorLayer, ol.layer.Vector);
  var renderGeometryFunctions = vectorLayer.getRenderGeometryFunctions();
  if (!goog.isDef(renderGeometryFunctions)) {
    return goog.functions.TRUE;
  }
  var renderGeometryFunctionsArray = renderGeometryFunctions.getArray();
  switch (renderGeometryFunctionsArray.length) {
    case 0:
      return goog.functions.TRUE;
    case 1:
      return renderGeometryFunctionsArray[0];
    default:
      return (
          /**
           * @param {ol.geom.Geometry} geometry Geometry.
           * @return {boolean} Render geometry.
           */
          function(geometry) {
            var i, ii;
            for (i = 0, ii = renderGeometryFunctionsArray.length; i < ii; ++i) {
              if (!renderGeometryFunctionsArray[i](geometry)) {
                return false;
              }
            }
            return true;
          });
  }
};

/**
 * Handle changes in image style state.
 * @param {goog.events.Event} event Image style change event.
 * @private
 */
ol.renderer.canvas.VectorLayer.prototype.handleImageChange_ =
    function(event) {
  this.renderIfReadyAndVisible();
};

/**
 * @inheritDoc
 */
ol.renderer.canvas.VectorLayer.prototype.prepareFrame =
    function(frameState, layerState) {

  var vectorLayer = this.getLayer();
  goog.asserts.assertInstanceof(vectorLayer, ol.layer.Vector);
  var vectorSource = vectorLayer.getSource();
  goog.asserts.assertInstanceof(vectorSource, ol.source.Vector);

  this.updateAttributions(
      frameState.attributions, vectorSource.getAttributions());
  this.updateLogos(frameState, vectorSource);

  if (!this.dirty_ && (frameState.viewHints[ol.ViewHint.ANIMATING] ||
      frameState.viewHints[ol.ViewHint.INTERACTING])) {
    return;
  }

  var frameStateExtent = frameState.extent;
  var frameStateResolution = frameState.view2DState.resolution;
  var pixelRatio = frameState.pixelRatio;
  var vectorLayerRevision = vectorLayer.getRevision();

  if (!this.dirty_ &&
      this.renderedResolution_ == frameStateResolution &&
      this.renderedRevision_ == vectorLayerRevision &&
      ol.extent.containsExtent(this.renderedExtent_, frameStateExtent)) {
    return;
  }

  var extent = this.renderedExtent_;
  var xBuffer = ol.extent.getWidth(frameStateExtent) / 4;
  var yBuffer = ol.extent.getHeight(frameStateExtent) / 4;
  extent[0] = frameStateExtent[0] - xBuffer;
  extent[1] = frameStateExtent[1] - yBuffer;
  extent[2] = frameStateExtent[2] + xBuffer;
  extent[3] = frameStateExtent[3] + yBuffer;

  // FIXME dispose of old replayGroup in post render
  goog.dispose(this.replayGroup_);
  this.replayGroup_ = null;

  this.dirty_ = false;

  var styleFunction = vectorLayer.getStyleFunction();
  if (!goog.isDef(styleFunction)) {
    styleFunction = ol.feature.defaultStyleFunction;
  }
  var tolerance = frameStateResolution / (2 * pixelRatio);
  var replayGroup = new ol.render.canvas.ReplayGroup(tolerance);
  vectorSource.forEachFeatureInExtent(extent,
      /**
       * @param {ol.Feature} feature Feature.
       */
      function(feature) {
        var dirty =
            this.renderFeature(feature, frameStateResolution, pixelRatio,
                styleFunction, replayGroup);
        this.dirty_ = this.dirty_ || dirty;
      }, this);
  replayGroup.finish();

  this.renderedResolution_ = frameStateResolution;
  this.renderedRevision_ = vectorLayerRevision;
  this.replayGroup_ = replayGroup;

};

/**
 * @param {ol.Feature} feature Feature.
 * @param {number} resolution Resolution.
 * @param {number} pixelRatio Pixel ratio.
 * @param {ol.feature.StyleFunction} styleFunction Style function.
 * @param {ol.render.canvas.ReplayGroup} replayGroup Replay group.
 * @return {boolean} `true` if an image is loading.
 */
ol.renderer.canvas.VectorLayer.prototype.renderFeature =
    function(feature, resolution, pixelRatio, styleFunction, replayGroup) {
  var styles = styleFunction(feature, resolution);
  if (!goog.isDefAndNotNull(styles)) {
    return false;
  }
  // simplify to a tolerance of half a device pixel
  var squaredTolerance =
      resolution * resolution / (4 * pixelRatio * pixelRatio);
  var i, ii, loading = false;
  for (i = 0, ii = styles.length; i < ii; ++i) {
    loading = ol.renderer.vector.renderFeature(
        replayGroup, feature, styles[i], squaredTolerance, feature,
        this.handleImageChange_, this) || loading;
  }
  return loading;
};
<commit_msg>Only replay replay group if it is not empty<commit_after>goog.provide('ol.renderer.canvas.VectorLayer');

goog.require('goog.asserts');
goog.require('goog.events');
goog.require('goog.functions');
goog.require('ol.ViewHint');
goog.require('ol.extent');
goog.require('ol.feature');
goog.require('ol.layer.Vector');
goog.require('ol.render.canvas.ReplayGroup');
goog.require('ol.renderer.canvas.Layer');
goog.require('ol.renderer.vector');
goog.require('ol.source.Vector');

/**
 * @constructor
 * @extends {ol.renderer.canvas.Layer}
 * @param {ol.renderer.Map} mapRenderer Map renderer.
 * @param {ol.layer.Vector} vectorLayer Vector layer.
 */
ol.renderer.canvas.VectorLayer = function(mapRenderer, vectorLayer) {

  goog.base(this, mapRenderer, vectorLayer);

  /**
   * @private
   * @type {boolean}
   */
  this.dirty_ = false;

  /**
   * @private
   * @type {number}
   */
  this.renderedRevision_ = -1;

  /**
   * @private
   * @type {number}
   */
  this.renderedResolution_ = NaN;

  /**
   * @private
   * @type {ol.Extent}
   */
  this.renderedExtent_ = ol.extent.createEmpty();

  /**
   * @private
   * @type {ol.render.canvas.ReplayGroup}
   */
  this.replayGroup_ = null;

};
goog.inherits(ol.renderer.canvas.VectorLayer, ol.renderer.canvas.Layer);

/**
 * @inheritDoc
 */
ol.renderer.canvas.VectorLayer.prototype.composeFrame =
    function(frameState, layerState, context) {

  var transform = this.getTransform(frameState);

  this.dispatchPreComposeEvent(context, frameState, transform);

  var replayGroup = this.replayGroup_;
  if (!goog.isNull(replayGroup) && !replayGroup.isEmpty()) {
    var renderGeometryFunction = this.getRenderGeometryFunction_();
    goog.asserts.assert(goog.isFunction(renderGeometryFunction));
    context.globalAlpha = layerState.opacity;
    replayGroup.replay(
        context, frameState.extent, frameState.pixelRatio, transform,
        renderGeometryFunction);
  }

  this.dispatchPostComposeEvent(context, frameState, transform);

};

/**
 * @inheritDoc
 */
ol.renderer.canvas.VectorLayer.prototype.forEachFeatureAtPixel =
    function(coordinate, frameState, callback, thisArg) {
  if (goog.isNull(this.replayGroup_)) {
    return undefined;
  } else {
    var extent = frameState.extent;
    var resolution = frameState.view2DState.resolution;
    var rotation = frameState.view2DState.rotation;
    var layer = this.getLayer();
    var renderGeometryFunction = this.getRenderGeometryFunction_();
    goog.asserts.assert(goog.isFunction(renderGeometryFunction));
    return this.replayGroup_.forEachGeometryAtPixel(extent, resolution,
        rotation, coordinate, renderGeometryFunction,
        /**
         * @param {ol.geom.Geometry} geometry Geometry.
         * @param {Object} data Data.
         * @return {?} Callback result.
         */
        function(geometry, data) {
          var feature = /** @type {ol.Feature} */ (data);
          goog.asserts.assert(goog.isDef(feature));
          return callback.call(thisArg, feature, layer);
        });
  }
};

/**
 * @private
 * @return {function(ol.geom.Geometry): boolean} Render geometry function.
 */
ol.renderer.canvas.VectorLayer.prototype.getRenderGeometryFunction_ =
    function() {
  var vectorLayer = this.getLayer();
  goog.asserts.assertInstanceof(vectorLayer, ol.layer.Vector);
  var renderGeometryFunctions = vectorLayer.getRenderGeometryFunctions();
  if (!goog.isDef(renderGeometryFunctions)) {
    return goog.functions.TRUE;
  }
  var renderGeometryFunctionsArray = renderGeometryFunctions.getArray();
  switch (renderGeometryFunctionsArray.length) {
    case 0:
      return goog.functions.TRUE;
    case 1:
      return renderGeometryFunctionsArray[0];
    default:
      return (
          /**
           * @param {ol.geom.Geometry} geometry Geometry.
           * @return {boolean} Render geometry.
           */
          function(geometry) {
            var i, ii;
            for (i = 0, ii = renderGeometryFunctionsArray.length; i < ii; ++i) {
              if (!renderGeometryFunctionsArray[i](geometry)) {
                return false;
              }
            }
            return true;
          });
  }
};

/**
 * Handle changes in image style state.
 * @param {goog.events.Event} event Image style change event.
 * @private
 */
ol.renderer.canvas.VectorLayer.prototype.handleImageChange_ =
    function(event) {
  this.renderIfReadyAndVisible();
};

/**
 * @inheritDoc
 */
ol.renderer.canvas.VectorLayer.prototype.prepareFrame =
    function(frameState, layerState) {

  var vectorLayer = this.getLayer();
  goog.asserts.assertInstanceof(vectorLayer, ol.layer.Vector);
  var vectorSource = vectorLayer.getSource();
  goog.asserts.assertInstanceof(vectorSource, ol.source.Vector);

  this.updateAttributions(
      frameState.attributions, vectorSource.getAttributions());
  this.updateLogos(frameState, vectorSource);

  if (!this.dirty_ && (frameState.viewHints[ol.ViewHint.ANIMATING] ||
      frameState.viewHints[ol.ViewHint.INTERACTING])) {
    return;
  }

  var frameStateExtent = frameState.extent;
  var frameStateResolution = frameState.view2DState.resolution;
  var pixelRatio = frameState.pixelRatio;
  var vectorLayerRevision = vectorLayer.getRevision();

  if (!this.dirty_ &&
      this.renderedResolution_ == frameStateResolution &&
      this.renderedRevision_ == vectorLayerRevision &&
      ol.extent.containsExtent(this.renderedExtent_, frameStateExtent)) {
    return;
  }

  var extent = this.renderedExtent_;
  var xBuffer = ol.extent.getWidth(frameStateExtent) / 4;
  var yBuffer = ol.extent.getHeight(frameStateExtent) / 4;
  extent[0] = frameStateExtent[0] - xBuffer;
  extent[1] = frameStateExtent[1] - yBuffer;
  extent[2] = frameStateExtent[2] + xBuffer;
  extent[3] = frameStateExtent[3] + yBuffer;

  // FIXME dispose of old replayGroup in post render
  goog.dispose(this.replayGroup_);
  this.replayGroup_ = null;

  this.dirty_ = false;

  var styleFunction = vectorLayer.getStyleFunction();
  if (!goog.isDef(styleFunction)) {
    styleFunction = ol.feature.defaultStyleFunction;
  }
  var tolerance = frameStateResolution / (2 * pixelRatio);
  var replayGroup = new ol.render.canvas.ReplayGroup(tolerance);
  vectorSource.forEachFeatureInExtent(extent,
      /**
       * @param {ol.Feature} feature Feature.
       */
      function(feature) {
        var dirty =
            this.renderFeature(feature, frameStateResolution, pixelRatio,
                styleFunction, replayGroup);
        this.dirty_ = this.dirty_ || dirty;
      }, this);
  replayGroup.finish();

  this.renderedResolution_ = frameStateResolution;
  this.renderedRevision_ = vectorLayerRevision;
  this.replayGroup_ = replayGroup;

};

/**
 * @param {ol.Feature} feature Feature.
 * @param {number} resolution Resolution.
 * @param {number} pixelRatio Pixel ratio.
 * @param {ol.feature.StyleFunction} styleFunction Style function.
 * @param {ol.render.canvas.ReplayGroup} replayGroup Replay group.
 * @return {boolean} `true` if an image is loading.
 */
ol.renderer.canvas.VectorLayer.prototype.renderFeature =
    function(feature, resolution, pixelRatio, styleFunction, replayGroup) {
  var styles = styleFunction(feature, resolution);
  if (!goog.isDefAndNotNull(styles)) {
    return false;
  }
  // simplify to a tolerance of half a device pixel
  var squaredTolerance =
      resolution * resolution / (4 * pixelRatio * pixelRatio);
  var i, ii, loading = false;
  for (i = 0, ii = styles.length; i < ii; ++i) {
    loading = ol.renderer.vector.renderFeature(
        replayGroup, feature, styles[i], squaredTolerance, feature,
        this.handleImageChange_, this) || loading;
  }
  return loading;
};
<|endoftext|>


<commit_before>const fs = require("fs").promises;
const glob = require("glob");
const zlib = require('zlib');
const { getLanguages } = require("./lib/language");
const { filter } = require("./lib/dependencies");
const config = require("./build_config");
const { install, installCleanCSS, mkdir } = require("./lib/makestuff");
const log = (...args) => console.log(...args);
const { buildBrowserHighlightJS } = require("./build_browser");
const { buildPackageJSON } = require("./build_node");
const path = require("path");
const bundling = require('./lib/bundling.js');

async function installPackageJSON() {
  await buildPackageJSON();
  const json = require(`${process.env.BUILD_DIR}/package`);
  json.name = "@highlightjs/cdn-assets";
  json.description = json.description.concat(" (pre-compiled CDN assets)");
  fs.writeFile(`${process.env.BUILD_DIR}/package.json`, JSON.stringify(json, null, '   '));
}

let shas = {};

async function buildCDN(options) {
  install("./LICENSE", "LICENSE");
  install("./README.CDN.md", "README.md");
  installPackageJSON();

  installStyles();

  // all the languages are built for the CDN and placed into `/languages`
  const languages = await getLanguages();
  await installLanguages(languages);

  // filter languages for inclusion in the highlight.js bundle
  let embedLanguages = filter(languages, options.languages);

  // it really makes no sense to embed ALL languages with the CDN build, it's
  // more likely we want to embed NONE and have completely separate run-time
  // loading of some sort
  if (embedLanguages.length === languages.length) {
    embedLanguages = [];
  }

  const size = await buildBrowserHighlightJS(embedLanguages, { minify: options.minify });
  shas = Object.assign({}, size.shas, shas);

  await buildSRIDigests(shas);

  log("-----");
  log("Embedded Lang       :",
    embedLanguages.map((el) => el.minified.length).reduce((acc, curr) => acc + curr, 0), "bytes");
  log("All Lang            :",
    languages.map((el) => el.minified.length).reduce((acc, curr) => acc + curr, 0), "bytes");
  log("highlight.js        :",
    size.full, "bytes");

  if (options.minify) {
    log("highlight.min.js    :", size.minified, "bytes");
    log("highlight.min.js.gz :", zlib.gzipSync(size.minifiedSrc).length, "bytes");
  } else {
    log("highlight.js.gz     :", zlib.gzipSync(size.fullSrc).length, "bytes");
  }
  log("-----");
}

async function buildSRIDigests(shas) {
  const temp = await fs.readFile("./tools/templates/DIGESTS.md");
  const DIGEST_MD = temp.toString();

  const version = require("../package").version;
  const digestList = Object.entries(shas).map(([k, v]) => `${v} ${k}`).join("\n");

  const out = DIGEST_MD
    .replace("<!-- $DIGEST_LIST -->", digestList)
    .replace("<!-- $MIN_JS_DIGEST -->", shas["highlight.min.js"])
    .replace("<!-- $GO_SHA -->", shas["languages/go.min.js"])
    .replace(/<!-- \$VERSION -->/g, version);
  fs.writeFile(`${process.env.BUILD_DIR}/DIGESTS.md`, out);
}

async function installLanguages(languages) {
  log("Building language files.");
  mkdir("languages");

  await Promise.all(
    languages.map(async(language) => {
      await buildCDNLanguage(language);
      process.stdout.write(".");
    })
  );
  log("");

  await Promise.all(
    languages.filter((l) => l.third_party)
      .map(async(language) => {
        await buildDistributable(language);
      })
  );

  log("");
}

function installStyles() {
  log("Writing style files.");
  mkdir("styles");

  glob.sync("*", { cwd: "./src/styles" }).forEach((file) => {
    if (file.endsWith(".css")) {
      installCleanCSS(`./src/styles/${file}`, `styles/${file.replace(".css", ".min.css")}`);
    } else {
      // images, backgrounds, etc
      install(`./src/styles/${file}`, `styles/${file}`);
    }
  });
}

async function buildDistributable(language) {
  const filename = `${language.name}.min.js`;

  const distDir = path.join(language.moduleDir, "dist");
  log(`Building ${distDir}/${filename}.`);
  await fs.mkdir(distDir, { recursive: true });
  fs.writeFile(path.join(language.moduleDir, "dist", filename), language.minified);
}

async function buildCDNLanguage(language) {
  const name = `languages/${language.name}.min.js`;
  const filename = `${process.env.BUILD_DIR}/${name}`;

  await language.compile({ terser: config.terser });
  shas[name] = bundling.sha384(language.minified);
  fs.writeFile(filename, language.minified);
}

module.exports.build = buildCDN;

<commit_msg>(chore) fix CDN build<commit_after>const fs = require("fs").promises;
const fss = require("fs");
const glob = require("glob");
const zlib = require('zlib');
const { getLanguages } = require("./lib/language");
const { filter } = require("./lib/dependencies");
const config = require("./build_config");
const { install, installCleanCSS, mkdir } = require("./lib/makestuff");
const log = (...args) => console.log(...args);
const { buildBrowserHighlightJS } = require("./build_browser");
const { buildPackageJSON } = require("./build_node");
const path = require("path");
const bundling = require('./lib/bundling.js');

async function installPackageJSON(options) {
  await buildPackageJSON(options);
  const json = require(`${process.env.BUILD_DIR}/package`);
  json.name = "@highlightjs/cdn-assets";
  json.description = json.description.concat(" (pre-compiled CDN assets)");
  fs.writeFile(`${process.env.BUILD_DIR}/package.json`, JSON.stringify(json, null, '   '));
}

let shas = {};

async function buildCDN(options) {
  install("./LICENSE", "LICENSE");
  install("./README.CDN.md", "README.md");
  installPackageJSON(options);

  installStyles();

  // all the languages are built for the CDN and placed into `/languages`
  const languages = await getLanguages();
  await installLanguages(languages);

  // filter languages for inclusion in the highlight.js bundle
  let embedLanguages = filter(languages, options.languages);

  // it really makes no sense to embed ALL languages with the CDN build, it's
  // more likely we want to embed NONE and have completely separate run-time
  // loading of some sort
  if (embedLanguages.length === languages.length) {
    embedLanguages = [];
  }

  const size = await buildBrowserHighlightJS(embedLanguages, { minify: options.minify });
  shas = Object.assign({}, size.shas, shas);

  await buildSRIDigests(shas);

  log("-----");
  log("Embedded Lang       :",
    embedLanguages.map((el) => el.minified.length).reduce((acc, curr) => acc + curr, 0), "bytes");
  log("All Lang            :",
    languages.map((el) => el.minified.length).reduce((acc, curr) => acc + curr, 0), "bytes");
  log("highlight.js        :",
    size.full, "bytes");

  if (options.minify) {
    log("highlight.min.js    :", size.minified, "bytes");
    log("highlight.min.js.gz :", zlib.gzipSync(size.minifiedSrc).length, "bytes");
  } else {
    log("highlight.js.gz     :", zlib.gzipSync(size.fullSrc).length, "bytes");
  }
  log("-----");
}

async function buildSRIDigests(shas) {
  const temp = await fs.readFile("./tools/templates/DIGESTS.md");
  const DIGEST_MD = temp.toString();

  const version = require("../package").version;
  const digestList = Object.entries(shas).map(([k, v]) => `${v} ${k}`).join("\n");

  const out = DIGEST_MD
    .replace("<!-- $DIGEST_LIST -->", digestList)
    .replace("<!-- $MIN_JS_DIGEST -->", shas["highlight.min.js"])
    .replace("<!-- $GO_SHA -->", shas["languages/go.min.js"])
    .replace(/<!-- \$VERSION -->/g, version);
  fs.writeFile(`${process.env.BUILD_DIR}/DIGESTS.md`, out);
}

async function installLanguages(languages) {
  log("Building language files.");
  mkdir("languages");

  await Promise.all(
    languages.map(async(language) => {
      await buildCDNLanguage(language);
      process.stdout.write(".");
    })
  );
  log("");

  await Promise.all(
    languages.filter((l) => l.third_party)
      .map(async(language) => {
        await buildDistributable(language);
      })
  );

  log("");
}

function installStyles() {
  log("Writing style files.");
  mkdir("styles/base16");

  glob.sync("**", { cwd: "./src/styles" }).forEach((file) => {
    const stat = fss.statSync(`./src/styles/${file}`);
    if (stat.isDirectory()) return;

    if (file.endsWith(".css")) {
      installCleanCSS(`./src/styles/${file}`, `styles/${file.replace(".css", ".min.css")}`);
    } else {
      // images, backgrounds, etc
      install(`./src/styles/${file}`, `styles/${file}`);
    }
  });
}

async function buildDistributable(language) {
  const filename = `${language.name}.min.js`;

  const distDir = path.join(language.moduleDir, "dist");
  log(`Building ${distDir}/${filename}.`);
  await fs.mkdir(distDir, { recursive: true });
  fs.writeFile(path.join(language.moduleDir, "dist", filename), language.minified);
}

async function buildCDNLanguage(language) {
  const name = `languages/${language.name}.min.js`;
  const filename = `${process.env.BUILD_DIR}/${name}`;

  await language.compile({ terser: config.terser });
  shas[name] = bundling.sha384(language.minified);
  fs.writeFile(filename, language.minified);
}

module.exports.build = buildCDN;

<|endoftext|>


<commit_before>var Transport = require('./transport'),
    uniqueId  = require('../util/uniqueId');

// Implement the transport class from the parent's perspective.
var ParentTransport = module.exports = Transport.extend({

  constructor: function(childOrigin, childPath) {
    this.id = uniqueId('ift');
    this.childOrigin = childOrigin || 'http://localhost:8000';
    this.childUri = childOrigin + childPath || '/child.html';
    this._createIframe(this.childUri, this.id);

    Transport.call(this, [childOrigin]);
  },

  listen: function() {
    var once;
    this.on('incoming', once = function(message) {
      if (message !== 'ready') return;
      this.readyState = 1;
      this.trigger('ready');
      this.off('incoming', once, this);
    }, this);
    return Transport.prototype.listen.apply(this, arguments);
  },

  send: function(message) {
    if (!this.iframe.contentWindow) {
      throw new Error("Parent iframe not ready, use Manager#ready or Transport#ready");
    }
    this.iframe.contentWindow.postMessage(message, this.childOrigin);
    this.trigger('outgoing', message);
  },

  destroy: function() {
    Transport.prototype.destroy.apply(this, arguments);
    this.iframe.parentNode.removeChild(this.iframe);
  },

  _createIframe: function(uri, id) {
    var iframe = this.iframe = document.getElementById(id);
    if (iframe) return;

    iframe = this.iframe = document.createElement('iframe');
    iframe.id = id;
    iframe.name = id;
    iframe.style.position = 'absolute';
    iframe.style.top = '-2000px';
    iframe.style.left = '0px';
    iframe.src = uri;
    iframe.border = iframe.frameBorder = 0;
    iframe.allowTransparency = true;

    document.body.appendChild(iframe);
  }

});
<commit_msg>Remove transport#iframe.id, no need for the string when we have a direct reference<commit_after>var Transport = require('./transport');

// Implement the transport class from the parent's perspective.
var ParentTransport = module.exports = Transport.extend({

  constructor: function(childOrigin, childPath) {
    this.childOrigin = childOrigin || 'http://localhost:8000';
    this.childUri = childOrigin + childPath || '/child.html';
    this._createIframe(this.childUri);

    Transport.call(this, [childOrigin]);
  },

  listen: function() {
    var once;
    this.on('incoming', once = function(message) {
      if (message !== 'ready') return;
      this.readyState = 1;
      this.trigger('ready');
      this.off('incoming', once, this);
    }, this);
    return Transport.prototype.listen.apply(this, arguments);
  },

  send: function(message) {
    if (!this.iframe.contentWindow) {
      throw new Error("Parent iframe not ready, use Manager#ready or Transport#ready");
    }
    this.iframe.contentWindow.postMessage(message, this.childOrigin);
    this.trigger('outgoing', message);
  },

  destroy: function() {
    Transport.prototype.destroy.apply(this, arguments);
    this.iframe.parentNode.removeChild(this.iframe);
  },

  _createIframe: function(uri) {
    var iframe = this.iframe = document.createElement('iframe');
    iframe.style.position = 'absolute';
    iframe.style.top = '-2000px';
    iframe.style.left = '0px';
    iframe.src = uri;
    iframe.border = iframe.frameBorder = 0;
    iframe.allowTransparency = true;

    document.body.appendChild(iframe);
  }

});
<|endoftext|>