<commit_before>// The Glyph object

'use strict';

var check = require('./check');
var draw = require('./draw');
var path = require('./path');

function getPathDefinition(glyph, path) {
    var _path = path || { commands: [] };
    return {
        configurable: true,

        get: function() {
            if (typeof _path === 'function') {
                _path = _path();
            }

            return _path;
        },

        set: function(p) {
            _path = p;
        }
    };
}

// A Glyph is an individual mark that often corresponds to a character.
// Some glyphs, such as ligatures, are a combination of many characters.
// Glyphs are the basic building blocks of a font.
//
// The `Glyph` class contains utility methods for drawing the path and its points.
function Glyph(options) {
    // By putting all the code on a prototype function (which is only declared once)
    // we reduce the memory requirements for larger fonts by some 2%
    this.bindConstructorValues(options);
}

Glyph.prototype.bindConstructorValues = function(options) {
    this.index = options.index || 0;

    // These three values cannnot be deferred for memory optimization:
    this.name = options.name || null;
    this.unicode = options.unicode || undefined;
    this.unicodes = options.unicodes || options.unicode !== undefined ? [options.unicode] : [];

    // But by binding these values only when necessary, we reduce can
    // the memory requirements by almost 3% for larger fonts.
    if (options.xMin) {
        this.xMin = options.xMin;
    }

    if (options.yMin) {
        this.yMin = options.yMin;
    }

    if (options.xMax) {
        this.xMax = options.xMax;
    }

    if (options.yMax) {
        this.yMax = options.yMax;
    }

    if (options.advanceWidth) {
        this.advanceWidth = options.advanceWidth;
    }

    // The path for a glyph is the most memory intensive, and is bound as a value
    // with a getter/setter to ensure we actually do path parsing only once the
    // path is actually needed by anything.
    Object.defineProperty(this, 'path', getPathDefinition(this, options.path));
};

Glyph.prototype.addUnicode = function(unicode) {
    if (this.unicodes.length === 0) {
        this.unicode = unicode;
    }

    this.unicodes.push(unicode);
};

// Convert the glyph to a Path we can draw on a drawing context.
//
// x - Horizontal position of the glyph. (default: 0)
// y - Vertical position of the *baseline* of the glyph. (default: 0)
// fontSize - Font size, in pixels (default: 72).
Glyph.prototype.getPath = function(x, y, fontSize) {
    x = x !== undefined ? x : 0;
    y = y !== undefined ? y : 0;
    fontSize = fontSize !== undefined ? fontSize : 72;
    var scale = 1 / this.path.unitsPerEm * fontSize;
    var p = new path.Path();
    var commands = this.path.commands;
    for (var i = 0; i < commands.length; i += 1) {
        var cmd = commands[i];
        if (cmd.type === 'M') {
            p.moveTo(x + (cmd.x * scale), y + (-cmd.y * scale));
        } else if (cmd.type === 'L') {
            p.lineTo(x + (cmd.x * scale), y + (-cmd.y * scale));
        } else if (cmd.type === 'Q') {
            p.quadraticCurveTo(x + (cmd.x1 * scale), y + (-cmd.y1 * scale),
                               x + (cmd.x * scale), y + (-cmd.y * scale));
        } else if (cmd.type === 'C') {
            p.curveTo(x + (cmd.x1 * scale), y + (-cmd.y1 * scale),
                      x + (cmd.x2 * scale), y + (-cmd.y2 * scale),
                      x + (cmd.x * scale), y + (-cmd.y * scale));
        } else if (cmd.type === 'Z') {
            p.closePath();
        }
    }

    return p;
};

// Split the glyph into contours.
// This function is here for backwards compatibility, and to
// provide raw access to the TrueType glyph outlines.
Glyph.prototype.getContours = function() {
    if (this.points === undefined) {
        return [];
    }

    var contours = [];
    var currentContour = [];
    for (var i = 0; i < this.points.length; i += 1) {
        var pt = this.points[i];
        currentContour.push(pt);
        if (pt.lastPointOfContour) {
            contours.push(currentContour);
            currentContour = [];
        }
    }

    check.argument(currentContour.length === 0, 'There are still points left in the current contour.');
    return contours;
};

// Calculate the xMin/yMin/xMax/yMax/lsb/rsb for a Glyph.
Glyph.prototype.getMetrics = function() {
    var commands = this.path.commands;
    var xCoords = [];
    var yCoords = [];
    for (var i = 0; i < commands.length; i += 1) {
        var cmd = commands[i];
        if (cmd.type !== 'Z') {
            xCoords.push(cmd.x);
            yCoords.push(cmd.y);
        }

        if (cmd.type === 'Q' || cmd.type === 'C') {
            xCoords.push(cmd.x1);
            yCoords.push(cmd.y1);
        }

        if (cmd.type === 'C') {
            xCoords.push(cmd.x2);
            yCoords.push(cmd.y2);
        }
    }

    var metrics = {
        xMin: Math.min.apply(null, xCoords),
        yMin: Math.min.apply(null, yCoords),
        xMax: Math.max.apply(null, xCoords),
        yMax: Math.max.apply(null, yCoords),
        leftSideBearing: 0
    };
    metrics.rightSideBearing = this.advanceWidth - metrics.leftSideBearing - (metrics.xMax - metrics.xMin);
    return metrics;
};

// Draw the glyph on the given context.
//
// ctx - The drawing context.
// x - Horizontal position of the glyph. (default: 0)
// y - Vertical position of the *baseline* of the glyph. (default: 0)
// fontSize - Font size, in pixels (default: 72).
Glyph.prototype.draw = function(ctx, x, y, fontSize) {
    this.getPath(x, y, fontSize).draw(ctx);
};

// Draw the points of the glyph.
// On-curve points will be drawn in blue, off-curve points will be drawn in red.
//
// ctx - The drawing context.
// x - Horizontal position of the glyph. (default: 0)
// y - Vertical position of the *baseline* of the glyph. (default: 0)
// fontSize - Font size, in pixels (default: 72).
Glyph.prototype.drawPoints = function(ctx, x, y, fontSize) {

    function drawCircles(l, x, y, scale) {
        var PI_SQ = Math.PI * 2;
        ctx.beginPath();
        for (var j = 0; j < l.length; j += 1) {
            ctx.moveTo(x + (l[j].x * scale), y + (l[j].y * scale));
            ctx.arc(x + (l[j].x * scale), y + (l[j].y * scale), 2, 0, PI_SQ, false);
        }

        ctx.closePath();
        ctx.fill();
    }

    x = x !== undefined ? x : 0;
    y = y !== undefined ? y : 0;
    fontSize = fontSize !== undefined ? fontSize : 24;
    var scale = 1 / this.path.unitsPerEm * fontSize;

    var blueCircles = [];
    var redCircles = [];
    var path = this.path;
    for (var i = 0; i < path.commands.length; i += 1) {
        var cmd = path.commands[i];
        if (cmd.x !== undefined) {
            blueCircles.push({x: cmd.x, y: -cmd.y});
        }

        if (cmd.x1 !== undefined) {
            redCircles.push({x: cmd.x1, y: -cmd.y1});
        }

        if (cmd.x2 !== undefined) {
            redCircles.push({x: cmd.x2, y: -cmd.y2});
        }
    }

    ctx.fillStyle = 'blue';
    drawCircles(blueCircles, x, y, scale);
    ctx.fillStyle = 'red';
    drawCircles(redCircles, x, y, scale);
};

// Draw lines indicating important font measurements.
// Black lines indicate the origin of the coordinate system (point 0,0).
// Blue lines indicate the glyph bounding box.
// Green line indicates the advance width of the glyph.
//
// ctx - The drawing context.
// x - Horizontal position of the glyph. (default: 0)
// y - Vertical position of the *baseline* of the glyph. (default: 0)
// fontSize - Font size, in pixels (default: 72).
Glyph.prototype.drawMetrics = function(ctx, x, y, fontSize) {
    var scale;
    x = x !== undefined ? x : 0;
    y = y !== undefined ? y : 0;
    fontSize = fontSize !== undefined ? fontSize : 24;
    scale = 1 / this.path.unitsPerEm * fontSize;
    ctx.lineWidth = 1;

    // Draw the origin
    ctx.strokeStyle = 'black';
    draw.line(ctx, x, -10000, x, 10000);
    draw.line(ctx, -10000, y, 10000, y);

    // This code is here due to memory optimization: by not using
    // defaults in the constructor, we save a notable amount of memory.
    var xMin = this.xMin || 0;
    var yMin = this.yMin || 0;
    var xMax = this.xMax || 0;
    var yMax = this.yMax || 0;
    var advanceWidth = this.advanceWidth || 0;

    // Draw the glyph box
    ctx.strokeStyle = 'blue';
    draw.line(ctx, x + (xMin * scale), -10000, x + (xMin * scale), 10000);
    draw.line(ctx, x + (xMax * scale), -10000, x + (xMax * scale), 10000);
    draw.line(ctx, -10000, y + (-yMin * scale), 10000, y + (-yMin * scale));
    draw.line(ctx, -10000, y + (-yMax * scale), 10000, y + (-yMax * scale));

    // Draw the advance width
    ctx.strokeStyle = 'green';
    draw.line(ctx, x + (advanceWidth * scale), -10000, x + (advanceWidth * scale), 10000);
};

exports.Glyph = Glyph;
<commit_msg>Give sensible metrics for empty glyphs (e.g. space).<commit_after>// The Glyph object

'use strict';

var check = require('./check');
var draw = require('./draw');
var path = require('./path');

function getPathDefinition(glyph, path) {
    var _path = path || { commands: [] };
    return {
        configurable: true,

        get: function() {
            if (typeof _path === 'function') {
                _path = _path();
            }

            return _path;
        },

        set: function(p) {
            _path = p;
        }
    };
}

// A Glyph is an individual mark that often corresponds to a character.
// Some glyphs, such as ligatures, are a combination of many characters.
// Glyphs are the basic building blocks of a font.
//
// The `Glyph` class contains utility methods for drawing the path and its points.
function Glyph(options) {
    // By putting all the code on a prototype function (which is only declared once)
    // we reduce the memory requirements for larger fonts by some 2%
    this.bindConstructorValues(options);
}

Glyph.prototype.bindConstructorValues = function(options) {
    this.index = options.index || 0;

    // These three values cannnot be deferred for memory optimization:
    this.name = options.name || null;
    this.unicode = options.unicode || undefined;
    this.unicodes = options.unicodes || options.unicode !== undefined ? [options.unicode] : [];

    // But by binding these values only when necessary, we reduce can
    // the memory requirements by almost 3% for larger fonts.
    if (options.xMin) {
        this.xMin = options.xMin;
    }

    if (options.yMin) {
        this.yMin = options.yMin;
    }

    if (options.xMax) {
        this.xMax = options.xMax;
    }

    if (options.yMax) {
        this.yMax = options.yMax;
    }

    if (options.advanceWidth) {
        this.advanceWidth = options.advanceWidth;
    }

    // The path for a glyph is the most memory intensive, and is bound as a value
    // with a getter/setter to ensure we actually do path parsing only once the
    // path is actually needed by anything.
    Object.defineProperty(this, 'path', getPathDefinition(this, options.path));
};

