<commit_before>let worstSeries = [];
for (i = 0; i < worstIssuers.length; i++) {
  worstSeries.push(timeseries[worstIssuers[i]]);
}
let top10series = [];
for (i = 0; i < topIssuers.length; i++) {
  top10series.push(timeseries[topIssuers[i]]);
}

let filteredIssuers = [];
function filterIssuersByIssuance() {
  // clear filteredIssuers but keep aliases to it
  while (filteredIssuers.shift()) {}
  filteredIssuers.push("Worst CAs");
  filteredIssuers.push("Top 10 CAs");

  let sliderValue = document.getElementById("minimumIssuance").value;
  let minimumIssuance = Math.ceil(Math.pow(maxIssuance, sliderValue / 100));
  let output = document.getElementById("minimumIssuanceOutput");
  output.value = minimumIssuance;

  for (let issuer of issuers) {
    if (issuer.totalIssuance >= minimumIssuance) {
      filteredIssuers.push(issuer.issuer);
    }
  }
}

$('#autocomplete').autocomplete({
  source: filteredIssuers,
  minLength: 0,
  select: function(event, suggestion) {
    makeChart(suggestion.item.value);
  }
});

function escapeName(name) {
  return name.replace(/[^A-Za-z0-9]/g, "_");
}

function getChartData(name, continuation) {
  let escapedName = escapeName(name);
  let req = new XMLHttpRequest();
  req.open("GET", "data/" + escapedName + ".json", true);
  req.onreadystatechange = function() {
    if (req.readyState == XMLHttpRequest.DONE && req.status == 200) {
      let data = JSON.parse(req.responseText);
      continuation(data);
    }
  };
  req.send();
}

let commonLegend = {
  enabled: true,
  layout: "vertical",
  align: "right",
  verticalAlign: "middle",
  borderWidth: 2
};

function makeChart(name) {
  clearExamples();
  let commonYAxis = [{ max: 1.0, min: 0.0 }, { min: 0, opposite: false }];
  if (name == "Worst CAs") {
    new Highcharts.StockChart({
      legend: commonLegend,
      series: worstSeries,
      yAxis: commonYAxis
    });
  } else if (name == "Top 10 CAs") {
    let top10tsChart = new Highcharts.StockChart({
      legend: commonLegend,
      series: top10series,
      yAxis: commonYAxis
    });
    document.getElementById("autocomplete").value = name;
  } else {
    getChartData(name, function(seriesAndExamples) {
      new Highcharts.StockChart({
        legend: commonLegend,
        series: seriesAndExamples.series,
        yAxis: commonYAxis
      });
      makeExamples(seriesAndExamples.examples);
    });
  }
  document.getElementById("autocomplete").value = name;
  setChartLink(name);
}

function setChartLink(name) {
  let link = document.getElementById("chartlink");
  link.href = "?" + encodeURIComponent(name);
}

function clearChildren(id) {
  let element = document.getElementById(id);
  while (element.children.length > 0) {
    element.children[0].remove();
  }
}

function clearExamples() {
  clearChildren("examplesHeader");
  clearChildren("examplesBody");
}

let months = [
  "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov",
  "Dec"
];

function makeExamples(examples) {
  // e.g. 'COMODO ECC Domain Validation Secure Server CA 2' has a perfect
  // score, so there are no examples of bad certificates issued by it.
  if (!examples) {
    return;
  }
  let examplesHeader = document.getElementById("examplesHeader");
  let examplesBody = document.getElementById("examplesBody");
  let exampleTypes = [];
  for (let key of Object.keys(examples)) {
    if (key.endsWith("Example") && examples[key]) {
      exampleTypes.push(key.substring(0, key.indexOf("Example")));
    }
  }
  for (let example of exampleTypes) {
    let header = document.createElement("th");
    let lastSeen = new Date(examples[example + "LastSeen"]);
    header.textContent = example + " (last seen " + lastSeen.getDate() + " " +
                         months[lastSeen.getMonth()] + " " +
                         lastSeen.getFullYear() + ")";
    examplesHeader.appendChild(header);
    let td = document.createElement("td");
    let pem = examples[example + "Example"]
                .replace(/[\r\n]/g, "")
                .replace(/-----(BEGIN|END) CERTIFICATE-----/g, "");
    let frame = document.createElement("iframe");
    frame.width = "600px";
    frame.height = "600px";
    frame.src = "certsplainer/?" + pem;
    td.appendChild(frame);
    examplesBody.appendChild(td);
  }
}

// Strangely, it looks like passing in values for legend and yAxis don't work,
// so they have to be specified with each chart created.
Highcharts.setOptions({
  chart: {
    renderTo: "timeseries"
  }
});

filterIssuersByIssuance();
makeChart(location.search ? decodeURIComponent(location.search.substring(1))
                          : filteredIssuers[0]);
<commit_msg>update location to match current chart<commit_after>let worstSeries = [];
for (i = 0; i < worstIssuers.length; i++) {
  worstSeries.push(timeseries[worstIssuers[i]]);
}
let top10series = [];
for (i = 0; i < topIssuers.length; i++) {
  top10series.push(timeseries[topIssuers[i]]);
}

let filteredIssuers = [];
function filterIssuersByIssuance() {
  // clear filteredIssuers but keep aliases to it
  while (filteredIssuers.shift()) {}
  filteredIssuers.push("Worst CAs");
  filteredIssuers.push("Top 10 CAs");

  let sliderValue = document.getElementById("minimumIssuance").value;
  let minimumIssuance = Math.ceil(Math.pow(maxIssuance, sliderValue / 100));
  let output = document.getElementById("minimumIssuanceOutput");
  output.value = minimumIssuance;

  for (let issuer of issuers) {
    if (issuer.totalIssuance >= minimumIssuance) {
      filteredIssuers.push(issuer.issuer);
    }
  }
}

$('#autocomplete').autocomplete({
  source: filteredIssuers,
  minLength: 0,
  select: function(event, suggestion) {
    makeChart(suggestion.item.value);
  }
});

function escapeName(name) {
  return name.replace(/[^A-Za-z0-9]/g, "_");
}

function getChartData(name, continuation) {
  let escapedName = escapeName(name);
  let req = new XMLHttpRequest();
  req.open("GET", "data/" + escapedName + ".json", true);
  req.onreadystatechange = function() {
    if (req.readyState == XMLHttpRequest.DONE && req.status == 200) {
      let data = JSON.parse(req.responseText);
      continuation(data);
    }
  };
  req.send();
}

let commonLegend = {
  enabled: true,
  layout: "vertical",
  align: "right",
  verticalAlign: "middle",
  borderWidth: 2
};

function makeChart(name) {
  clearExamples();
  let commonYAxis = [{ max: 1.0, min: 0.0 }, { min: 0, opposite: false }];
  if (name == "Worst CAs") {
    new Highcharts.StockChart({
      legend: commonLegend,
      series: worstSeries,
      yAxis: commonYAxis
    });
  } else if (name == "Top 10 CAs") {
    let top10tsChart = new Highcharts.StockChart({
      legend: commonLegend,
      series: top10series,
      yAxis: commonYAxis
    });
    document.getElementById("autocomplete").value = name;
  } else {
    getChartData(name, function(seriesAndExamples) {
      new Highcharts.StockChart({
        legend: commonLegend,
        series: seriesAndExamples.series,
        yAxis: commonYAxis
      });
      makeExamples(seriesAndExamples.examples);
    });
  }
  document.getElementById("autocomplete").value = name;
  let search = "?" + encodeURIComponent(name);
  document.getElementById("chartlink").href = search;
  history.replaceState(null, "", location.origin + location.pathname + search);
}

function clearChildren(id) {
  let element = document.getElementById(id);
  while (element.children.length > 0) {
    element.children[0].remove();
  }
}

function clearExamples() {
  clearChildren("examplesHeader");
  clearChildren("examplesBody");
}

let months = [
  "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov",
  "Dec"
];

function makeExamples(examples) {
  // e.g. 'COMODO ECC Domain Validation Secure Server CA 2' has a perfect
  // score, so there are no examples of bad certificates issued by it.
  if (!examples) {
    return;
  }
  let examplesHeader = document.getElementById("examplesHeader");
  let examplesBody = document.getElementById("examplesBody");
  let exampleTypes = [];
  for (let key of Object.keys(examples)) {
    if (key.endsWith("Example") && examples[key]) {
      exampleTypes.push(key.substring(0, key.indexOf("Example")));
    }
  }
  for (let example of exampleTypes) {
    let header = document.createElement("th");
    let lastSeen = new Date(examples[example + "LastSeen"]);
    header.textContent = example + " (last seen " + lastSeen.getDate() + " " +
                         months[lastSeen.getMonth()] + " " +
                         lastSeen.getFullYear() + ")";
    examplesHeader.appendChild(header);
    let td = document.createElement("td");
    let pem = examples[example + "Example"]
                .replace(/[\r\n]/g, "")
                .replace(/-----(BEGIN|END) CERTIFICATE-----/g, "");
    let frame = document.createElement("iframe");
    frame.width = "600px";
    frame.height = "600px";
    frame.src = "certsplainer/?" + pem;
    td.appendChild(frame);
    examplesBody.appendChild(td);
  }
}

// Strangely, it looks like passing in values for legend and yAxis don't work,
// so they have to be specified with each chart created.
Highcharts.setOptions({
  chart: {
    renderTo: "timeseries"
  }
});

filterIssuersByIssuance();
makeChart(location.search ? decodeURIComponent(location.search.substring(1))
                          : filteredIssuers[0]);
<|endoftext|>


<commit_before>// Provides req.data.global, an Apostrophe doc
// for sitewide content such as a footer displayed on all pages. You
// can also create site-wide preferences by adding schema fields. Just
// configure this module with the `addFields` option as you normally would
// for any widget or pieces module.
//
// ## options
//
// `deferWidgetLoading`: a performance option. if true, any widget loads that can be deferred
// will be until the end of the process of loading the global doc, reducing the number of queries
// for simple cases.
//
// Note that the `defer` option must also be set to `true` for all widget types
// you wish to defer loads for.
//
// To avoid causing problems for routes that depend on the middleware, loads are
// only deferred until the end of loading the global doc and anything it
// joins with; they are not merged with deferred loads for the actual page.
// This option defaults to `false` because in many cases performance is
// not improved, as the global doc often contains no deferrable widgets,
// or loads them efficiently already.
//
// `addFields`: if the schema contains fields, the "Global Content" admin bar button will
// launch the editor modal for those, otherwise it will shortcut directly to the versions dialog box
// which is still relevant on almost all sites because of the use of global header
// and footer areas, etc.
//
// This module provides middleware so that `req.data.global` is always available,
// even in requests that are not for Apostrophe pages. In a command line task, you can use
// the provided `findGlobal` method.
//
// ## properties
//
// `_id`: the MongoDB ID of the global doc. Available after `modulesReady`.

