<commit_before>-ace.define("ace/mode/verilog_highlight_rules", ["require", "exports", "module", "ace/lib/oop", "ace/mode/text_highlight_rules"], function(e, t, n) {
    "use strict";
    var r = e("../lib/oop"),
        i = e("./text_highlight_rules").TextHighlightRules,
        s = function() {
            var e = "if|endif|else\sif",
                t = "use",
                n = "near|with|around|mention",
                r = this.createKeywordMapper({
                    "support.function": n,
                    keyword: e,
                    "constant.language": t
                }, "identifier", !0);
            this.$rules = {
                start: [{
                    token: "comment",
                    regex: "//.*$"
                }, {
                    token: "comment.start",
                    regex: "/\\*",
                    next: [{
                        token: "comment.end",
                        regex: "\\*/",
                        next: "start"
                    }, {
                        defaultToken: "comment"
                    }]
                }, {
                    token: "string",
                    regex: '".*?"'
                }, {
                    token: "string",
                    regex: "'.*?'"
                }, {
                    token: "constant.numeric",
                    regex: "[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b"
                }, {
                    token: r,
                    regex: "[a-zA-Z_$][a-zA-Z0-9_$]*\\b"
                }, {
                    token: "keyword.operator",
                    regex: "\\+|\\-|\\/|\\/\\/|%|<@>|@>|<@|&|\\^|~|<|>|<=|=>|==|!=|<>|=|or"
                }, {
                    token: "paren.lparen",
                    regex: "[\\(]"
                }, {
                    token: "paren.rparen",
                    regex: "[\\)]"
                }, {
                    token: "text",
                    regex: "\\s+"
                }, {
                    token: "if.start",
                    regex: "IF"
                }, {
                    token: "if.end",
                    regex: "ENDIF"
                }]
            }, this.normalizeRules()
        };
    r.inherits(s, i), t.VerilogHighlightRules = s
}), ace.define("ace/mode/verilog", ["require", "exports", "module", "ace/lib/oop", "ace/mode/text", "ace/mode/verilog_highlight_rules", "ace/range"], function(e, t, n) {
    "use strict";
    var r = e("../lib/oop"),
        i = e("./text").Mode,
        s = e("./verilog_highlight_rules").VerilogHighlightRules,
        o = e("../range").Range,
        u = function() {
            this.HighlightRules = s, this.$behaviour = this.$defaultBehaviour
        };
    r.inherits(u, i),
        function() {
            this.lineCommentStart = "//", this.blockComment = {
                start: "/*",
                end: "*/"
            }, this.$id = "ace/mode/verilog"
        }.call(u.prototype), t.Mode = u
})
<commit_msg>Update mode-verilog.js<commit_after>-ace.define("ace/mode/verilog_highlight_rules", ["require", "exports", "module", "ace/lib/oop", "ace/mode/text_highlight_rules"], function(e, t, n) {
    "use strict";
    var r = e("../lib/oop"),
        i = e("./text_highlight_rules").TextHighlightRules,
        s = function() {
            var e = "if|endif|^else\sif$",
                t = "use",
                n = "near|with|around|mention",
                r = this.createKeywordMapper({
                    "support.function": n,
                    keyword: e,
                    "constant.language": t
                }, "identifier", !0);
            this.$rules = {
                start: [{
                    token: "comment",
                    regex: "//.*$"
                }, {
                    token: "comment.start",
                    regex: "/\\*",
                    next: [{
                        token: "comment.end",
                        regex: "\\*/",
                        next: "start"
                    }, {
                        defaultToken: "comment"
                    }]
                }, {
                    token: "string",
                    regex: '".*?"'
                }, {
                    token: "string",
                    regex: "'.*?'"
                }, {
                    token: "constant.numeric",
                    regex: "[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b"
                }, {
                    token: r,
                    regex: "[a-zA-Z_$][a-zA-Z0-9_$]*\\b"
                }, {
                    token: "keyword.operator",
                    regex: "\\+|\\-|\\/|\\/\\/|%|<@>|@>|<@|&|\\^|~|<|>|<=|=>|==|!=|<>|=|or"
                }, {
                    token: "paren.lparen",
                    regex: "[\\(]"
                }, {
                    token: "paren.rparen",
                    regex: "[\\)]"
                }, {
                    token: "text",
                    regex: "\\s+"
                }, {
                    token: "if.start",
                    regex: "IF"
                }, {
                    token: "if.end",
                    regex: "ENDIF"
                }]
            }, this.normalizeRules()
        };
    r.inherits(s, i), t.VerilogHighlightRules = s
}), ace.define("ace/mode/verilog", ["require", "exports", "module", "ace/lib/oop", "ace/mode/text", "ace/mode/verilog_highlight_rules", "ace/range"], function(e, t, n) {
    "use strict";
    var r = e("../lib/oop"),
        i = e("./text").Mode,
        s = e("./verilog_highlight_rules").VerilogHighlightRules,
        o = e("../range").Range,
        u = function() {
            this.HighlightRules = s, this.$behaviour = this.$defaultBehaviour
        };
    r.inherits(u, i),
        function() {
            this.lineCommentStart = "//", this.blockComment = {
                start: "/*",
                end: "*/"
            }, this.$id = "ace/mode/verilog"
        }.call(u.prototype), t.Mode = u
})
<|endoftext|>


<commit_before>/*
    #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
      This file is part of the Smart Developer Hub Project:
        http://www.smartdeveloperhub.org/
      Center for Open Middleware
            http://www.centeropenmiddleware.com/
    #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
      Copyright (C) 2015 Center for Open Middleware.
    #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
      You may obtain a copy of the License at
                http://www.apache.org/licenses/LICENSE-2.0
      Unless required by applicable law or agreed to in writing, software
      distributed under the License is distributed on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      See the License for the specific language governing permissions and
     limitations under the License.
    #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
*/

"use strict";

var Bridge = require('./PhantomBridge');

function WidgetSnapshotProvider (id, timeout) {
    this.id = id;
    this.timeout = timeout;
    this.creationDate = new Date();
    this.isReady = false;
    this.bridge = null;
    this.currentJob = null;
    this.currentJobs = 0;
}

WidgetSnapshotProvider.prototype = {
    constructor: WidgetSnapshotProvider

    /**
     * Initialize the web capturer.
     * @param onReady
     */
    , init: function(requireJsWidgetList, onReady) {

        if(typeof onReady !== 'function') {
            throw new Error(this.msg('A callback function must be specified in "init" method.'));
        }

        this.bridge = new Bridge(this.id);
        this.bridge.initFramework(requireJsWidgetList, phantomWebMessageHandler.bind(this), onReady);

    }

    , destroy: function() {

        this.isReady = false;
        this.bridge.close();
        this.bridge = null;

    }

    , getCreationDate: function() {
        return this.creationDate;
    }

    , isReady: function() {
        return this.isReady;
    }

    , getChartImage: function(chart, viewPort, metrics, config, onImageReady, onError) {

        if(typeof onImageReady !== 'function')
            throw new Error(this.msg('A onImageReady function must be specified in "getChartImage" method.'));

        if(this.currentJob != null) {
            throw new Error(this.msg('The WidgetSnapshotProvider instance is busy!'));
        }

        this.currentJob = {
            chart: chart,
            metrics: metrics,
            config: config,
            onImageReady: onImageReady,
            onError: onError
        };

        //Set the viewport
        this.bridge.getPage().viewportSize = viewPort;

        //Set the clipRect to be sure that the image generated is of the size we want
        this.bridge.getPage().clipRect = {
            top: 0,
            left: 0,
            width: viewPort.width,
            height: viewPort.height
        };

        //Load the chart in the web executor
        //The execution of the job will continue when the DATA_RECEIVED event is received
        var success = this.bridge.getPage().evaluate(chartCreateWebFunction, chart, metrics, config, this.timeout); //TODO: maybe asynchronous?

        if(!success) {
            this.bridge.getPage().evaluate(chartDeleteWebFunction);
            onError(); //Callback with empty file name
        }

    }

    , msg: function(txt) {
        return 'WidgetSnapshotProvider('+this.id+') ' + txt;
    },

    kill: function () {
        this.destroy();
        this.currentJobs = 0;
    },

    decrementJobCount: function() {
        if(this.currentJobs > 0) {
            this.currentJobs--;
        }
    },

    incrementJobCount: function() {
        if(this.currentJobs < 1) {
            this.currentJobs = 1;
        } else {
            throw new Error("This worker has reached the maximum of jobs");
        }
    },

    isCompletellyBusy: function() {
        return this.currentJobs === 1;
    }

};

var processDataReceivedEvent = function() {

    setTimeout(function() { //TODO: detect if the image has been rendered

        if(this.currentJob == null) {
            console.warn(this.msg("A job in the WidgetSnapshotProvider was lost!!!"));
        }

        var fileName = '/tmp/' + Math.round(Math.random() * 1000000000) + ".png"; //TODO: compatibility with Windows?
        var success = this.bridge.getPage().render(fileName);

        //Clear the chart
        this.bridge.getPage().evaluate(chartDeleteWebFunction);

        // Clear the current job information
        var onImageReady = this.currentJob.onImageReady;
        this.currentJob = null;

        // Execute the callback
        onImageReady(success ? fileName : undefined);

    }.bind(this), 500);

};