Glyph.prototype.addUnicode = function(unicode) {
    if (this.unicodes.length === 0) {
        this.unicode = unicode;
    }

    this.unicodes.push(unicode);
};

// Convert the glyph to a Path we can draw on a drawing context.
//
// x - Horizontal position of the glyph. (default: 0)
// y - Vertical position of the *baseline* of the glyph. (default: 0)
// fontSize - Font size, in pixels (default: 72).
Glyph.prototype.getPath = function(x, y, fontSize) {
    x = x !== undefined ? x : 0;
    y = y !== undefined ? y : 0;
    fontSize = fontSize !== undefined ? fontSize : 72;
    var scale = 1 / this.path.unitsPerEm * fontSize;
    var p = new path.Path();
    var commands = this.path.commands;
    for (var i = 0; i < commands.length; i += 1) {
        var cmd = commands[i];
        if (cmd.type === 'M') {
            p.moveTo(x + (cmd.x * scale), y + (-cmd.y * scale));
        } else if (cmd.type === 'L') {
            p.lineTo(x + (cmd.x * scale), y + (-cmd.y * scale));
        } else if (cmd.type === 'Q') {
            p.quadraticCurveTo(x + (cmd.x1 * scale), y + (-cmd.y1 * scale),
                               x + (cmd.x * scale), y + (-cmd.y * scale));
        } else if (cmd.type === 'C') {
            p.curveTo(x + (cmd.x1 * scale), y + (-cmd.y1 * scale),
                      x + (cmd.x2 * scale), y + (-cmd.y2 * scale),
                      x + (cmd.x * scale), y + (-cmd.y * scale));
        } else if (cmd.type === 'Z') {
            p.closePath();
        }
    }

    return p;
};

// Split the glyph into contours.
// This function is here for backwards compatibility, and to
// provide raw access to the TrueType glyph outlines.
Glyph.prototype.getContours = function() {
    if (this.points === undefined) {
        return [];
    }

    var contours = [];
    var currentContour = [];
    for (var i = 0; i < this.points.length; i += 1) {
        var pt = this.points[i];
        currentContour.push(pt);
        if (pt.lastPointOfContour) {
            contours.push(currentContour);
            currentContour = [];
        }
    }

    check.argument(currentContour.length === 0, 'There are still points left in the current contour.');
    return contours;
};

// Calculate the xMin/yMin/xMax/yMax/lsb/rsb for a Glyph.
Glyph.prototype.getMetrics = function() {
    var commands = this.path.commands;
    var xCoords = [];
    var yCoords = [];
    for (var i = 0; i < commands.length; i += 1) {
        var cmd = commands[i];
        if (cmd.type !== 'Z') {
            xCoords.push(cmd.x);
            yCoords.push(cmd.y);
        }

        if (cmd.type === 'Q' || cmd.type === 'C') {
            xCoords.push(cmd.x1);
            yCoords.push(cmd.y1);
        }

        if (cmd.type === 'C') {
            xCoords.push(cmd.x2);
            yCoords.push(cmd.y2);
        }
    }

    var metrics = {
        xMin: Math.min.apply(null, xCoords),
        yMin: Math.min.apply(null, yCoords),
        xMax: Math.max.apply(null, xCoords),
        yMax: Math.max.apply(null, yCoords),
        leftSideBearing: 0
    };

    if (!isFinite(metrics.xMin)) {
        metrics.xMin = 0;
    }

    if (!isFinite(metrics.xMax)) {
        metrics.xMax = this.advanceWidth;
    }

    if (!isFinite(metrics.yMin)) {
        metrics.yMin = 0;
    }

    if (!isFinite(metrics.yMax)) {
        metrics.yMax = 0;
    }

    metrics.rightSideBearing = this.advanceWidth - metrics.leftSideBearing - (metrics.xMax - metrics.xMin);
    return metrics;
};

// Draw the glyph on the given context.
//
// ctx - The drawing context.
// x - Horizontal position of the glyph. (default: 0)
// y - Vertical position of the *baseline* of the glyph. (default: 0)
// fontSize - Font size, in pixels (default: 72).
Glyph.prototype.draw = function(ctx, x, y, fontSize) {
    this.getPath(x, y, fontSize).draw(ctx);
};

// Draw the points of the glyph.
// On-curve points will be drawn in blue, off-curve points will be drawn in red.
//
// ctx - The drawing context.
// x - Horizontal position of the glyph. (default: 0)
// y - Vertical position of the *baseline* of the glyph. (default: 0)
// fontSize - Font size, in pixels (default: 72).
Glyph.prototype.drawPoints = function(ctx, x, y, fontSize) {

    function drawCircles(l, x, y, scale) {
        var PI_SQ = Math.PI * 2;
        ctx.beginPath();
        for (var j = 0; j < l.length; j += 1) {
            ctx.moveTo(x + (l[j].x * scale), y + (l[j].y * scale));
            ctx.arc(x + (l[j].x * scale), y + (l[j].y * scale), 2, 0, PI_SQ, false);
        }

        ctx.closePath();
        ctx.fill();
    }

    x = x !== undefined ? x : 0;
    y = y !== undefined ? y : 0;
    fontSize = fontSize !== undefined ? fontSize : 24;
    var scale = 1 / this.path.unitsPerEm * fontSize;

    var blueCircles = [];
    var redCircles = [];
    var path = this.path;
    for (var i = 0; i < path.commands.length; i += 1) {
        var cmd = path.commands[i];
        if (cmd.x !== undefined) {
            blueCircles.push({x: cmd.x, y: -cmd.y});
        }

        if (cmd.x1 !== undefined) {
            redCircles.push({x: cmd.x1, y: -cmd.y1});
        }

        if (cmd.x2 !== undefined) {
            redCircles.push({x: cmd.x2, y: -cmd.y2});
        }
    }

    ctx.fillStyle = 'blue';
    drawCircles(blueCircles, x, y, scale);
    ctx.fillStyle = 'red';
    drawCircles(redCircles, x, y, scale);
};

// Draw lines indicating important font measurements.
// Black lines indicate the origin of the coordinate system (point 0,0).
// Blue lines indicate the glyph bounding box.
// Green line indicates the advance width of the glyph.
//
// ctx - The drawing context.
// x - Horizontal position of the glyph. (default: 0)
// y - Vertical position of the *baseline* of the glyph. (default: 0)
// fontSize - Font size, in pixels (default: 72).
Glyph.prototype.drawMetrics = function(ctx, x, y, fontSize) {
    var scale;
    x = x !== undefined ? x : 0;
    y = y !== undefined ? y : 0;
    fontSize = fontSize !== undefined ? fontSize : 24;
    scale = 1 / this.path.unitsPerEm * fontSize;
    ctx.lineWidth = 1;

    // Draw the origin
    ctx.strokeStyle = 'black';
    draw.line(ctx, x, -10000, x, 10000);
    draw.line(ctx, -10000, y, 10000, y);

    // This code is here due to memory optimization: by not using
    // defaults in the constructor, we save a notable amount of memory.
    var xMin = this.xMin || 0;
    var yMin = this.yMin || 0;
    var xMax = this.xMax || 0;
    var yMax = this.yMax || 0;
    var advanceWidth = this.advanceWidth || 0;

    // Draw the glyph box
    ctx.strokeStyle = 'blue';
    draw.line(ctx, x + (xMin * scale), -10000, x + (xMin * scale), 10000);
    draw.line(ctx, x + (xMax * scale), -10000, x + (xMax * scale), 10000);
    draw.line(ctx, -10000, y + (-yMin * scale), 10000, y + (-yMin * scale));
    draw.line(ctx, -10000, y + (-yMax * scale), 10000, y + (-yMax * scale));

    // Draw the advance width
    ctx.strokeStyle = 'green';
    draw.line(ctx, x + (advanceWidth * scale), -10000, x + (advanceWidth * scale), 10000);
};

exports.Glyph = Glyph;
<|endoftext|>


<commit_before>'use strict';
var key = 'selectionCriteria';
var selectionCriteria = retrieveSelectionCriteria();
var imgDiv =  document.getElementById('img');
var regionDiv = document.getElementById('region');
var mapDiv = document.getElementById('map');
var diffDiv = document.getElementById('difficulty');
var trailDiv = document.getElementById('trailName');

