<commit_before>/*
 * Copyright 2016-2019 MarkLogic Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
'use strict';
const parameters = require("/MarkLogic/rest-api/endpoints/parameters.xqy");
const DataHub = require("/data-hub/5/datahub.sjs");
const datahub = new DataHub();

xdmp.securityAssert(['http://marklogic.com/xdmp/privileges/rest-reader'], 'execute');

const method = xdmp.getRequestMethod();

const requestParams = new Map();

parameters.queryParameter(requestParams, "flow-name",fn.true(),fn.false())
parameters.queryParameter(requestParams, "options",fn.false(),fn.false())
parameters.queryParameter(requestParams, "step",fn.false(),fn.false())
parameters.queryParameter(requestParams, "job-id",fn.true(),fn.false())
parameters.queryParameter(requestParams, "database",fn.true(),fn.false())

if(method === 'GET') {
  const flowName = requestParams["flow-name"];
  let step = requestParams.step;
  if (!step) {
    step = 1;
  }
  const jobId = requestParams["job-id"];
  const database = requestParams.database;
  let options = requestParams.options ? JSON.parse(requestParams.options) : {};

  let jobDoc = datahub.jobs.getJobDocWithId(jobId);
  try {
    datahub.jobs.updateJob(jobId, jobDoc.job.lastAttemptedStep, jobDoc.job.lastCompletedStep, "running step " + step);
  } catch (err) {
    datahub.jobs.createJob(flowName, jobId);
    datahub.jobs.updateJob(jobId, 0, 0, "running step " + step);
  }
  let flowDoc= datahub.flow.getFlow(flowName);
  let resp;
  if (!fn.exists(flowDoc)) {
    resp = fn.error(null, "RESTAPI-SRVEXERR", Sequence.from([404, "Not Found", "The requested flow was not found"]));
  } else {
    let stepDoc = flowDoc.steps[step];
    if (!stepDoc) {
      resp = fn.error(null, "RESTAPI-SRVEXERR", Sequence.from([404, "Not Found", `The step number "${step}" of the flow was not found`]));
    }
    let baseStep = datahub.flow.step.getStepByNameAndType(stepDoc.stepDefinitionName, stepDoc.stepDefinitionType);
    if (!baseStep) {
      resp = fn.error(null, "RESTAPI-SRVEXERR", Sequence.from([404, "Not Found", `A step with name "${stepDoc.stepDefinitionName}" and type of "${stepDoc.stepDefinitionType}" was not found`]));
    }
    let combinedOptions = Object.assign({}, baseStep.options, flowDoc.options, stepDoc.options, options);
    const database = combinedOptions.sourceDatabase || requestParams.database;
    if (stepDoc) {
      if(!combinedOptions.sourceQuery && flowDoc.sourceQuery) {
        combinedOptions.sourceQuery = flowDoc.sourceQuery;
      }
      let query = combinedOptions.sourceQuery;
      if (query) {
        try {
          resp = xdmp.eval(query, {options: options}, {database: xdmp.database(database)});
        } catch (err) {
          //TODO log error message from 'err'

          datahub.debug.log(err);
          let jobDoc = datahub.jobs.getJobDocWithId(jobId);
          datahub.jobs.updateJob(jobId, step, jobDoc.job.lastCompletedStep, "failed");
          resp = fn.error(null, 'RESTAPI-INVALIDREQ', err);
        }
      } else {
        resp = fn.error(null, "RESTAPI-SRVEXERR", Sequence.from([404, "Not Found", "The collector query was empty"]));
        datahub.debug.log("The collector query was empty");
        let jobDoc = datahub.jobs.getJobDocWithId(jobId);
        datahub.jobs.updateJob(jobId, step, jobDoc.job.lastCompletedStep, "failed");
      }
    } else {
      resp = fn.error(null, "RESTAPI-SRVEXERR", Sequence.from([404, "Not Found", "The requested step was not found"]));
      datahub.debug.log("The requested step was not found");
      let jobDoc = datahub.jobs.getJobDocWithId(jobId);
      datahub.jobs.updateJob(jobId, step, jobDoc.job.lastCompletedStep, "failed");
    }
  }
  resp
} else {
  fn.error(null, 'RESTAPI-INVALIDREQ', 'unsupported method: '+method);
}

<commit_msg>Wrap sourceQuery in cts.uri() for collector<commit_after>/*
 * Copyright 2016-2019 MarkLogic Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
'use strict';
const parameters = require("/MarkLogic/rest-api/endpoints/parameters.xqy");
const DataHub = require("/data-hub/5/datahub.sjs");
const datahub = new DataHub();

xdmp.securityAssert(['http://marklogic.com/xdmp/privileges/rest-reader'], 'execute');

const method = xdmp.getRequestMethod();

const requestParams = new Map();

parameters.queryParameter(requestParams, "flow-name",fn.true(),fn.false())
parameters.queryParameter(requestParams, "options",fn.false(),fn.false())
parameters.queryParameter(requestParams, "step",fn.false(),fn.false())
parameters.queryParameter(requestParams, "job-id",fn.true(),fn.false())
parameters.queryParameter(requestParams, "database",fn.true(),fn.false())

if(method === 'GET') {
  const flowName = requestParams["flow-name"];
  let step = requestParams.step;
  if (!step) {
    step = 1;
  }
  const jobId = requestParams["job-id"];
  const database = requestParams.database;
  let options = requestParams.options ? JSON.parse(requestParams.options) : {};

  let jobDoc = datahub.jobs.getJobDocWithId(jobId);
  try {
    datahub.jobs.updateJob(jobId, jobDoc.job.lastAttemptedStep, jobDoc.job.lastCompletedStep, "running step " + step);
  } catch (err) {
    datahub.jobs.createJob(flowName, jobId);
    datahub.jobs.updateJob(jobId, 0, 0, "running step " + step);
  }
  let flowDoc= datahub.flow.getFlow(flowName);
  let resp;
  if (!fn.exists(flowDoc)) {
    resp = fn.error(null, "RESTAPI-SRVEXERR", Sequence.from([404, "Not Found", "The requested flow was not found"]));
  } else {
    let stepDoc = flowDoc.steps[step];
    if (!stepDoc) {
      resp = fn.error(null, "RESTAPI-SRVEXERR", Sequence.from([404, "Not Found", `The step number "${step}" of the flow was not found`]));
    }
    let baseStep = datahub.flow.step.getStepByNameAndType(stepDoc.stepDefinitionName, stepDoc.stepDefinitionType);
    if (!baseStep) {
      resp = fn.error(null, "RESTAPI-SRVEXERR", Sequence.from([404, "Not Found", `A step with name "${stepDoc.stepDefinitionName}" and type of "${stepDoc.stepDefinitionType}" was not found`]));
    }
    let combinedOptions = Object.assign({}, baseStep.options, flowDoc.options, stepDoc.options, options);
    const database = combinedOptions.sourceDatabase || requestParams.database;
    if (stepDoc) {
      if(!combinedOptions.sourceQuery && flowDoc.sourceQuery) {
        combinedOptions.sourceQuery = flowDoc.sourceQuery;
      }
      let query = combinedOptions.sourceQuery;
      if (query) {
        try {
          resp = xdmp.eval("cts.uris(null, null, " + query + ")", {options: options}, {database: xdmp.database(database)});
        } catch (err) {
          //TODO log error message from 'err'

          datahub.debug.log(err);
          let jobDoc = datahub.jobs.getJobDocWithId(jobId);
          datahub.jobs.updateJob(jobId, step, jobDoc.job.lastCompletedStep, "failed");
          resp = fn.error(null, 'RESTAPI-INVALIDREQ', err);
        }
      } else {
        resp = fn.error(null, "RESTAPI-SRVEXERR", Sequence.from([404, "Not Found", "The collector query was empty"]));
        datahub.debug.log("The collector query was empty");
        let jobDoc = datahub.jobs.getJobDocWithId(jobId);
        datahub.jobs.updateJob(jobId, step, jobDoc.job.lastCompletedStep, "failed");
      }
    } else {
      resp = fn.error(null, "RESTAPI-SRVEXERR", Sequence.from([404, "Not Found", "The requested step was not found"]));
      datahub.debug.log("The requested step was not found");
      let jobDoc = datahub.jobs.getJobDocWithId(jobId);
      datahub.jobs.updateJob(jobId, step, jobDoc.job.lastCompletedStep, "failed");
    }
  }
  resp
} else {
  fn.error(null, 'RESTAPI-INVALIDREQ', 'unsupported method: '+method);
}

<|endoftext|>


<commit_before>/*
 *  How to use this module in IOTDB / HomeStar
 *  This is the best way to do this
 *  Note: to work, this package must have been installed by 'homestar install'
 */

"use strict";

var iotdb = require('iotdb');
var iot = iotdb.iot();

var things = iot.connect('PlugfestSomething');
things.on("state", function(thing) {
    console.log("+", "state", thing.thing_id(), "\n ", thing.state("istate"));
});
things.on("meta", function(thing) {
    console.log("+", "meta", thing.thing_id(), "\n ", thing.state("meta"));
});
things.on("thing", function(thing) {
    console.log("+", "discovered", thing.thing_id(), "\n ", thing.state("meta"));
});

<commit_msg>iotdb example<commit_after>/*
 *  How to use this module in IOTDB / HomeStar
 *  This is the best way to do this
 *  Note: to work, this package must have been installed by 'homestar install'
 */

"use strict";

var iotdb = require('iotdb');
var iot = iotdb.iot();