var async = require('async');
var Promise = require('bluebird');
var _ = require('@sailshq/lodash');

module.exports = {

  extend: 'apostrophe-pieces',

  name: 'apostrophe-global',

  alias: 'global',

  label: 'Global',

  pluralLabel: 'Global',

  whileBusyDelay: 60,

  whileBusyRetryAfter: 5,

  whileBusyRequestDelay: 10,

  searchable: false,

  beforeConstruct: function(self, options) {
    options.removeFields = [ 'title', 'slug', 'tags', 'published', 'trash' ].concat(options.removeFields || []);
  },

  afterConstruct: function(self) {
    self.enableMiddleware();
  },

  construct: function(self, options) {

    self.slug = options.slug || 'global';

    // Fetch the `global` doc object. On success, the callback is invoked
    // with `(null, global)`.

    self.findGlobal = function(req, callback) {
      return self.find(req, { slug: self.slug })
        .permission(false)
        .toObject(callback);
    };

    self.modulesReady = function(callback) {
      self.initGlobal(callback);
    };

    // Initialize the `global` doc, if necessary. Invoked late in the
    // startup process by `modulesReady`.

    self.initGlobal = function(callback) {
      var req = self.apos.tasks.getReq();
      var existing;
      return async.series({
        // Early in pre-2.0 code there was no type property for the global page.
        // We can't use a standard migration to fix that because initGlobal
        // is called too soon
        migrate: function(callback) {
          return self.apos.docs.db.update({
            slug: self.slug,
            $or: [
              // Could still be literally undefined, or it could have been
              // patched by the orphan doc type creator
              {
                type: { $exists: 0 }
              },
              {
                type: 'WASUNDEFINED'
              }
            ]
          }, {
            $set: {
              type: self.name
            }
          }, callback);
        },
        fetch: function(callback) {
          // Existence test must not load widgets etc. as this can lead
          // to chicken and egg problems if widgets join with page types
          // not yet registered
          return self.apos.docs.db.findOne({ slug: self.slug }, function(err, result) {
            if (err) {
              return callback(err);
            }
            existing = result;
            return callback();
          });
        },
        insert: function(callback) {
          if (existing) {
            return setImmediate(callback);
          }
          existing = { slug: self.slug, published: true, type: self.name };
          return self.apos.docs.insert(req, existing, callback);
        }
      }, function(err) {
        if (err) {
          return callback(err);
        }
        // Populated for bc, we now get the _id from the copy fetched
        // per request by the middleware
        self._id = existing._id;
        return callback(null);
      });
    };

    // Add the `addGlobalToData` middleware.

    self.enableMiddleware = function() {
      self.expressMiddleware = self.addGlobalToData;
    };

    // Fetch the global doc and add it to `req.data` as `req.data.global`, if it
    // is not already present. If it is already present, skip the
    // extra query.
    //
    // If called with three arguments, acts as middleware.
    //
    // If called with two arguments, the first is `req` and the second is
    // invoked as `callback`.
    //
    // If called with one argument, that argument is `req` and a promise
    // is returned.

    self.addGlobalToData = function(req, res, next) {
      if (arguments.length >= 3) {
        // middleware
        return body(function(err) {
          if (err) {
            self.apos.utils.error('ERROR loading global doc: ', err);
            // Here in middleware we can't tell if this would have been a page,
            // so we can't set `aposError` and wait. We have to force the issue
            res.status(500).send('error');
            return;
          }
          // Don't break other middleware or routes that might not be defer-aware.
          // The regular page rendering route will reenable this on its own
          req.deferWidgetLoading = false;
          return next();
        });
      } else if (arguments.length === 2) {
        // res is actually callback
        return body(res);
      } else {
        // just takes req and returns promise
        return Promise.promisify(body)();
      }

      function body(callback) {

        if (req.data.body) {
          return callback(null);
        }

        if (self.options.deferWidgetLoading) {
          req.deferWidgetLoading = true;
        }

        return async.series([ findGlobal, loadDeferredWidgets ], callback);

      }

      function findGlobal(callback) {
        return self.findGlobal(req, function(err, result) {
          var lockName = 'apostrophe-global-busy';
          var localeLockName;
          var propName = 'globalBusy';
          var localePropName;
          if (err) {
            return callback(err);
          }

          req.data.global = result;

          if (req.locale) {
            localeLockName = lockName + '-' + req.locale;
            localePropName = propName + req.locale;
          }

          return async.series([
            considerGlobal,
            considerLocale
          ], callback);

          function considerGlobal(callback) {
            return considerLock(propName, lockName, callback);
          }

          function considerLocale(callback) {
            if (!localePropName) {
              return callback(null);
            }
            return considerLock(localePropName, localeLockName, callback);
          }

          function considerLock(propName, lockName, callback) {
            if (req.data.global[propName]) {
              return self.apos.locks.lock(lockName, {
                wait: (req.res && req.res.send) ? self.options.whileBusyRequestDelay * 1000 : Number.MAX_VALUE,
                waitForSelf: true
              }, function(err) {
                if (!err) {
                  // We got in after a period of the system being busy,
                  // or the process with the lock went away. Either way,
                  // we should clear globalBusy and give up our lock,
                  // then continue normal operation.
                  return async.series([ unmark, unlock, refind ], callback);
                }
                // An error occurred. If it is because the lock is still
                // present after waiting as long as we could for this req,
                // send a try-again response to the user.
                if ((err === 'locked') && req.res && req.res.send) {
                  return self.busyTryAgainSoon(req);
                } else {
                  // All other errors propagate normally
                  return callback(err);
                }
              });
            }
            return callback(null);
            function unmark(callback) {
              var $set = {};
              $set[propName] = false;
              return self.apos.docs.db.update({
                _id: req.data.global._id
              }, {
                $set: $set
              }, callback);
            }
            function unlock(callback) {
              return self.apos.locks.unlock(lockName, callback);
            }
            function refind(callback) {
              return self.findGlobal(req, function(err, result) {
                if (err) {
                  return callback(err);
                }
                req.data.global = result;
                return callback(null);
              });
            }
          }
        });
      }

      function loadDeferredWidgets(callback) {
        if (!self.options.deferWidgetLoading) {
          return callback(null);
        }
        return self.apos.areas.loadDeferredWidgets(req, callback);
      }
    };

    self.busyTryAgainSoon = function(req) {
      if (!_.includes([ 'GET', 'HEAD' ], req.method)) {
        // Typically an API will receive this sad news
        return req.res.status(503).send({ status: 'busy' });
      }
      return req.res.status(503).set('Refresh', self.options.whileBusyRetryAfter).send(self.render(req, 'busy.html'));
    };

    // Run the given function while the entire site is marked as busy.
    //
    // This is a promise-based method. `fn` may return a promise, which will
    // be awaited. This method will return a promise, which must be awaited.
    //
    // While the site is busy new requests are delayed as much as possible,
    // then GET requests receive a simple "busy" page that retries
    // after an interval, etc. To address the issue of requests already
    // in progress, this method marks the site busy, then waits for
    // `options.whileBusyDelay` seconds before invoking `fn`.
    // That option defaults to 60 (one minute). Explicitly tracking
    // all requests in flight would have too much performance impact
    // on normal operation.
    //
    // This method should be used very rarely, for instance for a procedure
    // that deploys an entirely new set of content to the site. Use of
    // this method for anything more routine would have a crippling
    // performance impact.
    //
    // **Use with workflow**: if `options.locale` argument is present, only
    // the given locale name is marked busy. If `req` has any other
    // `req.locale` it proceeds normally. This option works only with
    // 'apostrophe-workflow' (the global docs must have `workflowLocale`
    // properties).

    self.whileBusy = function(fn, options) {
      var locked = false;
      var marked = false;
      var lockName = 'apostrophe-global-busy';
      var propName = 'globalBusy';
      var locale = options && options.locale;
      if (locale) {
        lockName += '-' + locale;
        propName += locale;
      }
      var criteria = {
        type: self.name
      };
      if (locale) {
        criteria.workflowLocale = locale;
      }
      return Promise.try(function() {
        return self.apos.locks.lock(lockName);
      }).then(function() {
        locked = true;
        var $set = {};
        $set[propName] = true;
        var args = {
          $set: $set
        };
        return self.apos.docs.db.update(criteria, args, {
          // so that if we really want to lock across all locales
          // (locale not passed and workflow present), we can
          multi: true
        });
      }).then(function() {
        marked = true;
        return Promise.delay(self.options.whileBusyDelay * 1000);
      }).then(function() {
        return fn();
      }).finally(function() {
        return Promise.try(function() {
          var $set = {};
          $set[propName] = false;
          var args = {
            $set: $set
          };
          if (marked) {
            return self.apos.docs.db.update(criteria, args, {
              // workflow-aware for cases where we really do want
              // to lock across all locales
              multi: true
            });
          }
        }).then(function() {
          if (locked) {
            return self.apos.locks.unlock(lockName);
          }
        });
      });
    };

    var superGetCreateSingletonOptions = self.getCreateSingletonOptions;
    self.getCreateSingletonOptions = function(req) {
      var browserOptions = superGetCreateSingletonOptions(req);
      // For compatibility with the workflow module try to get the _id
      // from the copy the middleware fetched for this specific request,
      // if not fall back to self._id
      browserOptions._id = (req.data.global && req.data.global._id) || self._id;
      return browserOptions;
    };

    // There is only one useful object of this type, so having access to the admin
    // bar button is not helpful unless you can edit that one, rather than
    // merely creating a new one (for which there is no UI). Thus we need
    // to set the permission requirement to admin-apostrophe-global.
    // This is called for you.

    self.addToAdminBar = function() {
      self.apos.adminBar.add(self.__meta.name, self.pluralLabel, 'admin-' + self.name);
    };

    var superGetEditControls = self.getEditControls;
    self.getEditControls = function(req) {
      var controls = superGetEditControls(req);
      var more = _.find(controls, { name: 'more' });
      if (more) {
        more.items = _.reject(more.items, function(item) {
          return _.contains([ 'trash', 'copy' ], item.action);
        });
      }
      return controls;
    };

  }
};
<commit_msg>Tom and Brian found this beaut together and reviewed the one-line fix. It was loading req.data.global many times per request when apostrophe-pieces-orderings-bundle was present.<commit_after>// Provides req.data.global, an Apostrophe doc
// for sitewide content such as a footer displayed on all pages. You
// can also create site-wide preferences by adding schema fields. Just
// configure this module with the `addFields` option as you normally would
// for any widget or pieces module.
//
// ## options
//
// `deferWidgetLoading`: a performance option. if true, any widget loads that can be deferred
// will be until the end of the process of loading the global doc, reducing the number of queries
// for simple cases.
//
// Note that the `defer` option must also be set to `true` for all widget types
// you wish to defer loads for.
//
// To avoid causing problems for routes that depend on the middleware, loads are
// only deferred until the end of loading the global doc and anything it
// joins with; they are not merged with deferred loads for the actual page.
// This option defaults to `false` because in many cases performance is
// not improved, as the global doc often contains no deferrable widgets,
// or loads them efficiently already.
//
// `addFields`: if the schema contains fields, the "Global Content" admin bar button will
// launch the editor modal for those, otherwise it will shortcut directly to the versions dialog box
// which is still relevant on almost all sites because of the use of global header
// and footer areas, etc.
//
// This module provides middleware so that `req.data.global` is always available,
// even in requests that are not for Apostrophe pages. In a command line task, you can use
// the provided `findGlobal` method.
//
// ## properties
//
// `_id`: the MongoDB ID of the global doc. Available after `modulesReady`.