var processErrorEvent = function(msg) {

    //Clear the chart
    this.bridge.getPage().evaluate(chartDeleteWebFunction);

    // Clear the current job information
    var onError = this.currentJob.onError;
    this.currentJob = null;

    // Execute error callback
    onError(msg);
};

/**
 * This method handles all the messages sent from the webExecutor to Phantom
 * @param data
 */
var phantomWebMessageHandler = function(data) {
    switch (data.type) {
        case 'DATA_RECEIVED': processDataReceivedEvent.call(this); break;
        case 'ERROR': processErrorEvent.call(this, data.data); break;
        default:
            console.warn(this.msg("Received unknown type in phantomWebMessageHandler!"));
            break;
    }
};

var chartDeleteWebFunction = function() {

    //Clear previous chart
    if(window.chart != null) {
        Bridge.stopEventTransmission(window.chart, "DATA_RECEIVED");
        window.chart.delete();
    }

    $("body").empty();

};

/**
 * This method is evaluated in the WebExecutor and creates the requested chart in the page
 * @param chartType Name of the class of the chart (the name with which the chart is registered in the sdh-framework).
 * @param metrics Metrics array to pass to the chart constructor.
 * @param config Configuration to pass to the chart constructor.
 * @param timeout Maximum execution time
 * @returns {boolean}
 */