var things = iot.connect('PlugfestLight', {
    url: 'coap://129.132.130.252:5082',
});
things.on("state", function(thing) {
    console.log("+", "state", thing.thing_id(), "\n ", thing.state("istate"));
});
things.on("meta", function(thing) {
    console.log("+", "meta", thing.thing_id(), "\n ", thing.state("meta"));
});
things.on("thing", function(thing) {
    console.log("+", "discovered", thing.thing_id(), "\n ", thing.state("meta"));
});

<|endoftext|>


<commit_before>var capitalizeFirstLetter = null;
var sort = null;
var data = {};
var curKey = "";
var curOrder = "country";
var timestamp = null;
var prevNav = $("#nav-mobile").children().first();
function sortBtnClickHandler() {
  if (!$.isEmptyObject(data)) {
    curOrder === "percentage" ? curOrder = "country" : curOrder = "percentage";
    sort(data[curKey], curOrder);
  }
}
function navClickHandler(e) {
  if (!$.isEmptyObject(data)) {
    if (prevNav) {
      prevNav.removeClass("active");
    }
    var nav = $(e).parent();
    nav.addClass("active");
    prevNav = nav;
    curKey = e.innerText.toLowerCase();
    curOrder = "country";
    sort(data[curKey], "country");
    $("#timestamp").text(timestamp + ", " + capitalizeFirstLetter(curKey));
  }
}
$.ajax({
  url: "/awwwards-analysis/data/result (nominees).csv",
}).then(function(d, stat, xhr) {
  timestamp = xhr.getResponseHeader("Last-Modified");
  /* main */
  function analyze(error, nominees, honorable, developer, sotd, sotm, soty) {
    if (error) {
      console.log(error);
    }
    $("#preloader").addClass("hidden");
    $("#tip").removeClass("hidden");
    $("#tipTriangle").removeClass("hidden");
    function parseData(d) {
      return {
        country: d.Country,
        percentage: +d.Percentage,
        submission: +d.Submission,
        population: +d.Population,
      };
    }
    data["nominees"] = nominees.map(parseData);
    data["honorable mention"] = honorable.map(parseData);
    data["developer award"] = developer.map(parseData);
    data["site of the day"] = sotd.map(parseData);
    data["site of the month"] = sotm.map(parseData);
    data["site of the year"] = soty.map(parseData);
    curKey = "nominees";
    function numberWithCommas(x) {
      return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
    }
    capitalizeFirstLetter = function(string) {
      return string.charAt(0).toUpperCase() + string.slice(1);
    }
    sort = function(data, order) {
      if (order === "country") {
        data = data.sort(function(a, b) {
          if (a.country > b.country) {
            return 1;
          } else if (a.country < b.country) {
            return -1;
          }
          return 0;
        });
      } else {
        data = data.sort(function(a, b) {
          return b.percentage - a.percentage;
        });
      }
      update(data, false);
    }
    var prevIdx = 0;
    function mousemove(el, data, xScale, yScale, mapXCoordToCountry, mapCountryToIdx) {
      // Invert x coordinate
      var country = mapXCoordToCountry(d3.mouse(el)[0]);
      var x = xScale(country);
      var idx = mapCountryToIdx(country);
      var y = yScale(data[idx].percentage);
      // Calculating the boundary index to rotate the tip
      var xAxisInterval = width / data.length;
      let sum = 0, lastIdx = data.length - 1;
      while(sum < 190) {
        sum += xAxisInterval;
        lastIdx--;
      }
      g.select(".guideline")
          .transition()
          .duration(50)
          .attr("x1", x)
          .attr("x2", x);
      g.selectAll("circle")
          .filter(function(d, i) { return i === prevIdx })
          .transition()
          .duration(50)
          .style("fill", "white")
          .attr("r", 3.5);
      g.selectAll("circle")
          .filter(function(d, i) { return i === idx })
          .transition()
          .duration(50)
          .style("fill", "#0f747f")
          .attr("r", 5);
      g.selectAll(".x-axis-text")
          .filter(function(d, i) { return i === prevIdx })
          .transition()
          .duration(50)
          .style("font-size", "10px");
      g.selectAll(".x-axis-text")
          .filter(function(d, i) { return i === idx })
          .transition()
          .duration(50)
          .style("font-size", "12px");
      if (idx <= lastIdx) {
        d3.select("#tip")
            .transition()
            .duration(50)
            .style("top", y + margin.top + tipMargin.top + "px")
            .style("left", x + margin.left + tipMargin.left + "px");
        d3.select("#tipTriangle")
            .style("transform", "rotate(45deg)")
            .transition()
            .duration(50)
            .style("bottom", "-35px")
            .style("left", "-15px");
      } else {
        d3.select("#tip")
            .transition()
            .duration(50)
            .style("top", y + margin.top + tipMargin.top + "px")
            .style("left", x - margin.left + "px");
        d3.select("#tipTriangle")
            .style("transform", "rotate(-45deg)")
            .transition()
            .duration(50)
            .style("bottom", "-35px")
            .style("left", "173px");
      }
      d3.select("#country")
          .text(data[idx].country);
      d3.select("#percentage")
          .text(data[idx].percentage.toFixed(11));
      d3.select("#submission")
          .text(data[idx].submission);
      d3.select("#population")
          .text(numberWithCommas(data[idx].population));
      prevIdx = idx;
    }
    function update(data, initialize) {
      var xScale = d3.scalePoint().domain(data.map(function(d) { return d.country; })).range([0, width]);
      var yScale = d3.scaleLinear().domain(d3.extent(data, function(d) { return d.percentage; })).range([height, 0]);
      // Used for mapping x coordinate to ordinal data
      var mapXCoordToCountry = d3.scaleQuantize().domain(xScale.range()).range(xScale.domain());
      // Used for mapping ordinal data to data index
      var mapCountryToIdx = d3.scaleBand().domain(data.map(function(d) { return d.country; })).range([0, data.length]);
      // Set up area, line, gridline
      var area = d3.area()
          .x(function(d) { return xScale(d.country); })
          .y0(height)
          .y1(function(d) { return yScale(d.percentage); })
          .curve(d3.curveMonotoneX);
      var line = d3.line()
          .x(function(d) { return xScale(d.country); })
          .y(function(d) { return yScale(d.percentage); })
          .curve(d3.curveMonotoneX);

      if (initialize) {
        // Draw area
        g.append("path")
            .data([data])
            .attr("class", "area")
            .attr("d", area)
            .style("fill", "url(#gradient)");
        // Draw x-axis
        g.append("g")
            .attr("class", "axis x-axis")
            .attr("transform", "translate(0," + height + ")")
            .call(d3.axisBottom(xScale))
            .selectAll("text")
            .attr("class", "x-axis-text")
            .attr("dx", "-0.8em")
            .attr("dy", "0.15em")
            .style("transform", "rotate(-65deg)")
            .style("text-anchor", "end");
        // Remove x-axis domain
        // g.select(".x-axis")
        //     .selectAll(".domain")
        //     .remove();
        // Draw y-axis
        g.append("g")
            .attr("class", "axis y-axis")
            .call(d3.axisLeft(yScale))
            .selectAll("text")
            .attr("class", "y-axis-text")
        // Draw y-axis label
        g.select(".y-axis")
            .append("text")
            .attr("transform", "rotate(-90)")
            .style("text-anchor", "end")
            .text("Percentage (%)");
        g.select(".y-axis")
            .append("text")
            .attr("id", "timestamp")
            .style("text-anchor", "end")
            .text(timestamp + ", " + capitalizeFirstLetter(curKey));
        // Draw trendline
        g.append("path")
            .datum(data)
            .attr("class", "trendline")
            .attr("d", line);
        // Draw guideline
        g.append("line")
            .attr("class", "guideline")
            .attr("x1", 0)
            .attr("y1", 0)
            .attr("x2", 0)
            .attr("y2", height);
        // Draw circle
        g.selectAll("circle")
            .data(data)
          .enter()
            .append("circle")
            .attr("class", "circle")
            .attr("cx", function(d) { return xScale(d.country); })
            .attr("cy", function(d) { return yScale(d.percentage); })
            .attr("r", 3.5)
            .filter(function(d, i) { return i === 0 })
            .style("fill", "#0f747f")
            .attr("r", 5);
        // Draw a transparent layer for detecting mouse event
        g.append("rect")
            .attr("class", "overlay")
            .attr("width", width)
            .attr("height", height)
            .attr("opacity", 0)
            .on("mousemove", function () {
              mousemove(this, data, xScale, yScale, mapXCoordToCountry, mapCountryToIdx);
            });
      } else {
        g.select(".area")
            .data([data])
            .transition()
            .duration(500)
            .attr("d", area);
        g.select(".trendline")
            .datum(data)
            .transition()
            .duration(500)
            .attr("d", line);
        // Exit circles
        g.selectAll("circle")
            .data(data)
          .exit()
            .remove();
        // Enter circles
        g.selectAll("circle")
            .data(data)
          .enter()
            .append("circle")
            .attr("class", "circle")
            .attr("r", 3.5);
        // Update circles
        g.selectAll("circle")
            .data(data)
            .style("fill", "white")
            .attr("r", 3.5)
            .transition()
            .duration(500)
            .attr("cx", function(d) { return xScale(d.country); })
            .attr("cy", function(d) { return yScale(d.percentage); })
            .filter(function(d, i) { return i === 0 })
            .style("fill", "#0f747f")
            .attr("r", 5);
        g.selectAll(".x-axis")
            .transition()
            .duration(500)
            .call(d3.axisBottom(xScale))
            .selectAll("text")
            .attr("class", "x-axis-text")
            .attr("dx", "-0.8em")
            .attr("dy", "0.15em")
            .style("transform", "rotate(-65deg)")
            .style("text-anchor", "end");
            // .selectAll(".domain")
            // .remove();
        // Update x-axis texts
        g.selectAll(".x-axis-text")
            .style("font-size", "10px")
            .filter(function(d, i) { return i === 0 })
            .style("font-size", "12px");
        g.selectAll(".y-axis")
            .transition()
            .duration(500)
            .call(d3.axisLeft(yScale));
        g.select(".overlay")
            .on("mousemove", function () {
              mousemove(this, data, xScale, yScale, mapXCoordToCountry, mapCountryToIdx);
            });
        prevIdx = 0;
      }
      g.select(".guideline")
          .transition()
          .duration(500)
          .attr("x1", 0)
          .attr("x2", 0);
      d3.select("#tip")
          .transition()
          .duration(500)
          .style("top", yScale(data[0].percentage) + margin.top + tipMargin.top + "px")
          .style("left", xScale(data[0].country) + margin.left + tipMargin.left + "px");
      d3.select("#tipTriangle")
          .style("transform", "rotate(45deg)")
          .transition()
          .duration(50)
          .style("bottom", "-35px")
          .style("left", "-15px");
      d3.select("#country")
          .text(data[0].country);
      d3.select("#percentage")
          .text(data[0].percentage.toFixed(11));
      d3.select("#submission")
          .text(data[0].submission);
      d3.select("#population")
          .text(numberWithCommas(data[0].population));
    }
    // Set up svg
    var svg = d3.select("svg"),
        margin = {
          top: 80,
          right: 80,
          bottom: 125,
          left: 100,
        },
        width = parseInt(d3.select("#chart").style("width")) - margin.left - margin.right,
        height = parseInt(d3.select("#chart").style("height")) - margin.top - margin.bottom;
    var g = svg.append("g")
        .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
    // Set up gradient color
    var gradient = svg.append("defs")
        .append("linearGradient")
        .attr("id", "gradient")
        .attr("x1", "0%")
        .attr("y1", "0%")
        .attr("x2", "0%")
        .attr("y2", "100%")
        .attr("spreadMethod", "pad");
    gradient.append("stop")
        .attr("offset", "0%")
        .attr("stop-color", "rgb(36,175,192)")
        .attr("stop-opacity", 1);
    gradient.append("stop")
        .attr("offset", "100%")
        .attr("stop-color", "rgb(206,254,226)")
        .attr("stop-opacity", 1);
    var tipMargin = {
      top: -60,
      left: 10,
    };
    update(data[curKey], true);
  }
  // Read data
  d3.queue()
    .defer(d3.csv, "./data/result (nominees).csv")
    .defer(d3.csv, "./data/result (honorable).csv")
    .defer(d3.csv, "./data/result (developer).csv")
    .defer(d3.csv, "./data/result (sites_of_the_day).csv")
    .defer(d3.csv, "./data/result (sites_of_the_month).csv")
    .defer(d3.csv, "./data/result (sites_of_the_year).csv")
    .await(analyze);
});
<commit_msg>Ajust timestamp<commit_after>var capitalizeFirstLetter = null;
var sort = null;
var data = {};
var curKey = "";
var curOrder = "country";
var timestamp = null;
var prevNav = $("#nav-mobile").children().first();
function sortBtnClickHandler() {
  if (!$.isEmptyObject(data)) {
    curOrder === "percentage" ? curOrder = "country" : curOrder = "percentage";
    sort(data[curKey], curOrder);
  }
}
function navClickHandler(e) {
  if (!$.isEmptyObject(data)) {
    if (prevNav) {
      prevNav.removeClass("active");
    }
    var nav = $(e).parent();
    nav.addClass("active");
    prevNav = nav;
    curKey = e.innerText.toLowerCase();
    curOrder = "country";
    sort(data[curKey], "country");
    $("#timestamp").text(timestamp + ", " + capitalizeFirstLetter(curKey));
  }
}
$.ajax({
  url: "/awwwards-analysis/data/result (nominees).csv",
}).then(function(d, stat, xhr) {
  timestamp = xhr.getResponseHeader("Last-Modified");
  /* main */
  function analyze(error, nominees, honorable, developer, sotd, sotm, soty) {
    if (error) {
      console.log(error);
    }
    $("#preloader").addClass("hidden");
    $("#tip").removeClass("hidden");
    $("#tipTriangle").removeClass("hidden");
    function parseData(d) {
      return {
        country: d.Country,
        percentage: +d.Percentage,
        submission: +d.Submission,
        population: +d.Population,
      };
    }
    data["nominees"] = nominees.map(parseData);
    data["honorable mention"] = honorable.map(parseData);
    data["developer award"] = developer.map(parseData);
    data["site of the day"] = sotd.map(parseData);
    data["site of the month"] = sotm.map(parseData);
    data["site of the year"] = soty.map(parseData);
    curKey = "nominees";
    function numberWithCommas(x) {
      return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
    }
    capitalizeFirstLetter = function(string) {
      return string.charAt(0).toUpperCase() + string.slice(1);
    }
    sort = function(data, order) {
      if (order === "country") {
        data = data.sort(function(a, b) {
          if (a.country > b.country) {
            return 1;
          } else if (a.country < b.country) {
            return -1;
          }
          return 0;
        });
      } else {
        data = data.sort(function(a, b) {
          return b.percentage - a.percentage;
        });
      }
      update(data, false);
    }
    var prevIdx = 0;
    function mousemove(el, data, xScale, yScale, mapXCoordToCountry, mapCountryToIdx) {
      // Invert x coordinate
      var country = mapXCoordToCountry(d3.mouse(el)[0]);
      var x = xScale(country);
      var idx = mapCountryToIdx(country);
      var y = yScale(data[idx].percentage);
      // Calculating the boundary index to rotate the tip
      var xAxisInterval = width / data.length;
      let sum = 0, lastIdx = data.length - 1;
      while(sum < 190) {
        sum += xAxisInterval;
        lastIdx--;
      }
      g.select(".guideline")
          .transition()
          .duration(50)
          .attr("x1", x)
          .attr("x2", x);
      g.selectAll("circle")
          .filter(function(d, i) { return i === prevIdx })
          .transition()
          .duration(50)
          .style("fill", "white")
          .attr("r", 3.5);
      g.selectAll("circle")
          .filter(function(d, i) { return i === idx })
          .transition()
          .duration(50)
          .style("fill", "#0f747f")
          .attr("r", 5);
      g.selectAll(".x-axis-text")
          .filter(function(d, i) { return i === prevIdx })
          .transition()
          .duration(50)
          .style("font-size", "10px");
      g.selectAll(".x-axis-text")
          .filter(function(d, i) { return i === idx })
          .transition()
          .duration(50)
          .style("font-size", "12px");
      if (idx <= lastIdx) {
        d3.select("#tip")
            .transition()
            .duration(50)
            .style("top", y + margin.top + tipMargin.top + "px")
            .style("left", x + margin.left + tipMargin.left + "px");
        d3.select("#tipTriangle")
            .style("transform", "rotate(45deg)")
            .transition()
            .duration(50)
            .style("bottom", "-35px")
            .style("left", "-15px");
      } else {
        d3.select("#tip")
            .transition()
            .duration(50)
            .style("top", y + margin.top + tipMargin.top + "px")
            .style("left", x - margin.left + "px");
        d3.select("#tipTriangle")
            .style("transform", "rotate(-45deg)")
            .transition()
            .duration(50)
            .style("bottom", "-35px")
            .style("left", "173px");
      }
      d3.select("#country")
          .text(data[idx].country);
      d3.select("#percentage")
          .text(data[idx].percentage.toFixed(11));
      d3.select("#submission")
          .text(data[idx].submission);
      d3.select("#population")
          .text(numberWithCommas(data[idx].population));
      prevIdx = idx;
    }
    function update(data, initialize) {
      var xScale = d3.scalePoint().domain(data.map(function(d) { return d.country; })).range([0, width]);
      var yScale = d3.scaleLinear().domain(d3.extent(data, function(d) { return d.percentage; })).range([height, 0]);
      // Used for mapping x coordinate to ordinal data
      var mapXCoordToCountry = d3.scaleQuantize().domain(xScale.range()).range(xScale.domain());
      // Used for mapping ordinal data to data index
      var mapCountryToIdx = d3.scaleBand().domain(data.map(function(d) { return d.country; })).range([0, data.length]);
      // Set up area, line, gridline
      var area = d3.area()
          .x(function(d) { return xScale(d.country); })
          .y0(height)
          .y1(function(d) { return yScale(d.percentage); })
          .curve(d3.curveMonotoneX);
      var line = d3.line()
          .x(function(d) { return xScale(d.country); })
          .y(function(d) { return yScale(d.percentage); })
          .curve(d3.curveMonotoneX);

      if (initialize) {
        // Draw area
        g.append("path")
            .data([data])
            .attr("class", "area")
            .attr("d", area)
            .style("fill", "url(#gradient)");
        // Draw x-axis
        g.append("g")
            .attr("class", "axis x-axis")
            .attr("transform", "translate(0," + height + ")")
            .call(d3.axisBottom(xScale))
            .selectAll("text")
            .attr("class", "x-axis-text")
            .attr("dx", "-0.8em")
            .attr("dy", "0.15em")
            .style("transform", "rotate(-65deg)")
            .style("text-anchor", "end");
        // Remove x-axis domain
        // g.select(".x-axis")
        //     .selectAll(".domain")
        //     .remove();
        // Draw y-axis
        g.append("g")
            .attr("class", "axis y-axis")
            .call(d3.axisLeft(yScale))
            .selectAll("text")
            .attr("class", "y-axis-text")
        // Draw y-axis label
        g.select(".y-axis")
            .append("text")
            .attr("transform", "rotate(-90)")
            .style("text-anchor", "end")
            .attr("y", "-60")
            .text("Percentage (%)");
        g.select(".y-axis")
            .append("text")
            .attr("id", "timestamp")
            .style("text-anchor", "end")
            .attr("y", "-30")
            .attr("dx", "160")
            .text(timestamp + ", " + capitalizeFirstLetter(curKey));
        // Draw trendline
        g.append("path")
            .datum(data)
            .attr("class", "trendline")
            .attr("d", line);
        // Draw guideline
        g.append("line")
            .attr("class", "guideline")
            .attr("x1", 0)
            .attr("y1", 0)
            .attr("x2", 0)
            .attr("y2", height);
        // Draw circle
        g.selectAll("circle")
            .data(data)
          .enter()
            .append("circle")
            .attr("class", "circle")
            .attr("cx", function(d) { return xScale(d.country); })
            .attr("cy", function(d) { return yScale(d.percentage); })
            .attr("r", 3.5)
            .filter(function(d, i) { return i === 0 })
            .style("fill", "#0f747f")
            .attr("r", 5);
        // Draw a transparent layer for detecting mouse event
        g.append("rect")
            .attr("class", "overlay")
            .attr("width", width)
            .attr("height", height)
            .attr("opacity", 0)
            .on("mousemove", function () {
              mousemove(this, data, xScale, yScale, mapXCoordToCountry, mapCountryToIdx);
            });
      } else {
        g.select(".area")
            .data([data])
            .transition()
            .duration(500)
            .attr("d", area);
        g.select(".trendline")
            .datum(data)
            .transition()
            .duration(500)
            .attr("d", line);
        // Exit circles
        g.selectAll("circle")
            .data(data)
          .exit()
            .remove();
        // Enter circles
        g.selectAll("circle")
            .data(data)
          .enter()
            .append("circle")
            .attr("class", "circle")
            .attr("r", 3.5);
        // Update circles
        g.selectAll("circle")
            .data(data)
            .style("fill", "white")
            .attr("r", 3.5)
            .transition()
            .duration(500)
            .attr("cx", function(d) { return xScale(d.country); })
            .attr("cy", function(d) { return yScale(d.percentage); })
            .filter(function(d, i) { return i === 0 })
            .style("fill", "#0f747f")
            .attr("r", 5);
        g.selectAll(".x-axis")
            .transition()
            .duration(500)
            .call(d3.axisBottom(xScale))
            .selectAll("text")
            .attr("class", "x-axis-text")
            .attr("dx", "-0.8em")
            .attr("dy", "0.15em")
            .style("transform", "rotate(-65deg)")
            .style("text-anchor", "end");
            // .selectAll(".domain")
            // .remove();
        // Update x-axis texts
        g.selectAll(".x-axis-text")
            .style("font-size", "10px")
            .filter(function(d, i) { return i === 0 })
            .style("font-size", "12px");
        g.selectAll(".y-axis")
            .transition()
            .duration(500)
            .call(d3.axisLeft(yScale));
        g.select(".overlay")
            .on("mousemove", function () {
              mousemove(this, data, xScale, yScale, mapXCoordToCountry, mapCountryToIdx);
            });
        prevIdx = 0;
      }
      g.select(".guideline")
          .transition()
          .duration(500)
          .attr("x1", 0)
          .attr("x2", 0);
      d3.select("#tip")
          .transition()
          .duration(500)
          .style("top", yScale(data[0].percentage) + margin.top + tipMargin.top + "px")
          .style("left", xScale(data[0].country) + margin.left + tipMargin.left + "px");
      d3.select("#tipTriangle")
          .style("transform", "rotate(45deg)")
          .transition()
          .duration(50)
          .style("bottom", "-35px")
          .style("left", "-15px");
      d3.select("#country")
          .text(data[0].country);
      d3.select("#percentage")
          .text(data[0].percentage.toFixed(11));
      d3.select("#submission")
          .text(data[0].submission);
      d3.select("#population")
          .text(numberWithCommas(data[0].population));
    }
    // Set up svg
    var svg = d3.select("svg"),
        margin = {
          top: 80,
          right: 80,
          bottom: 130,
          left: 100,
        },
        width = parseInt(d3.select("#chart").style("width")) - margin.left - margin.right,
        height = parseInt(d3.select("#chart").style("height")) - margin.top - margin.bottom;
    var g = svg.append("g")
        .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
    // Set up gradient color
    var gradient = svg.append("defs")
        .append("linearGradient")
        .attr("id", "gradient")
        .attr("x1", "0%")
        .attr("y1", "0%")
        .attr("x2", "0%")
        .attr("y2", "100%")
        .attr("spreadMethod", "pad");
    gradient.append("stop")
        .attr("offset", "0%")
        .attr("stop-color", "rgb(36,175,192)")
        .attr("stop-opacity", 1);
    gradient.append("stop")
        .attr("offset", "100%")
        .attr("stop-color", "rgb(206,254,226)")
        .attr("stop-opacity", 1);
    var tipMargin = {
      top: -60,
      left: 10,
    };
    update(data[curKey], true);
  }
  // Read data
  d3.queue()
    .defer(d3.csv, "./data/result (nominees).csv")
    .defer(d3.csv, "./data/result (honorable).csv")
    .defer(d3.csv, "./data/result (developer).csv")
    .defer(d3.csv, "./data/result (sites_of_the_day).csv")
    .defer(d3.csv, "./data/result (sites_of_the_month).csv")
    .defer(d3.csv, "./data/result (sites_of_the_year).csv")
    .await(analyze);
});
<|endoftext|>


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