var trails = [
  {
    name: 'Seward Park',
    region: 'south',
    difficulty: 'easy',
    elevation: 2,
    quality: 2,
    distance: 2,
    imgUrl: 'images/seward_park.jpg',
    map: 'map placeholder',
    description: 'Located southeast from downtown Seattle, Seward Park resides on the Bailey Peninsula. The park is home to a variety of educational, recreational, and cultural activities. Visitors can enjoy a 2.4 mile bike and walking loop, an amphitheater, a native plant garden, an art studio, sheltered picnic areas, slightly more challenging hiking trails, a swimming beach, and more.',
    source: 'source placeholder'
  },
  {
    name: 'Lincoln Park',
    region: 'west',
    difficulty: 'easy',
    elevation: 2,
    quality: 1,
    distance: 2,
    imgUrl:  'images/lincolnpark.jpg',
    map: 'https://goo.gl/maps/yAYQJDnsr8S2',
    description: 'Located on the western edge of West Seattle, Lincoln park offers 5 miles of trails, including a loop hike with bluff and beachfront views of Puget Sound, Vashon Island, and the Olympic Mountains. The park is family-friendly, with a wading pool, playground, bathroom facilities, ball fields, and multiple trail options.',
    source: 'source placeholder'
  },
  {
    name: 'Franklin Falls',
    region: 'east',
    difficulty: 'easy',
    elevation: 2,
    quality: 2,
    distance: 2,
    imgUrl: 'images/franklin_falls.jpg',
    map: 'https://goo.gl/maps/TBv5xjqZJwk',
    description: 'The trail to Franklin Falls combines history and natural beauty along a compact and easily accessible loop. A visit to the falls makes for a particularly enjoyable half-day\'s outing for anyone who wants to explore the Snoqualmie Pass Region but isn\'t looking for a demanding mountain hike.',
    source: '60 Hikes Within 60 Miles - Seattle'
  },
  {
    trails: 'Mount Si',
    region: 'east',
    difficulty: 'hard',
    elevation: 5,
    quality: 3,
    distance: 4,
    imgUrl: 'images/mount_si.jpg',
    map: 'https://goo.gl/maps/pJR8X8MW1rF2',
    description: 'Just as no tourist can claim to have seen downtown Seattle without a visit to Pike Place Market, no Seattle [can claim to be a] hiker who fails to climb Mount Si. Easy to reach, physically challenging, and capped by a commanding view, the mountain known simply as Si is like a city park crossed with a serious Cascade Mountain Peak.',
    source: '60 Hikes Within 60 Miles - Seattle'
  },
  {
    name: 'Mud Mountain Lake and White River Trail',
    region: 'south',
    difficulty: 'hard',
    elevation: 4,
    quality: 4,
    distance: 4,
    imgUrl: 'images/mud_mountain_dam.jpg',
    map: 'https://goo.gl/maps/ctvaYHwkmjr',
    description: 'This one-of-a-kind trail follows the White River above Mud Mountain Dam, first on a high bluff and then right along the water, providing the unique opportunity to walk on a part-time lake bed. With year-round access, limited traffic, and a feel more like a riparian zone in eastern Washington than anything in the Cascades, this hike is unlike any other in the region.',
    source: '60 Hikes Within 60 Miles - Seattle',
  },
  {
    name: 'Carkeek Park',
    region: 'north',
    difficulty: 'easy',
    elevation: 2,
    quality: 1,
    distance: 2,
    imgUrl:  'images/carkeek_park.jpg',
    map:'placeholder',
    description: 'Carkeek Park is located in northwest Seattle, between 3rd Ave NW and Puget Sound. The park includes all of Piper\'s Creek (sometimes written without the apostrophe) plus the adjoining side hills and some side streams, plus a beach area. Park trails can be accessed from several points, and there is an access road that leads to a parking area near the beach. Park entrance is free, and official hours are daily, 6 a.m. to 10 p.m.'
  },
  {
    name: 'Mt. Pilchuk',
    region: 'north',
    difficulty: 'hard',
    elevation: 2,
    quality: 1,
    distance: 2,
    imgUrl: 'images/mount_pilchuck.jpg',
    mapUrl: 'http://google.com',
    description: 'Despite the foot traffic Wallace Falls sees as one of Washington’s most popular attractions, those who get out early on the trailhead will be rewarded with a serene tranquility that few other hikes in the area can offer. And unlike many trails, which sacrifice peripheral scenery on the journey for the prospect of a grand summit view, the Woody Trail is consistently gorgeous as you wind your way along the Wallace River and approach the nine dazzling falls.'
  },
  {
    name: 'Gazzam Lake Nature Preserve',
    region: 'west',
    difficulty: 'hard',
    elevation: 5,
    quality: 3,
    distance: 5,
    imgUrl: 'images/gazzam_lake.jpg',
    mapUrl: 'http://google.com',
    description: 'An easy route with a challenging finish, the main trail through Gazzam Lake Nature Preserve meanders through second-growth forest on Bainbridge Island, plunging down its finish at a small, scenic section of rocky beach.'
  }
];

function renderTrail(trail) {
  //grab each
  var trailEl = document.createElement('h1');
  trailEl.textContent = trail.name;
  trailDiv.appendChild(trailEl);

  var regionEl = document.createElement('p');
  regionEl.textContent = trail.region;
  regionDiv.appendChild(regionEl);

  var diffEl = document.createElement('p');
  diffEl.textContent = trail.difficulty;
  diffDiv.appendChild(diffEl);

  var mapEl = document.createElement('a');
  mapEl.setAttribute('href', trail.mapUrl);
  mapEl.textContent= 'click for map';
  mapDiv.appendChild(mapEl);

  var imgEl = document.createElement('img');
  imgEl.setAttribute('src', trail.imgUrl);
  imgDiv.appendChild(imgEl);
}

//createOrUpdateEntries
function retrieveSelectionCriteria() {
  var stringifiedSelectionCriteria = localStorage.getItem(key);
  selectionCriteria = JSON.parse(stringifiedSelectionCriteria);
  return selectionCriteria;
}

//turn array to objects
//event listener
//render function
<commit_msg>finished trails.js<commit_after>'use strict';
var key = 'selectionCriteria';
var selectionCriteria = retrieveSelectionCriteria();
var imgDiv =  document.getElementById('img');
var regionDiv = document.getElementById('region');
var mapDiv = document.getElementById('map');
var diffDiv = document.getElementById('difficulty');
var trailDiv = document.getElementById('trailName');

var trails = [
  {
    name: 'Seward Park',
    region: 'south',
    difficulty: 'easy',
    elevation: 2,
    quality: 2,
    distance: 2,
    imgUrl: 'images/seward_park.jpg',
    map: 'map placeholder',
    description: 'Located southeast from downtown Seattle, Seward Park resides on the Bailey Peninsula. The park is home to a variety of educational, recreational, and cultural activities. Visitors can enjoy a 2.4 mile bike and walking loop, an amphitheater, a native plant garden, an art studio, sheltered picnic areas, slightly more challenging hiking trails, a swimming beach, and more.',
    source: 'source placeholder'
  },
  {
    name: 'Lincoln Park',
    region: 'west',
    difficulty: 'easy',
    elevation: 2,
    quality: 1,
    distance: 2,
    imgUrl:  'images/lincoln_park.jpg',
    map: 'https://goo.gl/maps/yAYQJDnsr8S2',
    description: 'Located on the western edge of West Seattle, Lincoln park offers 5 miles of trails, including a loop hike with bluff and beachfront views of Puget Sound, Vashon Island, and the Olympic Mountains. The park is family-friendly, with a wading pool, playground, bathroom facilities, ball fields, and multiple trail options.',
    source: 'source placeholder'
  },
  {
    name: 'Franklin Falls',
    region: 'east',
    difficulty: 'easy',
    elevation: 2,
    quality: 2,
    distance: 2,
    imgUrl: 'images/franklin_falls.jpg',
    map: 'https://goo.gl/maps/TBv5xjqZJwk',
    description: 'The trail to Franklin Falls combines history and natural beauty along a compact and easily accessible loop. A visit to the falls makes for a particularly enjoyable half-day\'s outing for anyone who wants to explore the Snoqualmie Pass Region but isn\'t looking for a demanding mountain hike.',
    source: '60 Hikes Within 60 Miles - Seattle'
  },
  {
    name: 'Mount Si',
    region: 'east',
    difficulty: 'hard',
    elevation: 5,
    quality: 3,
    distance: 4,
    imgUrl: 'images/mount_si.jpg',
    map: 'https://goo.gl/maps/pJR8X8MW1rF2',
    description: 'Just as no tourist can claim to have seen downtown Seattle without a visit to Pike Place Market, no Seattle [can claim to be a] hiker who fails to climb Mount Si. Easy to reach, physically challenging, and capped by a commanding view, the mountain known simply as Si is like a city park crossed with a serious Cascade Mountain Peak.',
    source: '60 Hikes Within 60 Miles - Seattle'
  },
  {
    name: 'Mud Mountain Lake and White River Trail',
    region: 'south',
    difficulty: 'hard',
    elevation: 4,
    quality: 4,
    distance: 4,
    imgUrl: 'images/mud_mountain_dam.jpg',
    map: 'https://goo.gl/maps/ctvaYHwkmjr',
    description: 'This one-of-a-kind trail follows the White River above Mud Mountain Dam, first on a high bluff and then right along the water, providing the unique opportunity to walk on a part-time lake bed. With year-round access, limited traffic, and a feel more like a riparian zone in eastern Washington than anything in the Cascades, this hike is unlike any other in the region.',
    source: '60 Hikes Within 60 Miles - Seattle',
  },
  {
    name: 'Carkeek Park',
    region: 'north',
    difficulty: 'easy',
    elevation: 2,
    quality: 1,
    distance: 2,
    imgUrl:  'images/carkeek_park.jpg',
    map:'placeholder',
    description: 'Carkeek Park is located in northwest Seattle, between 3rd Ave NW and Puget Sound. The park includes all of Piper\'s Creek (sometimes written without the apostrophe) plus the adjoining side hills and some side streams, plus a beach area. Park trails can be accessed from several points, and there is an access road that leads to a parking area near the beach. Park entrance is free, and official hours are daily, 6 a.m. to 10 p.m.'
  },
  {
    name: 'Mt. Pilchuk',
    region: 'north',
    difficulty: 'hard',
    elevation: 2,
    quality: 1,
    distance: 2,
    imgUrl: 'images/mount_pilchuck.jpg',
    mapUrl: 'http://google.com',
    description: 'Despite the foot traffic Wallace Falls sees as one of Washington’s most popular attractions, those who get out early on the trailhead will be rewarded with a serene tranquility that few other hikes in the area can offer. And unlike many trails, which sacrifice peripheral scenery on the journey for the prospect of a grand summit view, the Woody Trail is consistently gorgeous as you wind your way along the Wallace River and approach the nine dazzling falls.'
  },
  {
    name: 'Gazzam Lake Nature Preserve',
    region: 'west',
    difficulty: 'hard',
    elevation: 5,
    quality: 3,
    distance: 5,
    imgUrl: 'images/gazzam_lake.jpg',
    mapUrl: 'http://google.com',
    description: 'An easy route with a challenging finish, the main trail through Gazzam Lake Nature Preserve meanders through second-growth forest on Bainbridge Island, plunging down its finish at a small, scenic section of rocky beach.'
  }
];

main();
function main() {
  //match selectionCriteria.region to the subset of trails in the correct region
  var regionalTrails = selectRegion();
  //select best match
  var bestTrail = selectTrail(regionalTrails);
  //render best trail
  renderTrail(bestTrail);
}
function selectRegion() {
  var result = [];
  for (var i = 0; i < trails.length; i++) {
    if (selectionCriteria.region === trails[i].region) {
      result.push(trails[i]);
    }
  }
  return result;
}

function selectTrail(trailList) {
  for (var i = 0; i < trailList.length; i++) {
    if (selectionCriteria.difficulty === trailList[i].difficulty) {
      return trailList[i];
    }
  }
}

function renderTrail(trail) {

  var trailEl = document.createElement('h1');
  trailEl.textContent = trail.name;
  trailDiv.appendChild(trailEl);

  var regionEl = document.createElement('p');
  regionEl.textContent = trail.region;
  regionDiv.appendChild(regionEl);

  var diffEl = document.createElement('p');
  diffEl.textContent = trail.difficulty;
  diffDiv.appendChild(diffEl);

  var mapEl = document.createElement('a');
  mapEl.setAttribute('href', trail.mapUrl);
  mapEl.textContent= 'click for map';
  mapDiv.appendChild(mapEl);

  var imgEl = document.createElement('img');
  imgEl.setAttribute('src', trail.imgUrl);
  imgDiv.appendChild(imgEl);
}