var async = require('async');
var Promise = require('bluebird');
var _ = require('@sailshq/lodash');

module.exports = {

  extend: 'apostrophe-pieces',

  name: 'apostrophe-global',

  alias: 'global',

  label: 'Global',

  pluralLabel: 'Global',

  whileBusyDelay: 60,

  whileBusyRetryAfter: 5,

  whileBusyRequestDelay: 10,

  searchable: false,

  beforeConstruct: function(self, options) {
    options.removeFields = [ 'title', 'slug', 'tags', 'published', 'trash' ].concat(options.removeFields || []);
  },

  afterConstruct: function(self) {
    self.enableMiddleware();
  },

  construct: function(self, options) {

    self.slug = options.slug || 'global';

    // Fetch the `global` doc object. On success, the callback is invoked
    // with `(null, global)`.

    self.findGlobal = function(req, callback) {
      return self.find(req, { slug: self.slug })
        .permission(false)
        .toObject(callback);
    };

    self.modulesReady = function(callback) {
      self.initGlobal(callback);
    };

    // Initialize the `global` doc, if necessary. Invoked late in the
    // startup process by `modulesReady`.

    self.initGlobal = function(callback) {
      var req = self.apos.tasks.getReq();
      var existing;
      return async.series({
        // Early in pre-2.0 code there was no type property for the global page.
        // We can't use a standard migration to fix that because initGlobal
        // is called too soon
        migrate: function(callback) {
          return self.apos.docs.db.update({
            slug: self.slug,
            $or: [
              // Could still be literally undefined, or it could have been
              // patched by the orphan doc type creator
              {
                type: { $exists: 0 }
              },
              {
                type: 'WASUNDEFINED'
              }
            ]
          }, {
            $set: {
              type: self.name
            }
          }, callback);
        },
        fetch: function(callback) {
          // Existence test must not load widgets etc. as this can lead
          // to chicken and egg problems if widgets join with page types
          // not yet registered
          return self.apos.docs.db.findOne({ slug: self.slug }, function(err, result) {
            if (err) {
              return callback(err);
            }
            existing = result;
            return callback();
          });
        },
        insert: function(callback) {
          if (existing) {
            return setImmediate(callback);
          }
          existing = { slug: self.slug, published: true, type: self.name };
          return self.apos.docs.insert(req, existing, callback);
        }
      }, function(err) {
        if (err) {
          return callback(err);
        }
        // Populated for bc, we now get the _id from the copy fetched
        // per request by the middleware
        self._id = existing._id;
        return callback(null);
      });
    };

    // Add the `addGlobalToData` middleware.

    self.enableMiddleware = function() {
      self.expressMiddleware = self.addGlobalToData;
    };

    // Fetch the global doc and add it to `req.data` as `req.data.global`, if it
    // is not already present. If it is already present, skip the
    // extra query.
    //
    // If called with three arguments, acts as middleware.
    //
    // If called with two arguments, the first is `req` and the second is
    // invoked as `callback`.
    //
    // If called with one argument, that argument is `req` and a promise
    // is returned.

    self.addGlobalToData = function(req, res, next) {
      if (arguments.length >= 3) {
        // middleware
        return body(function(err) {
          if (err) {
            self.apos.utils.error('ERROR loading global doc: ', err);
            // Here in middleware we can't tell if this would have been a page,
            // so we can't set `aposError` and wait. We have to force the issue
            res.status(500).send('error');
            return;
          }
          // Don't break other middleware or routes that might not be defer-aware.
          // The regular page rendering route will reenable this on its own
          req.deferWidgetLoading = false;
          return next();
        });
      } else if (arguments.length === 2) {
        // res is actually callback
        return body(res);
      } else {
        // just takes req and returns promise
        return Promise.promisify(body)();
      }

      function body(callback) {

        if (req.data.global) {
          return callback(null);
        }

        if (self.options.deferWidgetLoading) {
          req.deferWidgetLoading = true;
        }

        return async.series([ findGlobal, loadDeferredWidgets ], callback);

      }

      function findGlobal(callback) {
        return self.findGlobal(req, function(err, result) {
          var lockName = 'apostrophe-global-busy';
          var localeLockName;
          var propName = 'globalBusy';
          var localePropName;
          if (err) {
            return callback(err);
          }

          req.data.global = result;

          if (req.locale) {
            localeLockName = lockName + '-' + req.locale;
            localePropName = propName + req.locale;
          }

          return async.series([
            considerGlobal,
            considerLocale
          ], callback);

          function considerGlobal(callback) {
            return considerLock(propName, lockName, callback);
          }

          function considerLocale(callback) {
            if (!localePropName) {
              return callback(null);
            }
            return considerLock(localePropName, localeLockName, callback);
          }

          function considerLock(propName, lockName, callback) {
            if (req.data.global[propName]) {
              return self.apos.locks.lock(lockName, {
                wait: (req.res && req.res.send) ? self.options.whileBusyRequestDelay * 1000 : Number.MAX_VALUE,
                waitForSelf: true
              }, function(err) {
                if (!err) {
                  // We got in after a period of the system being busy,
                  // or the process with the lock went away. Either way,
                  // we should clear globalBusy and give up our lock,
                  // then continue normal operation.
                  return async.series([ unmark, unlock, refind ], callback);
                }
                // An error occurred. If it is because the lock is still
                // present after waiting as long as we could for this req,
                // send a try-again response to the user.
                if ((err === 'locked') && req.res && req.res.send) {
                  return self.busyTryAgainSoon(req);
                } else {
                  // All other errors propagate normally
                  return callback(err);
                }
              });
            }
            return callback(null);
            function unmark(callback) {
              var $set = {};
              $set[propName] = false;
              return self.apos.docs.db.update({
                _id: req.data.global._id
              }, {
                $set: $set
              }, callback);
            }
            function unlock(callback) {
              return self.apos.locks.unlock(lockName, callback);
            }
            function refind(callback) {
              return self.findGlobal(req, function(err, result) {
                if (err) {
                  return callback(err);
                }
                req.data.global = result;
                return callback(null);
              });
            }
          }
        });
      }

      function loadDeferredWidgets(callback) {
        if (!self.options.deferWidgetLoading) {
          return callback(null);
        }
        return self.apos.areas.loadDeferredWidgets(req, callback);
      }
    };

    self.busyTryAgainSoon = function(req) {
      if (!_.includes([ 'GET', 'HEAD' ], req.method)) {
        // Typically an API will receive this sad news
        return req.res.status(503).send({ status: 'busy' });
      }
      return req.res.status(503).set('Refresh', self.options.whileBusyRetryAfter).send(self.render(req, 'busy.html'));
    };

    // Run the given function while the entire site is marked as busy.
    //
    // This is a promise-based method. `fn` may return a promise, which will
    // be awaited. This method will return a promise, which must be awaited.
    //
    // While the site is busy new requests are delayed as much as possible,
    // then GET requests receive a simple "busy" page that retries
    // after an interval, etc. To address the issue of requests already
    // in progress, this method marks the site busy, then waits for
    // `options.whileBusyDelay` seconds before invoking `fn`.
    // That option defaults to 60 (one minute). Explicitly tracking
    // all requests in flight would have too much performance impact
    // on normal operation.
    //
    // This method should be used very rarely, for instance for a procedure
    // that deploys an entirely new set of content to the site. Use of
    // this method for anything more routine would have a crippling
    // performance impact.
    //
    // **Use with workflow**: if `options.locale` argument is present, only
    // the given locale name is marked busy. If `req` has any other
    // `req.locale` it proceeds normally. This option works only with
    // 'apostrophe-workflow' (the global docs must have `workflowLocale`
    // properties).

    self.whileBusy = function(fn, options) {
      var locked = false;
      var marked = false;
      var lockName = 'apostrophe-global-busy';
      var propName = 'globalBusy';
      var locale = options && options.locale;
      if (locale) {
        lockName += '-' + locale;
        propName += locale;
      }
      var criteria = {
        type: self.name
      };
      if (locale) {
        criteria.workflowLocale = locale;
      }
      return Promise.try(function() {
        return self.apos.locks.lock(lockName);
      }).then(function() {
        locked = true;
        var $set = {};
        $set[propName] = true;
        var args = {
          $set: $set
        };
        return self.apos.docs.db.update(criteria, args, {
          // so that if we really want to lock across all locales
          // (locale not passed and workflow present), we can
          multi: true
        });
      }).then(function() {
        marked = true;
        return Promise.delay(self.options.whileBusyDelay * 1000);
      }).then(function() {
        return fn();
      }).finally(function() {
        return Promise.try(function() {
          var $set = {};
          $set[propName] = false;
          var args = {
            $set: $set
          };
          if (marked) {
            return self.apos.docs.db.update(criteria, args, {
              // workflow-aware for cases where we really do want
              // to lock across all locales
              multi: true
            });
          }
        }).then(function() {
          if (locked) {
            return self.apos.locks.unlock(lockName);
          }
        });
      });
    };

    var superGetCreateSingletonOptions = self.getCreateSingletonOptions;
    self.getCreateSingletonOptions = function(req) {
      var browserOptions = superGetCreateSingletonOptions(req);
      // For compatibility with the workflow module try to get the _id
      // from the copy the middleware fetched for this specific request,
      // if not fall back to self._id
      browserOptions._id = (req.data.global && req.data.global._id) || self._id;
      return browserOptions;
    };

    // There is only one useful object of this type, so having access to the admin
    // bar button is not helpful unless you can edit that one, rather than
    // merely creating a new one (for which there is no UI). Thus we need
    // to set the permission requirement to admin-apostrophe-global.
    // This is called for you.

    self.addToAdminBar = function() {
      self.apos.adminBar.add(self.__meta.name, self.pluralLabel, 'admin-' + self.name);
    };

    var superGetEditControls = self.getEditControls;
    self.getEditControls = function(req) {
      var controls = superGetEditControls(req);
      var more = _.find(controls, { name: 'more' });
      if (more) {
        more.items = _.reject(more.items, function(item) {
          return _.contains([ 'trash', 'copy' ], item.action);
        });
      }
      return controls;
    };

  }
};
<|endoftext|>