/*
 * This file provides the functionality that reads the ZAP data from a database
 * and exports it into a file.
 */
const os = require('os')
const fs = require('fs')
const path = require('path')
const env = require('../util/env.js')
const querySession = require('../db/query-session.js')
const queryConfig = require('../db/query-config.js')
const queryImpExp = require('../db/query-impexp.js')
const dbEnum = require('../../src-shared/db-enum.js')
const util = require('../util/util.js')

async function exportEndpointType(db, endpointType) {
  return queryImpExp
    .exportClustersFromEndpointType(db, endpointType.endpointTypeId)
    .then((data) => {
      endpointType.clusters = data

      let ps = []
      data.forEach((endpointCluster) => {
        let endpointClusterId = endpointCluster.endpointClusterId
        delete endpointCluster.endpointClusterId
        ps.push(
          queryImpExp
            .exportCommandsFromEndpointTypeCluster(
              db,
              endpointType.endpointTypeId,
              endpointClusterId
            )
            .then((commands) => {
              endpointCluster.commands = commands
            })
            .then(() =>
              queryImpExp
                .exportAttributesFromEndpointTypeCluster(
                  db,
                  endpointType.endpointTypeId,
                  endpointClusterId
                )
                .then((attributes) => {
                  endpointCluster.attributes = attributes
                })
            )
        )
      })
      return Promise.all(ps)
    })
}