//createOrUpdateEntries
function retrieveSelectionCriteria() {
  var stringifiedSelectionCriteria = localStorage.getItem(key);
  selectionCriteria = JSON.parse(stringifiedSelectionCriteria);
  return selectionCriteria;
}

//turn array to objects
//event listener
//render function
<|endoftext|>


<commit_before>import {Origin} from 'aurelia-metadata';
import {Loader} from 'aurelia-loader';
import {join} from 'aurelia-path';

if(!window.System || !window.System.import){
  var sys = window.System = window.System || {};
  sys.polyfilled = true;
  sys.map = {};
  sys['import'] = function(moduleId){
    return new Promise((resolve, reject) => {
      require([moduleId], resolve, reject);
    });
  };
  sys.normalize = function(url){
    return Promise.resolve(url);
  };
}

function ensureOriginOnExports(executed, name){
  var target = executed,
      key, exportedValue;

  if(target.__useDefault){
    target = target['default'];
  }

  Origin.set(target, new Origin(name, 'default'));

  for (key in target) {
    exportedValue = target[key];

    if (typeof exportedValue === "function") {
      Origin.set(exportedValue, new Origin(name, key));
    }
  }

  return executed;
}

Loader.createDefaultLoader = function(){
  return new SystemJSLoader();
};

export class SystemJSLoader extends Loader {
  constructor(){
    this.baseUrl = System.baseUrl;
    this.baseViewUrl = System.baseViewUrl || System.baseUrl;
    this.registry = {};
  }

  loadModule(id, baseUrl){
    baseUrl = baseUrl === undefined ? this.baseUrl : baseUrl;

    if(baseUrl && !id.startsWith(baseUrl)){
      id = join(baseUrl, id);
    }

    return System.normalize(id).then(newId => {
      var existing = this.registry[newId];
      if(existing){
        return existing;
      }

      return System.import(newId).then(m => {
        this.registry[newId] = m;
        return ensureOriginOnExports(m, newId);
      });
    });
  }

  loadAllModules(ids){
    var loads = [], i, ii, loader = this.loader;

    for(i = 0, ii = ids.length; i < ii; ++i){
      loads.push(this.loadModule(ids[i]));
    }

    return Promise.all(loads);
  }

  loadTemplate(url){
    if(this.baseViewUrl && !url.startsWith(this.baseViewUrl)){
      url = join(this.baseViewUrl, url);
    }

    return this.importTemplate(url);
  }
}<commit_msg>fix(loader): correct name of exported DefaultLoader class<commit_after>import {Origin} from 'aurelia-metadata';
import {Loader} from 'aurelia-loader';
import {join} from 'aurelia-path';

if(!window.System || !window.System.import){
  var sys = window.System = window.System || {};
  sys.polyfilled = true;
  sys.map = {};
  sys['import'] = function(moduleId){
    return new Promise((resolve, reject) => {
      require([moduleId], resolve, reject);
    });
  };
  sys.normalize = function(url){
    return Promise.resolve(url);
  };
}

function ensureOriginOnExports(executed, name){
  var target = executed,
      key, exportedValue;

  if(target.__useDefault){
    target = target['default'];
  }

  Origin.set(target, new Origin(name, 'default'));

  for (key in target) {
    exportedValue = target[key];

    if (typeof exportedValue === "function") {
      Origin.set(exportedValue, new Origin(name, key));
    }
  }

  return executed;
}

Loader.createDefaultLoader = function(){
  return new DefaultLoader();
};

export class DefaultLoader extends Loader {
  constructor(){
    this.baseUrl = System.baseUrl;
    this.baseViewUrl = System.baseViewUrl || System.baseUrl;
    this.registry = {};
  }

  loadModule(id, baseUrl){
    baseUrl = baseUrl === undefined ? this.baseUrl : baseUrl;

    if(baseUrl && !id.startsWith(baseUrl)){
      id = join(baseUrl, id);
    }

    return System.normalize(id).then(newId => {
      var existing = this.registry[newId];
      if(existing){
        return existing;
      }

      return System.import(newId).then(m => {
        this.registry[newId] = m;
        return ensureOriginOnExports(m, newId);
      });
    });
  }

  loadAllModules(ids){
    var loads = [], i, ii, loader = this.loader;

    for(i = 0, ii = ids.length; i < ii; ++i){
      loads.push(this.loadModule(ids[i]));
    }

    return Promise.all(loads);
  }

  loadTemplate(url){
    if(this.baseViewUrl && !url.startsWith(this.baseViewUrl)){
      url = join(this.baseViewUrl, url);
    }

    return this.importTemplate(url);
  }
}<|endoftext|>


<commit_before>// The Glyph object

import check from './check';
import draw from './draw';
import Path from './path';
// import glyf from './tables/glyf' Can't be imported here, because it's a circular dependency

function getPathDefinition(glyph, path) {
    let _path = path || new Path();
    return {
        configurable: true,

        get: function() {
            if (typeof _path === 'function') {
                _path = _path();
            }

            return _path;
        },

        set: function(p) {
            _path = p;
        }
    };
}
/**
 * @typedef GlyphOptions
 * @type Object
 * @property {string} [name] - The glyph name
 * @property {number} [unicode]
 * @property {Array} [unicodes]
 * @property {number} [xMin]
 * @property {number} [yMin]
 * @property {number} [xMax]
 * @property {number} [yMax]
 * @property {number} [advanceWidth]
 */

// A Glyph is an individual mark that often corresponds to a character.
// Some glyphs, such as ligatures, are a combination of many characters.
// Glyphs are the basic building blocks of a font.
//
// The `Glyph` class contains utility methods for drawing the path and its points.
/**
 * @exports opentype.Glyph
 * @class
 * @param {GlyphOptions}
 * @constructor
 */
function Glyph(options) {
    // By putting all the code on a prototype function (which is only declared once)
    // we reduce the memory requirements for larger fonts by some 2%
    this.bindConstructorValues(options);
}

/**
 * @param  {GlyphOptions}
 */
Glyph.prototype.bindConstructorValues = function(options) {
    this.index = options.index || 0;

    // These three values cannot be deferred for memory optimization:
    this.name = options.name || null;
    this.unicode = options.unicode || undefined;
    this.unicodes = options.unicodes || options.unicode !== undefined ? [options.unicode] : [];

    // But by binding these values only when necessary, we reduce can
    // the memory requirements by almost 3% for larger fonts.
    if (options.xMin) {
        this.xMin = options.xMin;
    }

    if (options.yMin) {
        this.yMin = options.yMin;
    }

    if (options.xMax) {
        this.xMax = options.xMax;
    }

    if (options.yMax) {
        this.yMax = options.yMax;
    }

    if (options.advanceWidth) {
        this.advanceWidth = options.advanceWidth;
    }

    // The path for a glyph is the most memory intensive, and is bound as a value
    // with a getter/setter to ensure we actually do path parsing only once the
    // path is actually needed by anything.
    Object.defineProperty(this, 'path', getPathDefinition(this, options.path));
};

/**
 * @param {number}
 */
Glyph.prototype.addUnicode = function(unicode) {
    if (this.unicodes.length === 0) {
        this.unicode = unicode;
    }

    this.unicodes.push(unicode);
};

/**
 * Calculate the minimum bounding box for this glyph.
 * @return {opentype.BoundingBox}
 */
Glyph.prototype.getBoundingBox = function() {
    return this.path.getBoundingBox();
};

/**
 * Convert the glyph to a Path we can draw on a drawing context.
 * @param  {number} [x=0] - Horizontal position of the beginning of the text.
 * @param  {number} [y=0] - Vertical position of the *baseline* of the text.
 * @param  {number} [fontSize=72] - Font size in pixels. We scale the glyph units by `1 / unitsPerEm * fontSize`.
 * @param  {Object=} options - xScale, yScale to stretch the glyph.
 * @param  {opentype.Font} if hinting is to be used, the font
 * @return {opentype.Path}
 */
Glyph.prototype.getPath = function(x, y, fontSize, options, font) {
    x = x !== undefined ? x : 0;
    y = y !== undefined ? y : 0;
    fontSize = fontSize !== undefined ? fontSize : 72;
    let commands;
    let hPoints;
    if (!options) options = { };
    let xScale = options.xScale;
    let yScale = options.yScale;

    if (options.hinting && font && font.hinting) {
        // in case of hinting, the hinting engine takes care
        // of scaling the points (not the path) before hinting.
        hPoints = this.path && font.hinting.exec(this, fontSize);
        // in case the hinting engine failed hPoints is undefined
        // and thus reverts to plain rending
    }

    if (hPoints) {
        // Call font.hinting.getCommands instead of `glyf.getPath(hPoints).commands` to avoid a circular dependency
        commands = font.hinting.getCommands(hPoints);
        x = Math.round(x);
        y = Math.round(y);
        // TODO in case of hinting xyScaling is not yet supported
        xScale = yScale = 1;
    } else {
        commands = this.path.commands;
        const scale = 1 / (this.path.unitsPerEm || 1000) * fontSize;
        if (xScale === undefined) xScale = scale;
        if (yScale === undefined) yScale = scale;
    }

    const p = new Path();
    for (let i = 0; i < commands.length; i += 1) {
        const cmd = commands[i];
        if (cmd.type === 'M') {
            p.moveTo(x + (cmd.x * xScale), y + (-cmd.y * yScale));
        } else if (cmd.type === 'L') {
            p.lineTo(x + (cmd.x * xScale), y + (-cmd.y * yScale));
        } else if (cmd.type === 'Q') {
            p.quadraticCurveTo(x + (cmd.x1 * xScale), y + (-cmd.y1 * yScale),
                               x + (cmd.x * xScale), y + (-cmd.y * yScale));
        } else if (cmd.type === 'C') {
            p.curveTo(x + (cmd.x1 * xScale), y + (-cmd.y1 * yScale),
                      x + (cmd.x2 * xScale), y + (-cmd.y2 * yScale),
                      x + (cmd.x * xScale), y + (-cmd.y * yScale));
        } else if (cmd.type === 'Z') {
            p.closePath();
        }
    }

    return p;
};

/**
 * Split the glyph into contours.
 * This function is here for backwards compatibility, and to
 * provide raw access to the TrueType glyph outlines.
 * @return {Array}
 */
Glyph.prototype.getContours = function() {
    if (this.points === undefined) {
        return [];
    }

    const contours = [];
    let currentContour = [];
    for (let i = 0; i < this.points.length; i += 1) {
        const pt = this.points[i];
        currentContour.push(pt);
        if (pt.lastPointOfContour) {
            contours.push(currentContour);
            currentContour = [];
        }
    }

    check.argument(currentContour.length === 0, 'There are still points left in the current contour.');
    return contours;
};

/**
 * Calculate the xMin/yMin/xMax/yMax/lsb/rsb for a Glyph.
 * @return {Object}
 */