<commit_before>import { Context }  from 'material-flux';
import Util         from '../common/Util.js';
import SampleStore  from './store/SampleStore.js';
import SampleAction from './action/SampleAction.js';

/**
 * Application context.
 */
export default class AppContext extends Context {
  /**
   * Initialize instance.
   */
  constructor() {
    super();

    if( DEBUG ) {
      Util.log( 'Initialize AppContext' );
    }

    /**
     * Object for using modules main process from the renderer.
     * @type {Object}
     */
    this.remote = window.require( 'remote' );

    /**
     * Object for using inter-process communication.
     * @type {Object}
     */
    this.ipc = window.require( 'ipc' );

    /**
     * Sample store.
     * @type {SampleStore}
     */
    this.sampleStore = new SampleStore( this );

    /**
     * Sample actions.
     * @type {SampleAction}
     */
    this.sampleAction = new SampleAction( this );
  }
}
<commit_msg>#17 コンパイル エラーを修正<commit_after>import { Context }       from 'material-flux';
import Util              from '../common/Util.js';
import AudioPlayerStore  from './store/AudioPlayerStore.js';
import AudioPlayerAction from './action/AudioPlayerAction.js';

/**
 * Application context.
 */
export default class AppContext extends Context {
  /**
   * Initialize instance.
   */
  constructor() {
    super();

    if( DEBUG ) {
      Util.log( 'Initialize AppContext' );
    }

    /**
     * Object for using modules main process from the renderer.
     * @type {Object}
     */
    this.remote = window.require( 'remote' );

    /**
     * Object for using inter-process communication.
     * @type {Object}
     */
    this.ipc = window.require( 'ipc' );

    /**
     * Audio player store.
     * @type {AudioPlayerStore}
     */
    this.audioPlayerStore = new AudioPlayerStore( this );

    /**
     * Audio player actions.
     * @type {AudioPlayerAction}
     */
    this.audioPlayerAction = new AudioPlayerAction( this );
  }
}
<|endoftext|>


<commit_before>/**
 * @depend ../../sinon.js
 * @depend event.js
 */
/*jslint eqeqeq: false, onevar: false*/
/*global sinon, module, require, XDomainRequest*/
/**
 * Fake XDomainRequest object
 */
"use strict";

if (typeof sinon == "undefined") {
    this.sinon = {};
}
sinon.xdr = { XDomainRequest: this.XDomainRequest };

// wrapper for global
(function (global) {
    var xdr = sinon.xdr;
    xdr.GlobalXDomainRequest = global.XDomainRequest;
    xdr.supportsXDR = typeof xdr.GlobalXDomainRequest != "undefined";
    xdr.workingXDR = xdr.supportsXDR ? xdr.GlobalXDomainRequest :  false;

    function FakeXDomainRequest() {
        this.readyState = FakeXDomainRequest.UNSENT;
        this.requestBody = null;
        this.status = 0;

        if (typeof FakeXDomainRequest.onCreate == "function") {
            FakeXDomainRequest.onCreate(this);
        }
    }

    function verifyState(xdr) {
        if (xdr.readyState !== FakeXDomainRequest.OPENED) {
            throw new Error("INVALID_STATE_ERR");
        }

        if (xdr.sendFlag) {
            throw new Error("INVALID_STATE_ERR");
        }
    }

    function verifyRequestSent(xdr) {
        if (xdr.readyState == FakeXDomainRequest.DONE) {
            throw new Error("Request done");
        }
    }

    function verifyResponseBodyType(body) {
        if (typeof body != "string") {
            var error = new Error("Attempted to respond to fake XDomainRequest with " +
                                 body + ", which is not a string.");
            error.name = "InvalidBodyException";
            throw error;
        }
    }

    sinon.extend(FakeXDomainRequest.prototype, sinon.EventTarget, {
        open: function open(method, url) {
            this.method = method;
            this.url = url;

            this.responseText = null;
            this.sendFlag = false;

            this.readyStateChange(FakeXDomainRequest.OPENED);
        },

        readyStateChange: function readyStateChange(state) {
            this.readyState = state;
            var eventName = '';
            switch (this.readyState) {
                case FakeXDomainRequest.UNSENT:
                    break;
                case FakeXDomainRequest.OPENED:
                    break;
                case FakeXDomainRequest.LOADING:
                    if (this.sendFlag){
                        //raise the progress event
                        eventName = 'onprogress';
                    }
                    break;
                case FakeXDomainRequest.DONE:
                    if (this.errorFlag || (this.status < 200 || this.status > 299)) {
                        eventName = 'onerror';
                    }
                    else if (this.isTimeout){
                        eventName = 'ontimeout'
                    }
                    else {
                        eventName = 'onload'
                    }
                    break;
            }

            // raising event (if defined)
            if (eventName) {
                if (typeof this[eventName] == "function") {
                    try {
                        this[eventName]();
                    } catch (e) {
                        sinon.logError("Fake XHR " + eventName + " handler", e);
                    }
                }
            }
        },

        send: function send(data) {
            verifyState(this);

            if (!/^(get|head)$/i.test(this.method)) {
                this.requestBody = data;
            }

            this.errorFlag = false;
            this.sendFlag = true;
            this.readyStateChange(FakeXDomainRequest.OPENED);

            if (typeof this.onSend == "function") {
                this.onSend(this);
            }
        },

        abort: function abort() {
            this.aborted = true;
            this.responseText = null;
            this.errorFlag = true;

            if (this.readyState > sinon.FakeXDomainRequest.UNSENT && this.sendFlag) {
                this.readyStateChange(sinon.FakeXDomainRequest.DONE);
                this.sendFlag = false;
            }
        },
        setResponseBody: function setResponseBody(body) {
            verifyRequestSent(this);
            verifyResponseBodyType(body);

            var chunkSize = this.chunkSize || 10;
            var index = 0;
            this.responseText = "";

            do {
                this.readyStateChange(FakeXDomainRequest.LOADING);
                this.responseText += body.substring(index, index + chunkSize);
                index += chunkSize;
            } while (index < body.length);

            this.readyStateChange(FakeXDomainRequest.DONE);
        },

        respond: function respond(status, contentType, body) {
            // content-type ignored, since XDomainRequest does not carry this
            // we keep the same syntax for respond(...) as for FakeXMLHttpRequest to ease
            // test integration across browsers
            this.status = typeof status == "number" ? status : 200;
            this.setResponseBody(body || "");
        },
        simulatetimeout: function(){
            this.status = 0;
            this.isTimeout = true;
            this.setResponseBody("");
        }
    });

    sinon.extend(FakeXDomainRequest, {
        UNSENT: 0,
        OPENED: 1,
        LOADING: 3,
        DONE: 4
    });

    sinon.useFakeXDomainRequest = function () {
        sinon.FakeXDomainRequest.restore = function restore(keepOnCreate) {
            if (xdr.supportsXDR) {
                global.XDomainRequest = xdr.GlobalXDomainRequest;
            }

            delete sinon.FakeXDomainRequest.restore;

            if (keepOnCreate !== true) {
                delete sinon.FakeXDomainRequest.onCreate;
            }
        };
        if (xdr.supportsXDR) {
            global.XDomainRequest = sinon.FakeXDomainRequest;
        }
        return sinon.FakeXDomainRequest;
    };

    sinon.FakeXDomainRequest = FakeXDomainRequest;
})(this);

if (typeof module == "object" && typeof require == "function") {
    module.exports = sinon;
}
<commit_msg>XDomainRequest has content-type request header, even if always set to text/plain<commit_after>/**
 * @depend ../../sinon.js
 * @depend event.js
 */
/*jslint eqeqeq: false, onevar: false*/
/*global sinon, module, require, XDomainRequest*/
/**
 * Fake XDomainRequest object
 */
"use strict";

if (typeof sinon == "undefined") {
    this.sinon = {};
}
sinon.xdr = { XDomainRequest: this.XDomainRequest };