/**
 * Resolves to an array of endpoint types.
 *
 * @export
 * @param {*} db
 * @param {*} sessionId
 * @returns Promise to retrieve all endpoint types.
 */
async function exportEndpointTypes(db, sessionId) {
  return queryImpExp
    .exportEndpointTypes(db, sessionId)
    .then((endpointTypes) => {
      let promises = []
      endpointTypes.forEach((endpointType) => {
        promises.push(exportEndpointType(db, endpointType))
      })

      return Promise.all(promises)
        .then(() => queryImpExp.exportEndpoints(db, sessionId, endpointTypes))
        .then((endpoints) => {
          endpointTypes.forEach((ept) => {
            delete ept.endpointTypeId
          })
          endpoints.forEach((ep) => {
            delete ep.endpointTypeRef
          })
          return { endpointTypes: endpointTypes, endpoints: endpoints }
        })
    })
}

/**
 * Resolves with data for packages.
 *
 * @param {*} db
 * @param {*} sessionId
 */
async function exportSessionPackages(db, sessionId, zapProjectFileLocation) {
  return queryImpExp.exportPackagesFromSession(db, sessionId).then((packages) =>
    packages.map((p) => {
      let pathRelativity = dbEnum.pathRelativity.relativeToUserHome
      let relativePath = path.relative(os.homedir(), p.path)
      if (zapProjectFileLocation != null) {
        let rel = path.relative(path.dirname(zapProjectFileLocation), p.path)
        if (rel.length > 0) {
          relativePath = rel
          pathRelativity = dbEnum.pathRelativity.relativeToZap
        }
      }
      return {
        pathRelativity: pathRelativity,
        path: relativePath,
        version: p.version,
        type: p.type,
      }
    })
  )
}

/**
 * Toplevel file that takes a given session ID and exports the data into the file
 *
 * @export
 * @param {*} db
 * @param {*} sessionId
 * @param {*} filePath
 * @returns A promise that resolves with the path of the file written.
 */
async function exportDataIntoFile(
  db,
  sessionId,
  filePath,
  options = {
    removeLog: false,
  }
) {
  env.logDebug(`Writing state from session ${sessionId} into file ${filePath}`)
  let state = await createStateFromDatabase(db, sessionId)
  await new Promise((resolve, reject) => {
    if (options.removeLog) delete state.log
    fs.writeFile(filePath, JSON.stringify(state, null, 2), (err) => {
      if (err) reject(err)
      resolve()
    })
  })
  await querySession.setSessionClean(db, sessionId)
  return filePath
}

/**
 * Given a database and a session id, this method returns a promise that
 * resolves with a state object that needs to be saved into a file.
 *
 * @export
 * @param {*} db
 * @param {*} sessionId
 * @returns state object that needs to be saved into a file.
 */