Glyph.prototype.getMetrics = function() {
    const commands = this.path.commands;
    const xCoords = [];
    const yCoords = [];
    for (let i = 0; i < commands.length; i += 1) {
        const cmd = commands[i];
        if (cmd.type !== 'Z') {
            xCoords.push(cmd.x);
            yCoords.push(cmd.y);
        }

        if (cmd.type === 'Q' || cmd.type === 'C') {
            xCoords.push(cmd.x1);
            yCoords.push(cmd.y1);
        }

        if (cmd.type === 'C') {
            xCoords.push(cmd.x2);
            yCoords.push(cmd.y2);
        }
    }

    const metrics = {
        xMin: Math.min.apply(null, xCoords),
        yMin: Math.min.apply(null, yCoords),
        xMax: Math.max.apply(null, xCoords),
        yMax: Math.max.apply(null, yCoords),
        leftSideBearing: this.leftSideBearing
    };

    if (!isFinite(metrics.xMin)) {
        metrics.xMin = 0;
    }

    if (!isFinite(metrics.xMax)) {
        metrics.xMax = this.advanceWidth;
    }

    if (!isFinite(metrics.yMin)) {
        metrics.yMin = 0;
    }

    if (!isFinite(metrics.yMax)) {
        metrics.yMax = 0;
    }

    metrics.rightSideBearing = this.advanceWidth - metrics.leftSideBearing - (metrics.xMax - metrics.xMin);
    return metrics;
};

/**
 * Draw the glyph on the given context.
 * @param  {CanvasRenderingContext2D} ctx - A 2D drawing context, like Canvas.
 * @param  {number} [x=0] - Horizontal position of the beginning of the text.
 * @param  {number} [y=0] - Vertical position of the *baseline* of the text.
 * @param  {number} [fontSize=72] - Font size in pixels. We scale the glyph units by `1 / unitsPerEm * fontSize`.
 * @param  {Object=} options - xScale, yScale to stretch the glyph.
 */
Glyph.prototype.draw = function(ctx, x, y, fontSize, options) {
    this.getPath(x, y, fontSize, options).draw(ctx);
};

/**
 * Draw the points of the glyph.
 * On-curve points will be drawn in blue, off-curve points will be drawn in red.
 * @param  {CanvasRenderingContext2D} ctx - A 2D drawing context, like Canvas.
 * @param  {number} [x=0] - Horizontal position of the beginning of the text.
 * @param  {number} [y=0] - Vertical position of the *baseline* of the text.
 * @param  {number} [fontSize=72] - Font size in pixels. We scale the glyph units by `1 / unitsPerEm * fontSize`.
 */
Glyph.prototype.drawPoints = function(ctx, x, y, fontSize) {
    function drawCircles(l, x, y, scale) {
        ctx.beginPath();
        for (let j = 0; j < l.length; j += 1) {
            ctx.moveTo(x + (l[j].x * scale), y + (l[j].y * scale));
            ctx.arc(x + (l[j].x * scale), y + (l[j].y * scale), 2, 0, Math.PI * 2, false);
        }

        ctx.closePath();
        ctx.fill();
    }

    x = x !== undefined ? x : 0;
    y = y !== undefined ? y : 0;
    fontSize = fontSize !== undefined ? fontSize : 24;
    const scale = 1 / this.path.unitsPerEm * fontSize;

    const blueCircles = [];
    const redCircles = [];
    const path = this.path;
    for (let i = 0; i < path.commands.length; i += 1) {
        const cmd = path.commands[i];
        if (cmd.x !== undefined) {
            blueCircles.push({x: cmd.x, y: -cmd.y});
        }

        if (cmd.x1 !== undefined) {
            redCircles.push({x: cmd.x1, y: -cmd.y1});
        }

        if (cmd.x2 !== undefined) {
            redCircles.push({x: cmd.x2, y: -cmd.y2});
        }
    }

    ctx.fillStyle = 'blue';
    drawCircles(blueCircles, x, y, scale);
    ctx.fillStyle = 'red';
    drawCircles(redCircles, x, y, scale);
};

/**
 * Draw lines indicating important font measurements.
 * Black lines indicate the origin of the coordinate system (point 0,0).
 * Blue lines indicate the glyph bounding box.
 * Green line indicates the advance width of the glyph.
 * @param  {CanvasRenderingContext2D} ctx - A 2D drawing context, like Canvas.
 * @param  {number} [x=0] - Horizontal position of the beginning of the text.
 * @param  {number} [y=0] - Vertical position of the *baseline* of the text.
 * @param  {number} [fontSize=72] - Font size in pixels. We scale the glyph units by `1 / unitsPerEm * fontSize`.
 */
Glyph.prototype.drawMetrics = function(ctx, x, y, fontSize) {
    let scale;
    x = x !== undefined ? x : 0;
    y = y !== undefined ? y : 0;
    fontSize = fontSize !== undefined ? fontSize : 24;
    scale = 1 / this.path.unitsPerEm * fontSize;
    ctx.lineWidth = 1;

    // Draw the origin
    ctx.strokeStyle = 'black';
    draw.line(ctx, x, -10000, x, 10000);
    draw.line(ctx, -10000, y, 10000, y);

    // This code is here due to memory optimization: by not using
    // defaults in the constructor, we save a notable amount of memory.
    const xMin = this.xMin || 0;
    let yMin = this.yMin || 0;
    const xMax = this.xMax || 0;
    let yMax = this.yMax || 0;
    const advanceWidth = this.advanceWidth || 0;

    // Draw the glyph box
    ctx.strokeStyle = 'blue';
    draw.line(ctx, x + (xMin * scale), -10000, x + (xMin * scale), 10000);
    draw.line(ctx, x + (xMax * scale), -10000, x + (xMax * scale), 10000);
    draw.line(ctx, -10000, y + (-yMin * scale), 10000, y + (-yMin * scale));
    draw.line(ctx, -10000, y + (-yMax * scale), 10000, y + (-yMax * scale));

    // Draw the advance width
    ctx.strokeStyle = 'green';
    draw.line(ctx, x + (advanceWidth * scale), -10000, x + (advanceWidth * scale), 10000);
};

export default Glyph;
<commit_msg>fix GlyphOptions with falsy values<commit_after>// The Glyph object

import check from './check';
import draw from './draw';
import Path from './path';
// import glyf from './tables/glyf' Can't be imported here, because it's a circular dependency

function getPathDefinition(glyph, path) {
    let _path = path || new Path();
    return {
        configurable: true,

        get: function() {
            if (typeof _path === 'function') {
                _path = _path();
            }

            return _path;
        },

        set: function(p) {
            _path = p;
        }
    };
}
/**
 * @typedef GlyphOptions
 * @type Object
 * @property {string} [name] - The glyph name
 * @property {number} [unicode]
 * @property {Array} [unicodes]
 * @property {number} [xMin]
 * @property {number} [yMin]
 * @property {number} [xMax]
 * @property {number} [yMax]
 * @property {number} [advanceWidth]
 */

// A Glyph is an individual mark that often corresponds to a character.
// Some glyphs, such as ligatures, are a combination of many characters.
// Glyphs are the basic building blocks of a font.
//
// The `Glyph` class contains utility methods for drawing the path and its points.
/**
 * @exports opentype.Glyph
 * @class
 * @param {GlyphOptions}
 * @constructor
 */
function Glyph(options) {
    // By putting all the code on a prototype function (which is only declared once)
    // we reduce the memory requirements for larger fonts by some 2%
    this.bindConstructorValues(options);
}

/**
 * @param  {GlyphOptions}
 */
Glyph.prototype.bindConstructorValues = function(options) {
    this.index = options.index || 0;

    // These three values cannot be deferred for memory optimization:
    this.name = options.name || null;
    this.unicode = options.unicode || undefined;
    this.unicodes = options.unicodes || options.unicode !== undefined ? [options.unicode] : [];

    // But by binding these values only when necessary, we reduce can
    // the memory requirements by almost 3% for larger fonts.
    if ('xMin' in options) {
        this.xMin = options.xMin;
    }

    if ('yMin' in options) {
        this.yMin = options.yMin;
    }

    if ('xMax' in options) {
        this.xMax = options.xMax;
    }

    if ('yMax' in options) {
        this.yMax = options.yMax;
    }

    if ('advanceWidth' in options) {
        this.advanceWidth = options.advanceWidth;
    }

    // The path for a glyph is the most memory intensive, and is bound as a value
    // with a getter/setter to ensure we actually do path parsing only once the
    // path is actually needed by anything.
    Object.defineProperty(this, 'path', getPathDefinition(this, options.path));
};

/**
 * @param {number}
 */
Glyph.prototype.addUnicode = function(unicode) {
    if (this.unicodes.length === 0) {
        this.unicode = unicode;
    }

    this.unicodes.push(unicode);
};

/**
 * Calculate the minimum bounding box for this glyph.
 * @return {opentype.BoundingBox}
 */
Glyph.prototype.getBoundingBox = function() {
    return this.path.getBoundingBox();
};

/**
 * Convert the glyph to a Path we can draw on a drawing context.
 * @param  {number} [x=0] - Horizontal position of the beginning of the text.
 * @param  {number} [y=0] - Vertical position of the *baseline* of the text.
 * @param  {number} [fontSize=72] - Font size in pixels. We scale the glyph units by `1 / unitsPerEm * fontSize`.
 * @param  {Object=} options - xScale, yScale to stretch the glyph.
 * @param  {opentype.Font} if hinting is to be used, the font
 * @return {opentype.Path}
 */
Glyph.prototype.getPath = function(x, y, fontSize, options, font) {
    x = x !== undefined ? x : 0;
    y = y !== undefined ? y : 0;
    fontSize = fontSize !== undefined ? fontSize : 72;
    let commands;
    let hPoints;
    if (!options) options = { };
    let xScale = options.xScale;
    let yScale = options.yScale;

    if (options.hinting && font && font.hinting) {
        // in case of hinting, the hinting engine takes care
        // of scaling the points (not the path) before hinting.
        hPoints = this.path && font.hinting.exec(this, fontSize);
        // in case the hinting engine failed hPoints is undefined
        // and thus reverts to plain rending
    }

    if (hPoints) {
        // Call font.hinting.getCommands instead of `glyf.getPath(hPoints).commands` to avoid a circular dependency
        commands = font.hinting.getCommands(hPoints);
        x = Math.round(x);
        y = Math.round(y);
        // TODO in case of hinting xyScaling is not yet supported
        xScale = yScale = 1;
    } else {
        commands = this.path.commands;
        const scale = 1 / (this.path.unitsPerEm || 1000) * fontSize;
        if (xScale === undefined) xScale = scale;
        if (yScale === undefined) yScale = scale;
    }

    const p = new Path();
    for (let i = 0; i < commands.length; i += 1) {
        const cmd = commands[i];
        if (cmd.type === 'M') {
            p.moveTo(x + (cmd.x * xScale), y + (-cmd.y * yScale));
        } else if (cmd.type === 'L') {
            p.lineTo(x + (cmd.x * xScale), y + (-cmd.y * yScale));
        } else if (cmd.type === 'Q') {
            p.quadraticCurveTo(x + (cmd.x1 * xScale), y + (-cmd.y1 * yScale),
                               x + (cmd.x * xScale), y + (-cmd.y * yScale));
        } else if (cmd.type === 'C') {
            p.curveTo(x + (cmd.x1 * xScale), y + (-cmd.y1 * yScale),
                      x + (cmd.x2 * xScale), y + (-cmd.y2 * yScale),
                      x + (cmd.x * xScale), y + (-cmd.y * yScale));
        } else if (cmd.type === 'Z') {
            p.closePath();
        }
    }

    return p;
};