// wrapper for global
(function (global) {
    var xdr = sinon.xdr;
    xdr.GlobalXDomainRequest = global.XDomainRequest;
    xdr.supportsXDR = typeof xdr.GlobalXDomainRequest != "undefined";
    xdr.workingXDR = xdr.supportsXDR ? xdr.GlobalXDomainRequest :  false;

    function FakeXDomainRequest() {
        this.readyState = FakeXDomainRequest.UNSENT;
        this.requestBody = null;
        this.requestHeaders = {};
        this.status = 0;

        if (typeof FakeXDomainRequest.onCreate == "function") {
            FakeXDomainRequest.onCreate(this);
        }
    }

    function verifyState(xdr) {
        if (xdr.readyState !== FakeXDomainRequest.OPENED) {
            throw new Error("INVALID_STATE_ERR");
        }

        if (xdr.sendFlag) {
            throw new Error("INVALID_STATE_ERR");
        }
    }

    function verifyRequestSent(xdr) {
        if (xdr.readyState == FakeXDomainRequest.DONE) {
            throw new Error("Request done");
        }
    }

    function verifyResponseBodyType(body) {
        if (typeof body != "string") {
            var error = new Error("Attempted to respond to fake XDomainRequest with " +
                                 body + ", which is not a string.");
            error.name = "InvalidBodyException";
            throw error;
        }
    }

    sinon.extend(FakeXDomainRequest.prototype, sinon.EventTarget, {
        open: function open(method, url) {
            this.method = method;
            this.url = url;

            this.responseText = null;
            this.sendFlag = false;

            this.readyStateChange(FakeXDomainRequest.OPENED);
        },

        readyStateChange: function readyStateChange(state) {
            this.readyState = state;
            var eventName = '';
            switch (this.readyState) {
                case FakeXDomainRequest.UNSENT:
                    break;
                case FakeXDomainRequest.OPENED:
                    break;
                case FakeXDomainRequest.LOADING:
                    if (this.sendFlag){
                        //raise the progress event
                        eventName = 'onprogress';
                    }
                    break;
                case FakeXDomainRequest.DONE:
                    if (this.errorFlag || (this.status < 200 || this.status > 299)) {
                        eventName = 'onerror';
                    }
                    else if (this.isTimeout){
                        eventName = 'ontimeout'
                    }
                    else {
                        eventName = 'onload'
                    }
                    break;
            }

            // raising event (if defined)
            if (eventName) {
                if (typeof this[eventName] == "function") {
                    try {
                        this[eventName]();
                    } catch (e) {
                        sinon.logError("Fake XHR " + eventName + " handler", e);
                    }
                }
            }
        },

        send: function send(data) {
            verifyState(this);

            if (!/^(get|head)$/i.test(this.method)) {
                this.requestBody = data;
            }
            this.requestHeaders["Content-Type"] = "text/plain;charset=utf-8";

            this.errorFlag = false;
            this.sendFlag = true;
            this.readyStateChange(FakeXDomainRequest.OPENED);

            if (typeof this.onSend == "function") {
                this.onSend(this);
            }
        },

        abort: function abort() {
            this.aborted = true;
            this.responseText = null;
            this.errorFlag = true;

            if (this.readyState > sinon.FakeXDomainRequest.UNSENT && this.sendFlag) {
                this.readyStateChange(sinon.FakeXDomainRequest.DONE);
                this.sendFlag = false;
            }
        },
        setResponseBody: function setResponseBody(body) {
            verifyRequestSent(this);
            verifyResponseBodyType(body);

            var chunkSize = this.chunkSize || 10;
            var index = 0;
            this.responseText = "";

            do {
                this.readyStateChange(FakeXDomainRequest.LOADING);
                this.responseText += body.substring(index, index + chunkSize);
                index += chunkSize;
            } while (index < body.length);

            this.readyStateChange(FakeXDomainRequest.DONE);
        },

        respond: function respond(status, contentType, body) {
            // content-type ignored, since XDomainRequest does not carry this
            // we keep the same syntax for respond(...) as for FakeXMLHttpRequest to ease
            // test integration across browsers
            this.status = typeof status == "number" ? status : 200;
            this.setResponseBody(body || "");
        },
        simulatetimeout: function(){
            this.status = 0;
            this.isTimeout = true;
            this.setResponseBody("");
        }
    });

    sinon.extend(FakeXDomainRequest, {
        UNSENT: 0,
        OPENED: 1,
        LOADING: 3,
        DONE: 4
    });

    sinon.useFakeXDomainRequest = function () {
        sinon.FakeXDomainRequest.restore = function restore(keepOnCreate) {
            if (xdr.supportsXDR) {
                global.XDomainRequest = xdr.GlobalXDomainRequest;
            }

            delete sinon.FakeXDomainRequest.restore;

            if (keepOnCreate !== true) {
                delete sinon.FakeXDomainRequest.onCreate;
            }
        };
        if (xdr.supportsXDR) {
            global.XDomainRequest = sinon.FakeXDomainRequest;
        }
        return sinon.FakeXDomainRequest;
    };

    sinon.FakeXDomainRequest = FakeXDomainRequest;
})(this);

if (typeof module == "object" && typeof require == "function") {
    module.exports = sinon;
}
<|endoftext|>


<commit_before>'use strict';

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.makeTelegramDriver = makeTelegramDriver;

var _rx = require('rx');

var _rx2 = _interopRequireDefault(_rx);

var _ramda = require('ramda');

var _sources = require('./sources');

var _apiRequest = require('./api-request');

var _types = require('../types');

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

function makeEventsSelector(sources) {
  return function events(eventName) {
    var messageSources = {
      'message': sources.message.share()
    };

    var inlineQuerySources = {
      'inline_query': sources.inlineQuery.share(),
      'chosen_inline_result': sources.chosenInlineResult.share()
    };

    var callbackQuerySources = {
      'callback_query': sources.callbackQuery.share()
    };

    // return interface
    return _rx2.default.Observable.case(function () {
      return eventName;
    }, Object.assign({}, messageSources, inlineQuerySources, callbackQuerySources));
  };
}

var handleWebhook = function handleWebhook(token, request, action) {
  return request.mergeAll().filter(_types.WebhookResponse.is).map((0, _ramda.prop)('update')).subscribe(function (upd) {
    return action.onNext([upd]);
  }, function (err) {
    return console.error('request error: ', err);
  });
};

var handleRequest = function handleRequest(token, request) {
  return request.mergeAll().filter(_types.Request.is).flatMap(function (_ref) {
    var method = _ref.method;
    var query = _ref.options;
    return (0, _apiRequest.makeAPIRequest)({ token: token, method: method, query: query });
  });
};

function makeTelegramDriver(token) {
  var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];

  var state = {
    startDate: options.startDate || Date.now(),
    offset: 0,
    updates: []
  };

  var proxy = (0, _sources.makeUpdates)(state, token);
  var action = new _rx2.default.Subject();

  if (options.webhook) {
    proxy = (0, _sources.makeWebHook)(state, action);
  }

  var updates = proxy.doOnError(function (err) {
    return console.error('updates error: ', err);
  }).replay(null, 1);

  var sources = (0, _sources.makeSources)(updates);
  var disposable = updates.connect();

  return function telegramDriver(request) {
    // pass request
    if (options.webhook) {
      // handle webhook
      handleWebhook(token, request, action);
    }

    var newRequest = handleRequest(token, request).share();

    newRequest.subscribeOnError(function (err) {
      return console.error('request error: ', err);
    });

    // return interface
    return {
      token: token,
      observable: updates,
      responses: newRequest, // handle request
      events: makeEventsSelector(sources),
      dispose: function dispose() {
        return disposable.dispose();
      }
    };
  };
}<commit_msg>update lib<commit_after>'use strict';

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.makeTelegramDriver = makeTelegramDriver;

var _rx = require('rx');

var _rx2 = _interopRequireDefault(_rx);

var _ramda = require('ramda');

var _sources = require('./sources');

var _apiRequest = require('./api-request');

var _types = require('../types');

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

function makeEventsSelector(sources) {
  return function events(eventName) {
    var messageSources = {
      'message': sources.message.share()
    };

    var inlineQuerySources = {
      'inline_query': sources.inlineQuery.share(),
      'chosen_inline_result': sources.chosenInlineResult.share()
    };

    var callbackQuerySources = {
      'callback_query': sources.callbackQuery.share()
    };

    // return interface
    return _rx2.default.Observable.case(function () {
      return eventName;
    }, (0, _ramda.merge)({}, messageSources, inlineQuerySources, callbackQuerySources));
  };
}

var handleWebhook = function handleWebhook(token, request, action) {
  return request.mergeAll().filter(_types.WebhookResponse.is).map((0, _ramda.prop)('update')).subscribe(function (upd) {
    return action.onNext([upd]);
  }, function (err) {
    return console.error('request error: ', err);
  });
};

var handleRequest = function handleRequest(token, request) {
  return request.mergeAll().filter(_types.Request.is).flatMap(function (_ref) {
    var method = _ref.method;
    var query = _ref.options;
    return (0, _apiRequest.makeAPIRequest)({ token: token, method: method, query: query });
  });
};

function makeTelegramDriver(token) {
  var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];

  var state = {
    startDate: options.startDate || Date.now(),
    offset: 0,
    updates: []
  };

  var proxy = (0, _sources.makeUpdates)(state, token);
  var action = new _rx2.default.Subject();

  if (options.webhook) {
    proxy = (0, _sources.makeWebHook)(state, action);
  }

  var updates = proxy.doOnError(function (err) {
    return console.error('updates error: ', err);
  }).replay(null, 1);

  var sources = (0, _sources.makeSources)(updates);
  var disposable = updates.connect();

  return function telegramDriver(request) {
    // pass request
    if (options.webhook) {
      // handle webhook
      handleWebhook(token, request, action);
    }

    var newRequest = handleRequest(token, request).share();

    newRequest.subscribeOnError(function (err) {
      return console.error('request error: ', err);
    });

    // return interface
    return {
      token: token,
      observable: updates,
      responses: newRequest, // handle request
      events: makeEventsSelector(sources),
      dispose: function dispose() {
        return disposable.dispose();
      }
    };
  };
}<|endoftext|>


<commit_before>  var TAU = Math.PI*2;
  // min value to render a line.
  // it does not make sense to render a line of a width is not even visible
  var LINEWIDTH_MIN_VALUE = 0.05;

  function renderPoint(ctx, st) {
    ctx.fillStyle = st['marker-fill'];
    var pixel_size = st['marker-width'];

    // render a circle
    // TODO: fill and stroke order should depend on the order of the properties
    // in the cartocss.

    // fill
    ctx.beginPath();
    ctx.arc(0, 0, pixel_size, 0, TAU, true, true);
    ctx.closePath();
    if (st['marker-fill']) {
      if (st['marker-fill-opacity'] !== undefined || st['marker-opacity'] !== undefined) {
        ctx.globalAlpha = st['marker-fill-opacity'] || st['marker-opacity'];
      }
      ctx.fill();
    }

    // stroke
    ctx.globalAlpha = 1.0;
    if (st['marker-line-color'] && st['marker-line-width'] && st['marker-line-width'] > LINEWIDTH_MIN_VALUE) {
      if (st['marker-line-opacity'] !== undefined) {
        ctx.globalAlpha = st['marker-line-opacity'];
      }
      if (st['marker-line-width'] !== undefined) {
        ctx.lineWidth = st['marker-line-width'];
      }
      ctx.strokeStyle = st['marker-line-color'];

      // do not render for alpha = 0
      if (ctx.globalAlpha > 0) {
        ctx.stroke();
      }
    }
  }

  function renderRectangle(ctx, st) {
    ctx.fillStyle = st['marker-fill'];
    var pixel_size = st['marker-width'];
    var w = pixel_size * 2;

    // fill
    if (st['marker-fill']) {
      if (st['marker-fill-opacity'] !== undefined || st['marker-opacity'] !== undefined) {
        ctx.globalAlpha = st['marker-fill-opacity'] || st['marker-opacity'];
      }
      ctx.fillRect(-pixel_size, -pixel_size, w, w)
    }

    // stroke
    ctx.globalAlpha = 1.0;
    if (st['markker-line-color'] && st['marker-line-width']) {
      if (st['marker-line-opacity']) {
        ctx.globalAlpha = st['marker-line-opacity'];
      }
      if (st['marker-line-width']) {
        ctx.lineWidth = st['marker-line-width'];
      }
      ctx.strokeStyle = st['marker-line-color'];

      // do not render for alpha = 0
      if (ctx.globalAlpha > 0) {
        ctx.strokeRect(-pixel_size, -pixel_size, w, w)
      }
    }
  }

  function renderSprite(ctx, st) {
    var img = st['point-file'] || st['marker-file'];
    var ratio = img.height/img.width;
    var w = st['marker-width'] || img.width;
    var h = st['marker-width'] || st['marker-height'] || w*ratio;
    ctx.drawImage(img, 0, 0, w, h);
  }