async function createStateFromDatabase(db, sessionId) {
  let state = {
    featureLevel: env.zapVersion().featureLevel,
    creator: 'zap',
  }
  let promises = []
  let excludedKeys = [dbEnum.sessionKey.filePath]

  env.logInfo(`Exporting data for session: ${sessionId}`)
  // Deal with the key/value table
  let getKeyValuesPromise = querySession
    .getAllSessionKeyValues(db, sessionId)
    .then((data) => {
      env.logDebug(`Retrieved session keys: ${data.length}`)
      let zapFilePath = null
      let storedKeyValuePairs = data.filter(
        (datum) => !excludedKeys.includes(datum.key)
      )
      let x = data.filter((datum) => datum.key == dbEnum.sessionKey.filePath)
      if (x.length > 0) zapFilePath = x[0].value
      return {
        key: 'keyValuePairs',
        data: storedKeyValuePairs,
        zapFilePath: zapFilePath,
      }
    })
    .then((data) => {
      return exportSessionPackages(db, sessionId, data.zapFilePath).then(
        (d) => {
          return [data, { key: 'package', data: d }]
        }
      )
    })
  promises.push(getKeyValuesPromise)

  let allEndpointTypes = await exportEndpointTypes(db, sessionId)

  let parseEndpointTypes = Promise.resolve({
    key: 'endpointTypes',
    data: allEndpointTypes.endpointTypes,
  })

  let parseEndpoints = Promise.resolve({
    key: 'endpoints',
    data: allEndpointTypes.endpoints,
  })

  let appendLogPromise = querySession.readLog(db, sessionId).then((log) => {
    return { key: 'log', data: log }
  })

  promises.push(parseEndpointTypes)
  promises.push(parseEndpoints)
  promises.push(appendLogPromise)

  let data = await Promise.all(promises)
  data.flat().forEach((keyDataPair) => {
    state[keyDataPair.key] = keyDataPair.data
  })
  return state
}
// exports
exports.exportDataIntoFile = exportDataIntoFile
exports.createStateFromDatabase = createStateFromDatabase
<commit_msg>Clean up some exporter code.<commit_after>/**
 *
 *    Copyright (c) 2020 Silicon Labs
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

/*
 * This file provides the functionality that reads the ZAP data from a database
 * and exports it into a file.
 */
const os = require('os')
const fs = require('fs')
const path = require('path')
const env = require('../util/env.js')
const querySession = require('../db/query-session.js')
const queryConfig = require('../db/query-config.js')
const queryImpExp = require('../db/query-impexp.js')
const dbEnum = require('../../src-shared/db-enum.js')
const util = require('../util/util.js')

async function exportEndpointType(db, endpointType) {
  let data = await queryImpExp.exportClustersFromEndpointType(
    db,
    endpointType.endpointTypeId
  )

  endpointType.clusters = data

  let ps = data.map(async (endpointCluster) => {
    let endpointClusterId = endpointCluster.endpointClusterId
    delete endpointCluster.endpointClusterId
    endpointCluster.commands = await queryImpExp.exportCommandsFromEndpointTypeCluster(
      db,
      endpointType.endpointTypeId,
      endpointClusterId
    )

    endpointCluster.attributes = await queryImpExp.exportAttributesFromEndpointTypeCluster(
      db,
      endpointType.endpointTypeId,
      endpointClusterId
    )
  })
  return Promise.all(ps)
}

/**
 * Resolves to an array of endpoint types.
 *
 * @export
 * @param {*} db
 * @param {*} sessionId
 * @returns Promise to retrieve all endpoint types.
 */
async function exportEndpointTypes(db, sessionId) {
  return queryImpExp
    .exportEndpointTypes(db, sessionId)
    .then((endpointTypes) => {
      let promises = endpointTypes.map((endpointType) =>
        exportEndpointType(db, endpointType)
      )

      return Promise.all(promises)
        .then(() => queryImpExp.exportEndpoints(db, sessionId, endpointTypes))
        .then((endpoints) => {
          endpointTypes.forEach((ept) => {
            delete ept.endpointTypeId
          })
          endpoints.forEach((ep) => {
            delete ep.endpointTypeRef
          })
          return { endpointTypes: endpointTypes, endpoints: endpoints }
        })
    })
}

/**
 * Resolves with data for packages.
 *
 * @param {*} db
 * @param {*} sessionId
 */
async function exportSessionPackages(db, sessionId, zapProjectFileLocation) {
  return queryImpExp.exportPackagesFromSession(db, sessionId).then((packages) =>
    packages.map((p) => {
      let pathRelativity = dbEnum.pathRelativity.relativeToUserHome
      let relativePath = path.relative(os.homedir(), p.path)
      if (zapProjectFileLocation != null) {
        let rel = path.relative(path.dirname(zapProjectFileLocation), p.path)
        if (rel.length > 0) {
          relativePath = rel
          pathRelativity = dbEnum.pathRelativity.relativeToZap
        }
      }
      return {
        pathRelativity: pathRelativity,
        path: relativePath,
        version: p.version,
        type: p.type,
      }
    })
  )
}

/**
 * Toplevel file that takes a given session ID and exports the data into the file
 *
 * @export
 * @param {*} db
 * @param {*} sessionId
 * @param {*} filePath
 * @returns A promise that resolves with the path of the file written.
 */
async function exportDataIntoFile(
  db,
  sessionId,
  filePath,
  options = {
    removeLog: false,
  }
) {
  env.logDebug(`Writing state from session ${sessionId} into file ${filePath}`)
  let state = await createStateFromDatabase(db, sessionId)
  await new Promise((resolve, reject) => {
    if (options.removeLog) delete state.log
    fs.writeFile(filePath, JSON.stringify(state, null, 2), (err) => {
      if (err) reject(err)
      resolve()
    })
  })
  await querySession.setSessionClean(db, sessionId)
  return filePath
}

/**
 * Given a database and a session id, this method returns a promise that
 * resolves with a state object that needs to be saved into a file.
 *
 * @export
 * @param {*} db
 * @param {*} sessionId
 * @returns state object that needs to be saved into a file.
 */
async function createStateFromDatabase(db, sessionId) {
  let state = {
    featureLevel: env.zapVersion().featureLevel,
    creator: 'zap',
  }
  let promises = []
  let excludedKeys = [dbEnum.sessionKey.filePath]

  env.logInfo(`Exporting data for session: ${sessionId}`)
  // Deal with the key/value table
  let getKeyValuesPromise = querySession
    .getAllSessionKeyValues(db, sessionId)
    .then((data) => {
      env.logDebug(`Retrieved session keys: ${data.length}`)
      let zapFilePath = null
      let storedKeyValuePairs = data.filter(
        (datum) => !excludedKeys.includes(datum.key)
      )
      let x = data.filter((datum) => datum.key == dbEnum.sessionKey.filePath)
      if (x.length > 0) zapFilePath = x[0].value
      return {
        key: 'keyValuePairs',
        data: storedKeyValuePairs,
        zapFilePath: zapFilePath,
      }
    })
    .then((data) => {
      return exportSessionPackages(db, sessionId, data.zapFilePath).then(
        (d) => {
          return [data, { key: 'package', data: d }]
        }
      )
    })
  promises.push(getKeyValuesPromise)

  let allEndpointTypes = await exportEndpointTypes(db, sessionId)

  let parseEndpointTypes = Promise.resolve({
    key: 'endpointTypes',
    data: allEndpointTypes.endpointTypes,
  })

  let parseEndpoints = Promise.resolve({
    key: 'endpoints',
    data: allEndpointTypes.endpoints,
  })

  let appendLogPromise = querySession.readLog(db, sessionId).then((log) => {
    return { key: 'log', data: log }
  })

  promises.push(parseEndpointTypes)
  promises.push(parseEndpoints)
  promises.push(appendLogPromise)

  let data = await Promise.all(promises)
  data.flat().forEach((keyDataPair) => {
    state[keyDataPair.key] = keyDataPair.data
  })
  return state
}
// exports
exports.exportDataIntoFile = exportDataIntoFile
exports.createStateFromDatabase = createStateFromDatabase
<|endoftext|>


<commit_before>/*
 * grunt-available-tasks
 * https://github.com/ben-eb/grunt-available-tasks
 *
 * Copyright (c) 2013-2014 Ben Briggs
 * Licensed under the MIT license.
 */

'use strict';

var _  = require('lodash'),
    _s = require('underscore.string');

function setTaskInfo(grunt, name, info) {
    grunt.task._tasks[name].info = info;
}