/**
 * Split the glyph into contours.
 * This function is here for backwards compatibility, and to
 * provide raw access to the TrueType glyph outlines.
 * @return {Array}
 */
Glyph.prototype.getContours = function() {
    if (this.points === undefined) {
        return [];
    }

    const contours = [];
    let currentContour = [];
    for (let i = 0; i < this.points.length; i += 1) {
        const pt = this.points[i];
        currentContour.push(pt);
        if (pt.lastPointOfContour) {
            contours.push(currentContour);
            currentContour = [];
        }
    }

    check.argument(currentContour.length === 0, 'There are still points left in the current contour.');
    return contours;
};

/**
 * Calculate the xMin/yMin/xMax/yMax/lsb/rsb for a Glyph.
 * @return {Object}
 */
Glyph.prototype.getMetrics = function() {
    const commands = this.path.commands;
    const xCoords = [];
    const yCoords = [];
    for (let i = 0; i < commands.length; i += 1) {
        const cmd = commands[i];
        if (cmd.type !== 'Z') {
            xCoords.push(cmd.x);
            yCoords.push(cmd.y);
        }

        if (cmd.type === 'Q' || cmd.type === 'C') {
            xCoords.push(cmd.x1);
            yCoords.push(cmd.y1);
        }

        if (cmd.type === 'C') {
            xCoords.push(cmd.x2);
            yCoords.push(cmd.y2);
        }
    }

    const metrics = {
        xMin: Math.min.apply(null, xCoords),
        yMin: Math.min.apply(null, yCoords),
        xMax: Math.max.apply(null, xCoords),
        yMax: Math.max.apply(null, yCoords),
        leftSideBearing: this.leftSideBearing
    };

    if (!isFinite(metrics.xMin)) {
        metrics.xMin = 0;
    }

    if (!isFinite(metrics.xMax)) {
        metrics.xMax = this.advanceWidth;
    }

    if (!isFinite(metrics.yMin)) {
        metrics.yMin = 0;
    }

    if (!isFinite(metrics.yMax)) {
        metrics.yMax = 0;
    }

    metrics.rightSideBearing = this.advanceWidth - metrics.leftSideBearing - (metrics.xMax - metrics.xMin);
    return metrics;
};

/**
 * Draw the glyph on the given context.
 * @param  {CanvasRenderingContext2D} ctx - A 2D drawing context, like Canvas.
 * @param  {number} [x=0] - Horizontal position of the beginning of the text.
 * @param  {number} [y=0] - Vertical position of the *baseline* of the text.
 * @param  {number} [fontSize=72] - Font size in pixels. We scale the glyph units by `1 / unitsPerEm * fontSize`.
 * @param  {Object=} options - xScale, yScale to stretch the glyph.
 */
Glyph.prototype.draw = function(ctx, x, y, fontSize, options) {
    this.getPath(x, y, fontSize, options).draw(ctx);
};

/**
 * Draw the points of the glyph.
 * On-curve points will be drawn in blue, off-curve points will be drawn in red.
 * @param  {CanvasRenderingContext2D} ctx - A 2D drawing context, like Canvas.
 * @param  {number} [x=0] - Horizontal position of the beginning of the text.
 * @param  {number} [y=0] - Vertical position of the *baseline* of the text.
 * @param  {number} [fontSize=72] - Font size in pixels. We scale the glyph units by `1 / unitsPerEm * fontSize`.
 */
Glyph.prototype.drawPoints = function(ctx, x, y, fontSize) {
    function drawCircles(l, x, y, scale) {
        ctx.beginPath();
        for (let j = 0; j < l.length; j += 1) {
            ctx.moveTo(x + (l[j].x * scale), y + (l[j].y * scale));
            ctx.arc(x + (l[j].x * scale), y + (l[j].y * scale), 2, 0, Math.PI * 2, false);
        }

        ctx.closePath();
        ctx.fill();
    }

    x = x !== undefined ? x : 0;
    y = y !== undefined ? y : 0;
    fontSize = fontSize !== undefined ? fontSize : 24;
    const scale = 1 / this.path.unitsPerEm * fontSize;

    const blueCircles = [];
    const redCircles = [];
    const path = this.path;
    for (let i = 0; i < path.commands.length; i += 1) {
        const cmd = path.commands[i];
        if (cmd.x !== undefined) {
            blueCircles.push({x: cmd.x, y: -cmd.y});
        }

        if (cmd.x1 !== undefined) {
            redCircles.push({x: cmd.x1, y: -cmd.y1});
        }

        if (cmd.x2 !== undefined) {
            redCircles.push({x: cmd.x2, y: -cmd.y2});
        }
    }

    ctx.fillStyle = 'blue';
    drawCircles(blueCircles, x, y, scale);
    ctx.fillStyle = 'red';
    drawCircles(redCircles, x, y, scale);
};

/**
 * Draw lines indicating important font measurements.
 * Black lines indicate the origin of the coordinate system (point 0,0).
 * Blue lines indicate the glyph bounding box.
 * Green line indicates the advance width of the glyph.
 * @param  {CanvasRenderingContext2D} ctx - A 2D drawing context, like Canvas.
 * @param  {number} [x=0] - Horizontal position of the beginning of the text.
 * @param  {number} [y=0] - Vertical position of the *baseline* of the text.
 * @param  {number} [fontSize=72] - Font size in pixels. We scale the glyph units by `1 / unitsPerEm * fontSize`.
 */
Glyph.prototype.drawMetrics = function(ctx, x, y, fontSize) {
    let scale;
    x = x !== undefined ? x : 0;
    y = y !== undefined ? y : 0;
    fontSize = fontSize !== undefined ? fontSize : 24;
    scale = 1 / this.path.unitsPerEm * fontSize;
    ctx.lineWidth = 1;

    // Draw the origin
    ctx.strokeStyle = 'black';
    draw.line(ctx, x, -10000, x, 10000);
    draw.line(ctx, -10000, y, 10000, y);

    // This code is here due to memory optimization: by not using
    // defaults in the constructor, we save a notable amount of memory.
    const xMin = this.xMin || 0;
    let yMin = this.yMin || 0;
    const xMax = this.xMax || 0;
    let yMax = this.yMax || 0;
    const advanceWidth = this.advanceWidth || 0;

    // Draw the glyph box
    ctx.strokeStyle = 'blue';
    draw.line(ctx, x + (xMin * scale), -10000, x + (xMin * scale), 10000);
    draw.line(ctx, x + (xMax * scale), -10000, x + (xMax * scale), 10000);
    draw.line(ctx, -10000, y + (-yMin * scale), 10000, y + (-yMin * scale));
    draw.line(ctx, -10000, y + (-yMax * scale), 10000, y + (-yMax * scale));

    // Draw the advance width
    ctx.strokeStyle = 'green';
    draw.line(ctx, x + (advanceWidth * scale), -10000, x + (advanceWidth * scale), 10000);
};

export default Glyph;
<|endoftext|>


<commit_before>'use strict';
import request from 'request-promise';

/**
 * Koa-ses middleware to listen to get notifications and confirm subscription
 * by SNS from SES (services of AWS).
 * @param  {Function} callback [Called when a message notification occurs]
 * @param  {Object}   options
 * @return Void
 */
function koaSES(callback, options){

  let defaultOptions = {
    path: '/ses/notification'
  };

  options = Object.assign(defaultOptions, options);

  // Check if is set the callback
  if(!callback || !(callback instanceof Function)) {
    throw new Error('Missing a callback function to handle notifications received of SES from SNS.');
  }

  return function *(next) {

    // Check path based on options to handle SNS notifications
    if(this.path === options.path && this.method === 'POST') {

      try {

        // Get the body data and parse json from the http/s notification
        let getSNSBody = ()=> {
          return new Promise((resolve, reject)=>{
            try {
              let bodyData = [];
              this.req.on('data', (chunk)=>{ bodyData.push(chunk); });
              this.req.on('end', ()=>{
                bodyData = bodyData.join('');
                if(!bodyData) throw new Error('No body content in notification');
                return resolve(JSON.parse(bodyData));
              });
            } catch (e) {
              if(e) reject(e);
            }
          });
        };

        // Get the header of message type from SNS
        let requestMessageType = this.request.get('x-amz-sns-message-type');
        if(!requestMessageType) throw new Error('Header x-amz-sns-message-type is not set');

        let snsBody = yield getSNSBody();
        switch (requestMessageType) {
          case 'SubscriptionConfirmation':
            // The confirmSubscription is called when a SNS suscription channel
            // is added to a topic so the "subscriber" must confirm the
            // subscription calling the Subscription url
            try {
              yield request.get(snsBody.SubscribeURL);
              this.body = 'Suscription confirmed';
            }
            catch (e) {
              throw new Error(`SNS Subscription confirmation for Topic ARN [${snsBody.TopicArn}] failed`);
            }
            break;
          case 'Notification':
              // Get the message data of the notification to update email
              let snsMessage = JSON.parse(snsBody.Message);
              // Execute custom logic of callback and pass parameters
              let funcRes = yield callback.call(this, {
                messageId: snsMessage.mail.messageId,
                serviceStatus:snsMessage.notificationType,
                from:snsMessage.mail.source,
                status: (snsMessage.type === 'Delivery') ? 'Sent' : 'Failed',
                destination: snsMessage.mail.destination,
                timestamp: snsMessage.mail.timestamp,
                rawMessage: snsMessage
              });
              // Skip response if function returned value is false
              if(funcRes || typeof funcRes === 'undefined') {
                this.body = 'Ok';
              }
            break;
          default:
            this.status = 400;
            this.body = 'Unknow Message type';
        }

      } catch (e) {
        if(e) throw e;
      }

    } else {
      yield next;
    }
  };

}

module.exports = koaSES;
<commit_msg>Fix bad property name<commit_after>'use strict';
import request from 'request-promise';