module.exports = {
    renderPoint: renderPoint,
    renderSprite: renderSprite,
    renderRectangle: renderRectangle
};
<commit_msg>fixed property name<commit_after>  var TAU = Math.PI*2;
  // min value to render a line.
  // it does not make sense to render a line of a width is not even visible
  var LINEWIDTH_MIN_VALUE = 0.05;

  function renderPoint(ctx, st) {
    ctx.fillStyle = st['marker-fill'];
    var pixel_size = st['marker-width'];

    // render a circle
    // TODO: fill and stroke order should depend on the order of the properties
    // in the cartocss.

    // fill
    ctx.beginPath();
    ctx.arc(0, 0, pixel_size, 0, TAU, true, true);
    ctx.closePath();
    if (st['marker-fill']) {
      if (st['marker-fill-opacity'] !== undefined || st['marker-opacity'] !== undefined) {
        ctx.globalAlpha = st['marker-fill-opacity'] || st['marker-opacity'];
      }
      ctx.fill();
    }

    // stroke
    ctx.globalAlpha = 1.0;
    if (st['marker-line-color'] && st['marker-line-width'] && st['marker-line-width'] > LINEWIDTH_MIN_VALUE) {
      if (st['marker-line-opacity'] !== undefined) {
        ctx.globalAlpha = st['marker-line-opacity'];
      }
      if (st['marker-line-width'] !== undefined) {
        ctx.lineWidth = st['marker-line-width'];
      }
      ctx.strokeStyle = st['marker-line-color'];

      // do not render for alpha = 0
      if (ctx.globalAlpha > 0) {
        ctx.stroke();
      }
    }
  }

  function renderRectangle(ctx, st) {
    ctx.fillStyle = st['marker-fill'];
    var pixel_size = st['marker-width'];
    var w = pixel_size * 2;

    // fill
    if (st['marker-fill']) {
      if (st['marker-fill-opacity'] !== undefined || st['marker-opacity'] !== undefined) {
        ctx.globalAlpha = st['marker-fill-opacity'] || st['marker-opacity'];
      }
      ctx.fillRect(-pixel_size, -pixel_size, w, w)
    }

    // stroke
    ctx.globalAlpha = 1.0;
    if (st['marker-line-color'] && st['marker-line-width']) {
      if (st['marker-line-opacity']) {
        ctx.globalAlpha = st['marker-line-opacity'];
      }
      if (st['marker-line-width']) {
        ctx.lineWidth = st['marker-line-width'];
      }
      ctx.strokeStyle = st['marker-line-color'];

      // do not render for alpha = 0
      if (ctx.globalAlpha > 0) {
        ctx.strokeRect(-pixel_size, -pixel_size, w, w)
      }
    }
  }

  function renderSprite(ctx, st) {
    var img = st['point-file'] || st['marker-file'];
    var ratio = img.height/img.width;
    var w = st['marker-width'] || img.width;
    var h = st['marker-width'] || st['marker-height'] || w*ratio;
    ctx.drawImage(img, 0, 0, w, h);
  }

module.exports = {
    renderPoint: renderPoint,
    renderSprite: renderSprite,
    renderRectangle: renderRectangle
};
<|endoftext|>


<commit_before>var Montage = require("montage").Montage;

/**
 * This object represents the data necessary for a DataService to connect to it's data source
 * It formalizes a name and an authorization object, but leaves to RawDataServices the role
 * to specialize it in a way that reflects what they need.
 *
 * @class
 * @extends external:Montage
 */
exports.ConnectionDescriptor = Montage.specialize(/** @lends DataIdentifier.prototype */ {

    /**
     * The name of this descriptor
     *
     * @type {String}
     */
    name: {
        value: undefined
    },

    /**
     * The authorization obtained by a DataServie if any
     *
     * @type {Object}
     */
    authorization: {
        value: undefined
    }

});
<commit_msg>Adds connection-descriptor<commit_after>var Montage = require("montage").Montage;

/**
 * This object represents the data necessary for a DataService to connect to it's data source,
 * but leaves to RawDataServices the role
 * to specialize it in a way that reflects what they need.
 *
 * @class
 * @extends external:Montage
 */
exports.ConnectionDescriptor = Montage.specialize(/** @lends DataIdentifier.prototype */ {

    /**
     * The name of this descriptor
     *
     * @type {String}
     */
    name: {
        value: undefined
    }

});
<|endoftext|>


<commit_before>// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// MIT License. See license.txt

// My HTTP Request

frappe.provide('frappe.request');
frappe.request.url = '/';
frappe.request.ajax_count = 0;
frappe.request.waiting_for_ajax = [];

frappe.xcall = function(method, params) {
	return new Promise((resolve, reject) => {
		frappe.call({
			method: method,
			args: params,
			callback: (r) => {
				resolve(r.message);
			},
			error: (r) => {
				reject(r.message);
			}
		});
	});
};

// generic server call (call page, object)
frappe.call = function(opts) {
	if (!frappe.is_online()) {
		frappe.show_alert({
			indicator: 'orange',
			message: __('You are not connected to Internet. Retry after sometime.')
		}, 3);
		return;
	}
	if (typeof arguments[0]==='string') {
		opts = {
			method: arguments[0],
			args: arguments[1],
			callback: arguments[2],
			headers: arguments[3]
		}
	}

	if(opts.quiet) {
		opts.no_spinner = true;
	}
	var args = $.extend({}, opts.args);

	// cmd
	if(opts.module && opts.page) {
		args.cmd = opts.module+'.page.'+opts.page+'.'+opts.page+'.'+opts.method;
	} else if(opts.doc) {
		$.extend(args, {
			cmd: "runserverobj",
			docs: frappe.get_doc(opts.doc.doctype, opts.doc.name),
			method: opts.method,
			args: opts.args,
		});
	} else if(opts.method) {
		args.cmd = opts.method;
	}

	var callback = function(data, response_text) {
		if(data.task_id) {
			// async call, subscribe
			frappe.socketio.subscribe(data.task_id, opts);

			if(opts.queued) {
				opts.queued(data);
			}
		}
		else if (opts.callback) {
			// ajax
			return opts.callback(data, response_text);
		}
	}

	let url = opts.url;
	if (!url) {
		url = '/api/method/' + args.cmd;
		delete args.cmd;
	}

	return frappe.request.call({
		type: opts.type || "POST",
		args: args,
		success: callback,
		error: opts.error,
		always: opts.always,
		btn: opts.btn,
		freeze: opts.freeze,
		freeze_message: opts.freeze_message,
		headers: opts.headers || {},
		// show_spinner: !opts.no_spinner,
		async: opts.async,
		url,
	});
}

frappe.request.call = function(opts) {
	frappe.request.prepare(opts);

	var statusCode = {
		200: function(data, xhr) {
			opts.success_callback && opts.success_callback(data, xhr.responseText);
		},
		401: function(xhr) {
			if(frappe.app.session_expired_dialog && frappe.app.session_expired_dialog.display) {
				frappe.app.redirect_to_login();
			} else {
				frappe.app.handle_session_expired();
			}
		},
		404: function(xhr) {
			frappe.msgprint({title:__("Not found"), indicator:'red',
				message: __('The resource you are looking for is not available')});
		},
		403: function(xhr) {
			if (frappe.get_cookie('sid')==='Guest') {
				// session expired
				frappe.app.handle_session_expired();
			}
			else if(xhr.responseJSON && xhr.responseJSON._error_message) {
				frappe.msgprint({
					title:__("Not permitted"), indicator:'red',
					message: xhr.responseJSON._error_message
				});

				xhr.responseJSON._server_messages = null;
			}
			else if (xhr.responseJSON && xhr.responseJSON._server_messages) {
				var _server_messages = JSON.parse(xhr.responseJSON._server_messages);

				// avoid double messages
				if (_server_messages.indexOf(__("Not permitted"))!==-1) {
					return;
				}
			}
			else {
				frappe.msgprint({
					title:__("Not permitted"), indicator:'red',
					message: __('You do not have enough permissions to access this resource. Please contact your manager to get access.')});
			}

		},
		508: function(xhr) {
			frappe.utils.play_sound("error");
			frappe.msgprint({title:__('Please try again'), indicator:'red',
				message:__("Another transaction is blocking this one. Please try again in a few seconds.")});
		},
		413: function(data, xhr) {
			frappe.msgprint({indicator:'red', title:__('File too big'), message:__("File size exceeded the maximum allowed size of {0} MB",
				[(frappe.boot.max_file_size || 5242880) / 1048576])});
		},
		417: function(xhr) {
			var r = xhr.responseJSON;
			if (!r) {
				try {
					r = JSON.parse(xhr.responseText);
				} catch (e) {
					r = xhr.responseText;
				}
			}

			opts.error_callback && opts.error_callback(r);
		},
		501: function(data, xhr) {
			if(typeof data === "string") data = JSON.parse(data);
			opts.error_callback && opts.error_callback(data, xhr.responseText);
		},
		500: function(xhr) {
			frappe.utils.play_sound("error");
			try {
				opts.error_callback && opts.error_callback();
				frappe.request.report_error(xhr, opts);
			} catch (e) {
				frappe.request.report_error(xhr, opts);
			}
		},
		504: function(xhr) {
			frappe.msgprint(__("Request Timed Out"))
			opts.error_callback && opts.error_callback();
		},
		502: function(xhr) {
			frappe.msgprint(__("Internal Server Error"));
		}
	};

	var ajax_args = {
		url: opts.url || frappe.request.url,
		data: opts.args,
		type: opts.type,
		dataType: opts.dataType || 'json',
		async: opts.async,
		headers: Object.assign({
			"X-Frappe-CSRF-Token": frappe.csrf_token,
			"Accept": "application/json"
		}, opts.headers),
		cache: false
	};

	frappe.last_request = ajax_args.data;

	return $.ajax(ajax_args)
		.done(function(data, textStatus, xhr) {
			try {
				if(typeof data === "string") data = JSON.parse(data);

				// sync attached docs
				if(data.docs || data.docinfo) {
					frappe.model.sync(data);
				}

				// sync translated messages
				if(data.__messages) {
					$.extend(frappe._messages, data.__messages);
				}

				// callbacks
				var status_code_handler = statusCode[xhr.statusCode().status];
				if (status_code_handler) {
					status_code_handler(data, xhr);
				}
			} catch(e) {
				console.log("Unable to handle success response"); // eslint-disable-line
				console.trace(e); // eslint-disable-line
			}

		})
		.always(function(data, textStatus, xhr) {
			try {
				if(typeof data==="string") {
					data = JSON.parse(data);
				}
				if(data.responseText) {
					var xhr = data;
					data = JSON.parse(data.responseText);
				}
			} catch(e) {
				data = null;
				// pass
			}
			frappe.request.cleanup(opts, data);
			if(opts.always) {
				opts.always(data);
			}
		})
		.fail(function(xhr, textStatus) {
			try {
				var status_code_handler = statusCode[xhr.statusCode().status];
				if (status_code_handler) {
					status_code_handler(xhr);
				} else {
					// if not handled by error handler!
					opts.error_callback && opts.error_callback(xhr);
				}
			} catch(e) {
				console.log("Unable to handle failed response"); // eslint-disable-line
				console.trace(e); // eslint-disable-line
			}
		});
}

