<commit_before>// Backbone.Router
// -------------------

var _ = require('underscore');
var Events = require('timoxley-backbone-events');
var History = require('spini-backbone-history');

// Routers map faux-URLs to actions, and fire events when routes are
// matched. Creating a new one sets its `routes` hash, if not set statically.
var Router = module.exports = function(options) {
  options || (options = {});
  if (options.routes) this.routes = options.routes;
  this._bindRoutes();
  this.initialize.apply(this, arguments);
};

// Cached regular expressions for matching named param parts and splatted
// parts of route strings.
var namedParam    = /:\w+/g;
var splatParam    = /\*\w+/g;
var escapeRegExp  = /[-[\]{}()+?.,\\^$|#\s]/g;

// Set up all inheritable **Backbone.Router** properties and methods.
_.extend(Router.prototype, Events, {

  // Initialize is an empty function by default. Override it with your own
  // initialization logic.
  initialize: function(){},

  // Manually bind a single named route to a callback. For example:
  //
  //     this.route('search/:query/p:num', 'search', function(query, num) {
  //       ...
  //     });
  //
  route: function(route, name, callback) {
    Backbone = Backbone || {};
    Backbone.history || (Backbone.history = new History);
    if (!_.isRegExp(route)) route = this._routeToRegExp(route);
    if (!callback) callback = this[name];
    Backbone.history.route(route, _.bind(function(fragment) {
      var args = this._extractParameters(route, fragment);
      callback && callback.apply(this, args);
      this.trigger.apply(this, ['route:' + name].concat(args));
      Backbone.history.trigger('route', this, name, args);
    }, this));
    return this;
  },

  // Simple proxy to `Backbone.history` to save a fragment into the history.
  navigate: function(fragment, options) {
    Backbone.history.navigate(fragment, options);
  },

  // Bind all defined routes to `Backbone.history`. We have to reverse the
  // order of the routes here to support behavior where the most general
  // routes can be defined at the bottom of the route map.
  _bindRoutes: function() {
    if (!this.routes) return;
    var routes = [];
    for (var route in this.routes) {
      routes.unshift([route, this.routes[route]]);
    }
    for (var i = 0, l = routes.length; i < l; i++) {
      this.route(routes[i][0], routes[i][1], this[routes[i][1]]);
    }
  },

  // Convert a route string into a regular expression, suitable for matching
  // against the current location hash.
  _routeToRegExp: function(route) {
    route = route.replace(escapeRegExp, '\\$&')
                 .replace(namedParam, '([^\/]+)')
                 .replace(splatParam, '(.*?)');
    return new RegExp('^' + route + '$');
  },

  // Given a route, and a URL fragment that it matches, return the array of
  // extracted parameters.
  _extractParameters: function(route, fragment) {
    return route.exec(fragment).slice(1);
  }

});

// Helpers
// -------

// Helper function to correctly set up the prototype chain, for subclasses.
// Similar to `goog.inherits`, but uses a hash of prototype properties and
// class properties to be extended.
var extend = function(protoProps, staticProps) {
  var parent = this;
  var child;

  // The constructor function for the new subclass is either defined by you
  // (the "constructor" property in your `extend` definition), or defaulted
  // by us to simply call the parent's constructor.
  if (protoProps && _.has(protoProps, 'constructor')) {
    child = protoProps.constructor;
  } else {
    child = function(){ parent.apply(this, arguments); };
  }

  // Add static properties to the constructor function, if supplied.
  _.extend(child, parent, staticProps);

  // Set the prototype chain to inherit from `parent`, without calling
  // `parent`'s constructor function.
  var Surrogate = function(){ this.constructor = child; };
  Surrogate.prototype = parent.prototype;
  child.prototype = new Surrogate;

  // Add prototype properties (instance properties) to the subclass,
  // if supplied.
  if (protoProps) _.extend(child.prototype, protoProps);

  // Set a convenience property in case the parent's prototype is needed
  // later.
  child.__super__ = parent.prototype;

  return child;
};

module.exports.extend = extend;
<commit_msg>understanding require<commit_after>// Backbone.Router
// -------------------

var _ = require('underscore');
var Events = require('backbone-events');
var History = require('backbone-history');

// Routers map faux-URLs to actions, and fire events when routes are
// matched. Creating a new one sets its `routes` hash, if not set statically.
var Router = module.exports = function(options) {
  options || (options = {});
  if (options.routes) this.routes = options.routes;
  this._bindRoutes();
  this.initialize.apply(this, arguments);
};

// Cached regular expressions for matching named param parts and splatted
// parts of route strings.
var namedParam    = /:\w+/g;
var splatParam    = /\*\w+/g;
var escapeRegExp  = /[-[\]{}()+?.,\\^$|#\s]/g;

// Set up all inheritable **Backbone.Router** properties and methods.
_.extend(Router.prototype, Events, {

  // Initialize is an empty function by default. Override it with your own
  // initialization logic.
  initialize: function(){},

  // Manually bind a single named route to a callback. For example:
  //
  //     this.route('search/:query/p:num', 'search', function(query, num) {
  //       ...
  //     });
  //
  route: function(route, name, callback) {
    Backbone = Backbone || {};
    Backbone.history || (Backbone.history = new History);
    if (!_.isRegExp(route)) route = this._routeToRegExp(route);
    if (!callback) callback = this[name];
    Backbone.history.route(route, _.bind(function(fragment) {
      var args = this._extractParameters(route, fragment);
      callback && callback.apply(this, args);
      this.trigger.apply(this, ['route:' + name].concat(args));
      Backbone.history.trigger('route', this, name, args);
    }, this));
    return this;
  },

  // Simple proxy to `Backbone.history` to save a fragment into the history.
  navigate: function(fragment, options) {
    Backbone.history.navigate(fragment, options);
  },

  // Bind all defined routes to `Backbone.history`. We have to reverse the
  // order of the routes here to support behavior where the most general
  // routes can be defined at the bottom of the route map.
  _bindRoutes: function() {
    if (!this.routes) return;
    var routes = [];
    for (var route in this.routes) {
      routes.unshift([route, this.routes[route]]);
    }
    for (var i = 0, l = routes.length; i < l; i++) {
      this.route(routes[i][0], routes[i][1], this[routes[i][1]]);
    }
  },

  // Convert a route string into a regular expression, suitable for matching
  // against the current location hash.
  _routeToRegExp: function(route) {
    route = route.replace(escapeRegExp, '\\$&')
                 .replace(namedParam, '([^\/]+)')
                 .replace(splatParam, '(.*?)');
    return new RegExp('^' + route + '$');
  },

  // Given a route, and a URL fragment that it matches, return the array of
  // extracted parameters.
  _extractParameters: function(route, fragment) {
    return route.exec(fragment).slice(1);
  }

});

// Helpers
// -------

// Helper function to correctly set up the prototype chain, for subclasses.
// Similar to `goog.inherits`, but uses a hash of prototype properties and
// class properties to be extended.
var extend = function(protoProps, staticProps) {
  var parent = this;
  var child;

  // The constructor function for the new subclass is either defined by you
  // (the "constructor" property in your `extend` definition), or defaulted
  // by us to simply call the parent's constructor.
  if (protoProps && _.has(protoProps, 'constructor')) {
    child = protoProps.constructor;
  } else {
    child = function(){ parent.apply(this, arguments); };
  }

  // Add static properties to the constructor function, if supplied.
  _.extend(child, parent, staticProps);

  // Set the prototype chain to inherit from `parent`, without calling
  // `parent`'s constructor function.
  var Surrogate = function(){ this.constructor = child; };
  Surrogate.prototype = parent.prototype;
  child.prototype = new Surrogate;

  // Add prototype properties (instance properties) to the subclass,
  // if supplied.
  if (protoProps) _.extend(child.prototype, protoProps);

  // Set a convenience property in case the parent's prototype is needed
  // later.
  child.__super__ = parent.prototype;

  return child;
};

module.exports.extend = extend;
<|endoftext|>


<commit_before>'use strict';

const Promise = require('bluebird');
const upyun = require('upyun');
const urlParse = require('url').parse;
const moment = require('moment');
const util = require('util');
const BaseAdapter = require('ghost-storage-base');

class UpyunAdapter extends BaseAdapter {
  constructor(options) {
    super(options);
    this.options = options || {};
    this.client = new upyun.Client(new upyun.Bucket(this.options.bucket, this.options.operator, this.options.password));
  }

  /**
   * Saves the image to storage
   * - image is the express image object
   * - returns a promise which ultimately returns the full url to the uploaded image
   *
   * @param file
   * @param targetDir
   * @returns {*}
   */
  save(file, targetDir) {
    const client = this.client;
    const _this = this;

    return new Promise(function(resolve, reject) {
      const remotePath = _this.getRemotePath(file);
      const remoteDomain = _this.options.domain;
      client.putFile(remotePath, file.path).then(function (result) {
        if (_this.options.imageVersion !== undefined) {
          resolve(remoteDomain + remotePath + _this.options.imageVersion);
        } else {
          resolve(remoteDomain + remotePath);
        }
      }, function (error) {
        reject('[' + result.data.code + '] ' + result.data.msg);
      })
    });
  }

  /**
   * don't need it in Upyun
   * @param filename
   * @param targetDir
   * @returns {*|bluebird}
   * TODO: if fileKey option set, should use key to check file whether exists
   */
  exists(filename, targetDir) {
    return new Promise(function(resolve, reject) {
      resolve(false);
    });
  }

  // middleware for serving the files
  serve() {
    // a no-op, these are absolute URLs
    return function(req, res, next) {
      next();
    };
  }

  /**
   * Not implemented.
   * @description not really delete from Upyun, may be implemented later
   * @param fileName
   * @param targetDir
   * @returns {*|bluebird}
   */
  delete(fileName, targetDir) {
    // return Promise.reject('not implemented');
    return new Promise(function(resolve, reject) {
      resolve(true);
    });
  }

  /**
   * Reads bytes from Upyun for a target image
   *
   * @param options
   */
  read(options) {
    options = options || {};

    const client = this.client;
    const key = urlParse(options.path).pathname.slice(1);

    return new Promise(function(resolve, reject) {
      client.getFile(key).then(function (result) {
        resolve(result);
      }, function (error) {
        reject('Could not read image');
      })
    });
  }

  getRemotePath(image) {
    const folder = moment().format(this.options.folder || 'YYYY/MM/').replace(/^\//, '');

    return '/' + this.options.prefix + folder + image.name;
  }
}

module.exports = UpyunAdapter;
<commit_msg>Promise bug fixed<commit_after>'use strict';

const Promise = require('bluebird');
const upyun = require('upyun');
const urlParse = require('url').parse;
const moment = require('moment');
const util = require('util');
const BaseAdapter = require('ghost-storage-base');

class UpyunAdapter extends BaseAdapter {
  constructor(options) {
    super(options);
    this.options = options || {};
    const bucket = new upyun.Bucket(this.options.bucket, this.options.operator, this.options.password);
    this.client = new upyun.Client(bucket);
  }

  /**
   * Saves the image to storage
   * - image is the express image object
   * - returns a promise which ultimately returns the full url to the uploaded image
   *
   * @param file
   * @param targetDir
   * @returns {*}
   */
  save(file, targetDir) {
    const client = this.client;
    const _this = this;

    return new Promise(function(resolve, reject) {
      const remotePath = _this.getRemotePath(file);
      const remoteDomain = _this.options.domain;
      client.putFile(remotePath, file.path).then(function(result) {
        if (_this.options.imageVersion !== undefined) {
          resolve(remoteDomain + remotePath + _this.options.imageVersion);
        } else {
          resolve(remoteDomain + remotePath);
        }
      }).catch(function(error) {
        reject('[' + result.data.code + '] ' + result.data.msg);
      });
    });
  }

  /**
   * don't need it in Upyun
   * @param filename
   * @param targetDir
   * @returns {*|bluebird}
   * TODO: if fileKey option set, should use key to check file whether exists
   */
  exists(filename, targetDir) {
    return new Promise(function(resolve, reject) {
      resolve(false);
    });
  }

  // middleware for serving the files
  serve() {
    // a no-op, these are absolute URLs
    return function(req, res, next) {
      next();
    };
  }

  /**
   * Not implemented.
   * @description not really delete from Upyun, may be implemented later
   * @param fileName
   * @param targetDir
   * @returns {*|bluebird}
   */
  delete(fileName, targetDir) {
    // return Promise.reject('not implemented');
    return new Promise(function(resolve, reject) {
      resolve(true);
    });
  }

  /**
   * Reads bytes from Upyun for a target image
   *
   * @param options
   */
  read(options) {
    options = options || {};

    const client = this.client;
    const key = urlParse(options.path).pathname.slice(1);

    return new Promise(function(resolve, reject) {
      client.getFile(key).then(function(result) {
        resolve(result);
      }).catch(function(error) {
        reject('Could not read image');
      });
    });
  }

  getRemotePath(image) {
    const folder = moment().format(this.options.folder || 'YYYY/MM/').replace(/^\//, '');

    return '/' + this.options.prefix + folder + image.name;
  }
}

module.exports = UpyunAdapter;
<|endoftext|>


<commit_before>/* dynamic xformat helper for timelines */
var xFormatter = function(xAxis, xextent) {
    var cWidth = document.body.clientWidth;
    //console.log("Xaxis extent diff, client width", xextent[1] - xextent[0], document.body.clientWidth);

    // Reduce numer of ticks if small amount of pixels available
    var widthFactor = 1;
    if(cWidth < 700) {
        widthFactor = 2;
    }else if(cWidth < 500) {
        widthFactor = 3;
    }

    var xdiff = xextent[1] - xextent[0];
    if (xdiff >= 3628800000) { // a monthish
        xAxis.ticks(d3.time.months, 1*widthFactor).tickFormat(d3.time.format('%d.%m'));
    }
    else if (xdiff >= 2674800000) { // a monthish
        //xAxis.ticks(d3.time.months, 1).tickFormat(d3.time.format('%b %Y'));
        xAxis.ticks(d3.time.days, 9*widthFactor).tickFormat(d3.time.format('%d.%m'));
    }
    else if (xdiff >= 345600000) { // a weekish
        //xAxis.ticks(d3.time.months, 1).tickFormat(d3.time.format('%b %Y'));
        xAxis.ticks(d3.time.hours, 24*widthFactor).tickFormat(d3.time.format('%d.%m'));
    }
    else if (xdiff >= 100800000) { // 3 days
        xAxis.ticks(d3.time.hours, 6*widthFactor).tickFormat(d3.time.format('%a %H'));
    }
    else {
        xAxis.ticks(d3.time.hours, 1*widthFactor).tickFormat(d3.time.format('%H'));
    }
}

// Helps out with the bars
var bartender = function(target, key, legend, width, height) {
    // Fetch new json data
    d3.json("/api/max?key="+key, function(source) {

        valfmt = function(d) { return d.val }
        if (key == 'temp') {
            valfmt = function(d) {
                return rivets.formatters.temp(d.val)
            }
        }
        else if (key == 'rain') {
            valfmt = function(d) {
                return rivets.formatters.rain(d.val)
            }
        }
        else if (key == 'windspeed') {
            valfmt = function(d) {
                return rivets.formatters.wind(d.val)
            }
        }
        else if (key == 'wind') {
            valfmt = function(d) {
                return rivets.formatters.wind(d.val)
            }
        }
        drawbars(target, source, key, null, valfmt, legend, width, height);
    });

}

var draw = function(source) {
    gsource = source;
    //console.log('Current dataset', source);
    /* First remove any existing svg */
    /* Remove any spinners */
    $('.svgholder').empty();

    // The date format of SQL
    var parseDate = d3.time.format("%Y-%m-%d %H:%M:%S").parse;

    // Add d3 js date for each datum
    source.forEach(function(d) {
        d.date = parseDate(d.datetime);
        // also fix wind speed to be in m/s
        d.windspeed = d.windspeed/3.6;
        d.windgust = d.windgust/3.6;
    });
    var width = $('#main').css('width').split('px')[0];
    var height = width/4;

    /* Line graphs */
    var tempgraph = temprain('#temp', source, width, height);
    // Less height for less important graphs
    var height = width/4;
    /*
    drawlines('#pressure', source, 'barometer','Air pressure (hPa)', width, height);
    drawlines('#wind', source, 'windspeed', 'Wind speed m/s', width, height);
    /* Disable rain graph as it is part of temp graph now
    drawlines('#rain', source, 'rain','Daily rain (mm)', width, height);
    drawlines('#winddir', source, 'winddir','Wind direction (°)', width, height);
    //drawlines('#humidity', source, 'outhumidity','Humidity (%)', width, height);

    */
    var vals = ['windspeed', 'windgust', 'outhumidity', 'winddir', 'rain', 'barometer', 'inhumidity', 'intemp', 'outtemp', 'dewpoint', 'heatindex', 'windchill'];
    d3.select('#graphtabs ul.nav-tabs').selectAll('li')
        .data(vals)
      .enter().append('li')
        .classed('active', function(d,i) {
            if (i == 0) {
                return true;
            }
            return false;
        }
        )
        .html(function(d, i) {
            return ''+d.charAt(0).toUpperCase() + d.substr(1).toLowerCase()+''
        });
    d3.select('#graphtabs .tab-content').selectAll('div')
        .data(vals)
      .enter().append('div')
        .classed('tab-pane', true)
        .classed('active', function(d,i) {
            if (i == 0) {
                return true;
            }
            return false;
        }
        )
        .attr('id', function(d,i) { return 'tab_graph_'+d; })
        .html(function(d, i) {
            return '

';
        });
    vals.forEach(function(k,v) {
        if(source[0][k] != undefined && source[0][k] != NaN && source[0][k] != null) {
            d3.select("#graphtabs .svgholder."+k)
            .datum(source)
            .call(timeSeriesChart()
                .width(width)
                .height(height)
                .x(function(d) { return d.date; })
                .y(function(d) { return +d[k]; }));
        }
    });

    /* Bar graphs */
    /*
    bartender('#rain', 'rain', 'Daily Rain', width, height);
    bartender('#temp', 'temp', 'Daily Max Temp', width, height);
    bartender('#wind', 'windspeed', 'Daily Max Wind', width, height);
    */

    // Get the last element and populate rivets bindings with it
    rivets.bind(document.getElementById('main'), {
        current: source.slice(-1)[0],
        first: source.slice(0)[0]
    });
}

/* Container for assorted helpers */
var amatyrlib = function() {
    this.that = this;
    that = this;
    this.addGradient = function(target, w, h) {
        /*
        var gradient = target.append("svg:defs")
          .append("svg:linearGradient")
            .attr("id", "gradient")
            .attr("x1", "0%")
            .attr("y1", "0%")
            .attr("x2", "0%")
            .attr("y2", "100%")
            .attr("spreadMethod", "pad");

        gradient.append("svg:stop")
            .attr("offset", "0%")
            .attr("stop-color", "#fafafa")
            .attr("stop-opacity", 1);

        gradient.append("svg:stop")
            .attr("offset", "100%")
            .attr("stop-color", "#f0f0f0")
            .attr("stop-opacity", 1);
*/

        target.append("svg:rect")
            .attr("width", w)
            .attr("height", h)
            .style("fill", "url(#myLinearGradient1)");
    }
    /* Pad helper */
    Number.prototype.pad = function (len) {
            return (new Array(len+1).join("0") + this).slice(-len);
    }

    /* Rivets formatters */
    rivets.formatters.temp = function(value) {
        if(!value)
            return '';
        if (value != undefined)
            return Number((value).toFixed(1))+ ' °C';
    }
    rivets.formatters.pressure = function(value) {
        if (value)
            return Number((value).toFixed(1)) + ' hPa';
    }
    rivets.formatters.rain = function(value) {
        if(value)
            return Number((value).toFixed(1)) + ' mm';
        return '0 mm';
    }
    rivets.formatters.wind = function(value) {
        if (value)
            return Number(value/3.6).toFixed(1) + ' m/s';
        return '0 m/s'
    }
    rivets.formatters.degree = function(value) {
        if (value)
            return Number((value).toFixed(1)) + ' °';
        return '0 °';
    }
    rivets.formatters.percent = function(value) {
        if (value)
            return Number((value).toFixed(0)) + ' %';
        return '0%'
    }
    rivets.formatters.rotate = function(value) {
        return 'display:inline-block;-o-transform: rotate('+value+'deg);-ms-transform: rotate('+value+'deg);-moz-transform: rotate('+value+'deg);-webkit-transform: rotate('+value+'deg);transform: rotate('+value+'deg);'
    }
    rivets.formatters.date = function(date) {
        var parseDate = d3.time.format("%Y-%m-%d %H:%M:%S").parse;
        var date = parseDate(date);
        return date.getHours().pad(2) + ':' + date.getMinutes().pad(2);
    }

    /* Configure Rivets to work with Watch JS */
    rivets.configure({
        adapter: {
            subscribe: function(obj, keypath, callback) {
                watch(obj, keypath, callback)
            },
            unsubscribe: function(obj, keypath, callback) {
                unwatch(obj, keypath, callback)
            },
            read: function(obj, keypath) {
                return obj[keypath]
            },
            publish: function(obj, keypath, value) {
                obj[keypath] = value
            }
        }
    });

    /* Formatter helper */
    this.autoformat = function(name, value) {
        var parseDate = d3.time.format("%Y-%m-%d %H:%M:%S").parse;
        if (name == 'datetime') {
            var date = parseDate(value);
            return date.getMonth().pad(2) + '.' + date.getDate().pad(2);
        }
        if (name == 'dayrain') {
            var val = Number((Number(value)).toFixed(0)).pad(1) + ' mm';
            if (val == "0 mm") {
                return '0 mm';
            }
            return val;
        }
        if (name == 'outtemp') {
            var val = Number((value).toFixed(1));
            var color;
            if (val < 0) {
                color = 'steelblue';
            }else {
                color = 'red';
            }
            return ''+val+ ' °C';
        }
        if (name == 'windspeed')
            return rivets.formatters.wind(value);
        if (name == 'winddir')
            return Number((value).toFixed(0)).pad(3) + ' °';

        return value;
    }

    /* Create a custom rivets binder that looks into data changed and transitions the update in data with colorful updating depending on if the value decreased or increase.

     It expects data in the following form
       float unit
       eg. -2.9 hPa
     and will only look at the value
    */
    rivets.binders.texttransition = function(el, value) {
        var newVal, oldVal, transitonTime = 5*1000, color;
        if (value != null) {
            newVal = parseFloat(value.split(' ')[0]);
            if (el.textContent != null) {
                var val = parseFloat(el.textContent.split(' ')[0]);
                if (val != NaN) {
                    oldVal = val;
                }
            }
        }
        if(oldVal > newVal) {
            // Value decrease, we show this as red
            color = '#b5152b';
        }else if (oldVal < newVal) {
            // Value increase, we show this as green
            color = '#5c8843';
        }
        // Animate if color
        if (color) {
            // There
            d3.select(el.parentNode).transition()
                .style('background-color', color)
                .duration(transitonTime);
            d3.select(el)
                .classed('trans', true)
            // And back again
            d3.select(el.parentNode).transition()
                .style('background-color', 'inherit')
                .duration(transitonTime)
                .delay(transitonTime);
            // remove trans class for font styling
            setTimeout(function() {
                d3.select(el)
                .classed('trans', false)
            }, transitonTime);
        }
        if (el.innerText != null) {
            return el.innerText = value != null ? value : '';
        } else {
            return el.textContent = value != null ? value : '';
        }
    }
    return this;
}
<commit_msg>Use arrow instead of text for wind direction column<commit_after>/* dynamic xformat helper for timelines */
var xFormatter = function(xAxis, xextent) {
    var cWidth = document.body.clientWidth;
    //console.log("Xaxis extent diff, client width", xextent[1] - xextent[0], document.body.clientWidth);

    // Reduce numer of ticks if small amount of pixels available
    var widthFactor = 1;
    if(cWidth < 700) {
        widthFactor = 2;
    }else if(cWidth < 500) {
        widthFactor = 3;
    }

    var xdiff = xextent[1] - xextent[0];
    if (xdiff >= 3628800000) { // a monthish
        xAxis.ticks(d3.time.months, 1*widthFactor).tickFormat(d3.time.format('%d.%m'));
    }
    else if (xdiff >= 2674800000) { // a monthish
        //xAxis.ticks(d3.time.months, 1).tickFormat(d3.time.format('%b %Y'));
        xAxis.ticks(d3.time.days, 9*widthFactor).tickFormat(d3.time.format('%d.%m'));
    }
    else if (xdiff >= 345600000) { // a weekish
        //xAxis.ticks(d3.time.months, 1).tickFormat(d3.time.format('%b %Y'));
        xAxis.ticks(d3.time.hours, 24*widthFactor).tickFormat(d3.time.format('%d.%m'));
    }
    else if (xdiff >= 100800000) { // 3 days
        xAxis.ticks(d3.time.hours, 6*widthFactor).tickFormat(d3.time.format('%a %H'));
    }
    else {
        xAxis.ticks(d3.time.hours, 1*widthFactor).tickFormat(d3.time.format('%H'));
    }
}

// Helps out with the bars
var bartender = function(target, key, legend, width, height) {
    // Fetch new json data
    d3.json("/api/max?key="+key, function(source) {

        valfmt = function(d) { return d.val }
        if (key == 'temp') {
            valfmt = function(d) {
                return rivets.formatters.temp(d.val)
            }
        }
        else if (key == 'rain') {
            valfmt = function(d) {
                return rivets.formatters.rain(d.val)
            }
        }
        else if (key == 'windspeed') {
            valfmt = function(d) {
                return rivets.formatters.wind(d.val)
            }
        }
        else if (key == 'wind') {
            valfmt = function(d) {
                return rivets.formatters.wind(d.val)
            }
        }
        drawbars(target, source, key, null, valfmt, legend, width, height);
    });

}

var draw = function(source) {
    gsource = source;
    //console.log('Current dataset', source);
    /* First remove any existing svg */
    /* Remove any spinners */
    $('.svgholder').empty();

    // The date format of SQL
    var parseDate = d3.time.format("%Y-%m-%d %H:%M:%S").parse;

    // Add d3 js date for each datum
    source.forEach(function(d) {
        d.date = parseDate(d.datetime);
        // also fix wind speed to be in m/s
        d.windspeed = d.windspeed/3.6;
        d.windgust = d.windgust/3.6;
    });
    var width = $('#main').css('width').split('px')[0];
    var height = width/4;

    /* Line graphs */
    var tempgraph = temprain('#temp', source, width, height);
    // Less height for less important graphs
    var height = width/4;
    /*
    drawlines('#pressure', source, 'barometer','Air pressure (hPa)', width, height);
    drawlines('#wind', source, 'windspeed', 'Wind speed m/s', width, height);
    /* Disable rain graph as it is part of temp graph now
    drawlines('#rain', source, 'rain','Daily rain (mm)', width, height);
    drawlines('#winddir', source, 'winddir','Wind direction (°)', width, height);
    //drawlines('#humidity', source, 'outhumidity','Humidity (%)', width, height);

    */
    var vals = ['windspeed', 'windgust', 'outhumidity', 'winddir', 'rain', 'barometer', 'inhumidity', 'intemp', 'outtemp', 'dewpoint', 'heatindex', 'windchill'];
    d3.select('#graphtabs ul.nav-tabs').selectAll('li')
        .data(vals)
      .enter().append('li')
        .classed('active', function(d,i) {
            if (i == 0) {
                return true;
            }
            return false;
        }
        )
        .html(function(d, i) {
            return ''+d.charAt(0).toUpperCase() + d.substr(1).toLowerCase()+''
        });
    d3.select('#graphtabs .tab-content').selectAll('div')
        .data(vals)
      .enter().append('div')
        .classed('tab-pane', true)
        .classed('active', function(d,i) {
            if (i == 0) {
                return true;
            }
            return false;
        }
        )
        .attr('id', function(d,i) { return 'tab_graph_'+d; })
        .html(function(d, i) {
            return '

';
        });
    vals.forEach(function(k,v) {
        if(source[0][k] != undefined && source[0][k] != NaN && source[0][k] != null) {
            d3.select("#graphtabs .svgholder."+k)
            .datum(source)
            .call(timeSeriesChart()
                .width(width)
                .height(height)
                .x(function(d) { return d.date; })
                .y(function(d) { return +d[k]; }));
        }
    });

    /* Bar graphs */
    /*
    bartender('#rain', 'rain', 'Daily Rain', width, height);
    bartender('#temp', 'temp', 'Daily Max Temp', width, height);
    bartender('#wind', 'windspeed', 'Daily Max Wind', width, height);
    */

    // Get the last element and populate rivets bindings with it
    rivets.bind(document.getElementById('main'), {
        current: source.slice(-1)[0],
        first: source.slice(0)[0]
    });
}

/* Container for assorted helpers */
var amatyrlib = function() {
    this.that = this;
    that = this;
    this.addGradient = function(target, w, h) {
        /*
        var gradient = target.append("svg:defs")
          .append("svg:linearGradient")
            .attr("id", "gradient")
            .attr("x1", "0%")
            .attr("y1", "0%")
            .attr("x2", "0%")
            .attr("y2", "100%")
            .attr("spreadMethod", "pad");

        gradient.append("svg:stop")
            .attr("offset", "0%")
            .attr("stop-color", "#fafafa")
            .attr("stop-opacity", 1);

        gradient.append("svg:stop")
            .attr("offset", "100%")
            .attr("stop-color", "#f0f0f0")
            .attr("stop-opacity", 1);
*/

        target.append("svg:rect")
            .attr("width", w)
            .attr("height", h)
            .style("fill", "url(#myLinearGradient1)");
    }
    /* Pad helper */
    Number.prototype.pad = function (len) {
            return (new Array(len+1).join("0") + this).slice(-len);
    }

    /* Rivets formatters */
    rivets.formatters.temp = function(value) {
        if(!value)
            return '';
        if (value != undefined)
            return Number((value).toFixed(1))+ ' °C';
    }
    rivets.formatters.pressure = function(value) {
        if (value)
            return Number((value).toFixed(1)) + ' hPa';
    }
    rivets.formatters.rain = function(value) {
        if(value)
            return Number((value).toFixed(1)) + ' mm';
        return '0 mm';
    }
    rivets.formatters.wind = function(value) {
        if (value)
            return Number(value/3.6).toFixed(1) + ' m/s';
        return '0 m/s'
    }
    rivets.formatters.degree = function(value) {
        if (value)
            return Number((value).toFixed(1)) + ' °';
        return '0 °';
    }
    rivets.formatters.percent = function(value) {
        if (value)
            return Number((value).toFixed(0)) + ' %';
        return '0%'
    }
    rivets.formatters.rotate = function(value) {
        return 'display:inline-block;-o-transform: rotate('+value+'deg);-ms-transform: rotate('+value+'deg);-moz-transform: rotate('+value+'deg);-webkit-transform: rotate('+value+'deg);transform: rotate('+value+'deg);'
    }
    rivets.formatters.date = function(date) {
        var parseDate = d3.time.format("%Y-%m-%d %H:%M:%S").parse;
        var date = parseDate(date);
        return date.getHours().pad(2) + ':' + date.getMinutes().pad(2);
    }

    /* Configure Rivets to work with Watch JS */
    rivets.configure({
        adapter: {
            subscribe: function(obj, keypath, callback) {
                watch(obj, keypath, callback)
            },
            unsubscribe: function(obj, keypath, callback) {
                unwatch(obj, keypath, callback)
            },
            read: function(obj, keypath) {
                return obj[keypath]
            },
            publish: function(obj, keypath, value) {
                obj[keypath] = value
            }
        }
    });

    /* Formatter helper */
    this.autoformat = function(name, value) {
        var parseDate = d3.time.format("%Y-%m-%d %H:%M:%S").parse;
        if (name == 'datetime') {
            var date = parseDate(value);
            return date.getMonth().pad(2) + '.' + date.getDate().pad(2);
        }
        if (name == 'dayrain') {
            var val = Number((Number(value)).toFixed(0)).pad(1) + ' mm';
            if (val == "0 mm") {
                return '0 mm';
            }
            return val;
        }
        if (name == 'outtemp') {
            var val = Number((value).toFixed(1));
            var color;
            if (val < 0) {
                color = 'steelblue';
            }else {
                color = 'red';
            }
            return ''+val+ ' °C';
        }
        if (name == 'windspeed')
            return rivets.formatters.wind(value);
        if (name == 'winddir') {
            var degree = Number((value).toFixed(0))
            return '';
        }

        return value;
    }

    /* Create a custom rivets binder that looks into data changed and transitions the update in data with colorful updating depending on if the value decreased or increase.

     It expects data in the following form
       float unit
       eg. -2.9 hPa
     and will only look at the value
    */
    rivets.binders.texttransition = function(el, value) {
        var newVal, oldVal, transitonTime = 5*1000, color;
        if (value != null) {
            newVal = parseFloat(value.split(' ')[0]);
            if (el.textContent != null) {
                var val = parseFloat(el.textContent.split(' ')[0]);
                if (val != NaN) {
                    oldVal = val;
                }
            }
        }
        if(oldVal > newVal) {
            // Value decrease, we show this as red
            color = '#b5152b';
        }else if (oldVal < newVal) {
            // Value increase, we show this as green
            color = '#5c8843';
        }
        // Animate if color
        if (color) {
            // There
            d3.select(el.parentNode).transition()
                .style('background-color', color)
                .duration(transitonTime);
            d3.select(el)
                .classed('trans', true)
            // And back again
            d3.select(el.parentNode).transition()
                .style('background-color', 'inherit')
                .duration(transitonTime)
                .delay(transitonTime);
            // remove trans class for font styling
            setTimeout(function() {
                d3.select(el)
                .classed('trans', false)
            }, transitonTime);
        }
        if (el.innerText != null) {
            return el.innerText = value != null ? value : '';
        } else {
            return el.textContent = value != null ? value : '';
        }
    }
    return this;
}
<|endoftext|>


<commit_before>'use strict'

var request = require('request')
var resolveURL = require('url').resolve

var P = (typeof Promise === 'undefined') ? require('es6-promise').Promise : Promise

module.exports = APIHTTP

function APIHTTP (baseURL, options) {
  if (!(this instanceof APIHTTP)) {
    // If `new` was not used:
    return new APIHTTP(baseURL, options)
  }

  if (typeof baseURL === 'object') {
    options = baseURL
    baseURL = options.baseURL
  }

  options = options || {}

  this.baseURL = baseURL

  if (options.baseURL) this.baseURL = options.baseURL
  if (options.error) this.error = options.error
  if (options.success) this.success = options.success
  if (options.headers) this.headers = options.headers

  if (options.Promise) this.Promise = options.promise
  if (options.accessToken) this.accessToken = options.accessToken
}

var proto = APIHTTP.prototype

// Allow promise library to be overriden
proto.Promise = P

proto.headers = function () {
  if (this.accessToken) {
    return {
      Authorization: 'Bearer ' + this.accessToken
    }
  }
  return {}
}

proto.token = function (accessToken) {
  var newClient = Object.create(this)
  newClient.accessToken = accessToken
  return newClient
}

proto.error = function (res) {
  var message = res.body.message || res.body.msg
  var name = res.body.name
  var code = res.body.code

  if (res.body.error) {
    var errData = res.body.error
    message = message || errData.error_user_msg || errData.message
    name = name || errData.type || errData.name
    code = code || errData.code
  }

  if (typeof res.body === 'string') message = res.body

  var error = new Error(message)

  // Detected parameters:
  error.name = name
  error.code = code

  // Response parameters:
  error.status = res.statusCode
  error.data = res.body

  throw error
}

proto.success = function (res) {
  return res.body
}

proto.request = function (method, path, body, query) {
  var self = this

  var url = resolveURL(this.baseURL || '/', path)
  var headers = this.headers()

  return new this.Promise(function (resolve, reject) {
    request({
      headers: headers,
      method: method,
      url: url,
      qs: query,
      json: true,
      body: body
    }, function (err, res, responseBody) {
      if (err) return reject(err)
      resolve(
        self.Promise.resolve()
        .then(function () {
          if (res.statusCode >= 400) {
            return self.error(res)
          } else {
            return self.success(res)
          }
        })
      )
    })
  })
}

// Methods without body:
var methodsWithoutBody = ['get', 'delete', 'head']
methodsWithoutBody.forEach(function (method) {
  proto[method] = function (path, query) {
    return this.request(method, path, null, query)
  }
})

// Other Methods:
require('methods').forEach(function (method) {
  if (proto[method]) return
  proto[method] = function (path, body, query) {
    return this.request(method, path, body, query)
  }
})
<commit_msg>Fix bug<commit_after>'use strict'

var request = require('request')
var resolveURL = require('url').resolve

var P = (typeof Promise === 'undefined') ? require('es6-promise').Promise : Promise

module.exports = APIHTTP

function APIHTTP (baseURL, options) {
  if (!(this instanceof APIHTTP)) {
    // If `new` was not used:
    return new APIHTTP(baseURL, options)
  }

  if (typeof baseURL === 'object') {
    options = baseURL
    baseURL = options.baseURL
  }

  options = options || {}

  this.baseURL = baseURL

  if (options.baseURL) this.baseURL = options.baseURL
  if (options.error) this.error = options.error
  if (options.success) this.success = options.success
  if (options.headers) this.headers = options.headers

  if (options.Promise) this.Promise = options.promise
  if (options.accessToken) this.accessToken = options.accessToken
}

var proto = APIHTTP.prototype

// Allow promise library to be overriden
proto.Promise = P

proto.headers = function () {
  if (this.accessToken) {
    return {
      Authorization: 'Bearer ' + this.accessToken
    }
  }
  return {}
}

proto.token = function (accessToken) {
  var newClient = Object.create(this)
  newClient.accessToken = accessToken
  return newClient
}

proto.error = function (res) {
  var message = res.body.message || res.body.msg
  var name = res.body.name
  var code = res.body.code

  if (res.body.error) {
    var errData = res.body.error
    message = message || errData.error_user_msg || errData.message
    name = name || errData.type || errData.name
    code = code || errData.code
  }

  if (typeof res.body === 'string') message = res.body

  var error = new Error(message)

  // Detected parameters:
  error.name = name
  error.code = code

  // Response parameters:
  error.status = res.statusCode
  error.data = res.body

  throw error
}

proto.success = function (res) {
  return res.body
}

proto.request = function (method, path, body, query) {
  var self = this

  var url = resolveURL(this.baseURL || '/', path)
  var headers = this.headers()

  return new this.Promise(function (resolve, reject) {
    request({
      headers: headers,
      method: method,
      url: url,
      qs: query,
      json: true,
      body: body
    }, function (err, res, responseBody) {
      if (err) return reject(err)
      resolve(
        self.Promise.resolve()
        .then(function () {
          if (res.statusCode >= 400) {
            return self.error(res)
          } else {
            return self.success(res)
          }
        })
      )
    })
  })
}

// Methods without body:
var methodsWithoutBody = ['get', 'delete', 'head']
methodsWithoutBody.forEach(function (method) {
  proto[method] = function (path, query) {
    return this.request(method, path, undefined, query)
  }
})

// Other Methods:
require('methods').forEach(function (method) {
  if (proto[method]) return
  proto[method] = function (path, body, query) {
    return this.request(method, path, body, query)
  }
})
<|endoftext|>


<commit_before>/*
    Color Picker: Classic : 2011/02/26
    ---------------------------------------
    http://www.colorjack.com/opensource/dhtml+color+picker.html

    Native support:  Firefox 2+, Safari 3+, Opera 9+, Google Chrome, IE9+

    This color picker is dual licenced under Creative Commons & GPL.
*/

if(window.Color == undefined) Color = {};

Color.Picker = function (props) {

    /// loading properties
    if (typeof(props) == "undefined") props = {};
    this.callback = props.callback; // bind custom function
    this.hue = props.hue || 0; // 0-360
    this.sat = props.sat || 0; // 0-100
    this.val = props.val || 100; // 0-100
    this.element = props.element || document.body;
    this.size = props.size || 165; // size of colorpicker
    this.margin = 10; // margins on colorpicker
    this.offset = this.margin / 2;
    this.hueWidth = 30;

    /// creating colorpicker (header)
    var plugin = document.createElement("div");
    plugin.id = "colorjack_square";
    plugin.style.cssText = "height: " + (this.size + this.margin * 2) + "px";
    plugin.style.cssText+= ";width:" + (this.size + this.margin + this.hueWidth) + "px";

    // shows current selected color as the background of this box
    var hexBox = document.createElement("div");
    hexBox.className = "hexBox";
    plugin.appendChild(hexBox);

    // shows current selected color as HEX string
    var hexString = document.createElement("div");
    hexString.className = "hexString";
    plugin.appendChild(hexString);

    // close the plugin
    /*var hexClose = document.createElement("div");
    hexClose.className = "hexClose";
    hexClose.textContent = "X";
    hexClose.onclick = function () { // close colorpicker
	plugin.style.display = (plugin.style.display == "none") ? "block" : "none";
    };
    plugin.appendChild(hexClose);
    plugin.appendChild(document.createElement("br"));*/

    /// creating media-resources
    var arrows = document.createElement("canvas");
    arrows.width = 40;
    arrows.height = 5;
    (function () { // creating arrows
	var ctx = arrows.getContext("2d");
	var width = 3;
	var height = 5;
	var size = 9;
	var top = -size / 4;
	var left = 1;
	for (var n = 0; n < 20; n++) { // multiply anti-aliasing
	    ctx.beginPath();
	    ctx.fillStyle = "#FFF";
	    ctx.moveTo(left + size / 4, size / 2 + top);
	    ctx.lineTo(left, size / 4 + top);
	    ctx.lineTo(left, size / 4 * 3 + top);
	    ctx.fill();
	}
	ctx.translate(width, height);
	ctx.rotate(180 * Math.PI / 180); // rotate arrows
	ctx.drawImage(arrows, -29, 0);
	ctx.translate(-width, -height);
    })();

    var circle = document.createElement("canvas");
    circle.width = 10;
    circle.height = 10;
    (function () { // creating circle-selection
	var ctx = circle.getContext("2d");
	ctx.lineWidth = 1;
	ctx.beginPath();
	var x = circle.width / 2;
	var y = circle.width / 2;
	ctx.arc(x, y, 4.5, 0, Math.PI * 2, true);
	ctx.strokeStyle = '#000';
	ctx.stroke();
	ctx.beginPath();
	ctx.arc(x, y, 3.5, 0, Math.PI * 2, true);
	ctx.strokeStyle = '#FFF';
	ctx.stroke();
    })();

    /// creating colorpicker sliders
    var canvas = document.createElement("canvas");
    var ctx = canvas.getContext("2d");
    canvas.style.cssText = "position: absolute; top: 19px; left: " + (this.offset) + "px;";
    canvas.width = this.size + this.hueWidth + this.margin;
    canvas.height = this.size + this.margin;
    plugin.appendChild(canvas);
    plugin.onmousemove =
    plugin.onmousedown = function (e) {
	var down = (e.type == "mousedown");
	var offset = that.margin / 2;
	var abs = abPos(canvas);
	var x0 = (e.pageX - abs.x) - offset;
	var y0 = (e.pageY - abs.y) - offset;
	var x = clamp(x0, 0, canvas.width);
	var y = clamp(y0, 0, that.size);
	if (e.target.className == "hexString") {
	    plugin.style.cursor = "text";
	    return; // allow selection of HEX
	}/* else if (x != x0 || y != y0) { // move colorpicker
	    plugin.style.cursor = "move";
	    if (down) dragElement({
		type: "difference",
		event: e,
		element: plugin,
		callback: function (coords, state) {
		    plugin.style.left = coords.x + "px";
		    plugin.style.top = coords.y + "px";
		}
	    });
	}*/ else if (x <= that.size) { // saturation-value selection
	    plugin.style.cursor = "crosshair";
	    if (down) dragElement({
		type: "relative",
		event: e,
		element: canvas,
		callback: function (coords, state) {
		    var x = clamp(coords.x - that.offset, 0, that.size);
		    var y = clamp(coords.y - that.offset, 0, that.size);
		    that.sat = x / that.size * 100; // scale saturation
		    that.val = 100 - (y / that.size * 100); // scale value
		    that.drawSample();
		}
	    });
	} else if (x > that.size + that.margin && x <= that.size + that.hueWidth) { // hue selection
	    plugin.style.cursor = "crosshair";
	    if (down) dragElement({
		type: "relative",
		event: e,
		element: canvas,
		callback: function (coords, state) {
		    var y = clamp(coords.y - that.offset, 0, that.size);
		    that.hue = Math.min(1, y / that.size) * 360;
		    that.drawSample();
		}
	    });
	} else { // margin between hue/saturation-value
	    plugin.style.cursor = "default";
	}
	return false; // prevent selection
    };
    // appending to element
    this.element.appendChild(plugin);

    /// helper functions
    var that = this;
    this.el = plugin;
    this.drawSample = function () {
	// clearing canvas
	ctx.clearRect(0, 0, canvas.width, canvas.height)
	that.drawSquare();
	that.drawHue();
	// retrieving hex-code
	var hex = Color.HSV_HEX({
	    H: that.hue,
	    S: that.sat,
	    V: that.val
	});
	// display hex string
	hexString.textContent = hex.toUpperCase();
	// display background color
	hexBox.style.backgroundColor = "#" + hex;
	// arrow-selection
	var y = (that.hue / 362) * that.size - 2;
	ctx.drawImage(arrows, that.size + that.offset + 4, Math.round(y) + that.offset);
	// circle-selection
	var x = that.sat / 100 * that.size;
	var y = (1 - (that.val / 100)) * that.size;
	x = x - circle.width / 2;
	y = y - circle.height / 2;
	ctx.drawImage(circle, Math.round(x) + that.offset, Math.round(y) + that.offset);
	// run custom code
	if (that.callback) that.callback(hex);
    };

    this.drawSquare = function () {
	// retrieving hex-code
	var hex = Color.HSV_HEX({
	    H: that.hue,
	    S: 100,
	    V: 100
	});
	var offset = that.offset;
	var size = that.size;
	// drawing color
	ctx.fillStyle = "#" + hex;
	ctx.fillRect(offset, offset, size, size);
	// overlaying saturation
	var gradient = ctx.createLinearGradient(offset, offset, size + offset, 0);
	gradient.addColorStop(0, "rgba(255, 255, 255, 1)");
	gradient.addColorStop(1, "rgba(255, 255, 255, 0)");
	ctx.fillStyle = gradient;
	ctx.fillRect(offset, offset, size, size);
	// overlaying value
	var gradient = ctx.createLinearGradient(offset, offset, 0, size + offset);
	gradient.addColorStop(0, "rgba(0, 0, 0, 0)");
	gradient.addColorStop(1, "rgba(0, 0, 0, 1)");
	ctx.fillStyle = gradient;
	ctx.fillRect(offset, offset, size, size);
	// drawing outer bounds
	ctx.strokeStyle = "rgba(255,255,255,0.15)";
	ctx.strokeRect(offset+0.5, offset+0.5, size-1, size-1);
    };

    this.drawHue = function () {
	// drawing hue selector
	var left = that.size + that.margin + that.offset;
	var gradient = ctx.createLinearGradient(0, 0, 0, that.size);
	gradient.addColorStop(0, "rgba(255, 0, 0, 1)");
	gradient.addColorStop(0.15, "rgba(255, 255, 0, 1)");
	gradient.addColorStop(0.3, "rgba(0, 255, 0, 1)");
	gradient.addColorStop(0.5, "rgba(0, 255, 255, 1)");
	gradient.addColorStop(0.65, "rgba(0, 0, 255, 1)");
	gradient.addColorStop(0.8, "rgba(255, 0, 255, 1)");
	gradient.addColorStop(1, "rgba(255, 0, 0, 1)");
	ctx.fillStyle = gradient;
	ctx.fillRect(left, that.offset, 20, that.size);
	// drawing outer bounds
	ctx.strokeStyle = "rgba(255,255,255,0.2)";
	ctx.strokeRect(left + 0.5, that.offset + 0.5, 19, that.size-1);
    };

    this.destory = function () {
	document.body.removeChild(plugin);
	for (var key in that) delete that[key];
    };

    // drawing color selection
    this.drawSample();

    return this;
};

/* GLOBALS LIBRARY */

var dragElement = function(props) {
    function mouseMove(e, state) {
	if (typeof(state) == "undefined") state = "move";
	var coord = XY(e);
	switch (props.type) {
	    case "difference":
		props.callback({
		    x: coord.x + oX - eX,
		    y: coord.y + oY - eY
		}, state);
		break;
	    case "relative":
		props.callback({
		    x: coord.x - oX,
		    y: coord.y - oY
		}, state);
		break;
	    default: // "absolute"
		props.callback({
		    x: coord.x,
		    y: coord.y
		}, state);
		break;
	}
    };
    function mouseUp(e) {
	window.removeEventListener("mousemove", mouseMove, false);
	window.removeEventListener("mouseup", mouseUp, false);
	mouseMove(e, "up");
    };
    // current element position
    var el = props.element;
    var origin = abPos(el);
    var oX = origin.x;
    var oY = origin.y;
    // current mouse position
    var e = props.event;
    var coord = XY(e);
    var eX = coord.x;
    var eY = coord.y;
    // events
    window.addEventListener("mousemove", mouseMove, false);
    window.addEventListener("mouseup", mouseUp, false);
    mouseMove(e, "down"); // run mouse-down
};

var clamp = function(n, min, max) {
    return (n < min) ? min : ((n > max) ? max : n);
};

var XY = window.ActiveXObject ? // fix XY to work in various browsers
    function(event) {
	return {
	    x: event.clientX + document.documentElement.scrollLeft,
	    y: event.clientY + document.documentElement.scrollTop
	};
    } : function(event) {
	return {
	    x: event.pageX,
	    y: event.pageY
	};
    };

var abPos = function(o) {
    o = typeof(o) == 'object' ? o : $(o);
    var offset = { x: 0, y: 0 };
    while(o != null) {
	offset.x += o.offsetLeft;
	offset.y += o.offsetTop;
	o = o.offsetParent;
    };
    return offset;
};

/* COLOR LIBRARY */

Color.HEX_STRING = function (o) {
    var z = o.toString(16);
    var n = z.length;
    while (n < 6) {
	z = '0' + z;
	n ++;
    }
    return z;
};

Color.RGB_HEX = function (o) {
    return o.R << 16 | o.G << 8 | o.B;
};

Color.HSV_RGB = function (o) {
    var H = o.H / 360,
	S = o.S / 100,
	V = o.V / 100,
	R, G, B;
    var A, B, C, D;
    if (S == 0) {
	R = G = B = Math.round(V * 255);
    } else {
	if (H >= 1) H = 0;
	H = 6 * H;
	D = H - Math.floor(H);
	A = Math.round(255 * V * (1 - S));
	B = Math.round(255 * V * (1 - (S * D)));
	C = Math.round(255 * V * (1 - (S * (1 - D))));
	V = Math.round(255 * V);
	switch (Math.floor(H)) {
	    case 0:
		R = V;
		G = C;
		B = A;
		break;
	    case 1:
		R = B;
		G = V;
		B = A;
		break;
	    case 2:
		R = A;
		G = V;
		B = C;
		break;
	    case 3:
		R = A;
		G = B;
		B = V;
		break;
	    case 4:
		R = C;
		G = A;
		B = V;
		break;
	    case 5:
		R = V;
		G = A;
		B = B;
		break;
	}
    }
    return {
	R: R,
	G: G,
	B: B
    };
};

Color.HSV_HEX = function (o) {
    return Color.HEX_STRING(Color.RGB_HEX(Color.HSV_RGB(o)));
};

/* DEMO CODE */

// var swatch = document.getElementById("testSwatch");

/*
window.onload = function() {
    var picker = new Color.Picker({
	callback: function(hex) {
	    swatch.style.backgroundColor = "#" + hex;
	}
    });
    picker.el.style.top = (swatch.offsetTop) + "px";
    picker.el.style.left = (swatch.offsetLeft - 240) + "px";
};
*/
<commit_msg>Add a resize method.<commit_after>/*
    Color Picker: Classic : 2011/02/26
    ---------------------------------------
    http://www.colorjack.com/opensource/dhtml+color+picker.html

    Native support:  Firefox 2+, Safari 3+, Opera 9+, Google Chrome, IE9+

    This color picker is dual licenced under Creative Commons & GPL.
*/

if(window.Color == undefined) Color = {};

Color.Picker = function (props) {

    /// loading properties
    if (typeof(props) == "undefined") props = {};
    this.callback = props.callback; // bind custom function
    this.hue = props.hue || 0; // 0-360
    this.sat = props.sat || 0; // 0-100
    this.val = props.val || 100; // 0-100
    this.element = props.element || document.body;
    this.size = props.size || 165; // size of colorpicker
    this.margin = 10; // margins on colorpicker
    this.offset = this.margin / 2;
    this.hueWidth = 30;

    /// creating colorpicker (header)
    var plugin = document.createElement("div");
    plugin.id = "colorjack_square";
    plugin.style.cssText = "height: " + (this.size + this.margin * 2) + "px";
    plugin.style.cssText+= ";width:" + (this.size + this.margin + this.hueWidth) + "px";

    // shows current selected color as the background of this box
    var hexBox = document.createElement("div");
    hexBox.className = "hexBox";
    plugin.appendChild(hexBox);

    // shows current selected color as HEX string
    var hexString = document.createElement("div");
    hexString.className = "hexString";
    plugin.appendChild(hexString);

    // close the plugin
    /*var hexClose = document.createElement("div");
    hexClose.className = "hexClose";
    hexClose.textContent = "X";
    hexClose.onclick = function () { // close colorpicker
	plugin.style.display = (plugin.style.display == "none") ? "block" : "none";
    };
    plugin.appendChild(hexClose);
    plugin.appendChild(document.createElement("br"));*/

    /// creating media-resources
    var arrows = document.createElement("canvas");
    arrows.width = 40;
    arrows.height = 5;
    (function () { // creating arrows
	var ctx = arrows.getContext("2d");
	var width = 3;
	var height = 5;
	var size = 9;
	var top = -size / 4;
	var left = 1;
	for (var n = 0; n < 20; n++) { // multiply anti-aliasing
	    ctx.beginPath();
	    ctx.fillStyle = "#FFF";
	    ctx.moveTo(left + size / 4, size / 2 + top);
	    ctx.lineTo(left, size / 4 + top);
	    ctx.lineTo(left, size / 4 * 3 + top);
	    ctx.fill();
	}
	ctx.translate(width, height);
	ctx.rotate(180 * Math.PI / 180); // rotate arrows
	ctx.drawImage(arrows, -29, 0);
	ctx.translate(-width, -height);
    })();

    var circle = document.createElement("canvas");
    circle.width = 10;
    circle.height = 10;
    (function () { // creating circle-selection
	var ctx = circle.getContext("2d");
	ctx.lineWidth = 1;
	ctx.beginPath();
	var x = circle.width / 2;
	var y = circle.width / 2;
	ctx.arc(x, y, 4.5, 0, Math.PI * 2, true);
	ctx.strokeStyle = '#000';
	ctx.stroke();
	ctx.beginPath();
	ctx.arc(x, y, 3.5, 0, Math.PI * 2, true);
	ctx.strokeStyle = '#FFF';
	ctx.stroke();
    })();

    /// creating colorpicker sliders
    var canvas = document.createElement("canvas");
    var ctx = canvas.getContext("2d");
    canvas.style.cssText = "position: absolute; top: 19px; left: " + (this.offset) + "px;";
    canvas.width = this.size + this.hueWidth + this.margin;
    canvas.height = this.size + this.margin;
    plugin.appendChild(canvas);
    plugin.onmousemove =
    plugin.onmousedown = function (e) {
	var down = (e.type == "mousedown");
	var offset = that.margin / 2;
	var abs = abPos(canvas);
	var x0 = (e.pageX - abs.x) - offset;
	var y0 = (e.pageY - abs.y) - offset;
	var x = clamp(x0, 0, canvas.width);
	var y = clamp(y0, 0, that.size);
	if (e.target.className == "hexString") {
	    plugin.style.cursor = "text";
	    return; // allow selection of HEX
	}/* else if (x != x0 || y != y0) { // move colorpicker
	    plugin.style.cursor = "move";
	    if (down) dragElement({
		type: "difference",
		event: e,
		element: plugin,
		callback: function (coords, state) {
		    plugin.style.left = coords.x + "px";
		    plugin.style.top = coords.y + "px";
		}
	    });
	}*/ else if (x <= that.size) { // saturation-value selection
	    plugin.style.cursor = "crosshair";
	    if (down) dragElement({
		type: "relative",
		event: e,
		element: canvas,
		callback: function (coords, state) {
		    var x = clamp(coords.x - that.offset, 0, that.size);
		    var y = clamp(coords.y - that.offset, 0, that.size);
		    that.sat = x / that.size * 100; // scale saturation
		    that.val = 100 - (y / that.size * 100); // scale value
		    that.drawSample();
		}
	    });
	} else if (x > that.size + that.margin && x <= that.size + that.hueWidth) { // hue selection
	    plugin.style.cursor = "crosshair";
	    if (down) dragElement({
		type: "relative",
		event: e,
		element: canvas,
		callback: function (coords, state) {
		    var y = clamp(coords.y - that.offset, 0, that.size);
		    that.hue = Math.min(1, y / that.size) * 360;
		    that.drawSample();
		}
	    });
	} else { // margin between hue/saturation-value
	    plugin.style.cursor = "default";
	}
	return false; // prevent selection
    };
    // appending to element
    this.element.appendChild(plugin);

    /// helper functions
    var that = this;
    this.el = plugin;
    this.drawSample = function () {
	// clearing canvas
	ctx.clearRect(0, 0, canvas.width, canvas.height)
	that.drawSquare();
	that.drawHue();
	// retrieving hex-code
	var hex = Color.HSV_HEX({
	    H: that.hue,
	    S: that.sat,
	    V: that.val
	});
	// display hex string
	hexString.textContent = hex.toUpperCase();
	// display background color
	hexBox.style.backgroundColor = "#" + hex;
	// arrow-selection
	var y = (that.hue / 362) * that.size - 2;
	ctx.drawImage(arrows, that.size + that.offset + 4, Math.round(y) + that.offset);
	// circle-selection
	var x = that.sat / 100 * that.size;
	var y = (1 - (that.val / 100)) * that.size;
	x = x - circle.width / 2;
	y = y - circle.height / 2;
	ctx.drawImage(circle, Math.round(x) + that.offset, Math.round(y) + that.offset);
	// run custom code
	if (that.callback) that.callback(hex);
    };

    this.drawSquare = function () {
	// retrieving hex-code
	var hex = Color.HSV_HEX({
	    H: that.hue,
	    S: 100,
	    V: 100
	});
	var offset = that.offset;
	var size = that.size;
	// drawing color
	ctx.fillStyle = "#" + hex;
	ctx.fillRect(offset, offset, size, size);
	// overlaying saturation
	var gradient = ctx.createLinearGradient(offset, offset, size + offset, 0);
	gradient.addColorStop(0, "rgba(255, 255, 255, 1)");
	gradient.addColorStop(1, "rgba(255, 255, 255, 0)");
	ctx.fillStyle = gradient;
	ctx.fillRect(offset, offset, size, size);
	// overlaying value
	var gradient = ctx.createLinearGradient(offset, offset, 0, size + offset);
	gradient.addColorStop(0, "rgba(0, 0, 0, 0)");
	gradient.addColorStop(1, "rgba(0, 0, 0, 1)");
	ctx.fillStyle = gradient;
	ctx.fillRect(offset, offset, size, size);
	// drawing outer bounds
	ctx.strokeStyle = "rgba(255,255,255,0.15)";
	ctx.strokeRect(offset+0.5, offset+0.5, size-1, size-1);
    };

    this.drawHue = function () {
	// drawing hue selector
	var left = that.size + that.margin + that.offset;
	var gradient = ctx.createLinearGradient(0, 0, 0, that.size);
	gradient.addColorStop(0, "rgba(255, 0, 0, 1)");
	gradient.addColorStop(0.15, "rgba(255, 255, 0, 1)");
	gradient.addColorStop(0.3, "rgba(0, 255, 0, 1)");
	gradient.addColorStop(0.5, "rgba(0, 255, 255, 1)");
	gradient.addColorStop(0.65, "rgba(0, 0, 255, 1)");
	gradient.addColorStop(0.8, "rgba(255, 0, 255, 1)");
	gradient.addColorStop(1, "rgba(255, 0, 0, 1)");
	ctx.fillStyle = gradient;
	ctx.fillRect(left, that.offset, 20, that.size);
	// drawing outer bounds
	ctx.strokeStyle = "rgba(255,255,255,0.2)";
	ctx.strokeRect(left + 0.5, that.offset + 0.5, 19, that.size-1);
    };

    this.destory = function () {
	document.body.removeChild(plugin);
	for (var key in that) delete that[key];
    };

    // drawing color selection
    this.drawSample();

    this.resize = function (new_size) {
        this.size = new_size;
        // resize elements
        plugin.style.height = (this.size + this.margin * 2) + "px";
        plugin.style.width = (this.size + this.margin + this.hueWidth) + "px";
        canvas.width = this.size + this.hueWidth + this.margin;
        canvas.height = this.size + this.margin;
        // redraw
        that.drawSample();
    };
    return this;
};

/* GLOBALS LIBRARY */

var dragElement = function(props) {
    function mouseMove(e, state) {
	if (typeof(state) == "undefined") state = "move";
	var coord = XY(e);
	switch (props.type) {
	    case "difference":
		props.callback({
		    x: coord.x + oX - eX,
		    y: coord.y + oY - eY
		}, state);
		break;
	    case "relative":
		props.callback({
		    x: coord.x - oX,
		    y: coord.y - oY
		}, state);
		break;
	    default: // "absolute"
		props.callback({
		    x: coord.x,
		    y: coord.y
		}, state);
		break;
	}
    };
    function mouseUp(e) {
	window.removeEventListener("mousemove", mouseMove, false);
	window.removeEventListener("mouseup", mouseUp, false);
	mouseMove(e, "up");
    };
    // current element position
    var el = props.element;
    var origin = abPos(el);
    var oX = origin.x;
    var oY = origin.y;
    // current mouse position
    var e = props.event;
    var coord = XY(e);
    var eX = coord.x;
    var eY = coord.y;
    // events
    window.addEventListener("mousemove", mouseMove, false);
    window.addEventListener("mouseup", mouseUp, false);
    mouseMove(e, "down"); // run mouse-down
};

var clamp = function(n, min, max) {
    return (n < min) ? min : ((n > max) ? max : n);
};

var XY = window.ActiveXObject ? // fix XY to work in various browsers
    function(event) {
	return {
	    x: event.clientX + document.documentElement.scrollLeft,
	    y: event.clientY + document.documentElement.scrollTop
	};
    } : function(event) {
	return {
	    x: event.pageX,
	    y: event.pageY
	};
    };

var abPos = function(o) {
    o = typeof(o) == 'object' ? o : $(o);
    var offset = { x: 0, y: 0 };
    while(o != null) {
	offset.x += o.offsetLeft;
	offset.y += o.offsetTop;
	o = o.offsetParent;
    };
    return offset;
};

/* COLOR LIBRARY */

Color.HEX_STRING = function (o) {
    var z = o.toString(16);
    var n = z.length;
    while (n < 6) {
	z = '0' + z;
	n ++;
    }
    return z;
};

Color.RGB_HEX = function (o) {
    return o.R << 16 | o.G << 8 | o.B;
};

Color.HSV_RGB = function (o) {
    var H = o.H / 360,
	S = o.S / 100,
	V = o.V / 100,
	R, G, B;
    var A, B, C, D;
    if (S == 0) {
	R = G = B = Math.round(V * 255);
    } else {
	if (H >= 1) H = 0;
	H = 6 * H;
	D = H - Math.floor(H);
	A = Math.round(255 * V * (1 - S));
	B = Math.round(255 * V * (1 - (S * D)));
	C = Math.round(255 * V * (1 - (S * (1 - D))));
	V = Math.round(255 * V);
	switch (Math.floor(H)) {
	    case 0:
		R = V;
		G = C;
		B = A;
		break;
	    case 1:
		R = B;
		G = V;
		B = A;
		break;
	    case 2:
		R = A;
		G = V;
		B = C;
		break;
	    case 3:
		R = A;
		G = B;
		B = V;
		break;
	    case 4:
		R = C;
		G = A;
		B = V;
		break;
	    case 5:
		R = V;
		G = A;
		B = B;
		break;
	}
    }
    return {
	R: R,
	G: G,
	B: B
    };
};

Color.HSV_HEX = function (o) {
    return Color.HEX_STRING(Color.RGB_HEX(Color.HSV_RGB(o)));
};

/* DEMO CODE */

// var swatch = document.getElementById("testSwatch");

/*
window.onload = function() {
    var picker = new Color.Picker({
	callback: function(hex) {
	    swatch.style.backgroundColor = "#" + hex;
	}
    });
    picker.el.style.top = (swatch.offsetTop) + "px";
    picker.el.style.left = (swatch.offsetLeft - 240) + "px";
};
*/
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2019 Google LLC.
 * This code may only be used under the BSD style license found at
 * http://polymer.github.io/LICENSE.txt
 * Code distributed by Google as part of this project is also
 * subject to an additional IP rights grant found at
 * http://polymer.github.io/PATENTS.txt
 */

/* global browser */

const {waitForServer, seconds, waitFor, click, keys, openNewArc, marshalPersona, openArc} = require('../utils.js');

const sleep = s => browser.pause(seconds(s));
const searchFor = text => keys('input[search]', text);
const chooseSuggestion = async name => {
  await click(`[title*="${name}"]`);
};

// TODO(sjmiles): replace this with some WDIO work to
// poll the server until it's up
describe('wait for server', () => {
  it('is not a test', async function() {
    // wait for ALDS to finish init ...
    console.log('waiting for ALDS to spin up...');
    await waitForServer();
    console.log('...done');
  });
});

const persona = `${marshalPersona('volatile')}`;
describe(`WASM (${persona})`, () => {
  it('loads Kotlin Tutorial 1', async function() {
    console.log(`running "${this.test.fullTitle()}"`);
    await openArc(persona);
    await searchFor('Kotlin');
    await chooseSuggestion('Kotlin Tutorial 1');
    // TODO(sjmiles): allowing time to settle, we should prefer explicit signal
    await sleep(5);
    await waitFor(`[particle="HelloWorldParticle"]`);
  });
});

['pouchdb', 'firebase'].forEach(async storageType => {
  describe('demo ' + storageType, () => {
    it('restaurants', async function() {
      await openNewArc(this.test.fullTitle(), storageType);
      await searchFor(`restaurants`);
      await chooseSuggestion('Find restaurants');
      //
      // TODO(sjmiles): disabling this bit for now for KISS
      // TODO(sjmiles): rendering tiles takes forever to stabilize
      //await browser.pause(seconds(10));
      //const restaurantItem = `#webtest-title`;
      //await click(restaurantItem);
      //
      // TODO(sjmiles): bug in description generator means we don't know
      // if first letter is "Y" or "y", also you could be "free" or "busy"
      await chooseSuggestion('ou are');
      const calendarNode = `[particle="Calendar"]`;
      await waitFor(calendarNode);
    });
    it('gifts', async function() {
      await openNewArc(this.test.fullTitle(), storageType);
      await searchFor(`products`);
      await chooseSuggestion('Create shopping list');
      await chooseSuggestion('Buy gifts');
      await chooseSuggestion('Check manufacturer');
      await chooseSuggestion('Find out');
    });
  });

  const persona = `${marshalPersona(storageType)}-persistence`;
  describe(`persistence (${persona})`, () => {
    it('persists BasicProfile arc', async function() {
      console.log(`running "${this.test.fullTitle()}"`);
      await openArc(persona);
      await searchFor('profile');
      await chooseSuggestion('Edit user profile');
      // TODO(sjmiles): allowing time to settle, we should prefer explicit signal
      await sleep(5);
      await openArc(persona);
      // TODO(sjmiles): put something more obvious on this node
      const arcTileNode = 'div[chip]';
      await waitFor(arcTileNode);
    });
  });

});

<commit_msg>Disable Kotlin/Wasm particle test. (#4022)<commit_after>/**
 * @license
 * Copyright 2019 Google LLC.
 * This code may only be used under the BSD style license found at
 * http://polymer.github.io/LICENSE.txt
 * Code distributed by Google as part of this project is also
 * subject to an additional IP rights grant found at
 * http://polymer.github.io/PATENTS.txt
 */

/* global browser */

const {waitForServer, seconds, waitFor, click, keys, openNewArc, marshalPersona, openArc} = require('../utils.js');

const sleep = s => browser.pause(seconds(s));
const searchFor = text => keys('input[search]', text);
const chooseSuggestion = async name => {
  await click(`[title*="${name}"]`);
};

// TODO(sjmiles): replace this with some WDIO work to
// poll the server until it's up
describe('wait for server', () => {
  it('is not a test', async function() {
    // wait for ALDS to finish init ...
    console.log('waiting for ALDS to spin up...');
    await waitForServer();
    console.log('...done');
  });
});

const persona = `${marshalPersona('volatile')}`;
describe(`WASM (${persona})`, () => {
  // TODO(csilvestrini): Re-enable this test once Wasm particle
  // blaze builds are operational again.
  // https://github.com/PolymerLabs/arcs/issues/4018
  it.skip('loads Kotlin Tutorial 1', async function() {
    console.log(`running "${this.test.fullTitle()}"`);
    await openArc(persona);
    await searchFor('Kotlin');
    await chooseSuggestion('Kotlin Tutorial 1');
    // TODO(sjmiles): allowing time to settle, we should prefer explicit signal
    await sleep(5);
    await waitFor(`[particle="HelloWorldParticle"]`);
  });
});

['pouchdb', 'firebase'].forEach(async storageType => {
  describe('demo ' + storageType, () => {
    it('restaurants', async function() {
      await openNewArc(this.test.fullTitle(), storageType);
      await searchFor(`restaurants`);
      await chooseSuggestion('Find restaurants');
      //
      // TODO(sjmiles): disabling this bit for now for KISS
      // TODO(sjmiles): rendering tiles takes forever to stabilize
      //await browser.pause(seconds(10));
      //const restaurantItem = `#webtest-title`;
      //await click(restaurantItem);
      //
      // TODO(sjmiles): bug in description generator means we don't know
      // if first letter is "Y" or "y", also you could be "free" or "busy"
      await chooseSuggestion('ou are');
      const calendarNode = `[particle="Calendar"]`;
      await waitFor(calendarNode);
    });
    it('gifts', async function() {
      await openNewArc(this.test.fullTitle(), storageType);
      await searchFor(`products`);
      await chooseSuggestion('Create shopping list');
      await chooseSuggestion('Buy gifts');
      await chooseSuggestion('Check manufacturer');
      await chooseSuggestion('Find out');
    });
  });

  const persona = `${marshalPersona(storageType)}-persistence`;
  describe(`persistence (${persona})`, () => {
    it('persists BasicProfile arc', async function() {
      console.log(`running "${this.test.fullTitle()}"`);
      await openArc(persona);
      await searchFor('profile');
      await chooseSuggestion('Edit user profile');
      // TODO(sjmiles): allowing time to settle, we should prefer explicit signal
      await sleep(5);
      await openArc(persona);
      // TODO(sjmiles): put something more obvious on this node
      const arcTileNode = 'div[chip]';
      await waitFor(arcTileNode);
    });
  });

});

<|endoftext|>