/**
 * Koa-ses middleware to listen to get notifications and confirm subscription
 * by SNS from SES (services of AWS).
 * @param  {Function} callback [Called when a message notification occurs]
 * @param  {Object}   options
 * @return Void
 */
function koaSES(callback, options){

  let defaultOptions = {
    path: '/ses/notification'
  };

  options = Object.assign(defaultOptions, options);

  // Check if is set the callback
  if(!callback || !(callback instanceof Function)) {
    throw new Error('Missing a callback function to handle notifications received of SES from SNS.');
  }

  return function *(next) {

    // Check path based on options to handle SNS notifications
    if(this.path === options.path && this.method === 'POST') {

      try {

        // Get the body data and parse json from the http/s notification
        let getSNSBody = ()=> {
          return new Promise((resolve, reject)=>{
            try {
              let bodyData = [];
              this.req.on('data', (chunk)=>{ bodyData.push(chunk); });
              this.req.on('end', ()=>{
                bodyData = bodyData.join('');
                if(!bodyData) throw new Error('No body content in notification');
                return resolve(JSON.parse(bodyData));
              });
            } catch (e) {
              if(e) reject(e);
            }
          });
        };

        // Get the header of message type from SNS
        let requestMessageType = this.request.get('x-amz-sns-message-type');
        if(!requestMessageType) throw new Error('Header x-amz-sns-message-type is not set');

        let snsBody = yield getSNSBody();
        switch (requestMessageType) {
          case 'SubscriptionConfirmation':
            // The confirmSubscription is called when a SNS suscription channel
            // is added to a topic so the "subscriber" must confirm the
            // subscription calling the Subscription url
            try {
              yield request.get(snsBody.SubscribeURL);
              this.body = 'Suscription confirmed';
            }
            catch (e) {
              throw new Error(`SNS Subscription confirmation for Topic ARN [${snsBody.TopicArn}] failed`);
            }
            break;
          case 'Notification':
              // Get the message data of the notification to update email
              let snsMessage = JSON.parse(snsBody.Message);
              // Execute custom logic of callback and pass parameters
              let funcRes = yield callback.call(this, {
                messageId: snsMessage.mail.messageId,
                serviceStatus:snsMessage.notificationType,
                from:snsMessage.mail.source,
                status: (snsMessage.notificationType === 'Delivery') ? 'Sent' : 'Failed',
                destination: snsMessage.mail.destination,
                timestamp: snsMessage.mail.timestamp,
                rawMessage: snsMessage
              });
              // Skip response if function returned value is false
              if(funcRes || typeof funcRes === 'undefined') {
                this.body = 'Ok';
              }
            break;
          default:
            this.status = 400;
            this.body = 'Unknow Message type';
        }

      } catch (e) {
        if(e) throw e;
      }

    } else {
      yield next;
    }
  };

}

module.exports = koaSES;
<|endoftext|>


<commit_before>'use strict';

var debug = require('debug')('ftp-stream');
var deferred = require('deferred-stream');
var FtpClient = require('ftp');
var File = require('vinyl');
var async = require('async');

function _streamFtpGet(ftpConnectOptions, files, deferredStream) {
      var c = new FtpClient();
      c.on('error', function(e) {
		deferredStream.emit('error', e);
	});

      c.on('ready', function() {
        debug('ready to download %s', files);

        var getCalls = files.map(function(filePath){
          return function(callback) {
            debug('GETting `%s`', filePath);

            c.get(filePath, function(err, stream) {
              if (err) {
                if(err.code === 550) {
                  debug('File not found: %s', filePath);
                  err = new Error("File Not Found: " + filePath)
                }
                deferredStream.emit('error', err);
                return callback(err);
              }
              debug('got `%s`', filePath);

              stream.on('error',function(e){
                debug('Error transfering `%s`: %s', filePath, e);
                callback(e);
              });
              stream.on('end',function(){
                callback();
              });

              deferredStream.write(new File({
                path: filePath,
                contents: stream
              }));
            });
          };
        });

        //NOTE: as far as I can tell, FTP only supports on GET at a time
        // on a single connection, so this enforces that.
        async.series(getCalls, function(err){
          if(!err) {
            deferredStream.end();
          }
          c.end();
        });

      });

      c.connect(ftpConnectOptions);
}

function ftpStream(ftpConnectOptions, files) {
  //adjust for optional ftpConnectOptions
  if(!files){
    files = ftpConnectOptions;
    ftpConnectOptions = null;
  }
  //ensure files specified
  if(!files) {
    throw new Error('`files` must be specified');
  }
  //ensure array
  if(!Array.isArray(files)) {
    files = [files];
  }

  return deferred({objectMode: true},function(deferredStream) {
    _streamFtpGet(ftpConnectOptions, files, deferredStream);
  });
}

module.exports = ftpStream;
<commit_msg>add debug on error<commit_after>'use strict';

var debug = require('debug')('ftp-stream');
var deferred = require('deferred-stream');
var FtpClient = require('ftp');
var File = require('vinyl');
var async = require('async');

function _streamFtpGet(ftpConnectOptions, files, deferredStream) {
      var c = new FtpClient();
      c.on('error', function(e) {
                debug('Connection Error: %s', e);
		deferredStream.emit('error', e);
	});

      c.on('ready', function() {
        debug('ready to download %s', files);

        var getCalls = files.map(function(filePath){
          return function(callback) {
            debug('GETting `%s`', filePath);

            c.get(filePath, function(err, stream) {
              if (err) {
                if(err.code === 550) {
                  debug('File not found: %s', filePath);
                  err = new Error("File Not Found: " + filePath)
                }
                deferredStream.emit('error', err);
                return callback(err);
              }
              debug('got `%s`', filePath);

              stream.on('error',function(e){
                debug('Error transfering `%s`: %s', filePath, e);
                callback(e);
              });
              stream.on('end',function(){
                callback();
              });

              deferredStream.write(new File({
                path: filePath,
                contents: stream
              }));
            });
          };
        });

        //NOTE: as far as I can tell, FTP only supports on GET at a time
        // on a single connection, so this enforces that.
        async.series(getCalls, function(err){
          if(!err) {
            deferredStream.end();
          }
          c.end();
        });

      });

      c.connect(ftpConnectOptions);
}

function ftpStream(ftpConnectOptions, files) {
  //adjust for optional ftpConnectOptions
  if(!files){
    files = ftpConnectOptions;
    ftpConnectOptions = null;
  }
  //ensure files specified
  if(!files) {
    throw new Error('`files` must be specified');
  }
  //ensure array
  if(!Array.isArray(files)) {
    files = [files];
  }

  return deferred({objectMode: true},function(deferredStream) {
    _streamFtpGet(ftpConnectOptions, files, deferredStream);
  });
}

module.exports = ftpStream;
<|endoftext|>