// call execute serverside request
frappe.request.prepare = function(opts) {
	$("body").attr("data-ajax-state", "triggered");

	// btn indicator
	if(opts.btn) $(opts.btn).prop("disabled", true);

	// freeze page
	if(opts.freeze) frappe.dom.freeze(opts.freeze_message);

	// stringify args if required
	for(var key in opts.args) {
		if(opts.args[key] && ($.isPlainObject(opts.args[key]) || $.isArray(opts.args[key]))) {
			opts.args[key] = JSON.stringify(opts.args[key]);
		}
	}

	// no cmd?
	if(!opts.args.cmd && !opts.url) {
		console.log(opts)
		throw "Incomplete Request";
	}

	opts.success_callback = opts.success;
	opts.error_callback = opts.error;
	delete opts.success;
	delete opts.error;

}

frappe.request.cleanup = function(opts, r) {
	// stop button indicator
	if(opts.btn) {
		$(opts.btn).prop("disabled", false);
	}

	$("body").attr("data-ajax-state", "complete");

	// un-freeze page
	if(opts.freeze) frappe.dom.unfreeze();

	if(r) {

		// session expired? - Guest has no business here!
		if(r.session_expired || frappe.get_cookie("sid")==="Guest") {
			frappe.app.handle_session_expired();
			return;
		}

		// show messages
		if(r._server_messages && !opts.silent) {
			r._server_messages = JSON.parse(r._server_messages);
			frappe.hide_msgprint();
			frappe.msgprint(r._server_messages);
		}

		// show errors
		if(r.exc) {
			r.exc = JSON.parse(r.exc);
			if(r.exc instanceof Array) {
				$.each(r.exc, function(i, v) {
					if(v) {
						console.log(v);
					}
				})
			} else {
				console.log(r.exc);
			}
		}

		// debug messages
		if(r._debug_messages) {
			if(opts.args) {
				console.log("======== arguments ========");
				console.log(opts.args);
				console.log("========")
			}
			$.each(JSON.parse(r._debug_messages), function(i, v) { console.log(v); });
			console.log("======== response ========");
			delete r._debug_messages;
			console.log(r);
			console.log("========");
		}
	}

	frappe.last_response = r;
}

frappe.after_server_call = () => {
	if(frappe.request.ajax_count) {
		return new Promise(resolve => {
			frappe.request.waiting_for_ajax.push(() => {
				resolve();
			});
		});
	} else {
		return null;
	}
};

frappe.after_ajax = function(fn) {
	return new Promise(resolve => {
		if(frappe.request.ajax_count) {
			frappe.request.waiting_for_ajax.push(() => {
				if(fn) fn();
				resolve();
			});
		} else {
			if(fn) fn();
			resolve();
		}
	});
};

frappe.request.report_error = function(xhr, request_opts) {
	var data = JSON.parse(xhr.responseText);
	if (data.exc) {
		var exc = (JSON.parse(data.exc) || []).join("\n");
		var locals = (JSON.parse(data.locals) || []).join("\n");
		delete data.exc;
		delete data.locals;
	} else {
		var exc = "";
		locals = "";
	}

	var show_communication = function() {
		var error_report_message = [
			'
Please type some additional information that could help us reproduce this issue:
',
			'

',
			'
',
			'
App Versions
',
			'
' + JSON.stringify(frappe.boot.versions, null, "\t") + '
',
			'
Route
',
			'
' + frappe.get_route_str() + '
',
			'
',
			'
Error Report
',
			'
' + exc + '
',
			'
',
			'
Request Data
',
			'
' + JSON.stringify(request_opts, null, "\t") + '
',
			'
',
			'
Response JSON
',
			'
' + JSON.stringify(data, null, '\t')+ '
'
		].join("\n");

		var communication_composer = new frappe.views.CommunicationComposer({
			subject: 'Error Report [' + frappe.datetime.nowdate() + ']',
			recipients: error_report_email,
			message: error_report_message,
			doc: {
				doctype: "User",
				name: frappe.session.user
			}
		});
		communication_composer.dialog.$wrapper.css("z-index", cint(msg_dialog.$wrapper.css("z-index")) + 1);
	}

	if (exc) {
		var error_report_email = (frappe.boot.error_report_email || []).join(", ");

		request_opts = frappe.request.cleanup_request_opts(request_opts);

		// window.msg_dialog = frappe.msgprint({message:error_message, indicator:'red', big: true});

		if (!frappe.error_dialog) {
			frappe.error_dialog = new frappe.ui.Dialog({
				title: 'Server Error',
				primary_action_label: __('Report'),
				primary_action: () => {
					if (error_report_email) {
						show_communication();
					} else {
						frappe.msgprint(__('Support Email Address Not Specified'));
					}
					frappe.error_dialog.hide();
				}
			});
			frappe.error_dialog.wrapper.classList.add('msgprint-dialog');

		}

		let parts = strip(exc).split('\n');

		frappe.error_dialog.$body.html(parts[parts.length - 1]);
		frappe.error_dialog.show();

	}
};

frappe.request.cleanup_request_opts = function(request_opts) {
	var doc = (request_opts.args || {}).doc;
	if (doc) {
		doc = JSON.parse(doc);
		$.each(Object.keys(doc), function(i, key) {
			if (key.indexOf("password")!==-1 && doc[key]) {
				// mask the password
				doc[key] = "*****";
			}
		});
		request_opts.args.doc = JSON.stringify(doc);
	}
	return request_opts;
};

$(document).ajaxSend(function() {
	frappe.request.ajax_count++;
});

$(document).ajaxComplete(function() {
	frappe.request.ajax_count--;
	if(!frappe.request.ajax_count) {
		$.each(frappe.request.waiting_for_ajax || [], function(i, fn) {
			fn();
		});
		frappe.request.waiting_for_ajax = [];
	}
});
<commit_msg>add frappe cmd and doctype in http header for better analytics and load balancing<commit_after>// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// MIT License. See license.txt

// My HTTP Request

frappe.provide('frappe.request');
frappe.request.url = '/';
frappe.request.ajax_count = 0;
frappe.request.waiting_for_ajax = [];

frappe.xcall = function(method, params) {
	return new Promise((resolve, reject) => {
		frappe.call({
			method: method,
			args: params,
			callback: (r) => {
				resolve(r.message);
			},
			error: (r) => {
				reject(r.message);
			}
		});
	});
};

// generic server call (call page, object)
frappe.call = function(opts) {
	if (!frappe.is_online()) {
		frappe.show_alert({
			indicator: 'orange',
			message: __('You are not connected to Internet. Retry after sometime.')
		}, 3);
		return;
	}
	if (typeof arguments[0]==='string') {
		opts = {
			method: arguments[0],
			args: arguments[1],
			callback: arguments[2],
			headers: arguments[3]
		}
	}

	if(opts.quiet) {
		opts.no_spinner = true;
	}
	var args = $.extend({}, opts.args);

	// cmd
	if(opts.module && opts.page) {
		args.cmd = opts.module+'.page.'+opts.page+'.'+opts.page+'.'+opts.method;
	} else if(opts.doc) {
		$.extend(args, {
			cmd: "runserverobj",
			docs: frappe.get_doc(opts.doc.doctype, opts.doc.name),
			method: opts.method,
			args: opts.args,
		});
	} else if(opts.method) {
		args.cmd = opts.method;
	}

	var callback = function(data, response_text) {
		if(data.task_id) {
			// async call, subscribe
			frappe.socketio.subscribe(data.task_id, opts);

			if(opts.queued) {
				opts.queued(data);
			}
		}
		else if (opts.callback) {
			// ajax
			return opts.callback(data, response_text);
		}
	}

	let url = opts.url;
	if (!url) {
		url = '/api/method/' + args.cmd;
		delete args.cmd;
	}

	return frappe.request.call({
		type: opts.type || "POST",
		args: args,
		success: callback,
		error: opts.error,
		always: opts.always,
		btn: opts.btn,
		freeze: opts.freeze,
		freeze_message: opts.freeze_message,
		headers: opts.headers || {},
		// show_spinner: !opts.no_spinner,
		async: opts.async,
		url,
	});
}