module.exports = function(grunt) {
    grunt.registerMultiTask('availabletasks', 'List available Grunt tasks & targets.', function() {
        var getOutput   = require('../lib/get_output'),
            filterTasks = require('../lib/filterTasks'),
            ids         = require('../lib/taskIdentifiers'),
            reporter    = require('../lib/reporters'),
            output      = [],
            header      = '',
            options     = this.options({
                filter       : false,
                tasks        : false,
                sort         : true,
                groups       : {},
                descriptions : {},
                showTasks    : ['single', 'multi', 'user'],
                reporter     : 'default'
            }),
            // Delete tasks that don't pass a filter
            tasks = filterTasks(options.filter, options.tasks, grunt.task._tasks);

        // Override descriptions with our own values
        _.each(Object.keys(options.descriptions), function(description) {
            setTaskInfo(grunt, description, options.descriptions[description]);
        });
        // Sort the tasks by name if sorting is enabled
        if (options.sort !== false) {
            tasks = _.sortBy(tasks, 'name');
        }
        // Did we define a custom sort?
        if (typeof options.sort === 'object') {
            tasks = _.sortBy(tasks, function(task) {
                var index = _.indexOf(options.sort, task.name);
                return (index === -1) ? options.sort.length : index;
            });
        }
        _.each(tasks, function(task) {
            var name    = task.name,
                config  = grunt.config(name),
                targets = [],
                type    = ids.user;
            // test if the task is a local config or something installed
            if (_s.include(task.meta.info, 'local Npm module')) {
                type = (task.multi) ? ids.multi : ids.single;
            }
            // Delete global options from the task targets
            if (typeof config === 'object' && task.multi) {
                delete config.options;
                targets = Object.keys(config);
            }
            // Get the output of the task
            var allowedTypes = _.map(Object.keys(ids), function(id) {
                if (_.contains(options.showTasks, id)) {
                    return ids[id];
                }
            });
            if (_.contains(allowedTypes, type)) {
                getOutput(output, options.groups, {
                    name    : task.name,
                    type    : type,
                    info    : task.info,
                    targets : targets
                });
            }
        });
        _.chain(output)
            .sortBy(function(value) {
                return (value.group === 'Ungrouped') ? 1 : 0;
            })
            .groupBy('group')
            .each(function(group) {
                header = group.group;
                _.each(group, function(o) {
                    var reportoptions = {
                        currentTask : o,
                        meta        : {
                            taskCount  : Object.keys(tasks).length,
                            groupCount : Object.keys(options.groups).length,
                            header     : header !== '',
                            longest    : _.max(tasks, function(task) {
                                return task.name.length;
                            }).name.length
                        }
                    };
                    header = '';
                    if (typeof options.reporter === 'function') {
                        options.reporter(reportoptions);
                    } else {
                        reporter(grunt, options.reporter, reportoptions);
                    }
                });
            });
    });
};
<commit_msg>Don't parse templates when getting config. Fixes #18.<commit_after>/*
 * grunt-available-tasks
 * https://github.com/ben-eb/grunt-available-tasks
 *
 * Copyright (c) 2013-2014 Ben Briggs
 * Licensed under the MIT license.
 */

'use strict';

var _  = require('lodash'),
    _s = require('underscore.string');

function setTaskInfo(grunt, name, info) {
    grunt.task._tasks[name].info = info;
}

module.exports = function(grunt) {
    grunt.registerMultiTask('availabletasks', 'List available Grunt tasks & targets.', function() {
        var getOutput   = require('../lib/get_output'),
            filterTasks = require('../lib/filterTasks'),
            ids         = require('../lib/taskIdentifiers'),
            reporter    = require('../lib/reporters'),
            output      = [],
            header      = '',
            options     = this.options({
                filter       : false,
                tasks        : false,
                sort         : true,
                groups       : {},
                descriptions : {},
                showTasks    : ['single', 'multi', 'user'],
                reporter     : 'default'
            }),
            // Delete tasks that don't pass a filter
            tasks = filterTasks(options.filter, options.tasks, grunt.task._tasks);

        // Override descriptions with our own values
        _.each(Object.keys(options.descriptions), function(description) {
            setTaskInfo(grunt, description, options.descriptions[description]);
        });
        // Sort the tasks by name if sorting is enabled
        if (options.sort !== false) {
            tasks = _.sortBy(tasks, 'name');
        }
        // Did we define a custom sort?
        if (typeof options.sort === 'object') {
            tasks = _.sortBy(tasks, function(task) {
                var index = _.indexOf(options.sort, task.name);
                return (index === -1) ? options.sort.length : index;
            });
        }
        _.each(tasks, function(task) {
            var name    = task.name,
                config  = grunt.config.getRaw(name),
                targets = [],
                type    = ids.user;
            // test if the task is a local config or something installed
            if (_s.include(task.meta.info, 'local Npm module')) {
                type = (task.multi) ? ids.multi : ids.single;
            }
            // Delete global options from the task targets
            if (typeof config === 'object' && task.multi) {
                delete config.options;
                targets = Object.keys(config);
            }
            // Get the output of the task
            var allowedTypes = _.map(Object.keys(ids), function(id) {
                if (_.contains(options.showTasks, id)) {
                    return ids[id];
                }
            });
            if (_.contains(allowedTypes, type)) {
                getOutput(output, options.groups, {
                    name    : task.name,
                    type    : type,
                    info    : task.info,
                    targets : targets
                });
            }
        });
        _.chain(output)
            .sortBy(function(value) {
                return (value.group === 'Ungrouped') ? 1 : 0;
            })
            .groupBy('group')
            .each(function(group) {
                header = group.group;
                _.each(group, function(o) {
                    var reportoptions = {
                        currentTask : o,
                        meta        : {
                            taskCount  : Object.keys(tasks).length,
                            groupCount : Object.keys(options.groups).length,
                            header     : header !== '',
                            longest    : _.max(tasks, function(task) {
                                return task.name.length;
                            }).name.length
                        }
                    };
                    header = '';
                    if (typeof options.reporter === 'function') {
                        options.reporter(reportoptions);
                    } else {
                        reporter(grunt, options.reporter, reportoptions);
                    }
                });
            });
    });
};
<|endoftext|>


<commit_before>import { ReactiveVar } from 'meteor/reactive-var';

var debug = false;

export class HighlightElementContext {
  /**
   * Context for a highlighted element in the Adventure Screen
   */
  constructor (instance, adventureContext) {
    this.instance = instance;

    // Create the set of reactive vars
    this.adventureContext = adventureContext;
    this.selectedElements = new ReactiveVar([]);
    this.inputText        = new ReactiveVar();
    this.checkResult      = new ReactiveVar();
  }
}<commit_msg>Renamed inputText to the more generic "selector" in HighlightElementContext<commit_after>import { ReactiveVar } from 'meteor/reactive-var';

var debug = false;

export class HighlightElementContext {
  /**
   * Context for a highlighted element in the Adventure Screen
   */
  constructor (instance, adventureContext) {
    this.instance = instance;

    // Create the set of reactive vars
    this.adventureContext = adventureContext;
    this.selectedElements = new ReactiveVar([]);
    this.selector         = new ReactiveVar();
    this.checkResult      = new ReactiveVar();
  }
}<|endoftext|>


<commit_before>#!/usr/bin/env node

var
	_       = require('lodash'),
	chalk   = require('chalk'),
	fs      = require('fs'),
	util    = require('util'),
	yargs   = require('yargs')
		.option('cutoff',
		{
			alias: 'c',
			description: 'tags with usage counts lower than this will not be considered'
		})
		.option('filter',
		{
			alias: 'f',
			description: 'string or pattern to filter for'
		})
		.option('transform',
		{
			alias: 't',
			type: 'boolean',
			description: 'transform tags to canonical form'
		})
		.option('sort',
		{
			alias: 's',
			description: 'sorting criterion: lexical or count',
			default: 'lexical'
		})
		.option('json',
		{
			alias: 'j',
			type: 'boolean',
			description: 'output results in json format',
		})
		.help('help')
		.usage('get a list of tags matching specific criteria')
		.example('$0 -c 200 -f hurt', 'filter for tags with "hurt" used at least 200 times')
		.example('$0 -c 5000 -s count', 'show tags used more than 3000 times sorted by usage count')
		.example('$0 -c 3000 file.json', 'read some other json file for data (defaults to tags.json)')
	args = yargs.argv
;

var source = args._.length ? args._[0] : 'tags.json';
var tags = JSON.parse(fs.readFileSync(source, 'utf8'));
var keys = Object.keys(tags);

if (args.f)
{
	var pattern = new RegExp(args.f, 'i');

	keys = keys.filter(function(item)
	{
		return (pattern.test(item));
	});
}

if (args.c)
{
	keys = keys.filter(function(item)
	{
		return (tags[item] > args.c);
	});
}

if (args.t)
{
	var newtags = {};
	keys = _.map(keys, function(k)
	{
		var out = k.toLowerCase();

		var matches = out.match(/(.*)\s+(kink|sex)$/);
		if (matches)
		{
			out = matches[2] + ':' + matches[1];
		}

		out = out.replace(/:\s+/g, ':')
			.replace(' - ', ':')
			.replace('- ', ':')
			.replace('--', ':')
			.replace('alternate universe', 'au')
			.replace(/\s+/g, '-')
			.replace('&', '&');

		newtags[out] = tags[k];
		return out;
	});
	tags = newtags;
}

if (args.sort === 'count')
{
	keys = keys.sort(function(l, r)
	{
		return tags[r] - tags[l];
	});
}
else
	keys = keys.sort();

var outtags = {};
_.each(keys, function(k)
{
	outtags[k] = tags[k];
});

console.log(keys.length + ' tags matching criteria\n');
if (args.json)
	console.log(util.inspect(outtags, {colors: true}));
else
{
	var results = [];
	_.each(keys, function(k)
	{
		console.log(chalk.blue(k) + ': ' + outtags[k]);
	})
}
<commit_msg>Clean up json output.<commit_after>#!/usr/bin/env node

var
	_       = require('lodash'),
	chalk   = require('chalk'),
	fs      = require('fs'),
	util    = require('util'),
	yargs   = require('yargs')
		.option('cutoff',
		{
			alias: 'c',
			description: 'tags with usage counts lower than this will not be considered'
		})
		.option('filter',
		{
			alias: 'f',
			description: 'string or pattern to filter for'
		})
		.option('transform',
		{
			alias: 't',
			type: 'boolean',
			description: 'transform tags to canonical form'
		})
		.option('sort',
		{
			alias: 's',
			description: 'sorting criterion: lexical or count',
			default: 'lexical'
		})
		.option('json',
		{
			alias: 'j',
			type: 'boolean',
			description: 'output results in json format',
		})
		.help('help')
		.usage('get a list of tags matching specific criteria')
		.example('$0 -c 200 -f hurt', 'filter for tags with "hurt" used at least 200 times')
		.example('$0 -c 5000 -s count', 'show tags used more than 3000 times sorted by usage count')
		.example('$0 -c 3000 file.json', 'read some other json file for data (defaults to tags.json)')
	args = yargs.argv