<commit_before>var IPHistoryUI = (function(){
    "use strict";

    var tableID = "login-history-table",
        columns = ["timestamp","action","browser","ip","status"];

    function createEmptyTable(){
        var header = [
            text.localize("Date and Time"),
            text.localize("Action"),
            text.localize("Browser"),
            text.localize("IP Address"),
            text.localize("Status"),
        ];
        var metadata = {
            id: tableID,
            cols: columns
        };
        var data = [];
        var $table = Table.createFlexTable(data,metadata,header);
        return $table;
    }

    function updateTable(history){
        Table.appendTableBody(tableID, history, createRow);
    }

    function createRow(data){
        var userAgent = data['environment'];
        var history = userAgent.split(' ');
        var timestamp = history[0];
        var ip = history[2].split('=')[1];
        var browser = "Unknown";
        var verOffset, ver;
        if ((verOffset = userAgent.indexOf("OPR")) != -1){
            browser = "Opera";
            ver = userAgent.substring(verOffset+4).split(" ")[0];
        } else if ((verOffset = userAgent.indexOf("Chrome")) != -1){
            browser = "Chrome";
            ver = userAgent.substring(verOffset+7).split(" ")[0];
        } else if ((verOffset = userAgent.indexOf("Safari")) != -1){
            browser = "Safari";
            ver = userAgent.substring(verOffset+7).split(" ")[0];
        } else if ((verOffset = userAgent.indexOf("Firefox")) != -1){
            browser = "Firefox";
            ver = userAgent.substring(verOffset+8).split(" ")[0];
        } else if ((verOffset = userAgent.indexOf("MSIE")) != -1){
            browser = "Internet Explorer";
            ver = userAgent.substring(verOffset+5).split(" ")[0];
        }
        var status = data['status'] === 1 ? text.localize('Successful') : text.localize('Failed');
        var browserString = browser + " v" + ver;
        var $row = Table.createFlexTableRow([timestamp, data['action'], browserString, ip, status], columns, "data");
        $row.children(".timestamp").first().append('
' + history[1]);
        return $row[0];
    }

    function clearTableContent(){
        Table.clearTableBody(tableID);
        $("#" + tableID +">tfoot").hide();
    }

    return{
        createEmptyTable: createEmptyTable,
        updateTable: updateTable,
        clearTableContent: clearTableContent
    };
}());
<commit_msg>detect Edge<commit_after>var IPHistoryUI = (function(){
    "use strict";

    var tableID = "login-history-table",
        columns = ["timestamp","action","browser","ip","status"];

    function createEmptyTable(){
        var header = [
            text.localize("Date and Time"),
            text.localize("Action"),
            text.localize("Browser"),
            text.localize("IP Address"),
            text.localize("Status"),
        ];
        var metadata = {
            id: tableID,
            cols: columns
        };
        var data = [];
        var $table = Table.createFlexTable(data,metadata,header);
        return $table;
    }

    function updateTable(history){
        Table.appendTableBody(tableID, history, createRow);
    }

    function createRow(data){
        var userAgent = data['environment'];
        var history = userAgent.split(' ');
        var timestamp = history[0];
        var ip = history[2].split('=')[1];
        var browser = "Unknown",
            ver = "Unknown",
            verOffset = 0;
        if (/(msie|trident)/i.test(userAgent)){
            browser = "Internet Explorer";
            verOffset = /(msie)/i.test(userAgent) ? userAgent.indexOf("MSIE") : verOffset;
            verOffset = /(trident)/i.test(userAgent) ? userAgent.indexOf("Trident") : verOffset;
            ver = userAgent.substring(verOffset+13).split(" ")[0].split(":")[1].split(")")[0];
        } else if ((verOffset = userAgent.indexOf("Edge")) != -1) {
            browser = "Edge";
            ver = userAgent.substring(verOffset).split("/")[1].split(" ")[0];
        } else if ((verOffset = userAgent.indexOf("OPR")) != -1){
            browser = "Opera";
            ver = userAgent.substring(verOffset+4).split(" ")[0];
        } else if ((verOffset = userAgent.indexOf("Chrome")) != -1){
            browser = "Chrome";
            ver = userAgent.substring(verOffset+7).split(" ")[0];
        } else if ((verOffset = userAgent.indexOf("Safari")) != -1){
            browser = "Safari";
            ver = userAgent.substring(verOffset+7).split(" ")[0];
        } else if ((verOffset = userAgent.indexOf("Firefox")) != -1){
            browser = "Firefox";
            ver = userAgent.substring(verOffset+8).split(" ")[0];
        }
        var status = data['status'] === 1 ? text.localize('Successful') : text.localize('Failed');
        var browserString = browser + " v" + ver;
        var $row = Table.createFlexTableRow([timestamp, data['action'], browserString, ip, status], columns, "data");
        $row.children(".timestamp").first().append('
' + history[1]);
        return $row[0];
    }

    function clearTableContent(){
        Table.clearTableBody(tableID);
        $("#" + tableID +">tfoot").hide();
    }

    return{
        createEmptyTable: createEmptyTable,
        updateTable: updateTable,
        clearTableContent: clearTableContent
    };
}());
<|endoftext|>


<commit_before>(function (win) {
    'use strict';

    if (!win.refreshAjax) return;
    var edit = false;

    refreshAjax.navigating(function (req, resp) {
        edit = req.data && (req.data.action == 'edit' || req.data.action == 'clear');
    });

    refreshAjax.updating(function (req, resp) {
        if (req.target.id === 'todo-form') {
            var newTodoId = 0;
            for (var id in resp.panels) {
                var todoId = Number(id.slice(4));
                if (todoId && newTodoId < todoId)
                    newTodoId = todoId;
            }
            if (newTodoId && !document.getElementById('todo' + newTodoId)) {
                document.getElementById('todo-list')
                    .insertAdjacentHTML('beforeend', '

');
            }
        }
        if (req.data && req.data.action === 'edit' && !edit)
            resp.panels = null;
    });

    refreshAjax.updated(function (req, resp) {
        if (req.target.getAttribute) {
            var todoId = req.target.getAttribute('data-todo');
            if (todoId && !resp.panels['todo' + todoId]) {
                var todo = document.getElementById('todo' + todoId);
                if (todo) {
                    var listItem = todo.parentNode;
                    listItem.parentNode.removeChild(listItem);
                }
            }
        }
        initEdit(req);
    });

    function initEdit(req) {
        var el = document.querySelector('#todo-list input[type="text"]');
        if (el) {
            el.focus();
            el.value = el.value;
            el.addEventListener('blur', function (e) {
                if (!edit)
                    refreshAjax.navigate({ action: 'edit', Title: el.value }, el.form);
            });
            el.addEventListener('keyup', function (e) {
                if (!edit && e.keyCode == 27)
                    refreshAjax.navigate({ action: 'clear' }, el.form);
            });
        } else if (req.target.id === 'todo-form') {
            document.getElementById('new-todo').focus();
        }
    }

    initEdit({ target: { id: 'todo-form' } });
})(window);
<commit_msg>Need to check for clear as well as edit. This is best checked in chrome with slowest connection emulated. Send cancel edit request then another request. When cancel edit response returns should ignore and let the second response process. If don't ignore it then the cancel edit response updates the url and prevents second response processing.<commit_after>(function (win) {
    'use strict';

    if (!win.refreshAjax) return;
    var edit = false;

    refreshAjax.navigating(function (req, resp) {
        edit = req.data && (req.data.action == 'edit' || req.data.action == 'clear');
    });

    refreshAjax.updating(function (req, resp) {
        if (req.target.id === 'todo-form') {
            var newTodoId = 0;
            for (var id in resp.panels) {
                var todoId = Number(id.slice(4));
                if (todoId && newTodoId < todoId)
                    newTodoId = todoId;
            }
            if (newTodoId && !document.getElementById('todo' + newTodoId)) {
                document.getElementById('todo-list')
                    .insertAdjacentHTML('beforeend', '

');
            }
        }
        if (req.data && (req.data.action == 'edit' || req.data.action == 'clear') && !edit)
            resp.panels = null;
    });

    refreshAjax.updated(function (req, resp) {
        if (req.target.getAttribute) {
            var todoId = req.target.getAttribute('data-todo');
            if (todoId && !resp.panels['todo' + todoId]) {
                var todo = document.getElementById('todo' + todoId);
                if (todo) {
                    var listItem = todo.parentNode;
                    listItem.parentNode.removeChild(listItem);
                }
            }
        }
        initEdit(req);
    });

    function initEdit(req) {
        var el = document.querySelector('#todo-list input[type="text"]');
        if (el) {
            el.focus();
            el.value = el.value;
            el.addEventListener('blur', function (e) {
                if (!edit)
                    refreshAjax.navigate({ action: 'edit', Title: el.value }, el.form);
            });
            el.addEventListener('keyup', function (e) {
                if (!edit && e.keyCode == 27)
                    refreshAjax.navigate({ action: 'clear' }, el.form);
            });
        } else if (req.target.id === 'todo-form') {
            document.getElementById('new-todo').focus();
        }
    }

    initEdit({ target: { id: 'todo-form' } });
})(window);
<|endoftext|>


<commit_before>( function ( $, vg ) {

	'use strict';
	/* global require */

	var wrapper,
		VegaWrapper = require( 'graph-shared' ),
		urlParse = require( 'url-parse' );

	wrapper = new VegaWrapper(
		vg.util.load, true,
		false,
		{
			'https': [
				'mediawiki.org',
				'wikibooks.org',
				'wikidata.org',
				'wikimedia.org',
				'wikimediafoundation.org',
				'wikinews.org',
				'wikipedia.org',
				'wikiquote.org',
				'wikisource.org',
				'wikiversity.org',
				'wikivoyage.org',
				'wiktionary.org',
			],
			'http': [ // optional
				'wmflabs.org',
			],
			'wikirawupload': [
				'upload.wikimedia.org',
				'upload.beta.wmflabs.org', // optional
			],
			'wikidatasparql': [
				'query.wikidata.org',
				'wdqs-test.wmflabs.org', // optional
			],
			'geoshape': [
				'maps.wikimedia.org',
			]
		},
		false,
		function ( warning ) {
			console.log( warning );
		}, $.extend, function ( opt ) {
			// Parse URL
			var uri = urlParse( opt.url, true );
			// reduce confusion, only keep expected values
			delete uri.port;
			// If url begins with   protocol:///...  mark it as having relative host
			if ( /^[a-z]+:\/\/\//.test( opt.url ) ) {
				uri.isRelativeHost = true;
			}
			return uri;
		}, function ( uri, opt ) {
			// Format URL back into a string
			// Revert path into pathname
			uri.path = uri.pathname;
			delete uri.pathname;

			if ( location.host.toLowerCase() === uri.host.toLowerCase() ) {
				// Only send this header when hostname is the same.
				// This is broader than the same-origin policy,
				// but playing on the safer side.
				opt.headers = { 'Treat-as-Untrusted': 1 };
			} else if ( opt.addCorsOrigin ) {
				// All CORS api calls require origin parameter.
				// It would be better to use location.origin,
				// but apparently it's not universal yet.
				uri.query.origin = location.protocol + '//' + location.host;
			}

			return uri.toString();
		} );

}( jQuery, vg ) );
<commit_msg>fix wrapper url parsing/formating<commit_after>( function ( $, vg ) {

	'use strict';
	/* global require */

	var wrapper,
		VegaWrapper = require( 'graph-shared' ),
		urlParse = require( 'url-parse' );

	wrapper = new VegaWrapper(
		vg.util.load, true,
		false,
		{
			'https': [
				'mediawiki.org',
				'wikibooks.org',
				'wikidata.org',
				'wikimedia.org',
				'wikimediafoundation.org',
				'wikinews.org',
				'wikipedia.org',
				'wikiquote.org',
				'wikisource.org',
				'wikiversity.org',
				'wikivoyage.org',
				'wiktionary.org',
			],
			'http': [ // optional
				'wmflabs.org',
			],
			'wikirawupload': [
				'upload.wikimedia.org',
				'upload.beta.wmflabs.org', // optional
			],
			'wikidatasparql': [
				'query.wikidata.org',
				'wdqs-test.wmflabs.org', // optional
			],
			'geoshape': [
				'maps.wikimedia.org',
			]
		},
		false,
		function ( warning ) {
			console.log( warning );
		}, $.extend, function ( opt ) {
			// Parse URL
			var uri = urlParse( opt.url, true );
			// reduce confusion, only keep expected values
			delete uri.port;
			// If url begins with   protocol:///...  mark it as having relative host
			if ( /^[a-z]+:\/\/\//.test( opt.url ) ) {
				uri.isRelativeHost = true;
			}
			if (uri.protocol && uri.protocol[uri.protocol.length - 1] === ':') {
				uri.protocol = uri.protocol.substring(0, uri.protocol.length - 1);
			}
			return uri;
		}, function ( uri, opt ) {
			// Format URL back into a string
			if ( location.host.toLowerCase() === uri.host.toLowerCase() ) {
				// Only send this header when hostname is the same.
				// This is broader than the same-origin policy,
				// but playing on the safer side.
				opt.headers = { 'Treat-as-Untrusted': 1 };
			} else if ( opt.addCorsOrigin ) {
				// All CORS api calls require origin parameter.
				// It would be better to use location.origin,
				// but apparently it's not universal yet.
				uri.query.origin = location.protocol + '//' + location.host;
			}

			return uri.toString();
		} );

}( jQuery, vg ) );
<|endoftext|>


<commit_before>angular.module("flooshie", [])
.controller("toiletCtrl", ["$scope", "$http", function($scope, $http){
    //MAKE URL VARIABLE
    $http.put(url)
    .success(function(data){
        console.log(data);
    });
    .error(function(){
        console.log("ERROR");
    });
}]);

if(localStorage["todos"]){
    var todos = JSON.parse(localStorage.getItem("todos"));
} else {
    localStorage.setItem("todos",JSON.stringify({}));
    var todos = {} ;
};

var flush = Function() {
    if button=pressed down {
        flush

    }
}
<commit_msg>Added empty flush functions<commit_after>angular.module("flooshie", [])
.controller("toiletCtrl", ["$scope", "$http", function($scope, $http){

    $("#poo").on("click", function(){

    };

    $("#pee").on("click", function(){

    };

    function liftSeat(){

    };

    function lowerSeat(){

    };

    function flush(){

    };

    //MAKE URL VARIABLE
    $http.put(url)
    .success(function(data){
        console.log(data);
    });
    .error(function(){
        console.log("ERROR");
    });
}]);

if(localStorage["todos"]){
    var todos = JSON.parse(localStorage.getItem("todos"));
} else {
    localStorage.setItem("todos",JSON.stringify({}));
    var todos = {} ;
};

var flush = Function() {
    if button=pressed down {
        flush

    }
}
<|endoftext|>