frappe.request.call = function(opts) {
	frappe.request.prepare(opts);

	var statusCode = {
		200: function(data, xhr) {
			opts.success_callback && opts.success_callback(data, xhr.responseText);
		},
		401: function(xhr) {
			if(frappe.app.session_expired_dialog && frappe.app.session_expired_dialog.display) {
				frappe.app.redirect_to_login();
			} else {
				frappe.app.handle_session_expired();
			}
		},
		404: function(xhr) {
			frappe.msgprint({title:__("Not found"), indicator:'red',
				message: __('The resource you are looking for is not available')});
		},
		403: function(xhr) {
			if (frappe.get_cookie('sid')==='Guest') {
				// session expired
				frappe.app.handle_session_expired();
			}
			else if(xhr.responseJSON && xhr.responseJSON._error_message) {
				frappe.msgprint({
					title:__("Not permitted"), indicator:'red',
					message: xhr.responseJSON._error_message
				});

				xhr.responseJSON._server_messages = null;
			}
			else if (xhr.responseJSON && xhr.responseJSON._server_messages) {
				var _server_messages = JSON.parse(xhr.responseJSON._server_messages);

				// avoid double messages
				if (_server_messages.indexOf(__("Not permitted"))!==-1) {
					return;
				}
			}
			else {
				frappe.msgprint({
					title:__("Not permitted"), indicator:'red',
					message: __('You do not have enough permissions to access this resource. Please contact your manager to get access.')});
			}

		},
		508: function(xhr) {
			frappe.utils.play_sound("error");
			frappe.msgprint({title:__('Please try again'), indicator:'red',
				message:__("Another transaction is blocking this one. Please try again in a few seconds.")});
		},
		413: function(data, xhr) {
			frappe.msgprint({indicator:'red', title:__('File too big'), message:__("File size exceeded the maximum allowed size of {0} MB",
				[(frappe.boot.max_file_size || 5242880) / 1048576])});
		},
		417: function(xhr) {
			var r = xhr.responseJSON;
			if (!r) {
				try {
					r = JSON.parse(xhr.responseText);
				} catch (e) {
					r = xhr.responseText;
				}
			}

			opts.error_callback && opts.error_callback(r);
		},
		501: function(data, xhr) {
			if(typeof data === "string") data = JSON.parse(data);
			opts.error_callback && opts.error_callback(data, xhr.responseText);
		},
		500: function(xhr) {
			frappe.utils.play_sound("error");
			try {
				opts.error_callback && opts.error_callback();
				frappe.request.report_error(xhr, opts);
			} catch (e) {
				frappe.request.report_error(xhr, opts);
			}
		},
		504: function(xhr) {
			frappe.msgprint(__("Request Timed Out"))
			opts.error_callback && opts.error_callback();
		},
		502: function(xhr) {
			frappe.msgprint(__("Internal Server Error"));
		}
	};

	var ajax_args = {
		url: opts.url || frappe.request.url,
		data: opts.args,
		type: opts.type,
		dataType: opts.dataType || 'json',
		async: opts.async,
		headers: Object.assign({
			"X-Frappe-CSRF-Token": frappe.csrf_token,
			"Accept": "application/json",
			"X-Frappe-CMD": (opts.args && opts.args.cmd  || '') || ''
		}, opts.headers),
		cache: false
	};

	if (opts.args && opts.args.doctype) {
		ajax_args.headers["X-Frappe-Doctype"] = opts.args.doctype;
	}

	frappe.last_request = ajax_args.data;

	return $.ajax(ajax_args)
		.done(function(data, textStatus, xhr) {
			try {
				if(typeof data === "string") data = JSON.parse(data);

				// sync attached docs
				if(data.docs || data.docinfo) {
					frappe.model.sync(data);
				}

				// sync translated messages
				if(data.__messages) {
					$.extend(frappe._messages, data.__messages);
				}

				// callbacks
				var status_code_handler = statusCode[xhr.statusCode().status];
				if (status_code_handler) {
					status_code_handler(data, xhr);
				}
			} catch(e) {
				console.log("Unable to handle success response"); // eslint-disable-line
				console.trace(e); // eslint-disable-line
			}

		})
		.always(function(data, textStatus, xhr) {
			try {
				if(typeof data==="string") {
					data = JSON.parse(data);
				}
				if(data.responseText) {
					var xhr = data;
					data = JSON.parse(data.responseText);
				}
			} catch(e) {
				data = null;
				// pass
			}
			frappe.request.cleanup(opts, data);
			if(opts.always) {
				opts.always(data);
			}
		})
		.fail(function(xhr, textStatus) {
			try {
				var status_code_handler = statusCode[xhr.statusCode().status];
				if (status_code_handler) {
					status_code_handler(xhr);
				} else {
					// if not handled by error handler!
					opts.error_callback && opts.error_callback(xhr);
				}
			} catch(e) {
				console.log("Unable to handle failed response"); // eslint-disable-line
				console.trace(e); // eslint-disable-line
			}
		});
}

// call execute serverside request
frappe.request.prepare = function(opts) {
	$("body").attr("data-ajax-state", "triggered");

	// btn indicator
	if(opts.btn) $(opts.btn).prop("disabled", true);

	// freeze page
	if(opts.freeze) frappe.dom.freeze(opts.freeze_message);

	// stringify args if required
	for(var key in opts.args) {
		if(opts.args[key] && ($.isPlainObject(opts.args[key]) || $.isArray(opts.args[key]))) {
			opts.args[key] = JSON.stringify(opts.args[key]);
		}
	}

	// no cmd?
	if(!opts.args.cmd && !opts.url) {
		console.log(opts)
		throw "Incomplete Request";
	}

	opts.success_callback = opts.success;
	opts.error_callback = opts.error;
	delete opts.success;
	delete opts.error;

}

frappe.request.cleanup = function(opts, r) {
	// stop button indicator
	if(opts.btn) {
		$(opts.btn).prop("disabled", false);
	}

	$("body").attr("data-ajax-state", "complete");

	// un-freeze page
	if(opts.freeze) frappe.dom.unfreeze();

	if(r) {

		// session expired? - Guest has no business here!
		if(r.session_expired || frappe.get_cookie("sid")==="Guest") {
			frappe.app.handle_session_expired();
			return;
		}

		// show messages
		if(r._server_messages && !opts.silent) {
			r._server_messages = JSON.parse(r._server_messages);
			frappe.hide_msgprint();
			frappe.msgprint(r._server_messages);
		}

		// show errors
		if(r.exc) {
			r.exc = JSON.parse(r.exc);
			if(r.exc instanceof Array) {
				$.each(r.exc, function(i, v) {
					if(v) {
						console.log(v);
					}
				})
			} else {
				console.log(r.exc);
			}
		}

		// debug messages
		if(r._debug_messages) {
			if(opts.args) {
				console.log("======== arguments ========");
				console.log(opts.args);
				console.log("========")
			}
			$.each(JSON.parse(r._debug_messages), function(i, v) { console.log(v); });
			console.log("======== response ========");
			delete r._debug_messages;
			console.log(r);
			console.log("========");
		}
	}

	frappe.last_response = r;
}

frappe.after_server_call = () => {
	if(frappe.request.ajax_count) {
		return new Promise(resolve => {
			frappe.request.waiting_for_ajax.push(() => {
				resolve();
			});
		});
	} else {
		return null;
	}
};

frappe.after_ajax = function(fn) {
	return new Promise(resolve => {
		if(frappe.request.ajax_count) {
			frappe.request.waiting_for_ajax.push(() => {
				if(fn) fn();
				resolve();
			});
		} else {
			if(fn) fn();
			resolve();
		}
	});
};

frappe.request.report_error = function(xhr, request_opts) {
	var data = JSON.parse(xhr.responseText);
	if (data.exc) {
		var exc = (JSON.parse(data.exc) || []).join("\n");
		var locals = (JSON.parse(data.locals) || []).join("\n");
		delete data.exc;
		delete data.locals;
	} else {
		var exc = "";
		locals = "";
	}

	var show_communication = function() {
		var error_report_message = [
			'
Please type some additional information that could help us reproduce this issue:
',
			'

',
			'
',
			'
App Versions
',
			'
' + JSON.stringify(frappe.boot.versions, null, "\t") + '
',
			'
Route
',
			'
' + frappe.get_route_str() + '
',
			'
',
			'
Error Report
',
			'
' + exc + '
',
			'
',
			'
Request Data
',
			'
' + JSON.stringify(request_opts, null, "\t") + '
',
			'
',
			'
Response JSON
',
			'
' + JSON.stringify(data, null, '\t')+ '
'
		].join("\n");

		var communication_composer = new frappe.views.CommunicationComposer({
			subject: 'Error Report [' + frappe.datetime.nowdate() + ']',
			recipients: error_report_email,
			message: error_report_message,
			doc: {
				doctype: "User",
				name: frappe.session.user
			}
		});
		communication_composer.dialog.$wrapper.css("z-index", cint(msg_dialog.$wrapper.css("z-index")) + 1);
	}

	if (exc) {
		var error_report_email = (frappe.boot.error_report_email || []).join(", ");

		request_opts = frappe.request.cleanup_request_opts(request_opts);

		// window.msg_dialog = frappe.msgprint({message:error_message, indicator:'red', big: true});

		if (!frappe.error_dialog) {
			frappe.error_dialog = new frappe.ui.Dialog({
				title: 'Server Error',
				primary_action_label: __('Report'),
				primary_action: () => {
					if (error_report_email) {
						show_communication();
					} else {
						frappe.msgprint(__('Support Email Address Not Specified'));
					}
					frappe.error_dialog.hide();
				}
			});
			frappe.error_dialog.wrapper.classList.add('msgprint-dialog');

		}

		let parts = strip(exc).split('\n');

		frappe.error_dialog.$body.html(parts[parts.length - 1]);
		frappe.error_dialog.show();

	}
};

frappe.request.cleanup_request_opts = function(request_opts) {
	var doc = (request_opts.args || {}).doc;
	if (doc) {
		doc = JSON.parse(doc);
		$.each(Object.keys(doc), function(i, key) {
			if (key.indexOf("password")!==-1 && doc[key]) {
				// mask the password
				doc[key] = "*****";
			}
		});
		request_opts.args.doc = JSON.stringify(doc);
	}
	return request_opts;
};

$(document).ajaxSend(function() {
	frappe.request.ajax_count++;
});

$(document).ajaxComplete(function() {
	frappe.request.ajax_count--;
	if(!frappe.request.ajax_count) {
		$.each(frappe.request.waiting_for_ajax || [], function(i, fn) {
			fn();
		});
		frappe.request.waiting_for_ajax = [];
	}
});
<|endoftext|>


<commit_before>Pipes = {
    handleResults : function(data) {
        var list = $(".results ul");
        $(".results span.total").text(data.size);
        $.each(data.items, function(idx, item){
            $("<li/>").addClass("list-group-item").text(item).appendTo(list);
        });
    },
    retrievePipePath : function() {
        path = document.location.pathname;
        return path.substring(0, path.indexOf(".html"));
    },
    emptyResultsList : function(data) {
            $( ".list-group-item" ).remove();
    }
};

$(document).ready(function(){
    $.getJSON(Pipes.retrievePipePath() + ".json").then(Pipes.handleResults);
    $('#select').val('slingPipes/base');
    $('.typeSelect').hide();
    $( ".divselector" ).each(function() {
        var value=$(this).parents('.subpipe').children('span').eq(1).children('.typeInput').text();
        $(this).children().val(value);
    });
    $.getJSON(Pipes.retrievePipePath() + ".json").then(Pipes.handleResults);
    $(".collapse").hide();
    $("#sideButton").click(function () {
       $(".collapse").toggle();
    });
});

<commit_msg>front is breaking when no result (#36)<commit_after>Pipes = {
    handleResults : function(data) {
        var list = $(".results ul");
        $(".results span.total").text(data.size);
        if (data.items){
            $.each(data.items, function(idx, item){
                $("<li/>").addClass("list-group-item").text(item).appendTo(list);
            });
        }
    },
    retrievePipePath : function() {
        path = document.location.pathname;
        return path.substring(0, path.indexOf(".html"));
    },
    emptyResultsList : function(data) {
            $( ".list-group-item" ).remove();
    }
};

$(document).ready(function(){
    $.getJSON(Pipes.retrievePipePath() + ".json").then(Pipes.handleResults);
    $('#select').val('slingPipes/base');
    $('.typeSelect').hide();
    $( ".divselector" ).each(function() {
        var value=$(this).parents('.subpipe').children('span').eq(1).children('.typeInput').text();
        $(this).children().val(value);
    });
    $.getJSON(Pipes.retrievePipePath() + ".json").then(Pipes.handleResults);
    $(".collapse").hide();
    $("#sideButton").click(function () {
       $(".collapse").toggle();
    });
});

<|endoftext|>