;

var source = args._.length ? args._[0] : 'tags.json';
var tags = JSON.parse(fs.readFileSync(source, 'utf8'));
var keys = Object.keys(tags);

if (args.f)
{
	var pattern = new RegExp(args.f, 'i');

	keys = keys.filter(function(item)
	{
		return (pattern.test(item));
	});
}

if (args.c)
{
	keys = keys.filter(function(item)
	{
		return (tags[item] > args.c);
	});
}

if (args.t)
{
	var newtags = {};
	keys = _.map(keys, function(k)
	{
		var out = k.toLowerCase();

		var matches = out.match(/(.*)\s+(kink|sex)$/);
		if (matches)
		{
			out = matches[2] + ':' + matches[1];
		}

		out = out.replace(/:\s+/g, ':')
			.replace(' - ', ':')
			.replace('- ', ':')
			.replace('--', ':')
			.replace('alternate universe', 'au')
			.replace(/\s+/g, '-')
			.replace('&', '&');

		newtags[out] = tags[k];
		return out;
	});
	tags = newtags;
}

if (args.sort === 'count')
{
	keys = keys.sort(function(l, r)
	{
		return tags[r] - tags[l];
	});
}
else
	keys = keys.sort();

var outtags = {};
_.each(keys, function(k)
{
	outtags[k] = tags[k];
});

if (args.json)
{
	console.error(keys.length + ' tags matching criteria\n');
	console.log(JSON.stringify(outtags, null, '    '));
}
else
{
	console.log(keys.length + ' tags matching criteria\n');
	var results = [];
	_.each(keys, function(k)
	{
		console.log(chalk.blue(k) + ': ' + outtags[k]);
	})
}
<|endoftext|>


<commit_before>define(['backbone', 'places/utils', 'moxie.position'], function(Backbone, utils, userPosition) {
    var MapView = Backbone.View.extend({

        initialize: function() {
            _.bindAll(this);
            this.collection.on("reset", this.resetMapContents, this);
            this.collection.on("add", this.placePOI, this);
            this.latlngs = [];
            this.markers = [];
            this.userPosition = null;
        },

        manage: true,

        beforeRender: function() {
            console.log("Rendering map");
            this.map = utils.getMap(this.el);
            userPosition.follow(this.handle_geolocation_query);
            console.log(this.map);
            return this;
        },

        afterRender: function() {
            this.invalidateMapSize();
        },

        handle_geolocation_query: function(position) {
            this.user_position = [position.coords.latitude, position.coords.longitude];
            var you = new L.LatLng(position.coords.latitude, position.coords.longitude);
            if (this.user_marker) {
                this.map.removeLayer(this.user_marker);
            }
            this.user_marker = L.circle(you, 10, {color: 'red', fillColor: 'red', fillOpacity: 1.0});
            this.map.addLayer(this.user_marker);
        },

        placePOI: function(poi) {
            var latlng = new L.LatLng(poi.attributes.lat, poi.attributes.lon);
            var marker = new L.marker(latlng, {'title': poi.attributes.name});
            marker.addTo(this.map);
            this.latlngs.push(latlng);
            this.markers.push(marker);
        },

        invalidateMapSize: function() {
            this.map.invalidateSize();
            return this;
        },

        setMapBounds: function() {
            var bounds = new L.LatLngBounds(this.latlngs);
            if (this.user_position) {
                bounds.extend(this.user_position);
            }
            bounds.pad(5);
            this.map.fitBounds(bounds);
        },

        resetMapContents: function(){
            // Remove the existing map markers
            _.each(this.markers, function(marker) {
                this.map.removeLayer(marker);
            }, this);
            // Create new list of markers from search results
            this.latlngs = [];
            this.markers = [];
            this.collection.each(this.placePOI);
            this.setMapBounds();
        },

        onClose: function() {
            userPosition.unfollow(this.handle_geolocation_query);
        }
    });
    return MapView;
});
<commit_msg>Handle updates to the MapView collection<commit_after>define(['backbone', 'places/utils', 'moxie.position'], function(Backbone, utils, userPosition) {
    var MapView = Backbone.View.extend({

        initialize: function() {
            _.bindAll(this);
            this.latlngs = [];
            this.markers = [];
            this.userPosition = null;
        },

        manage: true,
        id: "map",

        beforeRender: function() {
            this.map = utils.getMap(this.el);
            userPosition.follow(this.handle_geolocation_query);
            return this;
        },

        afterRender: function() {
            this.invalidateMapSize();
        },

        setCollection: function(collection) {
            this.unsetCollection();
            this.collection = collection;
            this.collection.on("reset", this.resetMapContents, this);
            this.collection.on("add", this.placePOI, this);
            if (this.collection.length) {
                this.resetMapContents();
            }
        },

        unsetCollection: function() {
            if (this.collection) {
                this.collection.off("reset", this.resetMapContents, this);
                this.collection.off("add", this.placePOI, this);
                this.collection = null;
            }
        },

        handle_geolocation_query: function(position) {
            this.user_position = [position.coords.latitude, position.coords.longitude];
            var you = new L.LatLng(position.coords.latitude, position.coords.longitude);
            if (this.user_marker) {
                this.map.removeLayer(this.user_marker);
            }
            this.user_marker = L.circle(you, 10, {color: 'red', fillColor: 'red', fillOpacity: 1.0});
            this.map.addLayer(this.user_marker);
        },

        placePOI: function(poi) {
            var latlng = new L.LatLng(poi.attributes.lat, poi.attributes.lon);
            var marker = new L.marker(latlng, {'title': poi.attributes.name});
            marker.addTo(this.map);
            this.latlngs.push(latlng);
            this.markers.push(marker);
        },

        invalidateMapSize: function() {
            this.map.invalidateSize();
            return this;
        },

        setMapBounds: function() {
            var bounds = new L.LatLngBounds(this.latlngs);
            if (this.user_position) {
                bounds.extend(this.user_position);
            }
            bounds.pad(5);
            this.map.fitBounds(bounds);
        },

        resetMapContents: function(){
            // Remove the existing map markers
            _.each(this.markers, function(marker) {
                this.map.removeLayer(marker);
            }, this);
            // Create new list of markers from search results
            this.latlngs = [];
            this.markers = [];
            this.collection.each(this.placePOI);
            this.setMapBounds();
        },

        onClose: function() {
            userPosition.unfollow(this.handle_geolocation_query);
        }
    });
    return MapView;
});
<|endoftext|>


<commit_before>/**
* Easylife_CmsRewrites extension
*
* NOTICE OF LICENSE
*
* This source file is subject to the MIT License
* that is bundled with this package in the file LICENSE_EASYLIFE_CMSREWRITES.txt.
* It is also available through the world-wide-web at this URL:
* http://opensource.org/licenses/mit-license.php
*
* @category       Easylife
* @package        Easylife_CmsRewrites
* @copyright      Copyright (c) 2013
* @license        http://opensource.org/licenses/mit-license.php MIT License
*/

if(typeof CMSRewrite=='undefined') {
    var CMSRewrite = {};
}
CMSRewrite.Rewrite = Class.create();
CMSRewrite.Rewrite.prototype = {
    initialize: function(config) {
        this.config = Object.extend({
            addRewriteTrigger    : ".add-rewrite",
            rewritesContainer   : 'rewrites-wrapper',
            templateId: 'rewrite_template'
        }, config);
        this.templateSyntax = /(^|.|\r|\n)({{(\w+)}})/;
        this.rows = [];
        this.index = 0;
        var that = this;
        $$(this.config.addRewriteTrigger).each(function(element){
            Element.observe(element, 'click', that.addRow.bind(that));
        });
    },
    addRow: function(){
        var that = this;
        var template = new Template($(this.config.templateId).innerHTML, this.templateSyntax);
        var rewriteTemplate = template.evaluate({
            id:this.index
        });
        $(this.config.rewritesContainer).insert({bottom:rewriteTemplate});
        var index = this.index;
        Element.observe($('row_' + this.index).select('button.delete')[0], 'click', function(){
            that.removeRow(index);
        });
        this.index++;
    },
    removeRow: function (index) {
        if (confirm(Translator.translate('Are you sure?'))) {
            $('row_' + index).remove();
        }
    }
}
<commit_msg>Fixed Issue When Merge JS Is Enabled<commit_after>/**
* Easylife_CmsRewrites extension
*
* NOTICE OF LICENSE
*
* This source file is subject to the MIT License
* that is bundled with this package in the file LICENSE_EASYLIFE_CMSREWRITES.txt.
* It is also available through the world-wide-web at this URL:
* http://opensource.org/licenses/mit-license.php
*
* @category       Easylife
* @package        Easylife_CmsRewrites
* @copyright      Copyright (c) 2013
* @license        http://opensource.org/licenses/mit-license.php MIT License
*/