var chartCreateWebFunction = function(chartType, metrics, config, timeout) {

    //TODO: allow functions in config??
    //TODO: improve function detection (with/without spaces, with/without name, etc)

    for(var param in config) {
        var val = config[param];
        if(typeof val === 'string' && val.indexOf('function (') === 0) {
            config[param] = createSandboxedFuntion(val)();
        }
    }

    $("body").append("

");

    var domElement = document.getElementById("chart");

    try {
        var constructor = framework.widgets[chartType];
        if(constructor != null) {

            //Handle errors
            constructor.prototype.onError = function(msg) {
                Bridge.sendToPhantom("ERROR", msg);
            };

            window.chart = new constructor(domElement, metrics, [], config);
            Bridge.transmitEventAndExecute(window.chart, "DATA_RECEIVED", false, function() {
                clearTimeout(window.chartTimeout);
                window.chartTimeout = null;
            });

            //Set a timeout
            window.chartTimeout = setTimeout(function() {
                window.chartTimeout = null;
                Bridge.sendToPhantom("ERROR", "Max execution time reached!");

            }, timeout);

            return true;
        }

    } catch(e) {
        console.error(e);
    }

    return false;

};

module.exports = WidgetSnapshotProvider;<commit_msg>Allow functions in metrics.<commit_after>/*
    #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
      This file is part of the Smart Developer Hub Project:
        http://www.smartdeveloperhub.org/
      Center for Open Middleware
            http://www.centeropenmiddleware.com/
    #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
      Copyright (C) 2015 Center for Open Middleware.
    #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
      You may obtain a copy of the License at
                http://www.apache.org/licenses/LICENSE-2.0
      Unless required by applicable law or agreed to in writing, software
      distributed under the License is distributed on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      See the License for the specific language governing permissions and
     limitations under the License.
    #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
*/

"use strict";

var Bridge = require('./PhantomBridge');

function WidgetSnapshotProvider (id, timeout) {
    this.id = id;
    this.timeout = timeout;
    this.creationDate = new Date();
    this.isReady = false;
    this.bridge = null;
    this.currentJob = null;
    this.currentJobs = 0;
}

WidgetSnapshotProvider.prototype = {
    constructor: WidgetSnapshotProvider

    /**
     * Initialize the web capturer.
     * @param onReady
     */
    , init: function(requireJsWidgetList, onReady) {

        if(typeof onReady !== 'function') {
            throw new Error(this.msg('A callback function must be specified in "init" method.'));
        }

        this.bridge = new Bridge(this.id);
        this.bridge.initFramework(requireJsWidgetList, phantomWebMessageHandler.bind(this), onReady);

    }

    , destroy: function() {

        this.isReady = false;
        this.bridge.close();
        this.bridge = null;

    }

    , getCreationDate: function() {
        return this.creationDate;
    }

    , isReady: function() {
        return this.isReady;
    }

    , getChartImage: function(chart, viewPort, metrics, config, onImageReady, onError) {

        if(typeof onImageReady !== 'function')
            throw new Error(this.msg('A onImageReady function must be specified in "getChartImage" method.'));

        if(this.currentJob != null) {
            throw new Error(this.msg('The WidgetSnapshotProvider instance is busy!'));
        }

        this.currentJob = {
            chart: chart,
            metrics: metrics,
            config: config,
            onImageReady: onImageReady,
            onError: onError
        };

        //Set the viewport
        this.bridge.getPage().viewportSize = viewPort;

        //Set the clipRect to be sure that the image generated is of the size we want
        this.bridge.getPage().clipRect = {
            top: 0,
            left: 0,
            width: viewPort.width,
            height: viewPort.height
        };

        //Load the chart in the web executor
        //The execution of the job will continue when the DATA_RECEIVED event is received
        var success = this.bridge.getPage().evaluate(chartCreateWebFunction, chart, metrics, config, this.timeout); //TODO: maybe asynchronous?

        if(!success) {
            this.bridge.getPage().evaluate(chartDeleteWebFunction);
            onError(); //Callback with empty file name
        }

    }

    , msg: function(txt) {
        return 'WidgetSnapshotProvider('+this.id+') ' + txt;
    },

    kill: function () {
        this.destroy();
        this.currentJobs = 0;
    },

    decrementJobCount: function() {
        if(this.currentJobs > 0) {
            this.currentJobs--;
        }
    },

    incrementJobCount: function() {
        if(this.currentJobs < 1) {
            this.currentJobs = 1;
        } else {
            throw new Error("This worker has reached the maximum of jobs");
        }
    },

    isCompletellyBusy: function() {
        return this.currentJobs === 1;
    }

};

var processDataReceivedEvent = function() {

    setTimeout(function() { //TODO: detect if the image has been rendered

        if(this.currentJob == null) {
            console.warn(this.msg("A job in the WidgetSnapshotProvider was lost!!!"));
        }

        var fileName = '/tmp/' + Math.round(Math.random() * 1000000000) + ".png"; //TODO: compatibility with Windows?
        var success = this.bridge.getPage().render(fileName);

        //Clear the chart
        this.bridge.getPage().evaluate(chartDeleteWebFunction);

        // Clear the current job information
        var onImageReady = this.currentJob.onImageReady;
        this.currentJob = null;

        // Execute the callback
        onImageReady(success ? fileName : undefined);

    }.bind(this), 500);

};

var processErrorEvent = function(msg) {

    //Clear the chart
    this.bridge.getPage().evaluate(chartDeleteWebFunction);

    // Clear the current job information
    var onError = this.currentJob.onError;
    this.currentJob = null;

    // Execute error callback
    onError(msg);
};

/**
 * This method handles all the messages sent from the webExecutor to Phantom
 * @param data
 */
var phantomWebMessageHandler = function(data) {
    switch (data.type) {
        case 'DATA_RECEIVED': processDataReceivedEvent.call(this); break;
        case 'ERROR': processErrorEvent.call(this, data.data); break;
        default:
            console.warn(this.msg("Received unknown type in phantomWebMessageHandler!"));
            break;
    }
};

var chartDeleteWebFunction = function() {

    //Clear previous chart
    if(window.chart != null) {
        Bridge.stopEventTransmission(window.chart, "DATA_RECEIVED");
        window.chart.delete();
    }

    $("body").empty();

};

/**
 * This method is evaluated in the WebExecutor and creates the requested chart in the page
 * @param chartType Name of the class of the chart (the name with which the chart is registered in the sdh-framework).
 * @param metrics Metrics array to pass to the chart constructor.
 * @param config Configuration to pass to the chart constructor.
 * @param timeout Maximum execution time
 * @returns {boolean}
 */
var chartCreateWebFunction = function(chartType, metrics, config, timeout) {

    //TODO: allow functions in config??
    //TODO: improve function detection (with/without spaces, with/without name, etc)

    for(var param in config) {
        var val = config[param];
        if(typeof val === 'string' && val.indexOf('function (') === 0) {
            config[param] = createSandboxedFuntion(val)();
        }
    }

    for(var i = 0; i < metrics.length; i++) {
        var metric = metrics[i];
        if(metric instanceof Object) {
            for(var param in metric) {
                var val = metric[param];
                if(typeof val === 'string' && val.indexOf('function (') === 0) {
                    metric[param] = createSandboxedFuntion(val)();
                }
            }
        }
    }

    $("body").append("

");

    var domElement = document.getElementById("chart");

    try {
        var constructor = framework.widgets[chartType];
        if(constructor != null) {

            //Handle errors
            constructor.prototype.onError = function(msg) {
                Bridge.sendToPhantom("ERROR", msg);
            };

            window.chart = new constructor(domElement, metrics, [], config);
            Bridge.transmitEventAndExecute(window.chart, "DATA_RECEIVED", false, function() {
                clearTimeout(window.chartTimeout);
                window.chartTimeout = null;
            });

            //Set a timeout
            window.chartTimeout = setTimeout(function() {
                window.chartTimeout = null;
                Bridge.sendToPhantom("ERROR", "Max execution time reached!");

            }, timeout);

            return true;
        }

    } catch(e) {
        console.error(e);
    }

    return false;

};

module.exports = WidgetSnapshotProvider;<|endoftext|>


<commit_before>'use strict';

var async = require('async');
var express = require('express');
var fs = require('fs');
var multiparty = require('multiparty');
var util = require('util');

var nodemailer = require('nodemailer');

/* Make an http server to receive the webhook. */
var server = express();

server.head('/webhook', function (req, res) {
    console.log('Received head request from webhook.');
    res.sendStatus(200);
});

server.post('/webhook', function (req, res) {
    console.log('Receiving webhook.');

    /* Respond early to avoid timouting the mailin server. */
    // res.send(200);

    /* Parse the multipart form. The attachments are parsed into fields and can
     * be huge, so set the maxFieldsSize accordingly. */
    var form = new multiparty.Form({
        maxFieldsSize: 70000000
    });

    form.on('progress', function () {
        var start = Date.now();
        var lastDisplayedPercentage = -1;
        return function (bytesReceived, bytesExpected) {
            var elapsed = Date.now() - start;
            var percentage = Math.floor(bytesReceived / bytesExpected * 100);
            if (percentage % 20 === 0 && percentage !== lastDisplayedPercentage) {
                lastDisplayedPercentage = percentage;
                console.log('Form upload progress ' +
                    percentage + '% of ' + bytesExpected / 1000000 + 'Mb. ' + elapsed + 'ms');
            }
        };
    }());

    form.parse(req, function (err, fields) {
        console.log(util.inspect(fields.mailinMsg, {
            depth: 5
        }));

        console.log('Parsed fields: ' + Object.keys(fields));

        /* Write down the payload for ulterior inspection. */
        async.auto({
            writeParsedMessage: function (cbAuto) {
                fs.writeFile('payload.json', fields.mailinMsg, cbAuto);
            },
            writeAttachments: function (cbAuto) {
                var msg = JSON.parse(fields.mailinMsg);
                async.eachLimit(msg.attachments, 3, function (attachment, cbEach) {
                    fs.writeFile(attachment.generatedFileName, fields[attachment.generatedFileName], 'base64', cbEach);
                }, cbAuto);
            }
        }, function (err) {
            if (err) {
                console.log(err.stack);
                res.sendStatus(500, 'Unable to write payload');
            } else {
                console.log('Webhook payload written.');
                res.sendStatus(200);
                var msg = JSON.parse(fields.mailinMsg);
                if (msg.to[0].address == 'simon@beardedmail.com') {
                    var nodemailer = require('nodemailer');
                    var transporter = nodemailer.createTransport();
                    transporter.sendMail({
                        from: 'admin@beardedmail.com',
                        to: 'simonhoye@gmail.com',
                        subject: 'You have BeardedMail from <'+msg.from[0].address + ">",
                        text: msg.subject,
                        html: msg.html
                    });
                }

            }
        });
    });
});

server.listen(3000, function (err) {
    if (err) {
        console.log(err);
    } else {
        console.log('Http server listening on port 3000');
    }
});<commit_msg>red wine causes silly mistakes<commit_after>'use strict';

var async = require('async');
var express = require('express');
var fs = require('fs');
var multiparty = require('multiparty');
var util = require('util');

var nodemailer = require('nodemailer');

/* Make an http server to receive the webhook. */
var server = express();

server.head('/webhook', function (req, res) {
    console.log('Received head request from webhook.');
    res.sendStatus(200);
});

server.post('/webhook', function (req, res) {
    console.log('Receiving webhook.');

    /* Respond early to avoid timouting the mailin server. */
    // res.send(200);

    /* Parse the multipart form. The attachments are parsed into fields and can
     * be huge, so set the maxFieldsSize accordingly. */
    var form = new multiparty.Form({
        maxFieldsSize: 70000000
    });

    form.on('progress', function () {
        var start = Date.now();
        var lastDisplayedPercentage = -1;
        return function (bytesReceived, bytesExpected) {
            var elapsed = Date.now() - start;
            var percentage = Math.floor(bytesReceived / bytesExpected * 100);
            if (percentage % 20 === 0 && percentage !== lastDisplayedPercentage) {
                lastDisplayedPercentage = percentage;
                console.log('Form upload progress ' +
                    percentage + '% of ' + bytesExpected / 1000000 + 'Mb. ' + elapsed + 'ms');
            }
        };
    }());

    form.parse(req, function (err, fields) {
        var that = this;
        console.log(util.inspect(fields.mailinMsg, {
            depth: 5
        }));

        console.log('Parsed fields: ' + Object.keys(fields));

        /* Write down the payload for ulterior inspection. */
        async.auto({
            writeParsedMessage: function (cbAuto) {
                fs.writeFile('payload.json', fields.mailinMsg, cbAuto);
            },
            writeAttachments: function (cbAuto) {
                var msg = JSON.parse(fields.mailinMsg);
                async.eachLimit(msg.attachments, 3, function (attachment, cbEach) {
                    fs.writeFile(attachment.generatedFileName, fields[attachment.generatedFileName], 'base64', cbEach);
                }, cbAuto);
            }
        }, function (err) {
            if (err) {
                console.log(err.stack);
                res.sendStatus(500, 'Unable to write payload');
            } else {
                console.log('Webhook payload written.');
                res.sendStatus(200);
                var msg = JSON.parse(that.fields.mailinMsg);
                if (msg.to[0].address == 'simon@beardedmail.com') {
                    var nodemailer = require('nodemailer');
                    var transporter = nodemailer.createTransport();
                    transporter.sendMail({
                        from: 'admin@beardedmail.com',
                        to: 'simonhoye@gmail.com',
                        subject: 'You have BeardedMail from <'+msg.from[0].address + ">",
                        text: msg.subject,
                        html: msg.html
                    });
                }

            }
        });
    });
});

server.listen(3000, function (err) {
    if (err) {
        console.log(err);
    } else {
        console.log('Http server listening on port 3000');
    }
});<|endoftext|>


<commit_before>/**
 * Copyright (c) 2013-2015 Yamagishi Kazutoshi
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
(function(global) {
  'use strict';

  var undefined;
  var window = global.window || {};
  var HEADLINE_SELECTOR = [
    'h1',
    'h2',
    'h3',
    'h4',
    'h5',
    'h6'
  ].map(function(selector) {
    return selector + ':first-child';
  }).join(', ');

  function removeChildNodes(node) {
    var document = node.ownerDocument;
    var headline = node.querySelector(HEADLINE_SELECTOR);
    var lastChild = node.querySelector(':last-child');
    var range = document.createRange();
    range.setStartAfter(headline);
    range.setEndBefore(lastChild);
    range.deleteContents();
    return lastChild;
  };

  function QueryString() {
  }

  QueryString.stringify = function stringify(value) {
    if (typeof value !== 'object') {
      return '' + value;
    }
    var pairs = [];
    var pair, key, item;
    for (key in value) {
      if (!value.hasOwnProperty(key) || !(item = value[key])) {
        continue;
      }
      pair = [encodeURIComponent(key)];
      if (typeof item !== 'boolean') {
        pair.push(encodeURIComponent(item));
      }
      pairs.push(pair.join('='));
    }
    return pairs.join('&');
  };

  function JSONHttpRequest() {
    this.method = undefined;
    this.uri = undefined;
    this.response = null;
    this.responseText = null;
    this.listeners = [];
  };

  (function(proto) {
    function executeListeners(event, listeners) {
      var len, i, listener;
      if (typeof listeners !== 'undefined') {
        len = listeners.length;
        for (i = 0; i < len; ++i) {
          listener = listeners[i];
          listen.call(this, event, listener);
        }
      }
    }

    function insertScript(uri) {
      var document = window.document;
      var body = document.getElementsByTagName('body')[0];
      var script = document.createElement('script');
      script.setAttribute('src', uri);
      body.appendChild(script);
      return script;
    }

    function listen(event, listener) {
      if (listener && typeof listener.handleEvent === 'function') {
        listener = listener.handleEvent.bind(listener);
      }
      if (typeof listener === 'function') {
        listener.call(this, event);
      }
    }

    proto.addEventListener = function addEventListener(type, handler) {
      if (typeof this.listeners[type] === 'undefined') {
        this.listeners[type] = [];
      }
      this.listeners[type].push(handler);
    };

    proto.open = function open(method, uri) {
      this.method = method;
      this.uri = uri;
    };

    proto.send = function send() {
      var listeners = this.listeners;
      var callbackName = '____________callback' + (new Date()).getTime();
      var uri = this.uri;
      uri += [
        uri.indexOf('?') >= 0 ? '&' : '?',
        'callback=',
        encodeURIComponent(callbackName)
      ].join('');
      var reset = function reset() {};
      var request = this;
      global[callbackName] = function successHandler(parsedJson) {
        var successListeners = listeners['load'];
        request.response = parsedJson;
        request.responseText = JSON.stringify(parsedJson);
        executeListeners.call(request, {
          target: request,
          type: 'load'
        }, successListeners);
        reset();
      };
      var errorHandler = function errorHandler(event) {
        var target = event.target;
        var errorListeners = listeners['error'];
        target.removeEventListener('error', errorHandler);
        executeListeners.call(request, {
          target: request,
          type: 'error'
        }, errorListeners);
        reset();
      };
      var script = insertScript(uri);
      reset = function reset() {
        try {
          delete global[callbackName];
        } catch (error) {
          global[callbackName] = undefined;
        }
        script.parentNode.removeChild(script);
      };
      script.addEventListener('error', errorHandler);
    };
  })(JSONHttpRequest.prototype);

  function RecentlyPosts(successHandler, errorHandler) {
    this.successHandler = successHandler;
    this.errorHandler = errorHandler;
  }

  RecentlyPosts.FEED_CONTENT_TYPES = [
    'application/xml',
    'application/atom+xml',
    'application/rdf+xml',
    'application/rss+xml'
  ];
  RecentlyPosts.ATOM_NAMESPACE_URI = 'http://www.w3.org/2005/Atom';
  RecentlyPosts.RDF_NAMESPACE_URI = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';

  (function(proto) {
    proto.get = function get(feedUri) {
      var client = new XMLHttpRequest();
      client.open('GET', feedUri);
      client.addEventListener('load', this, false);
      client.addEventListener('error', this, false);
      client.send(null);
    };

    proto.handleEvent = function handleEvent(event) {
      var client = event.target;
      var response = client.responseXML;
      var type = event.type;
      var parsedResponse;
      var error;
      if (type === 'error' || [200, 304].indexOf(client.status) < 0) {
        if (typeof this.errorHandler === 'function') {
          error = new TypeError('Don\'t get response.');
          this.errorHandler.call(this, error);
        }
        return;
      }
      try {
        parsedResponse = this.parseResponse(response);
      } catch (e) {
        this.errorHandler.call(this, e);
        return;
      }
      this.successHandler.call(this, parsedResponse);
    };

    proto.parseResponse = function parseResponse(xml) {
      var rootElement = xml.documentElement;
      var localName = rootElement.localName || (function(tagName) {
        var separatedTagName = (tagName || '').split(':');
        return separatedTagName.length > 1 ?
          separatedTagName.slice(1).join(':') : tagName;
      })(rootElement.tagName);
      var namespaceUri = rootElement.namespaceURI || null;
      if (localName === 'rss' && namespaceUri === null) {
        return this.parseRss2.apply(this, arguments);
      } else if (localName === 'RDF' && namespaceUri === RecentlyPosts.RDF_NAMESPACE_URI) {
        return 'parseRss'; // todo
      } else if (localName === 'feed' && namespaceUri === RecentlyPosts.ATOM_NAMESPACE_URI) {
        return 'parseAtom'; // todo
      }
      return {};
    };

    proto.parseRss2 = function parseRss2(xml) {
      var items = xml.querySelectorAll('item');
      return Array.prototype.map.call(items, this.parseRss2Item);
    };

    proto.parseRss2Item = function parseRss2Item(item) {
      var uri = item.getElementsByTagName('link')[0].textContent;
      var title = item.getElementsByTagName('title')[0].textContent;
      var summary = item.getElementsByTagName('description')[0].textContent;
      var date = (function() {
        var pubDate = item.getElementsByTagName('pubDate')[0].textContent;
        return new Date(pubDate);
      })();
      return {
        uri: uri,
        title: title,
        summary: summary,
        date: date
      };
    };
  })(RecentlyPosts.prototype);

  function PopularPosts(successHandler, errorHandler) {
    this.successHandler = successHandler;
    this.errorHandler = errorHandler;
  }

  (function(proto) {
    proto.get = function get(blogUri) {
      var apiUri = this.getApiUri(blogUri);
      var client = new JSONHttpRequest();
      client.open('get', apiUri);
      client.addEventListener('load', this);
      client.addEventListener('error', this);
      client.send(null);
    };

    proto.getApiUri = function getApiUri(uri) {
      var baseUri = 'http://b.hatena.ne.jp/entrylist/json';
      var queryString = QueryString.stringify({
        sort: 'count',
        url: uri
      });
      return [
        baseUri,
        queryString
      ].join('?');
    };

    proto.handleEvent = function handleEvent(event) {
      if (event.type !== 'load') {
        return;
      }
      var client = event.target;
      var response = client.response;
      var parsedResponse = this.parseResponse(response);
      this.successHandler.call(this, parsedResponse);
      return;
    };

    proto.parseResponse = function parseResponse(array) {
      return (array || []).map(function(object) {
        var title = object.title;
        title += ' (' + object.count + ')';
        return {
          title: title,
          uri: object.link
        };
      });
    };
  })(PopularPosts.prototype);

  function SiteScript(window) {
    window.addEventListener('DOMContentLoaded', this, false);
  }

  (function(proto) {
    proto.getEventHandler = function getEventHandler(event) {
      var methodNames = this.getMethodNames.apply(this, arguments);
      var methods = methodNames.map(function(methodName) {
        var method = this[methodName];
        return method;
      }, this).filter(function(method) {
        return typeof method === 'function';
      });
      var args = Array.prototype.slice.call(arguments);
      return function handler() {
        methods.some(function(method) {
          return event.defaultPrevented || method.apply(this, args);
        }, this);
      }.bind(this);
    };

    proto.getMethodNames = function getMethodNames(event) {
      var type = event.type;
      var methodNames = getMethodNames.list[type] || [];
      return methodNames;
    };

    proto.getMethodNames.list = {
      DOMContentLoaded: [
        'setPlaceholder',
        'showingPopularPosts',
        'showingRecentlyPosts'
      ]
    };

    proto.handleEvent = function handleEvent(event) {
      var handler = this.getEventHandler(event);
      return handler.apply(this, arguments);
    };

    proto.insertPosts = function insertPosts(container, entries) {
      var document = container.ownerDocument;
      var listElement = document.createElement('ol');
      var baseListItemElement = (function() {
        var listItemElement = document.createElement('li');
        var anchorElement = document.createElement('a');
        listItemElement.appendChild(anchorElement);
        return listItemElement;
      })();
      (entries || []).forEach(function(entry) {
        var listItemElement = baseListItemElement.cloneNode(true);
        var anchorElement = listItemElement.getElementsByTagName('a')[0];
        anchorElement.setAttribute('href', entry.uri);
        anchorElement.textContent = entry.title;
        listElement.appendChild(listItemElement);
      });
      if ((listElement.childNodes || []).length <= 0) {
        return;
      }
      var lastChild = removeChildNodes(container);
      container.insertBefore(listElement, lastChild);
    };

    proto.setPlaceholder = function setPlaceholder(event) {
      var document = event.target;
      var textFields = document.getElementsByClassName('search');
      Array.prototype.forEach.call(textFields, function(textField) {
        textField.placeholder = 'Search';
      });
    };

    proto.showingPopularPosts = function showingPopularPosts(event) {
      var document = event.target;
      var blogUri = (function(location) {
        var uri = location.href;
        var blogUri = (uri.match(/^(https?:\/\/[^\/]+\/).*$/) || [])[1];
        return blogUri;
      })(document.defaultView && document.defaultView.location);
      var popularPostsContainer = document.getElementById('popular-posts');
      var successHandler = this.insertPosts.bind(this, popularPostsContainer);;
      var popularPosts = new PopularPosts(successHandler);
      popularPosts.get(blogUri);
    };

    proto.showingRecentlyPosts = function showingRecentlyPosts(event) {
      var document = event.target;
      var feedUri = (function() {
        var alternateLinks = document.querySelectorAll('link[rel="alternate"]');
        var feedUri;
        Array.prototype.some.call(alternateLinks, function(alternateLink) {
          var contentType = alternateLink.getAttribute('type');
          if (RecentlyPosts.FEED_CONTENT_TYPES.indexOf(contentType) < 0) {
            return false;
          }
          feedUri = alternateLink.getAttribute('href');
          return true;
        });
        return feedUri;
      })();
      var recentPostsContainer = document.getElementById('recent-posts');
      var successHandler = this.insertPosts.bind(this, recentPostsContainer);
      var recentlyPosts = new RecentlyPosts(successHandler);
      recentlyPosts.get(feedUri);
    };
  })(SiteScript.prototype);

  function main(window) {
    new SiteScript(window);
  }

  if (window === global) {
    main(window);
  }
})(this);
<commit_msg>getElementsByTagName<commit_after>/**
 * Copyright (c) 2013-2015 Yamagishi Kazutoshi
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
(function(global) {
  'use strict';

  var undefined;
  var window = global.window || {};
  var HEADLINE_SELECTOR = [
    'h1',
    'h2',
    'h3',
    'h4',
    'h5',
    'h6'
  ].map(function(selector) {
    return selector + ':first-child';
  }).join(', ');

  function removeChildNodes(node) {
    var document = node.ownerDocument;
    var headline = node.querySelector(HEADLINE_SELECTOR);
    var lastChild = node.querySelector(':last-child');
    var range = document.createRange();
    range.setStartAfter(headline);
    range.setEndBefore(lastChild);
    range.deleteContents();
    return lastChild;
  };

  function QueryString() {
  }

  QueryString.stringify = function stringify(value) {
    if (typeof value !== 'object') {
      return '' + value;
    }
    var pairs = [];
    var pair, key, item;
    for (key in value) {
      if (!value.hasOwnProperty(key) || !(item = value[key])) {
        continue;
      }
      pair = [encodeURIComponent(key)];
      if (typeof item !== 'boolean') {
        pair.push(encodeURIComponent(item));
      }
      pairs.push(pair.join('='));
    }
    return pairs.join('&');
  };

  function JSONHttpRequest() {
    this.method = undefined;
    this.uri = undefined;
    this.response = null;
    this.responseText = null;
    this.listeners = [];
  };

  (function(proto) {
    function executeListeners(event, listeners) {
      var len, i, listener;
      if (typeof listeners !== 'undefined') {
        len = listeners.length;
        for (i = 0; i < len; ++i) {
          listener = listeners[i];
          listen.call(this, event, listener);
        }
      }
    }

    function insertScript(uri) {
      var document = window.document;
      var body = document.getElementsByTagName('body')[0];
      var script = document.createElement('script');
      script.setAttribute('src', uri);
      body.appendChild(script);
      return script;
    }

    function listen(event, listener) {
      if (listener && typeof listener.handleEvent === 'function') {
        listener = listener.handleEvent.bind(listener);
      }
      if (typeof listener === 'function') {
        listener.call(this, event);
      }
    }

    proto.addEventListener = function addEventListener(type, handler) {
      if (typeof this.listeners[type] === 'undefined') {
        this.listeners[type] = [];
      }
      this.listeners[type].push(handler);
    };

    proto.open = function open(method, uri) {
      this.method = method;
      this.uri = uri;
    };

    proto.send = function send() {
      var listeners = this.listeners;
      var callbackName = '____________callback' + (new Date()).getTime();
      var uri = this.uri;
      uri += [
        uri.indexOf('?') >= 0 ? '&' : '?',
        'callback=',
        encodeURIComponent(callbackName)
      ].join('');
      var reset = function reset() {};
      var request = this;
      global[callbackName] = function successHandler(parsedJson) {
        var successListeners = listeners['load'];
        request.response = parsedJson;
        request.responseText = JSON.stringify(parsedJson);
        executeListeners.call(request, {
          target: request,
          type: 'load'
        }, successListeners);
        reset();
      };
      var errorHandler = function errorHandler(event) {
        var target = event.target;
        var errorListeners = listeners['error'];
        target.removeEventListener('error', errorHandler);
        executeListeners.call(request, {
          target: request,
          type: 'error'
        }, errorListeners);
        reset();
      };
      var script = insertScript(uri);
      reset = function reset() {
        try {
          delete global[callbackName];
        } catch (error) {
          global[callbackName] = undefined;
        }
        script.parentNode.removeChild(script);
      };
      script.addEventListener('error', errorHandler);
    };
  })(JSONHttpRequest.prototype);

  function RecentlyPosts(successHandler, errorHandler) {
    this.successHandler = successHandler;
    this.errorHandler = errorHandler;
  }

  RecentlyPosts.FEED_CONTENT_TYPES = [
    'application/xml',
    'application/atom+xml',
    'application/rdf+xml',
    'application/rss+xml'
  ];
  RecentlyPosts.ATOM_NAMESPACE_URI = 'http://www.w3.org/2005/Atom';
  RecentlyPosts.RDF_NAMESPACE_URI = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';

  (function(proto) {
    proto.get = function get(feedUri) {
      var client = new XMLHttpRequest();
      client.open('GET', feedUri);
      client.addEventListener('load', this, false);
      client.addEventListener('error', this, false);
      client.send(null);
    };

    proto.handleEvent = function handleEvent(event) {
      var client = event.target;
      var response = client.responseXML;
      var type = event.type;
      var parsedResponse;
      var error;
      if (type === 'error' || [200, 304].indexOf(client.status) < 0) {
        if (typeof this.errorHandler === 'function') {
          error = new TypeError('Don\'t get response.');
          this.errorHandler.call(this, error);
        }
        return;
      }
      try {
        parsedResponse = this.parseResponse(response);
      } catch (e) {
        this.errorHandler.call(this, e);
        return;
      }
      this.successHandler.call(this, parsedResponse);
    };

    proto.parseResponse = function parseResponse(xml) {
      var rootElement = xml.documentElement;
      var localName = rootElement.localName || (function(tagName) {
        var separatedTagName = (tagName || '').split(':');
        return separatedTagName.length > 1 ?
          separatedTagName.slice(1).join(':') : tagName;
      })(rootElement.tagName);
      var namespaceUri = rootElement.namespaceURI || null;
      if (localName === 'rss' && namespaceUri === null) {
        return this.parseRss2.apply(this, arguments);
      } else if (localName === 'RDF' && namespaceUri === RecentlyPosts.RDF_NAMESPACE_URI) {
        return 'parseRss'; // todo
      } else if (localName === 'feed' && namespaceUri === RecentlyPosts.ATOM_NAMESPACE_URI) {
        return 'parseAtom'; // todo
      }
      return {};
    };

    proto.parseRss2 = function parseRss2(xml) {
      var items = xml.getElementsByTagName('item');
      return Array.prototype.map.call(items, this.parseRss2Item);
    };

    proto.parseRss2Item = function parseRss2Item(item) {
      var uri = item.getElementsByTagName('link')[0].firstChild.nodeValue;
      var title = item.getElementsByTagName('title')[0].firstChild.nodeValue;
      var summary = item.getElementsByTagName('description')[0].firstChild.nodeValue;
      var date = (function(pubDate) {
        return new Date(pubDate);
      })(item.getElementsByTagName('pubDate')[0].firstChild.nodeValue);
      return {
        uri: uri,
        title: title,
        summary: summary,
        date: date
      };
    };
  })(RecentlyPosts.prototype);

  function PopularPosts(successHandler, errorHandler) {
    this.successHandler = successHandler;
    this.errorHandler = errorHandler;
  }

  (function(proto) {
    proto.get = function get(blogUri) {
      var apiUri = this.getApiUri(blogUri);
      var client = new JSONHttpRequest();
      client.open('get', apiUri);
      client.addEventListener('load', this);
      client.addEventListener('error', this);
      client.send(null);
    };

    proto.getApiUri = function getApiUri(uri) {
      var baseUri = 'http://b.hatena.ne.jp/entrylist/json';
      var queryString = QueryString.stringify({
        sort: 'count',
        url: uri
      });
      return [
        baseUri,
        queryString
      ].join('?');
    };

    proto.handleEvent = function handleEvent(event) {
      if (event.type !== 'load') {
        return;
      }
      var client = event.target;
      var response = client.response;
      var parsedResponse = this.parseResponse(response);
      this.successHandler.call(this, parsedResponse);
      return;
    };

    proto.parseResponse = function parseResponse(array) {
      return (array || []).map(function(object) {
        var title = object.title;
        title += ' (' + object.count + ')';
        return {
          title: title,
          uri: object.link
        };
      });
    };
  })(PopularPosts.prototype);

  function SiteScript(window) {
    window.addEventListener('DOMContentLoaded', this, false);
  }

  (function(proto) {
    proto.getEventHandler = function getEventHandler(event) {
      var methodNames = this.getMethodNames.apply(this, arguments);
      var methods = methodNames.map(function(methodName) {
        var method = this[methodName];
        return method;
      }, this).filter(function(method) {
        return typeof method === 'function';
      });
      var args = Array.prototype.slice.call(arguments);
      return function handler() {
        methods.some(function(method) {
          return event.defaultPrevented || method.apply(this, args);
        }, this);
      }.bind(this);
    };

    proto.getMethodNames = function getMethodNames(event) {
      var type = event.type;
      var methodNames = getMethodNames.list[type] || [];
      return methodNames;
    };

    proto.getMethodNames.list = {
      DOMContentLoaded: [
        'setPlaceholder',
        'showingPopularPosts',
        'showingRecentlyPosts'
      ]
    };

    proto.handleEvent = function handleEvent(event) {
      var handler = this.getEventHandler(event);
      return handler.apply(this, arguments);
    };

    proto.insertPosts = function insertPosts(container, entries) {
      var document = container.ownerDocument;
      var listElement = document.createElement('ol');
      var baseListItemElement = (function() {
        var listItemElement = document.createElement('li');
        var anchorElement = document.createElement('a');
        listItemElement.appendChild(anchorElement);
        return listItemElement;
      })();
      (entries || []).forEach(function(entry) {
        var listItemElement = baseListItemElement.cloneNode(true);
        var anchorElement = listItemElement.getElementsByTagName('a')[0];
        anchorElement.setAttribute('href', entry.uri);
        anchorElement.textContent = entry.title;
        listElement.appendChild(listItemElement);
      });
      if ((listElement.childNodes || []).length <= 0) {
        return;
      }
      var lastChild = removeChildNodes(container);
      container.insertBefore(listElement, lastChild);
    };

    proto.setPlaceholder = function setPlaceholder(event) {
      var document = event.target;
      var textFields = document.getElementsByClassName('search');
      Array.prototype.forEach.call(textFields, function(textField) {
        textField.placeholder = 'Search';
      });
    };

    proto.showingPopularPosts = function showingPopularPosts(event) {
      var document = event.target;
      var blogUri = (function(location) {
        var uri = location.href;
        var blogUri = (uri.match(/^(https?:\/\/[^\/]+\/).*$/) || [])[1];
        return blogUri;
      })(document.defaultView && document.defaultView.location);
      var popularPostsContainer = document.getElementById('popular-posts');
      var successHandler = this.insertPosts.bind(this, popularPostsContainer);;
      var popularPosts = new PopularPosts(successHandler);
      popularPosts.get(blogUri);
    };

    proto.showingRecentlyPosts = function showingRecentlyPosts(event) {
      var document = event.target;
      var feedUri = (function() {
        var alternateLinks = document.querySelectorAll('link[rel="alternate"]');
        var feedUri;
        Array.prototype.some.call(alternateLinks, function(alternateLink) {
          var contentType = alternateLink.getAttribute('type');
          if (RecentlyPosts.FEED_CONTENT_TYPES.indexOf(contentType) < 0) {
            return false;
          }
          feedUri = alternateLink.getAttribute('href');
          return true;
        });
        return feedUri;
      })();
      var recentPostsContainer = document.getElementById('recent-posts');
      var successHandler = this.insertPosts.bind(this, recentPostsContainer);
      var recentlyPosts = new RecentlyPosts(successHandler);
      recentlyPosts.get(feedUri);
    };
  })(SiteScript.prototype);

  function main(window) {
    new SiteScript(window);
  }

  if (window === global) {
    main(window);
  }
})(this);
<|endoftext|>


<commit_before>import { html, LitElement } from 'lit-element';
import { nothing } from 'lit-html';
import SearchProvider from './providers/search.js';
import DownloadProvider from './providers/download.js';
import VisualAdjustmentProvider from './providers/visual-adjustments.js';
import SharingProvider from '../ItemNavigator/providers/sharing.js';
import BookmarksProvider from './providers/bookmarks.js';
import BRFullscreenMgr from './br-fullscreen-mgr.js';
import { Book } from './BookModel.js';
// import '../ItemNavigator/ItemNavigator.js';
import bookLoader from './book-loader.js';
import navigatorCSS from './styles/book-navigator.js';

const events = {
  menuUpdated: 'menuUpdated',
  updateSideMenu: 'updateSideMenu',
  ViewportInFullScreen: 'ViewportInFullScreen',
};
export class BookNavigator extends LitElement {
  static get styles() {
    return navigatorCSS;
  }

  static get properties() {
    return {
      book: { type: Object },
      mainBRSelector: { type: String },
      pageContainerSelector: { type: String },
      brWidth: { type: Number },
      bookReaderLoaded: { type: Boolean },
      bookreader: { type: Object },
      downloadableTypes: { type: Array },
      isAdmin: { type: Boolean },
      lendingInitialized: { type: Boolean },
      lendingStatus: { type: Object },
      menuProviders: { type: Object },
      menuShortcuts: { type: Array },
      sideMenuOpen: { type: Boolean },
      signedIn: { type: Boolean },
    };
  }

  constructor() {
    super();
    this.book = {};
    this.mainBRSelector = '#BookReader';
    this.pageContainerSelector = '.BRcontainer';
    this.brWidth = 0;
    this.bookReaderCannotLoad = false;
    this.bookReaderLoaded = false;
    this.bookreader = null;
    this.downloadableTypes = [];
    this.isAdmin = false;
    this.lendingInitialized = false;
    this.lendingStatus = {};
    this.menuProviders = {};
    this.menuShortcuts = [];
    this.sideMenuOpen = false;
    this.signedIn = false;

    // Untracked properties
    this.fullscreenMgr = new BRFullscreenMgr();
    this.model = new Book();
    this.shortcutOrder = ['volumes', 'search', 'bookmarks'];
  }

  firstUpdated() {
    this.model.setMetadata(this.book);
    this.bindEventListeners();
  }

  /**
   * Instantiates books submenus & their update callbacks
   *
   * NOTE: we are doing our best to scope bookreader's instance.
   * If your submenu provider uses a bookreader instance to read, manually
   * manipulate BookReader, please update the navigator's instance of it
   * to keep it in sync.
   */
  initializeBookSubmenus() {
    this.menuProviders = {
      search: new SearchProvider(
        (brInstance = null) => {
          if (brInstance) {
            /* refresh br instance reference */
            this.bookreader = brInstance;
          }
          this.updateMenuContents();
          if (this.brWidth >= 640) { /* open side search menu */
            this.openSideSearchMenu();
          }
        },
        this.bookreader,
      ),
      downloads: new DownloadProvider(),
      visualAdjustments: new VisualAdjustmentProvider({
        onOptionChange: (event, brInstance = null) => {
          if (brInstance) {
            /* refresh br instance reference */
            this.bookreader = brInstance;
          }
          this.updateMenuContents();
        },
        bookContainerSelector: this.pageContainerSelector,
        bookreader: this.bookreader,
      }),
      share: new SharingProvider(this.book.metadata, this.baseHost, this.itemType),
    };

    if (this.signedIn) {
      this.menuProviders.bookmarks = new BookmarksProvider(this.bookmarksOptions, this.bookreader);
    }

    this.addMenuShortcut('search'); /* start with search as a shortcut */
    this.updateMenuContents();
  }

  /** gets element that houses the bookreader in light dom */
  get mainBRContainer() {
    return document.querySelector(this.mainBRSelector);
  }

  get bookmarksOptions() {
    return {
      showItemNavigatorModal: this.showItemNavigatorModal.bind(this),
      closeItemNavigatorModal: this.closeItemNavigatorModal.bind(this),
      onBookmarksChanged: (bookmarks) => {
        const method = Object.keys(bookmarks).length ? 'add' : 'remove';
        this[`${method}MenuShortcut`]('bookmarks');
        this.updateMenuContents();
      },
    };
  }

  /**
   * Open side search menu
   */
  openSideSearchMenu() {
    const event = new CustomEvent(
      events.updateSideMenu, {
        detail: { menuId: 'search', action: 'open' },
      },
    );
    this.dispatchEvent(event);
  }

  /**
   * Sets order of menu and emits custom event when done
   */
  updateMenuContents() {
    const {
      search, downloads, visualAdjustments, share, bookmarks,
    } = this.menuProviders;
    const availableMenus = [search, bookmarks, visualAdjustments, share].filter((menu) => !!menu);

    if (this.shouldShowDownloadsMenu()) {
      downloads.update(this.downloadableTypes);
      availableMenus.splice(1, 0, downloads);
    }

    const event = new CustomEvent(
      events.menuUpdated, {
        detail: availableMenus,
      },
    );
    this.dispatchEvent(event);
  }

  /**
   * Confirms if we should show the downloads menu
   * @returns {bool}
   */
  shouldShowDownloadsMenu() {
    if (this.model.isRestricted === false) { return true; }
    if (this.isAdmin) { return true; }
    const { user_loan_record = {} } = this.lendingStatus;
    const hasNoLoanRecord = Array.isArray(user_loan_record); /* (bc PHP assoc. arrays) */

    if (hasNoLoanRecord) { return false; }

    const hasValidLoan = user_loan_record.type && (user_loan_record.type !== 'SESSION_LOAN');
    return hasValidLoan;
  }

  /**
   * Adds a provider object to the menuShortcuts array property if it isn't
   * already added. menuShortcuts are then sorted by shortcutOrder and
   * a menuShortcutsUpdated event is emitted.
   *
   * @param {string} menuId - a string matching the id property of a provider
   */
  addMenuShortcut(menuId) {
    if (this.menuShortcuts.find((m) => m.id === menuId)) { return; }

    this.menuShortcuts.push(this.menuProviders[menuId]);
    this.sortMenuShortcuts();
    this.emitMenuShortcutsUpdated();
  }

  /**
   * Removes a provider object from the menuShortcuts array and emits a
   * menuShortcutsUpdated event.
   *
   * @param {string} menuId - a string matching the id property of a provider
   */
  removeMenuShortcut(menuId) {
    this.menuShortcuts = this.menuShortcuts.filter((m) => m.id !== menuId);
    this.emitMenuShortcutsUpdated();
  }

  /**
   * Sorts the menuShortcuts property by comparing each provider's id to
   * the id in each iteration over the shortcutOrder array.
   */
  sortMenuShortcuts() {
    this.menuShortcuts = this.shortcutOrder.reduce((shortcuts, id) => {
      const menu = this.menuShortcuts.find((m) => m.id === id);
      if (menu) { shortcuts.push(menu); }
      return shortcuts;
    }, []);
  }

  emitMenuShortcutsUpdated() {
    const event = new CustomEvent('menuShortcutsUpdated', {
      detail: this.menuShortcuts,
    });
    this.dispatchEvent(event);
  }

  /**
   * Core bookreader event handler registry
   *
   * NOTE: we are trying to keep bookreader's instance in scope
   * Please update Book Navigator's instance reference of it to keep it current
   */
  bindEventListeners() {
    window.addEventListener('BookReader:PostInit', (e) => {
      this.bookreader = e.detail.props;
      this.bookReaderLoaded = true;
      this.initializeBookSubmenus();
      this.mainBRSelector = this.br?.el || '#BookReader';
      setTimeout(() => this.bookreader.resize(), 0);
      // eslint-disable-next-line compat/compat
      const brResizeObserver = new ResizeObserver((elements) => this.reactToBrResize(elements));
      brResizeObserver.observe(this.mainBRContainer);
    });
    window.addEventListener('BookReader:fullscreenToggled', (event) => {
      const { detail: { props: brInstance = null } } = event;
      if (brInstance) {
        this.bookreader = brInstance;
      }
      this.manageFullScreenBehavior(event);
    }, { passive: true });
    window.addEventListener('BookReader:ToggleSearchMenu', (event) => {
      this.dispatchEvent(new CustomEvent(events.updateSideMenu, {
        detail: { menuId: 'search', action: 'toggle' },
      }));
    });
    window.addEventListener('LendingFlow:PostInit', ({ detail }) => {
      const {
        downloadTypesAvailable, lendingStatus, isAdmin, previewType,
      } = detail;
      this.lendingInitialized = true;
      this.downloadableTypes = downloadTypesAvailable;
      this.lendingStatus = lendingStatus;
      this.isAdmin = isAdmin;
      this.bookReaderCannotLoad = previewType === 'singlePagePreview';
    });
    window.addEventListener('BRJSIA:PostInit', ({ detail }) => {
      const { isRestricted, downloadURLs } = detail;
      this.downloadableTypes = downloadURLs;
      this.model.setRestriction(isRestricted);
    });
  }

  /**
   * Uses resize observer to fire BookReader's `resize` functionality
   * We do not want to trigger resize IF:
   *  - book animation is happening
   *  - book is in fullscreen (fullscreen is handled separately)
   *
   * @param { Object } entries - resize observer entries
   */
  reactToBrResize(entries = []) {
    const startBrWidth = this.brWidth;
    const { animating } = this.bookreader;

    entries.forEach(({ contentRect, target }) => {
      if (target === this.mainBRContainer) {
        this.brWidth = contentRect.width;
      }
    });
    setTimeout(() => {
      if (startBrWidth && !animating) {
        this.bookreader.resize();
      }
    }, 0);
  }

  /**
   * Manages Fullscreen behavior
   * This makes sure that controls are _always_ in view
   * We need this to accommodate LOAN BAR during fullscreen
   * @param { Event } event
   */
  manageFullScreenBehavior(event) {
    this.emitFullScreenState(event);

    const { isFullscreenActive } = this.bookreader;

    if (!isFullscreenActive) {
      this.fullscreenMgr.teardown();
    } else {
      this.fullscreenMgr.setup();
    }
  }

  /**
   * Intercepts and relays fullscreen toggle events
   * @param {Event} e
   */
  emitFullScreenState({ detail }) {
    const { props: brInstance } = detail;

    const isFullScreen = brInstance.isFullscreenActive;
    const event = new CustomEvent('ViewportInFullScreen', {
      detail: { isFullScreen },
    });
    this.dispatchEvent(event);
  }

  emitShowItemNavigatorModal(e) {
    this.dispatchEvent(new CustomEvent('showItemNavigatorModal', {
      detail: e.detail,
    }));
  }

  emitCloseItemNavigatorModal() {
    this.dispatchEvent(new CustomEvent('closeItemNavigatorModal'));
  }

  showItemNavigatorModal(e) {
    this.emitShowItemNavigatorModal(e);
  }

  closeItemNavigatorModal() {
    this.emitCloseItemNavigatorModal();
  }

  get loader() {
    const loader = html`

${bookLoader}

Loading viewer

    `;
    return !this.bookReaderLoaded ? loader : nothing;
  }

  get loadingClass() {
    return !this.bookReaderLoaded ? 'loading' : '';
  }

  get itemImage() {
    const url = `https://${this.baseHost}/services/img/${this.book.metadata.identifier}`;
    return html`<img src="${url}" alt="cover image for ${this.book.metadata.identifier}">`;
  }

  render() {
    const placeholder = this.bookReaderCannotLoad ? this.itemImage : this.loader;
    return html`

      ${placeholder}
      <slot name="bookreader"></slot>

  `;
  }
}

customElements.define('book-navigator', BookNavigator);
<commit_msg>missing property setter<commit_after>import { html, LitElement } from 'lit-element';
import { nothing } from 'lit-html';
import SearchProvider from './providers/search.js';
import DownloadProvider from './providers/download.js';
import VisualAdjustmentProvider from './providers/visual-adjustments.js';
import SharingProvider from '../ItemNavigator/providers/sharing.js';
import BookmarksProvider from './providers/bookmarks.js';
import BRFullscreenMgr from './br-fullscreen-mgr.js';
import { Book } from './BookModel.js';
// import '../ItemNavigator/ItemNavigator.js';
import bookLoader from './book-loader.js';
import navigatorCSS from './styles/book-navigator.js';

const events = {
  menuUpdated: 'menuUpdated',
  updateSideMenu: 'updateSideMenu',
  ViewportInFullScreen: 'ViewportInFullScreen',
};
export class BookNavigator extends LitElement {
  static get styles() {
    return navigatorCSS;
  }

  static get properties() {
    return {
      book: { type: Object },
      mainBRSelector: { type: String },
      pageContainerSelector: { type: String },
      brWidth: { type: Number },
      bookReaderLoaded: { type: Boolean },
      bookreader: { type: Object },
      downloadableTypes: { type: Array },
      isAdmin: { type: Boolean },
      lendingInitialized: { type: Boolean },
      lendingStatus: { type: Object },
      menuProviders: { type: Object },
      menuShortcuts: { type: Array },
      sideMenuOpen: { type: Boolean },
      signedIn: { type: Boolean },
    };
  }

  constructor() {
    super();
    this.book = {};
    this.mainBRSelector = '#BookReader';
    this.pageContainerSelector = '.BRcontainer';
    this.brWidth = 0;
    this.bookReaderCannotLoad = false;
    this.bookReaderLoaded = false;
    this.bookreader = null;
    this.downloadableTypes = [];
    this.isAdmin = false;
    this.lendingInitialized = false;
    this.lendingStatus = {};
    this.menuProviders = {};
    this.menuShortcuts = [];
    this.sideMenuOpen = false;
    this.signedIn = false;

    // Untracked properties
    this.fullscreenMgr = new BRFullscreenMgr();
    this.model = new Book();
    this.shortcutOrder = ['volumes', 'search', 'bookmarks'];
  }

  firstUpdated() {
    this.model.setMetadata(this.book);
    this.bindEventListeners();
  }

  /**
   * Instantiates books submenus & their update callbacks
   *
   * NOTE: we are doing our best to scope bookreader's instance.
   * If your submenu provider uses a bookreader instance to read, manually
   * manipulate BookReader, please update the navigator's instance of it
   * to keep it in sync.
   */
  initializeBookSubmenus() {
    this.menuProviders = {
      search: new SearchProvider(
        (brInstance = null) => {
          if (brInstance) {
            /* refresh br instance reference */
            this.bookreader = brInstance;
          }
          this.updateMenuContents();
          if (this.brWidth >= 640) { /* open side search menu */
            this.openSideSearchMenu();
          }
        },
        this.bookreader,
      ),
      downloads: new DownloadProvider(),
      visualAdjustments: new VisualAdjustmentProvider({
        onOptionChange: (event, brInstance = null) => {
          if (brInstance) {
            /* refresh br instance reference */
            this.bookreader = brInstance;
          }
          this.updateMenuContents();
        },
        bookContainerSelector: this.pageContainerSelector,
        bookreader: this.bookreader,
      }),
      share: new SharingProvider(this.book.metadata, this.baseHost, this.itemType),
    };

    if (this.signedIn) {
      this.menuProviders.bookmarks = new BookmarksProvider(this.bookmarksOptions, this.bookreader);
    }

    this.addMenuShortcut('search'); /* start with search as a shortcut */
    this.updateMenuContents();
  }

  /** gets element that houses the bookreader in light dom */
  get mainBRContainer() {
    return document.querySelector(this.mainBRSelector);
  }

  get bookmarksOptions() {
    return {
      showItemNavigatorModal: this.showItemNavigatorModal.bind(this),
      closeItemNavigatorModal: this.closeItemNavigatorModal.bind(this),
      onBookmarksChanged: (bookmarks) => {
        const method = Object.keys(bookmarks).length ? 'add' : 'remove';
        this[`${method}MenuShortcut`]('bookmarks');
        this.updateMenuContents();
      },
    };
  }

  /**
   * Open side search menu
   */
  openSideSearchMenu() {
    const event = new CustomEvent(
      events.updateSideMenu, {
        detail: { menuId: 'search', action: 'open' },
      },
    );
    this.dispatchEvent(event);
  }

  /**
   * Sets order of menu and emits custom event when done
   */
  updateMenuContents() {
    const {
      search, downloads, visualAdjustments, share, bookmarks,
    } = this.menuProviders;
    const availableMenus = [search, bookmarks, visualAdjustments, share].filter((menu) => !!menu);

    if (this.shouldShowDownloadsMenu()) {
      downloads.update(this.downloadableTypes);
      availableMenus.splice(1, 0, downloads);
    }

    const event = new CustomEvent(
      events.menuUpdated, {
        detail: availableMenus,
      },
    );
    this.dispatchEvent(event);
  }

  /**
   * Confirms if we should show the downloads menu
   * @returns {bool}
   */
  shouldShowDownloadsMenu() {
    if (this.model.isRestricted === false) { return true; }
    if (this.isAdmin) { return true; }
    const { user_loan_record = {} } = this.lendingStatus;
    const hasNoLoanRecord = Array.isArray(user_loan_record); /* (bc PHP assoc. arrays) */

    if (hasNoLoanRecord) { return false; }

    const hasValidLoan = user_loan_record.type && (user_loan_record.type !== 'SESSION_LOAN');
    return hasValidLoan;
  }

  /**
   * Adds a provider object to the menuShortcuts array property if it isn't
   * already added. menuShortcuts are then sorted by shortcutOrder and
   * a menuShortcutsUpdated event is emitted.
   *
   * @param {string} menuId - a string matching the id property of a provider
   */
  addMenuShortcut(menuId) {
    if (this.menuShortcuts.find((m) => m.id === menuId)) { return; }

    this.menuShortcuts.push(this.menuProviders[menuId]);
    this.sortMenuShortcuts();
    this.emitMenuShortcutsUpdated();
  }

  /**
   * Removes a provider object from the menuShortcuts array and emits a
   * menuShortcutsUpdated event.
   *
   * @param {string} menuId - a string matching the id property of a provider
   */
  removeMenuShortcut(menuId) {
    this.menuShortcuts = this.menuShortcuts.filter((m) => m.id !== menuId);
    this.emitMenuShortcutsUpdated();
  }

  /**
   * Sorts the menuShortcuts property by comparing each provider's id to
   * the id in each iteration over the shortcutOrder array.
   */
  sortMenuShortcuts() {
    this.menuShortcuts = this.shortcutOrder.reduce((shortcuts, id) => {
      const menu = this.menuShortcuts.find((m) => m.id === id);
      if (menu) { shortcuts.push(menu); }
      return shortcuts;
    }, []);
  }

  emitMenuShortcutsUpdated() {
    const event = new CustomEvent('menuShortcutsUpdated', {
      detail: this.menuShortcuts,
    });
    this.dispatchEvent(event);
  }

  /**
   * Core bookreader event handler registry
   *
   * NOTE: we are trying to keep bookreader's instance in scope
   * Please update Book Navigator's instance reference of it to keep it current
   */
  bindEventListeners() {
    window.addEventListener('BookReader:PostInit', (e) => {
      this.bookreader = e.detail.props;
      this.bookReaderLoaded = true;
      this.bookReaderCannotLoad = false;
      this.initializeBookSubmenus();
      this.mainBRSelector = this.br?.el || '#BookReader';
      setTimeout(() => this.bookreader.resize(), 0);
      // eslint-disable-next-line compat/compat
      const brResizeObserver = new ResizeObserver((elements) => this.reactToBrResize(elements));
      brResizeObserver.observe(this.mainBRContainer);
    });
    window.addEventListener('BookReader:fullscreenToggled', (event) => {
      const { detail: { props: brInstance = null } } = event;
      if (brInstance) {
        this.bookreader = brInstance;
      }
      this.manageFullScreenBehavior(event);
    }, { passive: true });
    window.addEventListener('BookReader:ToggleSearchMenu', (event) => {
      this.dispatchEvent(new CustomEvent(events.updateSideMenu, {
        detail: { menuId: 'search', action: 'toggle' },
      }));
    });
    window.addEventListener('LendingFlow:PostInit', ({ detail }) => {
      const {
        downloadTypesAvailable, lendingStatus, isAdmin, previewType,
      } = detail;
      this.lendingInitialized = true;
      this.downloadableTypes = downloadTypesAvailable;
      this.lendingStatus = lendingStatus;
      this.isAdmin = isAdmin;
      this.bookReaderCannotLoad = previewType === 'singlePagePreview';
    });
    window.addEventListener('BRJSIA:PostInit', ({ detail }) => {
      const { isRestricted, downloadURLs } = detail;
      this.downloadableTypes = downloadURLs;
      this.model.setRestriction(isRestricted);
    });
  }

  /**
   * Uses resize observer to fire BookReader's `resize` functionality
   * We do not want to trigger resize IF:
   *  - book animation is happening
   *  - book is in fullscreen (fullscreen is handled separately)
   *
   * @param { Object } entries - resize observer entries
   */
  reactToBrResize(entries = []) {
    const startBrWidth = this.brWidth;
    const { animating } = this.bookreader;

    entries.forEach(({ contentRect, target }) => {
      if (target === this.mainBRContainer) {
        this.brWidth = contentRect.width;
      }
    });
    setTimeout(() => {
      if (startBrWidth && !animating) {
        this.bookreader.resize();
      }
    }, 0);
  }

  /**
   * Manages Fullscreen behavior
   * This makes sure that controls are _always_ in view
   * We need this to accommodate LOAN BAR during fullscreen
   * @param { Event } event
   */
  manageFullScreenBehavior(event) {
    this.emitFullScreenState(event);

    const { isFullscreenActive } = this.bookreader;

    if (!isFullscreenActive) {
      this.fullscreenMgr.teardown();
    } else {
      this.fullscreenMgr.setup();
    }
  }

  /**
   * Intercepts and relays fullscreen toggle events
   * @param {Event} e
   */
  emitFullScreenState({ detail }) {
    const { props: brInstance } = detail;

    const isFullScreen = brInstance.isFullscreenActive;
    const event = new CustomEvent('ViewportInFullScreen', {
      detail: { isFullScreen },
    });
    this.dispatchEvent(event);
  }

  emitShowItemNavigatorModal(e) {
    this.dispatchEvent(new CustomEvent('showItemNavigatorModal', {
      detail: e.detail,
    }));
  }

  emitCloseItemNavigatorModal() {
    this.dispatchEvent(new CustomEvent('closeItemNavigatorModal'));
  }

  showItemNavigatorModal(e) {
    this.emitShowItemNavigatorModal(e);
  }

  closeItemNavigatorModal() {
    this.emitCloseItemNavigatorModal();
  }

  get loader() {
    const loader = html`

${bookLoader}

Loading viewer

    `;
    return !this.bookReaderLoaded ? loader : nothing;
  }

  get loadingClass() {
    return !this.bookReaderLoaded ? 'loading' : '';
  }

  get itemImage() {
    const url = `https://${this.baseHost}/services/img/${this.book.metadata.identifier}`;
    return html`<img src="${url}" alt="cover image for ${this.book.metadata.identifier}">`;
  }

  render() {
    const placeholder = this.bookReaderCannotLoad ? this.itemImage : this.loader;
    return html`

      ${placeholder}
      <slot name="bookreader"></slot>

  `;
  }
}

customElements.define('book-navigator', BookNavigator);
<|endoftext|>


<commit_before>/**
 * Module dependencies
 */

var util          = require('util')
  , LocalStrategy = require('passport-local').Strategy
  , User          = require('../models/User')
  , mailer        = require('../boot/mailer')
  ;

/**
 * Verifier
 */

function verifier (req, email, password, done) {
  User.authenticate(email, password, function (err, user, info) {
    if (user) {
      // throw password value away so isn't included in URLs/logged
      delete req.connectParams.password;
      delete req.connectParams.email;
    }

    done(err, user, info);
  });
};

LocalStrategy.verifier = verifier;

/**
 * Initialize
 */

function initialize (provider, configuration) {
  if (configuration.verifyEmail && !mailer) {
    throw new Error("verifyEmail is true but no mailer defined");
  }
  return new LocalStrategy(provider, verifier);
}

LocalStrategy.initialize = initialize;

/**
 * Exports
 */

module.exports = LocalStrategy;
<commit_msg>fix(password): Remove dated configuration property check<commit_after>/**
 * Module dependencies
 */

var util          = require('util')
  , LocalStrategy = require('passport-local').Strategy
  , User          = require('../models/User')
  ;

/**
 * Verifier
 */

function verifier (req, email, password, done) {
  User.authenticate(email, password, function (err, user, info) {
    if (user) {
      // throw password value away so isn't included in URLs/logged
      delete req.connectParams.password;
      delete req.connectParams.email;
    }

    done(err, user, info);
  });
};

LocalStrategy.verifier = verifier;

/**
 * Initialize
 */

function initialize (provider, configuration) {
  return new LocalStrategy(provider, verifier);
}

LocalStrategy.initialize = initialize;

/**
 * Exports
 */

module.exports = LocalStrategy;
<|endoftext|>