if(typeof CMSRewrite=='undefined') {
    var CMSRewrite = {};
}
CMSRewrite.Rewrite = Class.create();
CMSRewrite.Rewrite.prototype = {
    initialize: function(config) {
        this.config = Object.extend({
            addRewriteTrigger    : ".add-rewrite",
            rewritesContainer   : 'rewrites-wrapper',
            templateId: 'rewrite_template'
        }, config);
        this.templateSyntax = /(^|.|\r|\n)({{(\w+)}})/;
        this.rows = [];
        this.index = 0;
        var that = this;
        $$(this.config.addRewriteTrigger).each(function(element){
            Element.observe(element, 'click', that.addRow.bind(that));
        });
    },
    addRow: function(){
        var that = this;
        var template = new Template($(this.config.templateId).innerHTML, this.templateSyntax);
        var rewriteTemplate = template.evaluate({
            id:this.index
        });
        $(this.config.rewritesContainer).insert({bottom:rewriteTemplate});
        var index = this.index;
        Element.observe($('row_' + this.index).select('button.delete')[0], 'click', function(){
            that.removeRow(index);
        });
        this.index++;
    },
    removeRow: function (index) {
        if (confirm(Translator.translate('Are you sure?'))) {
            $('row_' + index).remove();
        }
    }
};
<|endoftext|>


<commit_before>"use strict";

var _chalk = require('chalk');

function _buildMsg(task, step, message) {
	return task + "@" + step + ": " + message;
}

module.exports = function(grunt) {

	grunt.registerMultiTask('superglue', 'Multistep file processing.', function() {
		var _global = {};
		var _target = {};

		var _options = this.options({
			initTask : function(data) {},
			initDest : function(data, dest) {},
			initSrc  : function(data, dest, index, name, string) { return string; },
			concat   : function(data, dest, index, name, string) { return string; },
			write    : function(data, dest, string) { return string; },
			endDest  : function(data, dest) {},
			endTask  : function(data) {}
		});

		if (typeof _options.initTask === 'function') {
			try {
				var ret = _options.initTask(_global);
			}
			catch (err) {
				grunt.log.error(_buildMsg(this.name, "initTask", err.message));

				return false;
			}

			if (ret === false) {
				grunt.log.writeln(_buildMsg(this.name, "initTask", _chalk.yellow("aborted")));

				return true;
			}
		}

		for (var i = 0, file = this.files[0]; file !== undefined; file = this.files[++i]) {
			var dest    = file.dest;
			var context = {};

			for (var s in _global) {
				if (_global.hasOwnProperty(s)) Object.defineProperty(context, s, Object.getOwnPropertyDescriptor(_global, s));
			}

			var target = {
				name    : dest,
				process : true,
				context : context,
				source  : [],
				string  : ""
			};

			if (typeof _options.initDest === 'function') {
				try {
					target.process = _options.initDest(context, dest) !== false;
				}
				catch (err) {
					grunt.log.error(_buildMsg(this.name, "initDest", err.message));

					return false;
				}
			}

			if (!target.process) {
				grunt.log.writeln(_buildMsg(this.name, "initDest", _chalk.yellow("aborted") + " " + _chalk.cyan(target.dest)));

				continue;
			}

			for (var j = 0, path = file.src[0]; path !== undefined; path = file.src[++j]) {
				if (!grunt.file.exists(path)) {
					grunt.log.warn(_buildMsg(this.name, "initSrc", _chalk.cyan(path) + " " + _chalk.yellow("missing")));

					continue;
				}

				var source = {
					index  : j,
					name   : path,
					string : grunt.file.read(path)
				};

				if (typeof _options.initSrc === 'function') {
					try {
						var ret = _options.initSrc(target.context, target.name, source.index, source.name, source.string);
					}
					catch (err) {
						grunt.log.error(_buildMsg(this.name, "initSrc", err.message));

						return false;
					}

					if (ret !== undefined) source.string = String(ret);
				}

				target.source.push(source);
			}

			if (target.source.length === 0) {
				grunt.log.warn(_buildMsg(this.name, "initSrc", _chalk.cyan(target.dest) + " " + _chalk.yellow("skipped")));

				target.process = false;
			}

			_target[dest] = target;
		}

		for (var dest in _target) {
			var target = _target[dest];

			if (!target.process) continue;

			for (var i = 0, source = target.source[0]; source !== undefined; source = target.source[++i]) {
				if (typeof _options.concat === 'function') {
					try {
						var ret = _options.concat(target.context, target.name, source.index, source.name, source.string);
					}
					catch (err) {
						grunt.log.error(_buildMsg(this.name, "concat", err.message));

						return false;
					}

					if (ret !== undefined) target.string += String(ret);
				}
				else target.string += source.string;
			}

			if (typeof _options.write === 'function') {
				try {
					ret = _options.write(target.context, target.name, target.string);
				}
				catch (err) {
					grunt.log.error(_buildMsg(this.name, "write", err.message));

					return false;
				}

				if (ret !== undefined) target.string = String(ret);
			}

			if (target.string === "") {
				grunt.log.warn(_buildMsg(this.name, "write", _chalk.cyan(target.name) + " " + _chalk.yellow("skipped")));

				continue;
			}

			grunt.file.write(target.name, target.string);

			grunt.log.writeln(_buildMsg(this.name, "write", _chalk.cyan(target.name) + "..." + _chalk.green("OK")));

			if (typeof _options.endDest === 'function') {
				try {
					_options.endDest(target.context, target.name);
				}
				catch (err) {
					grunt.log.error(_buildMsg(this.name, "endDest", err.message));

					return false;
				}
			}
		}

		if (typeof _options.endTask === 'function') {
			try {
				_options.endTask(_global);
			}
			catch (err) {
				grunt.log.error(_buildMsg(this.name, "endTask", err.message));

				return false;
			}
		}

		return true;
	});
};<commit_msg>Changed the clone operation to Object.create()<commit_after>"use strict";

var _chalk = require('chalk');

function _buildMsg(task, step, message) {
	return task + "@" + step + ": " + message;
}

module.exports = function(grunt) {

	grunt.registerMultiTask('superglue', 'Multistep file processing.', function() {
		var _global = {};
		var _target = {};

		var _options = this.options({
			initTask : function(data) {},
			initDest : function(data, dest) {},
			initSrc  : function(data, dest, index, name, string) { return string; },
			concat   : function(data, dest, index, name, string) { return string; },
			write    : function(data, dest, string) { return string; },
			endDest  : function(data, dest) {},
			endTask  : function(data) {}
		});

		if (typeof _options.initTask === 'function') {
			try {
				var ret = _options.initTask(_global);
			}
			catch (err) {
				grunt.log.error(_buildMsg(this.name, "initTask", err.message));

				return false;
			}

			if (ret === false) {
				grunt.log.writeln(_buildMsg(this.name, "initTask", _chalk.yellow("aborted")));

				return true;
			}
		}

		for (var i = 0, file = this.files[0]; file !== undefined; file = this.files[++i]) {
			var dest    = file.dest;
			var context = Object.create(_global);

			var target = {
				name    : dest,
				process : true,
				context : context,
				source  : [],
				string  : ""
			};

			if (typeof _options.initDest === 'function') {
				try {
					target.process = _options.initDest(context, dest) !== false;
				}
				catch (err) {
					grunt.log.error(_buildMsg(this.name, "initDest", err.message));

					return false;
				}
			}

			if (!target.process) {
				grunt.log.writeln(_buildMsg(this.name, "initDest", _chalk.yellow("aborted") + " " + _chalk.cyan(target.dest)));

				continue;
			}

			for (var j = 0, path = file.src[0]; path !== undefined; path = file.src[++j]) {
				if (!grunt.file.exists(path)) {
					grunt.log.warn(_buildMsg(this.name, "initSrc", _chalk.cyan(path) + " " + _chalk.yellow("missing")));

					continue;
				}

				var source = {
					index  : j,
					name   : path,
					string : grunt.file.read(path)
				};

				if (typeof _options.initSrc === 'function') {
					try {
						var ret = _options.initSrc(target.context, target.name, source.index, source.name, source.string);
					}
					catch (err) {
						grunt.log.error(_buildMsg(this.name, "initSrc", err.message));

						return false;
					}

					if (ret !== undefined) source.string = String(ret);
				}

				target.source.push(source);
			}

			if (target.source.length === 0) {
				grunt.log.warn(_buildMsg(this.name, "initSrc", _chalk.cyan(target.dest) + " " + _chalk.yellow("skipped")));

				target.process = false;
			}

			_target[dest] = target;
		}

		for (var dest in _target) {
			var target = _target[dest];

			if (!target.process) continue;

			for (var i = 0, source = target.source[0]; source !== undefined; source = target.source[++i]) {
				if (typeof _options.concat === 'function') {
					try {
						var ret = _options.concat(target.context, target.name, source.index, source.name, source.string);
					}
					catch (err) {
						grunt.log.error(_buildMsg(this.name, "concat", err.message));

						return false;
					}

					if (ret !== undefined) target.string += String(ret);
				}
				else target.string += source.string;
			}

			if (typeof _options.write === 'function') {
				try {
					ret = _options.write(target.context, target.name, target.string);
				}
				catch (err) {
					grunt.log.error(_buildMsg(this.name, "write", err.message));

					return false;
				}

				if (ret !== undefined) target.string = String(ret);
			}

			if (target.string === "") {
				grunt.log.warn(_buildMsg(this.name, "write", _chalk.cyan(target.name) + " " + _chalk.yellow("skipped")));

				continue;
			}

			grunt.file.write(target.name, target.string);

			grunt.log.writeln(_buildMsg(this.name, "write", _chalk.cyan(target.name) + "..." + _chalk.green("OK")));

			if (typeof _options.endDest === 'function') {
				try {
					_options.endDest(target.context, target.name);
				}
				catch (err) {
					grunt.log.error(_buildMsg(this.name, "endDest", err.message));

					return false;
				}
			}
		}

		if (typeof _options.endTask === 'function') {
			try {
				_options.endTask(_global);
			}
			catch (err) {
				grunt.log.error(_buildMsg(this.name, "endTask", err.message));

				return false;
			}
		}

		return true;
	});
};<|endoftext|>