<commit_before>const fs = require('fs');
const _ = require('lodash');

const logger = require('./src/logger');
const github = require('./src/github/index');
const gephy = require('./src/gephy');

github
    .run([
        'fhnw-students',
        'w3tecch'
    ], (data) => {
        logger.info('[Crawler] Finished');
        // gephy.createFile(data);
    });

// function writeJsonFile(data) {
//     return new Promise((resolve, reject) => {
//         fs.writeFile(`${NAME}.json`, JSON.stringify(data), (err) => {
//             if (err) return logger.error(err);
//             logger.info('[Data] > ' + NAME + '.json');
//             resolve(data);
//         });
//     });
// }

// const data = require('./src/github/data');
// data.save().then((a)=>{
//     console.log(a);
// }).catch(err => {
//     console.log(err);
// });
<commit_msg>adds gephy interface<commit_after>const fs = require('fs');
const _ = require('lodash');

const logger = require('./src/logger');
const github = require('./src/github/index');
const githubData = require('./src/github/data');
const gephy = require('./src/gephy');

github
    .run([
        'fhnw-students',
        'w3tecch'
    ], (data) => {
        logger.info('[Crawler] Finished');
        gephy.createFile(githubData.getAll());
    });
<|endoftext|>


<commit_before>var fs = require('fs');
var exec = require('child_process').exec;
var config = require('./config');
var restify = require('restify');
var unirest = require('unirest');

var app = restify.createServer();
var lastSerial = 0;

app.use(restify.jsonp());
app.use(restify.queryParser());
app.use(restify.bodyParser());

app.use(function (req, res, next) {
  res.header('Access-Control-Allow-Origin', '*');
  next();
});

function updateDns(serial, servers, callback) {
    lastSerial = serial;
    var nsServers = [];
    var apiServers = [];
    var europeServers = [];
    var usServers = [];
    for (var i in servers) {
        var item = servers[i];
        nsServers.push(item['ns']);
        if (item['region'] == 'us') {
            usServers.push([item['ip'], 0]);
        } else if (item['region'] == 'europe') {
            europeServers.push([item['ip'], 0]);
        }
    }
    var dnsFile = {
        'serial': serial,
        'ttl': 120,
        'contact': 'staff.bukget.org',
        'data': {
            '': {
                'ns': nsServers
            }
        }
    };
    if (usServers.length > 0) {
        dnsFile.data[''].a = usServers;
    } else {
        dnsFile.data[''].a = europeServers;
    }
    if (europeServers.length > 0) {
        dnsFile.data.europe = {
            'a': europeServers
        }
    }
    for (var i in servers) {
        var item = servers[i];
        dnsFile['data'][item['name']] = { 'a': [ [item['ip'], 0] ] }
    }
    fs.writeFile(config.dnsFile, JSON.stringify(dnsFile), 'utf8', function (err) {
        if (err) {
            console.log('Error writing DNS config file');
            console.trace(err);
            callback(true);
        }
        exec('initctl restart geodns', function(error, stdout, stderr) {
            console.log('Updated dns!');
            callback(false);
        });
    });
}

app.get('/serial', function (req, res, next) {
    res.send({ 'serial': lastSerial });
});

app.post('/dnsupdate', function (req, res, next) {
    console.log('Incoming DNS update request');
    console.log(req.params);
    if (req.params.key != config.key) {
        return res.send(403);
    }
    updateDns(req.params.serial, JSON.parse(req.params.servers), function (err) {
        if (err) {
            return res.send(500);
        }
        return res.send(200);
    });
});

unirest.get('http://monitor.bukget.org/currentDNS').as.json(function (response) {
    if (response.error) {
      console.log('Couldn\'t get current dns config');
      return;
    }
    updateDns(response.body['serial'], response.body['servers']);
});

app.listen(process.env.PORT || 5555, function () {
  console.log('Listening on: %s', app.url);
});<commit_msg>Handle errors for initial sync<commit_after>var fs = require('fs');
var exec = require('child_process').exec;
var config = require('./config');
var restify = require('restify');
var unirest = require('unirest');

var app = restify.createServer();
var lastSerial = 0;

app.use(restify.jsonp());
app.use(restify.queryParser());
app.use(restify.bodyParser());

app.use(function (req, res, next) {
  res.header('Access-Control-Allow-Origin', '*');
  next();
});

function updateDns(serial, servers, callback) {
    lastSerial = serial;
    var nsServers = [];
    var apiServers = [];
    var europeServers = [];
    var usServers = [];
    for (var i in servers) {
        var item = servers[i];
        nsServers.push(item['ns']);
        if (item['region'] == 'us') {
            usServers.push([item['ip'], 0]);
        } else if (item['region'] == 'europe') {
            europeServers.push([item['ip'], 0]);
        }
    }
    var dnsFile = {
        'serial': serial,
        'ttl': 120,
        'contact': 'staff.bukget.org',
        'data': {
            '': {
                'ns': nsServers
            }
        }
    };
    if (usServers.length > 0) {
        dnsFile.data[''].a = usServers;
    } else {
        dnsFile.data[''].a = europeServers;
    }
    if (europeServers.length > 0) {
        dnsFile.data.europe = {
            'a': europeServers
        }
    }
    for (var i in servers) {
        var item = servers[i];
        dnsFile['data'][item['name']] = { 'a': [ [item['ip'], 0] ] }
    }
    fs.writeFile(config.dnsFile, JSON.stringify(dnsFile), 'utf8', function (err) {
        if (err) {
            console.log('Error writing DNS config file');
            console.trace(err);
            callback(true);
        }
        exec('initctl restart geodns', function(error, stdout, stderr) {
            console.log('Updated dns!');
            callback(false);
        });
    });
}

app.get('/serial', function (req, res, next) {
    res.send({ 'serial': lastSerial });
});

app.post('/dnsupdate', function (req, res, next) {
    console.log('Incoming DNS update request');
    console.log(req.params);
    if (req.params.key != config.key) {
        return res.send(403);
    }
    updateDns(req.params.serial, JSON.parse(req.params.servers), function (err) {
        if (err) {
            return res.send(500);
        }
        return res.send(200);
    });
});

unirest.get('http://monitor.bukget.org/currentDNS').as.json(function (response) {
    if (response.error) {
      console.log('Couldn\'t get current dns config');
      return;
    }
    updateDns(response.body['serial'], response.body['servers'], function (err) {
        if (err) {
            return console.log('Initial DNS sync failed');
        }
        console.log('Initial DNS sync successfull');
    });
});

app.listen(process.env.PORT || 5555, function () {
  console.log('Listening on: %s', app.url);
});<|endoftext|>


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

'use strict';

var fs = require('fs-plus');
var path = require('path');
var program = require('commander');
var pjson = require('./package.json');
var cucumber = require('cucumber');

function collectPaths(value, paths) {
    paths.push(value);
    return paths;
}

function coerceInt(value, defaultValue) {

    var int = parseInt(value);

    if (typeof int === 'number') return int;

    return defaultValue;
}

var config = {
    steps: './step-definitions',
    pageObjects: './page-objects',
    sharedObjects: './shared-objects',
    reports: './reports',
    browser: 'chrome',
    timeout: 15000
};

var configFileName = path.resolve(process.cwd(), 'selenium-cucumber-js.json');

if (fs.isFileSync(configFileName)) {
    config = Object.assign(config, require(configFileName));
}

program
    .version(pjson.version)
    .description(pjson.description)
    .option('-s, --steps <path>', 'path to step definitions. defaults to ' + config.steps, config.steps)
    .option('-p, --pageObjects <path>', 'path to page objects. defaults to ' + config.pageObjects, config.pageObjects)
    .option('-o, --sharedObjects [paths]', 'path to shared objects (repeatable). defaults to ' + config.sharedObjects, collectPaths, [config.sharedObjects])
    .option('-b, --browser <path>', 'name of browser to use. defaults to ' + config.browser, config.browser)
    .option('-r, --reports <path>', 'output path to save reports. defaults to ' + config.reports, config.reports)
    .option('-d, --disableLaunchReport [optional]', 'Disables the auto opening the browser with test report')
    .option('-j, --junit <path>', 'output path to save junit-report.xml defaults to ' + config.reports)
    .option('-t, --tags <tagName>', 'name of tag to run', collectPaths, [])
    .option('-f, --featureFile <path>', 'a specific feature file to run')
    .option('-x, --timeOut <n>', 'steps definition timeout in milliseconds. defaults to ' + config.timeout, coerceInt, config.timeout)
    .option('-n, --noScreenshot [optional]', 'disable auto capturing of screenshots when an error is encountered')
    .parse(process.argv);

program.on('--help', function () {
    console.log('  For more details please visit https://github.com/john-doherty/selenium-cucumber-js#readme\n');
});

// store browserName globally (used within world.js to build driver)
global.browserName = program.browser;

// store Eyes Api globally (used within world.js to set Eyes)
global.eyesKey = config.eye_key

// used within world.js to import page objects
global.pageObjectPath = path.resolve(program.pageObjects);

// used within world.js to output reports
global.reportsPath = path.resolve(program.reports);
if (!fs.existsSync(program.reports)) {
    fs.makeTreeSync(program.reports);
}

// used within world.js to decide if reports should be generated
global.disableLaunchReport = (program.disableLaunchReport);

// used with world.js to determine if a screenshot should be captured on error
global.noScreenshot = (program.noScreenshot);

// used within world.js to output junit reports
global.junitPath = path.resolve(program.junit || program.reports);

// set the default timeout to 10 seconds if not already globally defined or passed via the command line
global.DEFAULT_TIMEOUT = global.DEFAULT_TIMEOUT || program.timeOut || 10 * 1000;

// used within world.js to import shared objects into the shared namespace
global.sharedObjectPaths = program.sharedObjects.map(function (item) {
    return path.resolve(item);
});

// rewrite command line switches for cucumber
process.argv.splice(2, 100);

// allow a specific feature file to be executed
if (program.featureFile) {
    process.argv.push(program.featureFile);
}

// add switch to tell cucumber to produce json report files
process.argv.push('-f');
process.argv.push('pretty');
process.argv.push('-f');
process.argv.push('json:' + path.resolve(__dirname, global.reportsPath, 'cucumber-report.json'));

// add cucumber world as first required script (this sets up the globals)
process.argv.push('-r');
process.argv.push(path.resolve(__dirname, 'runtime/world.js'));

// add path to import step definitions
process.argv.push('-r');
process.argv.push(path.resolve(program.steps));

// add tag
if (program.tags) {
    program.tags.forEach(function (tag) {
        process.argv.push('-t');
        process.argv.push(tag);
    })
}

// add strict option (fail if there are any undefined or pending steps)
process.argv.push('-S');

//
// execute cucumber
//
var cucumberCli = cucumber.Cli(process.argv);

global.cucumber = cucumber;

cucumberCli.run(function (succeeded) {

    var code = succeeded ? 0 : 1;

    function exitNow() {
        process.exit(code);
    }

    if (process.stdout.write('')) {
        exitNow();
    }
    else {
        // write() returned false, kernel buffer is not empty yet...
        process.stdout.on('drain', exitNow);
    }
});
<commit_msg>added missing line terminators<commit_after>#!/usr/bin/env node

'use strict';

var fs = require('fs-plus');
var path = require('path');
var program = require('commander');
var pjson = require('./package.json');
var cucumber = require('cucumber');

function collectPaths(value, paths) {
    paths.push(value);
    return paths;
}

function coerceInt(value, defaultValue) {

    var int = parseInt(value);

    if (typeof int === 'number') return int;

    return defaultValue;
}

var config = {
    steps: './step-definitions',
    pageObjects: './page-objects',
    sharedObjects: './shared-objects',
    reports: './reports',
    browser: 'chrome',
    timeout: 15000
};

var configFileName = path.resolve(process.cwd(), 'selenium-cucumber-js.json');

if (fs.isFileSync(configFileName)) {
    config = Object.assign(config, require(configFileName));
}

program
    .version(pjson.version)
    .description(pjson.description)
    .option('-s, --steps <path>', 'path to step definitions. defaults to ' + config.steps, config.steps)
    .option('-p, --pageObjects <path>', 'path to page objects. defaults to ' + config.pageObjects, config.pageObjects)
    .option('-o, --sharedObjects [paths]', 'path to shared objects (repeatable). defaults to ' + config.sharedObjects, collectPaths, [config.sharedObjects])
    .option('-b, --browser <path>', 'name of browser to use. defaults to ' + config.browser, config.browser)
    .option('-r, --reports <path>', 'output path to save reports. defaults to ' + config.reports, config.reports)
    .option('-d, --disableLaunchReport [optional]', 'Disables the auto opening the browser with test report')
    .option('-j, --junit <path>', 'output path to save junit-report.xml defaults to ' + config.reports)
    .option('-t, --tags <tagName>', 'name of tag to run', collectPaths, [])
    .option('-f, --featureFile <path>', 'a specific feature file to run')
    .option('-x, --timeOut <n>', 'steps definition timeout in milliseconds. defaults to ' + config.timeout, coerceInt, config.timeout)
    .option('-n, --noScreenshot [optional]', 'disable auto capturing of screenshots when an error is encountered')
    .parse(process.argv);

program.on('--help', function () {
    console.log('  For more details please visit https://github.com/john-doherty/selenium-cucumber-js#readme\n');
});

// store browserName globally (used within world.js to build driver)
global.browserName = program.browser;

// store Eyes Api globally (used within world.js to set Eyes)
global.eyesKey = config.eye_key;

// used within world.js to import page objects
global.pageObjectPath = path.resolve(program.pageObjects);

// used within world.js to output reports
global.reportsPath = path.resolve(program.reports);
if (!fs.existsSync(program.reports)) {
    fs.makeTreeSync(program.reports);
}

// used within world.js to decide if reports should be generated
global.disableLaunchReport = (program.disableLaunchReport);

// used with world.js to determine if a screenshot should be captured on error
global.noScreenshot = (program.noScreenshot);

// used within world.js to output junit reports
global.junitPath = path.resolve(program.junit || program.reports);

// set the default timeout to 10 seconds if not already globally defined or passed via the command line
global.DEFAULT_TIMEOUT = global.DEFAULT_TIMEOUT || program.timeOut || 10 * 1000;

// used within world.js to import shared objects into the shared namespace
global.sharedObjectPaths = program.sharedObjects.map(function (item) {
    return path.resolve(item);
});

// rewrite command line switches for cucumber
process.argv.splice(2, 100);

// allow a specific feature file to be executed
if (program.featureFile) {
    process.argv.push(program.featureFile);
}

// add switch to tell cucumber to produce json report files
process.argv.push('-f');
process.argv.push('pretty');
process.argv.push('-f');
process.argv.push('json:' + path.resolve(__dirname, global.reportsPath, 'cucumber-report.json'));

// add cucumber world as first required script (this sets up the globals)
process.argv.push('-r');
process.argv.push(path.resolve(__dirname, 'runtime/world.js'));

// add path to import step definitions
process.argv.push('-r');
process.argv.push(path.resolve(program.steps));

// add tag
if (program.tags) {
    program.tags.forEach(function (tag) {
        process.argv.push('-t');
        process.argv.push(tag);
    });
}

// add strict option (fail if there are any undefined or pending steps)
process.argv.push('-S');

//
// execute cucumber
//
var cucumberCli = cucumber.Cli(process.argv);

global.cucumber = cucumber;

cucumberCli.run(function (succeeded) {

    var code = succeeded ? 0 : 1;

    function exitNow() {
        process.exit(code);
    }

    if (process.stdout.write('')) {
        exitNow();
    }
    else {
        // write() returned false, kernel buffer is not empty yet...
        process.stdout.on('drain', exitNow);
    }
});
<|endoftext|>


<commit_before>var jsdom = require("jsdom");
var ProfileClass = require("./data-containers/profile");
var Experience = require("./data-containers/experience");
var Honors = require("./data-containers/honors");
var Project = require("./data-containers/projects");
var Education = require("./data-containers/education");

function getProfile(linkedInURL, callback) {
    jsdom.env({
        url: linkedInURL,
        scripts: ["http://code.jquery.com/jquery.js"],
        done: function(errors, window) {
            var $ = window.$;
            var profile = new ProfileClass();
            profile.name = $("#name h1 span span").text();
            profile.headline = $("#headline p").text();
            profile.location = $("#location dl dd span").text();
            profile.current = $("#overview-summary-current td ol li a").text();
            $("#overview-summary-past td ol li").each(function() {
                var company = $(this).text();
                company = company.split(",")[0];
                profile.past.push(company);
            });

            profile.education = $("#overview-summary-education td ol li").text();
            $("#overview-summary-websites td ul li").each(function() {
                profile.websites.push($(this).find("a[href]").attr("href"));
            });
            $("#background-experience div div").each(function() {
                profile.experience.push(new Experience($(this).find("header h4").text(),
                    $(this).find("header a").text(),
                    $(this).find(".experience-date-locale").clone().find(".locality").remove().end().text(),
                    $(this).find("span span.locality").text(),
                    $(this).find("p").html()));
            });
            $("#background-honors div div div").each(function() {
                profile.honors.push(new Honors($(this).find("h4 span").text(),
                    $(this).find("h5 span").text(),
                    $(this).find("> span").text(),
                    $(this).find("p").text()));
            });

            $("#background-projects div div").each(function() {
                profile.projects.push(new Project($(this).find("hgroup h4 a span:first").text(),
                    $(this).find("> span.projects-date").text(),
                    $(this).find("> p").text(),
                    $(this).find("hgroup h4 a[href]").attr("href")));
            });

            $("#background-education div div div").each(function() {
                profile.educationlist.push(new Education($(this).find("header h4").text(),
                    $(this).find("header h4 a[href]").attr("href"),
                    $(this).find("header h5 span:first").text(),
                    $(this).find("header h5 span:eq(2)").text(),
                    $(this).find("header h5 span:last").text(),
                    $(this).find("> span").text()));
            });
            callback(profile);
        }
    });
}

module.exports = getProfile;<commit_msg>Adding skills parsing<commit_after>var jsdom = require("jsdom");
var ProfileClass = require("./data-containers/profile");
var Experience = require("./data-containers/experience");
var Honors = require("./data-containers/honors");
var Project = require("./data-containers/projects");
var Education = require("./data-containers/education");

function getProfile(linkedInURL, callback) {
    jsdom.env({
        url: linkedInURL,
        scripts: ["http://code.jquery.com/jquery.js"],
        done: function(errors, window) {
            var $ = window.$;
            var profile = new ProfileClass();
            profile.name = $("#name h1 span span").text();
            profile.headline = $("#headline p").text();
            profile.location = $("#location dl dd span").text();
            profile.current = $("#overview-summary-current td ol li a").text();
            $("#overview-summary-past td ol li").each(function() {
                var company = $(this).text();
                company = company.split(",")[0];
                profile.past.push(company);
            });

            profile.education = $("#overview-summary-education td ol li").text();
            $("#overview-summary-websites td ul li").each(function() {
                profile.websites.push($(this).find("a[href]").attr("href"));
            });
            $("#background-experience div div").each(function() {
                profile.experience.push(new Experience($(this).find("header h4").text(),
                    $(this).find("header a").text(),
                    $(this).find(".experience-date-locale").clone().find(".locality").remove().end().text(),
                    $(this).find("span span.locality").text(),
                    $(this).find("p").html()));
            });
            $("#background-honors div div div").each(function() {
                profile.honors.push(new Honors($(this).find("h4 span").text(),
                    $(this).find("h5 span").text(),
                    $(this).find("> span").text(),
                    $(this).find("p").text()));
            });

            $("#background-projects div div").each(function() {
                profile.projects.push(new Project($(this).find("hgroup h4 a span:first").text(),
                    $(this).find("> span.projects-date").text(),
                    $(this).find("> p").text(),
                    $(this).find("hgroup h4 a[href]").attr("href")));
            });

            $("#background-education div div div").each(function() {
                profile.educationlist.push(new Education($(this).find("header h4").text(),
                    $(this).find("header h4 a[href]").attr("href"),
                    $(this).find("header h5 span:first").text(),
                    $(this).find("header h5 span:eq(2)").text(),
                    $(this).find("header h5 span:last").text(),
                    $(this).find("> span").text()));
            });

			profile.skills = [];
			$("#profile-skills span.endorse-item-name a").each(function() {
				profile.skills.push($(this).text());
			});
            callback(profile);
        }
    });
}

module.exports = getProfile;
<|endoftext|>


<commit_before>/*jslint nomen: true, white: true, regexp: true*/
/*global $, _*/
/*jshint -W099*/

/**
* g is an easy way to render templates from an ajax request!
* Working example: http://jsfiddle.net/yuL2dugs/
*
* Future implementations:
*       - Handlebars integration
*       - Make it a Backbone Dependency
*       - Testing
*
* @example
*    g({ url: url }).using("#template").after("ul").now();
*
* @main g
* @author Guilherme Pontes
* @class g
* @constructor
* @param {Object} options It's an json object that handles the ajax configs
*/
(function(){
  var g = function gRequestRendering(options){
    "use strict";

    if("undefined" === typeof $) {
      throw new Error("g(): You need jQuery, sorry man.");
    }

    if("undefined" === typeof _) {
      throw new Error("g(): You need Underscore, sorry man.");
    }

    var __private, app;

    /**
     * Contains all private functions that cannot be used externally
     *
     * @property __private
    **/
    __private = {
      /**
       * Configuration of ajax configs
       *
       * @attribute config
       * @type Object
       */
      config: {
        cache: true
      },

      /**
       * HTML of generated template
       *
       * @attribute finalTemplate
       * @final
       * @type String
       */
      finalTemplate: "",

      /**
       * Handle the ajax request, parses and template generating
       *
       * @async
       * @method request
       * @return {undefined}
      **/
      request: function(options) {
        $.ajax(__private.config)
          .done(function(response){
              if(options && options.parseCollection) {
                  response = options.parseCollection(response);
              }

              if(options && options.handle) {
                  options.handle(response, app.templating);
                  return;
              }

              __private.make(response, options && options.parseModel);
          })
          .error(function(jqXHR, textStatus, errorThrown){
            if(options && options.error) {
              options.error(jqXHR, textStatus, errorThrown);
            }
          });
      },

      /**
       * Render the final template
       *
       * @method render
       * @return {undefined}
      **/
      render: function() {
          $(app.templating.target).html(this.finalTemplate);
      },

      /**
       * Loop through the array of objects and generate a template for
       * each item, adding a parse if available
       *
       * @method make
       * @return {undefined}
      **/
      make: function(response, parse) {
          _.each(response, function(item){
              this.add((parse && parse(item)) || item);
          }, this);

          this.render();
      },

      /**
       * Generates a template for a single model, appending to `app.finalTemplate`
       *
       * @method add
       * @return {undefined}
      **/
      add: function(item){
        var template = _.template( app.templating.template );
        this.finalTemplate += template(item);
      }
    };

    /**
     * The object that have all public functions and properties
     *
     * @property app
    **/
    app = {
      /**
       * Object that will store the template that will be handled and
       * the target element that will render the final template
       *
       * @attribute templating
       * @type Object
      **/
      templating: {
        target: false,
        template: false
      },

      /**
       * How the template will be rendered in the target element
       * Methods: [fill, append, prepend, after, before]
       *
       * @attribute how
       * @attribute
       * @type String
      **/
      how: null,

      /**
       * Underscore configuration
       *
       * @example
       *   Do something: {{ name = name.toLowerCase() }}
       *   Print Variable: {{= name}}
       *
       * @attribute settings
       * @method settings
       * @return {undefined}
      **/
      settings: function() {
        _.templateSettings = {
          interpolate: /\{\{=(.+?)\}\}/g,
          evaluate: /\{\{(.+?)\}\}/g
        };
      },

      /**
       * Set the base template that will evaluated for rendering
       *
       * @method using
       * @param {String} id Id of the DOM element that contains the base template
       * @required
       * @chainable
      **/
      using: function(id) {
        this.templating.template = $(id).html();
        return this;
      },

      /**
       * Set the base template that will evaluated for rendering
       *
       * @method using
       * @param {String} id Id of the DOM element that contains the base template
       * @return {undefined}
      **/
      setMethod: function(id, how) {
        if(this.how !== null) {
          throw new Error(how + "(): You've already set a method of rendering!");
        }

        this.templating.target = $(id);
        this.how = how;
      },

      /**
       * Set the method to fill, that will replace all content from an
       * DOM element
       *
       * @example
       *   Before:
       *

loading

       *   After:
       *

item 1

item 2

       *
       * @method fill
       * @param {String} id Id of the DOM element that contains the base template
       * @chainable
      **/
      fill: function(id) {
        this.setMethod(id, "fill");
        return this;
      },

      /**
       * Set the method to append that will only append to the DOM element
       *
       * @example
       *   Before:
       *

Listing

       *   After:
       *

Listing

item 1

item 2

       *
       * @method append
       * @param {String} id Id of the DOM element that contains the base template
       * @chainable
      **/
      append: function(id) {
        this.setMethod(id, "append");
        return this;
      },

      /**
       * Set the method to prepend that will only prepend to the DOM element
       *
       * @example
       *   Before:
       *

Listing

       *   After:
       *

item 1

item 2

Listing

       *
       * @method prepend
       * @param {String} id Id of the DOM element that contains the base template
       * @chainable
      **/
      prepend: function(id) {
        this.setMethod(id, "prepend");
        return this;
      },

      /**
       * Will add the evaluated template after the target DOM element
       *
       * @example
       *   Before:
       *

       *   After:
       *

 Try it now!
       *
       * @method after
       * @param {String} id Id of the DOM element that contains the base template
       * @chainable
      **/
      after: function(id) {
        this.setMethod(id, "after");
        return this;
      },

      /**
       * Will add the evaluated template before the target DOM element
       *
       * @example
       *   Before:
       *

       *   After:
       *     Try it now!

       *
       * @method before
       * @param {String} id Id of the DOM element that contains the base template
       * @chainable
      **/
      before: function(id) {
        this.setMethod(id, "before");
        return this;
      },

      /**
       *
       *  The now(optObj) method executes and handle the request. Simple as that.
       *
       * Available methods in now(optObj):
       *   handle(response, templating)
       *     - Basically, you'll handle the success method of jquery ajax.
       *       Params:
       *         `response`            : Response of the ajax request
       *         `templating`          : Object with templating configs
       *         `templating.template` : Base template, setted in using() method
       *         `templating.target`   : Base template, setted in [fill || append || prepend || after || before]() method
       *
       *   error(jqXHR, textStatus, errorThrown)
       *     - Handler for an failing ajax request
       *       Params:
       *         jqXHR        : XMLHttpRequest object
       *         textStatus   : String describing the type of error that occurred
       *         errorThrown  : When an HTTP error occurs, errorThrown receives the textual portion of the HTTP status
       *
       *   parseCollection(collection)
       *     -  It will parse all collection that was received from the request
       *        Params:
       *          collection: Array of objects
       *
       *   parseModel(model)
       *     -  It will parse a single model, for each item from the collection
       *        Params:
       *          model: Array of objects
       *
       * @method now
       * @param {Object} callbacks Callbacks adds lots of methods that you call handle the data from the request
       * @extends g().using g()[fill || append || prepend || after || before]
       * @return {undefined}a
       **/
      now: function(callbacks) {
        this.settings();

        if(this.setup(options)) {
          __private.request(callbacks);
        }
      },

      /**
       * Validates all options setted in the module
       *
       * @method setup
       * @return {Boolean}
      **/
      setup: function() {
        if(!options || !options.url) {
          throw new Error("g(): You must enter ajax options. Ex: url.");
        }

        if(!this.templating.template) {
          throw new Error("g.using(): You must enter a template.");
        }

        if(!this.templating.target) {
          throw new Error("g." + this.how + "(): You must enter a target to render the template.");
        }

        __private.config = $.extend({}, __private.config, options);

        return true;
      }
    };

    return app;
  };

  /**
   * g version
  **/
  g.version = "0.1.0";

  /**
   * setting gRender and __ as optional names
  **/
  window.g = window.gRender = window.__ = window.g || g;
}());
<commit_msg>removing future implementations<commit_after>/*jslint nomen: true, white: true, regexp: true*/
/*global $, _*/
/*jshint -W099*/

/**
* g is an easy way to render templates from an ajax request!
* Working example: http://jsfiddle.net/yuL2dugs/
*
*
* @example
*    g({ url: url }).using("#template").after("ul").now();
*
* @main g
* @author Guilherme Pontes
* @class g
* @constructor
* @param {Object} options It's an json object that handles the ajax configs
*/
(function(){
  var g = function gRequestRendering(options){
    "use strict";

    if("undefined" === typeof $) {
      throw new Error("g(): You need jQuery, sorry man.");
    }

    if("undefined" === typeof _) {
      throw new Error("g(): You need Underscore, sorry man.");
    }

    var __private, app;

    /**
     * Contains all private functions that cannot be used externally
     *
     * @property __private
    **/
    __private = {
      /**
       * Configuration of ajax configs
       *
       * @attribute config
       * @type Object
       */
      config: {
        cache: true
      },

      /**
       * HTML of generated template
       *
       * @attribute finalTemplate
       * @final
       * @type String
       */
      finalTemplate: "",

      /**
       * Handle the ajax request, parses and template generating
       *
       * @async
       * @method request
       * @return {undefined}
      **/
      request: function(options) {
        $.ajax(__private.config)
          .done(function(response){
              if(options && options.parseCollection) {
                  response = options.parseCollection(response);
              }

              if(options && options.handle) {
                  options.handle(response, app.templating);
                  return;
              }

              __private.make(response, options && options.parseModel);
          })
          .error(function(jqXHR, textStatus, errorThrown){
            if(options && options.error) {
              options.error(jqXHR, textStatus, errorThrown);
            }
          });
      },

      /**
       * Render the final template
       *
       * @method render
       * @return {undefined}
      **/
      render: function() {
          $(app.templating.target).html(this.finalTemplate);
      },

      /**
       * Loop through the array of objects and generate a template for
       * each item, adding a parse if available
       *
       * @method make
       * @return {undefined}
      **/
      make: function(response, parse) {
          _.each(response, function(item){
              this.add((parse && parse(item)) || item);
          }, this);

          this.render();
      },

      /**
       * Generates a template for a single model, appending to `app.finalTemplate`
       *
       * @method add
       * @return {undefined}
      **/
      add: function(item){
        var template = _.template( app.templating.template );
        this.finalTemplate += template(item);
      }
    };

    /**
     * The object that have all public functions and properties
     *
     * @property app
    **/
    app = {
      /**
       * Object that will store the template that will be handled and
       * the target element that will render the final template
       *
       * @attribute templating
       * @type Object
      **/
      templating: {
        target: false,
        template: false
      },

      /**
       * How the template will be rendered in the target element
       * Methods: [fill, append, prepend, after, before]
       *
       * @attribute how
       * @attribute
       * @type String
      **/
      how: null,

      /**
       * Underscore configuration
       *
       * @example
       *   Do something: {{ name = name.toLowerCase() }}
       *   Print Variable: {{= name}}
       *
       * @attribute settings
       * @method settings
       * @return {undefined}
      **/
      settings: function() {
        _.templateSettings = {
          interpolate: /\{\{=(.+?)\}\}/g,
          evaluate: /\{\{(.+?)\}\}/g
        };
      },

      /**
       * Set the base template that will evaluated for rendering
       *
       * @method using
       * @param {String} id Id of the DOM element that contains the base template
       * @required
       * @chainable
      **/
      using: function(id) {
        this.templating.template = $(id).html();
        return this;
      },

      /**
       * Set the base template that will evaluated for rendering
       *
       * @method using
       * @param {String} id Id of the DOM element that contains the base template
       * @return {undefined}
      **/
      setMethod: function(id, how) {
        if(this.how !== null) {
          throw new Error(how + "(): You've already set a method of rendering!");
        }

        this.templating.target = $(id);
        this.how = how;
      },

      /**
       * Set the method to fill, that will replace all content from an
       * DOM element
       *
       * @example
       *   Before:
       *

loading

       *   After:
       *

item 1

item 2

       *
       * @method fill
       * @param {String} id Id of the DOM element that contains the base template
       * @chainable
      **/
      fill: function(id) {
        this.setMethod(id, "fill");
        return this;
      },

      /**
       * Set the method to append that will only append to the DOM element
       *
       * @example
       *   Before:
       *

Listing

       *   After:
       *

Listing

item 1

item 2

       *
       * @method append
       * @param {String} id Id of the DOM element that contains the base template
       * @chainable
      **/
      append: function(id) {
        this.setMethod(id, "append");
        return this;
      },

      /**
       * Set the method to prepend that will only prepend to the DOM element
       *
       * @example
       *   Before:
       *

Listing

       *   After:
       *

item 1

item 2

Listing

       *
       * @method prepend
       * @param {String} id Id of the DOM element that contains the base template
       * @chainable
      **/
      prepend: function(id) {
        this.setMethod(id, "prepend");
        return this;
      },

      /**
       * Will add the evaluated template after the target DOM element
       *
       * @example
       *   Before:
       *

       *   After:
       *

 Try it now!
       *
       * @method after
       * @param {String} id Id of the DOM element that contains the base template
       * @chainable
      **/
      after: function(id) {
        this.setMethod(id, "after");
        return this;
      },

      /**
       * Will add the evaluated template before the target DOM element
       *
       * @example
       *   Before:
       *

       *   After:
       *     Try it now!

       *
       * @method before
       * @param {String} id Id of the DOM element that contains the base template
       * @chainable
      **/
      before: function(id) {
        this.setMethod(id, "before");
        return this;
      },

      /**
       *
       *  The now(optObj) method executes and handle the request. Simple as that.
       *
       * Available methods in now(optObj):
       *   handle(response, templating)
       *     - Basically, you'll handle the success method of jquery ajax.
       *       Params:
       *         `response`            : Response of the ajax request
       *         `templating`          : Object with templating configs
       *         `templating.template` : Base template, setted in using() method
       *         `templating.target`   : Base template, setted in [fill || append || prepend || after || before]() method
       *
       *   error(jqXHR, textStatus, errorThrown)
       *     - Handler for an failing ajax request
       *       Params:
       *         jqXHR        : XMLHttpRequest object
       *         textStatus   : String describing the type of error that occurred
       *         errorThrown  : When an HTTP error occurs, errorThrown receives the textual portion of the HTTP status
       *
       *   parseCollection(collection)
       *     -  It will parse all collection that was received from the request
       *        Params:
       *          collection: Array of objects
       *
       *   parseModel(model)
       *     -  It will parse a single model, for each item from the collection
       *        Params:
       *          model: Array of objects
       *
       * @method now
       * @param {Object} callbacks Callbacks adds lots of methods that you call handle the data from the request
       * @extends g().using g()[fill || append || prepend || after || before]
       * @return {undefined}a
       **/
      now: function(callbacks) {
        this.settings();

        if(this.setup(options)) {
          __private.request(callbacks);
        }
      },

      /**
       * Validates all options setted in the module
       *
       * @method setup
       * @return {Boolean}
      **/
      setup: function() {
        if(!options || !options.url) {
          throw new Error("g(): You must enter ajax options. Ex: url.");
        }

        if(!this.templating.template) {
          throw new Error("g.using(): You must enter a template.");
        }

        if(!this.templating.target) {
          throw new Error("g." + this.how + "(): You must enter a target to render the template.");
        }

        __private.config = $.extend({}, __private.config, options);

        return true;
      }
    };

    return app;
  };

  /**
   * g version
  **/
  g.version = "0.1.0";

  /**
   * setting gRender and __ as optional names
  **/
  window.g = window.gRender = window.__ = window.g || g;
}());
<|endoftext|>


<commit_before>var async = require('async');
var cheerio = require('cheerio');
var chalk = require('chalk');
var crypto = require('crypto');
var http = require('http');
var process = require('process');
var request = require('request');
var util = require('util');
var telegram = require('telegram-bot-api');

var uriencoder = require('./encoder');
var fixedURIencode = function(uri){
	return uriencoder(encodeURIComponent(uri));
};

var remover = require('./remover');
var config = require('./config/');

var api = new telegram({
	token: config.token,
	updates: {
		enabled: false
	}
});

global.api = api;
global.config = config;
var app = require('./app');

var namuwikiReqIds = [];
var inlineSession = {};
var inlineResults = [];
var lastRequest = 0;
var inlineId = 0;
var searchSelector = 'article.wiki-article section a:not(.page-link)';
var handleMessage = function(from, chatId, message){
	if(message.text.startsWith('/nw')){
		if(attempt(from, chatId)){
			api.sendMessage({
				chat_id: chatId,
				text: "조금 있다가 해보세요!\n(현재 60초에 명령어 " + config.commandAmount + "개로 제한하고 있습니다.)\n나무위키 본관측에 많은 트래픽이 가는 것을 방지하기 위한 조치이니 협조해주시면 감사하겠습니다!"
			}).catch(() => {});
		}

		var url = message.text.replace(/^\/nw(?:@[a-zA-Z0-9]*)?[ ]*/, '');
		if(url === ''){
			api.sendMessage({
				chat_id: chatId,
				text: '사용법: /nw [검색할 무언가]\n혹은 @namuwikiBot [검색할 무언가] 입력 후 기다리기\n\n개발자: @Khinenw\n사용한 이미지: 무냐 by eb\n세피로트 by SMINORFF_KAMCHATKA\n사용된 이미지는 모두 CC-BY-NC-SA 2.0 조건 하에 배포되고 있습니다.'
			}).catch(() => {});
			return;
		}

		var _url = url;
		getNamuwiki(url, function(err, url, overview){
			if(err){
				if(err === 404){
					request({
						method: 'get',
						headers: {
							'User-Agent': config.userAgent
						},
						url: config.searchUrl + fixedURIencode(_url)
					}, (err, response, body) => {
						if(!err && response.statusCode === 200){
							var $ = cheerio.load(body);
							var hrefs = $(searchSelector);
							var results = [];

							Array.apply(null, Array(config.inlineAmount)).map((v, k) => {return k;}).forEach((i) => {
								if(hrefs.length > i){
									var url = decodeURIComponent($(hrefs.get(i)).attr('href').replace('/w/', ''));
									var hash = crypto.createHash('md5').update(chatId + ':' + url).digest('hex');
									inlineResults[hash] = {
										url: '/nw ' + url,
										to: chatId,
										expires: Date.now() + 120 * 1000
									};

									results.push([{
										text: url,
										callback_data: hash
									}]);
								}
							});

							api.sendSticker({
								chat_id: chatId,
								sticker: config.failSticker[Math.floor(Math.random() * config.failSticker.length)],
								reply_markup: JSON.stringify({
									inline_keyboard: results
								})
							}).catch(() => {});
						}
					});
					return;
				}

				if(err === 503){
					api.sendMessage({
						chat_id: chatId,
						text: "현재 Cloudflare DDoS 프로텍션 때문에 문서에 접근이 불가합니다."
					}).catch(() => {});
					//TODO add bypassing sucuri ddos protection
					return;
				}
				return;
			}

			var text = "";
			if(config.useMarkdown){
				text = '**' + url + '**\n' + overview + '\n[자세히보기](' + config.url + fixedURIencode(url) + ')';
			}else{
				text = url + '\n' + overview + '\n' + config.url + fixedURIencode(url);
			}

			if(config.split && text.length > 4000){
				async.eachSeries(text.match(/[^]{1,4000}/g), function(v, cb){
					sendMarkdown(chatId, v, cb);
				});

				return;
			}

			sendMarkdown(chatId, text);
		});
	}
};

api.on('message', function(message){
	var chatId = message.chat.id;
	var from = message.from.id;
	if(typeof message.text !== 'string') return;

	handleMessage(from, chatId, message);
});

api.on('inline.callback.query', (query) => {
	var queryData = inlineResults[query.data];

	if(queryData === undefined){
		api.sendMessage({
			chat_id: query.from.id,
			text: '쿼리가 만료되었습니다! /nw@namuwikiBot 명령어를 다시 입력해주세요!'
		}).catch(() => {});
		return;
	}

	handleMessage(query.from.id, queryData.to, {
		text: queryData.url
	});
});

api.on('inline.query', (query) => {
	if(inlineSession[query.from.id] === undefined){
		inlineSession[query.from.id] = [];
	}

	inlineSession[query.from.id] = {
		query: query,
		time: Date.now() + config.querySpeed
	};
});

setInterval(() => {
	async.forEachOfSeries(inlineSession, (v, k, asyncCallback) => {
		if(v.done) return;
		if(Date.now() < v.time) return;

		inlineSession[k].done = true;

		var query = v.query;
		if(attempt(query.from.id)) return;

		request({
			method: 'get',
			headers: {
				'User-Agent': config.userAgent
			},
			url: config.searchUrl + fixedURIencode(query.query)
		}, (err, response, body) => {
			if(!err && response.statusCode === 200){
				var $ = cheerio.load(body);
				var hrefs = $(searchSelector);
				var results = [];

				async.eachSeries(Array.apply(null, Array(config.inlineAmount)).map((v, k) => {return k;}), (i, cb) => {
					if(hrefs.length > i){
						getNamuwiki(decodeURIComponent($(hrefs.get(i)).attr('href').replace('/w/', '')), (err, url, overview) => {
							if(err){
								return;
							}

							results.push({
								type: 'article',
								id: (++inlineId) + '',
								title: url,
								message_text: '**' + url + '**\n' + overview + '\n[자세히보기](' + config.url + fixedURIencode(url) + ')',
								//parse_mode: 'Markdown',
								url: config.url + fixedURIencode(url)
							});
							cb();
						}, 0, true);
					}
				}, () => {
					api.answerInlineQuery({
						inline_query_id: query.id,
						results: results
					}, (err, res) => {
						if(err){
							console.log(chalk.bgRed(util.inspect(err)));
							return;
						}
						asyncCallback();
					});
				});
			}
		});
	});

}, config.queryInterval);

setInterval(() => {
	Object.keys(inlineResults).forEach((k) => {
		if(inlineResults[k].expires < Date.now()){
			inlineResults[k] = undefined;
			delete inlineResults[k];
		}
	});
}, 60000);

function log(logContents, chatId){
	api.sendMessage({
		chat_id: chatId,
		text: "요청을 처리하는 도중 서버측에서 오류가 발생했습니다! :(\n@Khinenw 에게 제보하여주시면 감사하겠습니다!"
	}).catch(() => {});

	console.log(chalk.bgRed("=======Starting error report======="));
	async.forEachOfSeries(logContents, function(v, k, cb){
		console.log(chalk.yellow(k + " : " + v));
		cb();
	}, function(){
		console.log(chalk.bgRed("========End of error report========"));
	});
}

function attempt(from){
	if(namuwikiReqIds[from] !== undefined){
		if(namuwikiReqIds[from].date < Date.now()){
			namuwikiReqIds[from].count = 0;
			namuwikiReqIds[from].date = Date.now() + 60000;
		}

		if(namuwikiReqIds[from].count >= config.commandAmount){
			return true;
		}

		namuwikiReqIds[from].count++;
	}else{
		namuwikiReqIds[from] = {
			count: 0,
			date: Date.now() + 60000
		};
	}

	return false;
}

function sendMarkdown(chatId, v, cb){
	cb = cb || () => {};

	api.sendMessage({
		chat_id: chatId,
		text: v,
		parse_mode: 'Markdown'
	}, function(err, data){
		if(err){
			api.sendMessage({
				chat_id: chatId,
				text: v
			}, (err, data) => {
				if(err){
					log({
						'Time': (new Date()).toUTCString(),
						'Error 1': util.inspect(err)/*,
						'URL': url*/
					}, chatId);
				}

				cb();
			});
			return;
		}

		cb();
	});
}

function getNamuwiki(url, callback, redirectionCount, waited){
	if(!waited && lastRequest + config.requestInterval > Date.now()){
		setTimeout(() => {
			getNamuwiki(url, callback, redirectionCount, true);
		}, config.requestInterval);
		return;
	}

	lastRequest = Date.now();

	if(redirectionCount > config.maxRedirection){
		callback(new Error("Too many redirections!"));
	}

	request({
		method: 'get',
		headers: {
			'User-Agent': config.userAgent
		},
		url: config.rawUrl + fixedURIencode(url)
	}, function(err, response, body){
		if(!err && response.statusCode === 200){
			console.log(chalk.cyan(response.statusCode + ': ' + url));

			if(body.includes('#redirect ')){
				var redirectionTarget = body.match(/^\s*#redirect\s+(.*)\s*$/m);
				if(redirectionTarget && redirectionTarget[1]){
					getNamuwiki(redirectionTarget[1], callback, redirectionCount + 1, true);
					return;
				}
			}

			var split = body.split(/^\s*[=]+ .* [=]+\s*$/gm);
			var overview = "";

			if(split.length <= 1){
				overview = split[0];
			}else{
				overview = split[1];
			}

			async.forEachOfSeries(config.remove, function(v, k, cb){
				remover[k].remove(v, overview, function(returnVal){
					overview = returnVal;
					cb();
				});
			}, function(){
				callback(undefined, url, overview);
			});
		}else{
			if(err){
				console.error(chalk.bgRed(err.toString()));
				callback(500);
				return;
			}
			console.log(chalk.yellow(response.statusCode + ': ' + url));
			callback(response.statusCode);
			return;
		}
	});
}

var port = ((val) => {
	var portNumber = parseInt(val, 10);

	if(isNaN(portNumber)){
		return val;
	}

	if(portNumber >= 0){
		return portNumber;
	}

	return false;
})(process.env.PORT || '443');

var useCert = (process.env.CERT === 'true');

app.set('port', port);

var options;

if(useCert){
	options = {
		key: fs.readFileSync('/cert/key.pem'),
		crt: fs.readFileSync('/cert/crt.pem')
	};
}

if(useCert) var httpServer = http.createServer(options, app);
else var httpServer = http.createServer(app);

httpServer.listen(port);
httpServer.on('error', (err) => {
	if(err.syscall !== 'listen') throw err;
	var bind = typeof port === 'string' ? 'Pipe ' + port : 'Port ' + port;

	switch(err.code){
		case 'EACCES':
			console.error('Permission Denied!');
			process.exit(1);
			return;

		case 'EADDRINUSE':
			console.error('Address in use!');
			process.exit(1);
			return;
	}

	throw error;
});

httpServer.on('listening', () => {
	var addr = httpServer.address();
	console.log((typeof addr === 'string') ? 'Pipe ' + addr : 'Listening on port ' + addr.port);
});

if(!useCert){
	var _baseurl = 'https://api.telegram.org/bot' + config.token + '/';

	request({
		method: 'POST',
		json: true,
		formData: {
			url: config.hookUrl + config.token
		},
		url: _baseurl + 'setWebhook'
	});
}else api.setWebhook(config.hookUrl + config.token, options.crt);
<commit_msg>Added answerquery<commit_after>var async = require('async');
var cheerio = require('cheerio');
var chalk = require('chalk');
var crypto = require('crypto');
var http = require('http');
var process = require('process');
var request = require('request');
var util = require('util');
var telegram = require('telegram-bot-api');

var uriencoder = require('./encoder');
var fixedURIencode = function(uri){
	return uriencoder(encodeURIComponent(uri));
};

var remover = require('./remover');
var config = require('./config/');

var api = new telegram({
	token: config.token,
	updates: {
		enabled: false
	}
});

global.api = api;
global.config = config;
var app = require('./app');

var namuwikiReqIds = [];
var inlineSession = {};
var inlineResults = [];
var lastRequest = 0;
var inlineId = 0;
var searchSelector = 'article.wiki-article section a:not(.page-link)';
var handleMessage = function(from, chatId, message){
	if(message.text.startsWith('/nw')){
		if(attempt(from, chatId)){
			api.sendMessage({
				chat_id: chatId,
				text: "조금 있다가 해보세요!\n(현재 60초에 명령어 " + config.commandAmount + "개로 제한하고 있습니다.)\n나무위키 본관측에 많은 트래픽이 가는 것을 방지하기 위한 조치이니 협조해주시면 감사하겠습니다!"
			}).catch(() => {});
		}

		var url = message.text.replace(/^\/nw(?:@[a-zA-Z0-9]*)?[ ]*/, '');
		if(url === ''){
			api.sendMessage({
				chat_id: chatId,
				text: '사용법: /nw [검색할 무언가]\n혹은 @namuwikiBot [검색할 무언가] 입력 후 기다리기\n\n개발자: @Khinenw\n사용한 이미지: 무냐 by eb\n세피로트 by SMINORFF_KAMCHATKA\n사용된 이미지는 모두 CC-BY-NC-SA 2.0 조건 하에 배포되고 있습니다.'
			}).catch(() => {});
			return;
		}

		var _url = url;
		getNamuwiki(url, function(err, url, overview){
			if(err){
				if(err === 404){
					request({
						method: 'get',
						headers: {
							'User-Agent': config.userAgent
						},
						url: config.searchUrl + fixedURIencode(_url)
					}, (err, response, body) => {
						if(!err && response.statusCode === 200){
							var $ = cheerio.load(body);
							var hrefs = $(searchSelector);
							var results = [];

							Array.apply(null, Array(config.inlineAmount)).map((v, k) => {return k;}).forEach((i) => {
								if(hrefs.length > i){
									var url = decodeURIComponent($(hrefs.get(i)).attr('href').replace('/w/', ''));
									var hash = crypto.createHash('md5').update(chatId + ':' + url).digest('hex');
									inlineResults[hash] = {
										url: '/nw ' + url,
										to: chatId,
										expires: Date.now() + 120 * 1000
									};

									results.push([{
										text: url,
										callback_data: hash
									}]);
								}
							});

							api.sendSticker({
								chat_id: chatId,
								sticker: config.failSticker[Math.floor(Math.random() * config.failSticker.length)],
								reply_markup: JSON.stringify({
									inline_keyboard: results
								})
							}).catch(() => {});
						}
					});
					return;
				}

				if(err === 503){
					api.sendMessage({
						chat_id: chatId,
						text: "현재 Cloudflare DDoS 프로텍션 때문에 문서에 접근이 불가합니다."
					}).catch(() => {});
					//TODO add bypassing sucuri ddos protection
					return;
				}
				return;
			}

			var text = "";
			if(config.useMarkdown){
				text = '**' + url + '**\n' + overview + '\n[자세히보기](' + config.url + fixedURIencode(url) + ')';
			}else{
				text = url + '\n' + overview + '\n' + config.url + fixedURIencode(url);
			}

			if(config.split && text.length > 4000){
				async.eachSeries(text.match(/[^]{1,4000}/g), function(v, cb){
					sendMarkdown(chatId, v, cb);
				});

				return;
			}

			sendMarkdown(chatId, text);
		});
	}
};

api.on('message', function(message){
	var chatId = message.chat.id;
	var from = message.from.id;
	if(typeof message.text !== 'string') return;

	handleMessage(from, chatId, message);
});

api.on('inline.callback.query', (query) => {
	api.answerCallbackQuery({
		callback_query_id: query.id
	});
	var queryData = inlineResults[query.data];

	if(queryData === undefined){
		api.sendMessage({
			chat_id: query.from.id,
			text: '쿼리가 만료되었습니다! /nw@namuwikiBot 명령어를 다시 입력해주세요!'
		}).catch(() => {});
		return;
	}

	handleMessage(query.from.id, queryData.to, {
		text: queryData.url
	});
});

api.on('inline.query', (query) => {
	if(inlineSession[query.from.id] === undefined){
		inlineSession[query.from.id] = [];
	}

	inlineSession[query.from.id] = {
		query: query,
		time: Date.now() + config.querySpeed
	};
});

setInterval(() => {
	async.forEachOfSeries(inlineSession, (v, k, asyncCallback) => {
		if(v.done) return;
		if(Date.now() < v.time) return;

		inlineSession[k].done = true;

		var query = v.query;
		if(attempt(query.from.id)) return;

		request({
			method: 'get',
			headers: {
				'User-Agent': config.userAgent
			},
			url: config.searchUrl + fixedURIencode(query.query)
		}, (err, response, body) => {
			if(!err && response.statusCode === 200){
				var $ = cheerio.load(body);
				var hrefs = $(searchSelector);
				var results = [];

				async.eachSeries(Array.apply(null, Array(config.inlineAmount)).map((v, k) => {return k;}), (i, cb) => {
					if(hrefs.length > i){
						getNamuwiki(decodeURIComponent($(hrefs.get(i)).attr('href').replace('/w/', '')), (err, url, overview) => {
							if(err){
								return;
							}

							results.push({
								type: 'article',
								id: (++inlineId) + '',
								title: url,
								message_text: '**' + url + '**\n' + overview + '\n[자세히보기](' + config.url + fixedURIencode(url) + ')',
								//parse_mode: 'Markdown',
								url: config.url + fixedURIencode(url)
							});
							cb();
						}, 0, true);
					}
				}, () => {
					api.answerInlineQuery({
						inline_query_id: query.id,
						results: results
					}, (err, res) => {
						if(err){
							console.log(chalk.bgRed(util.inspect(err)));
							return;
						}
						asyncCallback();
					});
				});
			}
		});
	});

}, config.queryInterval);

setInterval(() => {
	Object.keys(inlineResults).forEach((k) => {
		if(inlineResults[k].expires < Date.now()){
			inlineResults[k] = undefined;
			delete inlineResults[k];
		}
	});
}, 60000);

function log(logContents, chatId){
	api.sendMessage({
		chat_id: chatId,
		text: "요청을 처리하는 도중 서버측에서 오류가 발생했습니다! :(\n@Khinenw 에게 제보하여주시면 감사하겠습니다!"
	}).catch(() => {});

	console.log(chalk.bgRed("=======Starting error report======="));
	async.forEachOfSeries(logContents, function(v, k, cb){
		console.log(chalk.yellow(k + " : " + v));
		cb();
	}, function(){
		console.log(chalk.bgRed("========End of error report========"));
	});
}

function attempt(from){
	if(namuwikiReqIds[from] !== undefined){
		if(namuwikiReqIds[from].date < Date.now()){
			namuwikiReqIds[from].count = 0;
			namuwikiReqIds[from].date = Date.now() + 60000;
		}

		if(namuwikiReqIds[from].count >= config.commandAmount){
			return true;
		}

		namuwikiReqIds[from].count++;
	}else{
		namuwikiReqIds[from] = {
			count: 0,
			date: Date.now() + 60000
		};
	}

	return false;
}

function sendMarkdown(chatId, v, cb){
	cb = cb || () => {};

	api.sendMessage({
		chat_id: chatId,
		text: v,
		parse_mode: 'Markdown'
	}, function(err, data){
		if(err){
			api.sendMessage({
				chat_id: chatId,
				text: v
			}, (err, data) => {
				if(err){
					log({
						'Time': (new Date()).toUTCString(),
						'Error 1': util.inspect(err)/*,
						'URL': url*/
					}, chatId);
				}

				cb();
			});
			return;
		}

		cb();
	});
}

function getNamuwiki(url, callback, redirectionCount, waited){
	if(!waited && lastRequest + config.requestInterval > Date.now()){
		setTimeout(() => {
			getNamuwiki(url, callback, redirectionCount, true);
		}, config.requestInterval);
		return;
	}

	lastRequest = Date.now();

	if(redirectionCount > config.maxRedirection){
		callback(new Error("Too many redirections!"));
	}

	request({
		method: 'get',
		headers: {
			'User-Agent': config.userAgent
		},
		url: config.rawUrl + fixedURIencode(url)
	}, function(err, response, body){
		if(!err && response.statusCode === 200){
			console.log(chalk.cyan(response.statusCode + ': ' + url));

			if(body.includes('#redirect ')){
				var redirectionTarget = body.match(/^\s*#redirect\s+(.*)\s*$/m);
				if(redirectionTarget && redirectionTarget[1]){
					getNamuwiki(redirectionTarget[1], callback, redirectionCount + 1, true);
					return;
				}
			}

			var split = body.split(/^\s*[=]+ .* [=]+\s*$/gm);
			var overview = "";

			if(split.length <= 1){
				overview = split[0];
			}else{
				overview = split[1];
			}

			async.forEachOfSeries(config.remove, function(v, k, cb){
				remover[k].remove(v, overview, function(returnVal){
					overview = returnVal;
					cb();
				});
			}, function(){
				callback(undefined, url, overview);
			});
		}else{
			if(err){
				console.error(chalk.bgRed(err.toString()));
				callback(500);
				return;
			}
			console.log(chalk.yellow(response.statusCode + ': ' + url));
			callback(response.statusCode);
			return;
		}
	});
}

var port = ((val) => {
	var portNumber = parseInt(val, 10);

	if(isNaN(portNumber)){
		return val;
	}

	if(portNumber >= 0){
		return portNumber;
	}

	return false;
})(process.env.PORT || '443');

var useCert = (process.env.CERT === 'true');

app.set('port', port);

var options;

if(useCert){
	options = {
		key: fs.readFileSync('/cert/key.pem'),
		crt: fs.readFileSync('/cert/crt.pem')
	};
}

if(useCert) var httpServer = http.createServer(options, app);
else var httpServer = http.createServer(app);

httpServer.listen(port);
httpServer.on('error', (err) => {
	if(err.syscall !== 'listen') throw err;
	var bind = typeof port === 'string' ? 'Pipe ' + port : 'Port ' + port;

	switch(err.code){
		case 'EACCES':
			console.error('Permission Denied!');
			process.exit(1);
			return;

		case 'EADDRINUSE':
			console.error('Address in use!');
			process.exit(1);
			return;
	}

	throw error;
});

httpServer.on('listening', () => {
	var addr = httpServer.address();
	console.log((typeof addr === 'string') ? 'Pipe ' + addr : 'Listening on port ' + addr.port);
});

if(!useCert){
	var _baseurl = 'https://api.telegram.org/bot' + config.token + '/';

	request({
		method: 'POST',
		json: true,
		formData: {
			url: config.hookUrl + config.token
		},
		url: _baseurl + 'setWebhook'
	});
}else api.setWebhook(config.hookUrl + config.token, options.crt);
<|endoftext|>


<commit_before>"use strict";

var util = require('util');
var stream = require('stream');
var EventEmitter = require('events');
var uwrap = require('bindings')('uwrap');
var debug = require('debug')("usocket");

//-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----
//--

exports.USocket = USocket;
function USocket(opts, cb) {
	if (!opts || typeof opts !== 'object')
		opts = { path: opts };

	var duplexOpts = { writableObjectMode: true };
	if ("allowHalfOpen" in opts)
		duplexOpts = opts.allowHalfOpen;
	stream.Duplex.call(this, duplexOpts);

	debug("new USocket", opts);
	if (opts.fd || opts.path)
		this.connect(opts, cb);
}

util.inherits(USocket, stream.Duplex);

USocket.prototype._read = function(size) {
	debug("USocket._read", size);
	if (this._wrap)
		this._wrap.resume();
};

USocket.prototype._write = function(chunk, encoding, callback) {
	if (!this._wrap)
		return callback(new Error("USocket not connected"));

	var data, fds, cb;
	if (Buffer.isBuffer(chunk)) {
		data = chunk;
	}
	else if (Array.isArray(chunk)) {
		fds = chunk;
	}
	else {
		cb = chunk.callback;
		data = chunk.data;
		fds = chunk.fds;
	}

	if (data && !Buffer.isBuffer(data))
		return callback(new Error("USocket data needs to be a buffer"));
	if (fds && !Array.isArray(fds))
		return callback(new Error("USocket fds needs to be an array"));
	if (cb && typeof cb !== 'function')
		return callback(new Error("USocket write callback needs to be a function"));
	if (!data && !fds)
		return callback(new Error("USocket write needs a data or array"));

	debug("USocket._write", data && data.length, fds);
	var r = this._wrap.write(data, fds);
	if (util.isError(r)) {
		debug("USocket._write error", r);
		return callback(r);
	}
	else if (r) {
		if (cb) cb(chunk);
		return callback();
	}

	debug("USocket._write wating");
	this._wrap.drain = this._write.bind(this, chunk, encoding, callback);
};

USocket.prototype.connect = function(opts, cb) {
	if (this._wrap)
		throw new Error("connect on already connected USocket");

	if (typeof opts === 'string') {
		opts = { path: opts };
	}

	if (typeof cb === 'function')
		this.once('connected', cb);

	debug("USocket connect", opts);

	this._wrap = new uwrap.USocketWrap(this._wrapEvent.bind(this));
	this._wrap.shutdownCalled = false;
	this._wrap.endReceived = false;
	this._wrap.drain = null;
	this._wrap.fds = [];

	if (typeof opts.fd === 'number') {
		this._wrap.adopt(opts.fd);
		this.fd = opts.fd;
		return;
	}

	if (typeof opts.path !== 'string')
		throw new Error("USocket#connect expects string path");
	this._wrap.connect(opts.path);
};

USocket.prototype._wrapEvent = function(event, a0, a1) {
	if (event === "connect") {
		this.fd = a0;
		debug("USocket connected on " + this.fd);
		this.emit('connected');
	}

	if (event === "error") {
		debug("USocket error", a0);
		this._wrap.close();
		this._wrap = null;
		this.emit("error", a0);
		this.emit('close', a0);
	}

	if (event === "data") {
		if (a1 && a1.length > 0) {
			debug("USocket received file descriptors", a1);
			this._wrap.fds = this._wrap.fds.concat(a1);
			this.emit('fds', a1);
		}

		if (a0) {
			if (!this.push(a0))
				this._wrap.pause();
		}

		if (a1 && !a0) {
			this.emit('readable');
		}

		if (!a0 && !a1 && !this._wrap.endReceived) {
			debug("USocket end of stream received");
			this._wrap.endReceived = true;
			this._wrap.pause();
			this.push(null);
			this.maybeClose();
		}
	}

	if (event === "drain") {
		var d = this._wrap.drain;
		this._wrap.drain = null;
		if (d) d();
	}
};

USocket.prototype.read = function(size, fdSize) {
	if (!this._wrap) return null;

	if (typeof fdSize === 'undefined')
		return stream.Duplex.prototype.read.apply(this, arguments);

	if (fdSize === null)
		fdSize = this._wrap.fds.length;
	else if (this._wrap.fds.length < fdSize)
		return null;

	var data = stream.Duplex.prototype.read.call(this, size);
	if (size && !data) return data;

	var fds = this._wrap.fds.splice(0, fdSize);
	return { data: data, fds: fds };
};

USocket.prototype.end = function(data, encoding, callback) {
	stream.Duplex.prototype.end.call(this, data, encoding, callback);
	if (this._wrap) {
		debug("USocket shutdown");
		this._wrap.shutdownCalled = true;
		this._wrap.shutdown();
		this.read(0);
		this.maybeClose();
	}
};

USocket.prototype.destroy = function() {
	if (!this._wrap)
		return;
	this._wrap.close();
	this._wrap = null;
};

USocket.prototype.maybeClose = function() {
	if (!this._wrap || !this._wrap.shutdownCalled || !this._wrap.endReceived)
		return;
	debug("USocket closing socket at end");
	this.destroy();
	this.emit('close');
};

//-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----
//--

exports.UServer = UServer;
function UServer() {
	this.paused = false;
	this.listening = false;
	EventEmitter.call(this);
}

util.inherits(UServer, EventEmitter);

UServer.prototype.listen = function(path, backlog, cb) {
	if (this._wrap || this.listening)
		throw new Error("listen on already listened UServer");

	if (typeof path === 'object') {
		backlog = path.backlog;
		path = path.path;
		cb = backlog;
	}
	else if (typeof backlog === 'function') {
		cb = backlog;
		backlog = 0;
	}

	backlog = backlog || 16;

	if (typeof path !== 'string')
		throw new Error("UServer expects valid path");

	if (typeof backlog !== 'number')
		throw new Error("UServer expects valid path");

	if (typeof cb === 'function')
		this.once('listening', cb);

	debug("creating UServerWrap");
	this._wrap = new uwrap.UServerWrap(this._wrapEvent.bind(this));
	debug("start UServerWrap#listen");
	this._wrap.listen(path, backlog);
};

UServer.prototype.pause = function() {
	this.paused = true;
	if (this.listening && this._wrap)
		this._wrap.pause();
};

UServer.prototype.resume = function() {
	this.paused = false;
	if (this.listening && this._wrap)
		this._wrap.resume();
};

UServer.prototype.close = function() {
	if (!this._wrap)
		return;
	this._wrap.close();
	this._wrap = undefined;
};

UServer.prototype._wrapEvent = function(event, a0, a1) {
	if (event === "listening") {
		this.fd = a0;
		debug("UServer listening on " + this.fd);
		this.emit('listening');
		this.listening = true;
		if (!this.paused)
			this._wrap.resume();
	}

	if (event === "error") {
		debug("UServer error", a0);
		this._wrap.close();
		this._wrap = null;
		this.emit("error", a0);
	}

	if (event === "accept") {
		debug("UServer accepted socket " + a0);
		var n = new USocket({ fd: a0 });
		this.emit('connection', n);
	}
};
<commit_msg>handle writes of strings with encodings<commit_after>"use strict";

var util = require('util');
var stream = require('stream');
var EventEmitter = require('events');
var uwrap = require('bindings')('uwrap');
var debug = require('debug')("usocket");

//-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----
//--

exports.USocket = USocket;
function USocket(opts, cb) {
	if (!opts || typeof opts !== 'object')
		opts = { path: opts };

	var duplexOpts = { writableObjectMode: true };
	if ("allowHalfOpen" in opts)
		duplexOpts = opts.allowHalfOpen;
	stream.Duplex.call(this, duplexOpts);

	debug("new USocket", opts);
	if (opts.fd || opts.path)
		this.connect(opts, cb);
}

util.inherits(USocket, stream.Duplex);

USocket.prototype._read = function(size) {
	debug("USocket._read", size);
	if (this._wrap)
		this._wrap.resume();
};

USocket.prototype._write = function(chunk, encoding, callback) {
	if (!this._wrap)
		return callback(new Error("USocket not connected"));

	var data, fds, cb;
	if (Buffer.isBuffer(chunk)) {
		data = chunk;
	}
	else if (Array.isArray(chunk)) {
		fds = chunk;
	}
	else {
		cb = chunk.callback;
		data = chunk.data;
		fds = chunk.fds;
	}

	if (data && !Buffer.isBuffer(data))
		return callback(new Error("USocket data needs to be a buffer"));
	if (fds && !Array.isArray(fds))
		return callback(new Error("USocket fds needs to be an array"));
	if (cb && typeof cb !== 'function')
		return callback(new Error("USocket write callback needs to be a function"));
	if (!data && !fds)
		return callback(new Error("USocket write needs a data or array"));

	debug("USocket._write", data && data.length, fds);
	var r = this._wrap.write(data, fds);
	if (util.isError(r)) {
		debug("USocket._write error", r);
		return callback(r);
	}
	else if (r) {
		if (cb) cb(chunk);
		return callback();
	}

	debug("USocket._write wating");
	this._wrap.drain = this._write.bind(this, chunk, encoding, callback);
};

USocket.prototype.connect = function(opts, cb) {
	if (this._wrap)
		throw new Error("connect on already connected USocket");

	if (typeof opts === 'string') {
		opts = { path: opts };
	}

	if (typeof cb === 'function')
		this.once('connected', cb);

	debug("USocket connect", opts);

	this._wrap = new uwrap.USocketWrap(this._wrapEvent.bind(this));
	this._wrap.shutdownCalled = false;
	this._wrap.endReceived = false;
	this._wrap.drain = null;
	this._wrap.fds = [];

	if (typeof opts.fd === 'number') {
		this._wrap.adopt(opts.fd);
		this.fd = opts.fd;
		return;
	}

	if (typeof opts.path !== 'string')
		throw new Error("USocket#connect expects string path");
	this._wrap.connect(opts.path);
};

USocket.prototype._wrapEvent = function(event, a0, a1) {
	if (event === "connect") {
		this.fd = a0;
		debug("USocket connected on " + this.fd);
		this.emit('connected');
	}

	if (event === "error") {
		debug("USocket error", a0);
		this._wrap.close();
		this._wrap = null;
		this.emit("error", a0);
		this.emit('close', a0);
	}

	if (event === "data") {
		if (a1 && a1.length > 0) {
			debug("USocket received file descriptors", a1);
			this._wrap.fds = this._wrap.fds.concat(a1);
			this.emit('fds', a1);
		}

		if (a0) {
			if (!this.push(a0))
				this._wrap.pause();
		}

		if (a1 && !a0) {
			this.emit('readable');
		}

		if (!a0 && !a1 && !this._wrap.endReceived) {
			debug("USocket end of stream received");
			this._wrap.endReceived = true;
			this._wrap.pause();
			this.push(null);
			this.maybeClose();
		}
	}

	if (event === "drain") {
		var d = this._wrap.drain;
		this._wrap.drain = null;
		if (d) d();
	}
};

USocket.prototype.read = function(size, fdSize) {
	if (!this._wrap) return null;

	if (typeof fdSize === 'undefined')
		return stream.Duplex.prototype.read.apply(this, arguments);

	if (fdSize === null)
		fdSize = this._wrap.fds.length;
	else if (this._wrap.fds.length < fdSize)
		return null;

	var data = stream.Duplex.prototype.read.call(this, size);
	if (size && !data) return data;

	var fds = this._wrap.fds.splice(0, fdSize);
	return { data: data, fds: fds };
};

USocket.prototype.write = function(chunk, encoding, callback) {
	if (typeof encoding === 'function') {
		callback = encoding;
		encoding = null;
	}

	if (typeof chunk === 'string') {
		chunk = new Buffer(chunk);
	}

	if (Buffer.isBuffer(chunk)) {
		chunk = { data: chunk };
	}

	stream.Duplex.prototype.write.call(this, chunk, null, callback);
};

USocket.prototype.end = function(data, encoding, callback) {
	stream.Duplex.prototype.end.call(this, data, encoding, callback);
	if (this._wrap) {
		debug("USocket shutdown");
		this._wrap.shutdownCalled = true;
		this._wrap.shutdown();
		this.read(0);
		this.maybeClose();
	}
};

USocket.prototype.destroy = function() {
	if (!this._wrap)
		return;
	this._wrap.close();
	this._wrap = null;
};

USocket.prototype.maybeClose = function() {
	if (!this._wrap || !this._wrap.shutdownCalled || !this._wrap.endReceived)
		return;
	debug("USocket closing socket at end");
	this.destroy();
	this.emit('close');
};

//-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----
//--

exports.UServer = UServer;
function UServer() {
	this.paused = false;
	this.listening = false;
	EventEmitter.call(this);
}

util.inherits(UServer, EventEmitter);

UServer.prototype.listen = function(path, backlog, cb) {
	if (this._wrap || this.listening)
		throw new Error("listen on already listened UServer");

	if (typeof path === 'object') {
		backlog = path.backlog;
		path = path.path;
		cb = backlog;
	}
	else if (typeof backlog === 'function') {
		cb = backlog;
		backlog = 0;
	}

	backlog = backlog || 16;

	if (typeof path !== 'string')
		throw new Error("UServer expects valid path");

	if (typeof backlog !== 'number')
		throw new Error("UServer expects valid path");

	if (typeof cb === 'function')
		this.once('listening', cb);

	debug("creating UServerWrap");
	this._wrap = new uwrap.UServerWrap(this._wrapEvent.bind(this));
	debug("start UServerWrap#listen");
	this._wrap.listen(path, backlog);
};

UServer.prototype.pause = function() {
	this.paused = true;
	if (this.listening && this._wrap)
		this._wrap.pause();
};

UServer.prototype.resume = function() {
	this.paused = false;
	if (this.listening && this._wrap)
		this._wrap.resume();
};

UServer.prototype.close = function() {
	if (!this._wrap)
		return;
	this._wrap.close();
	this._wrap = undefined;
};

UServer.prototype._wrapEvent = function(event, a0, a1) {
	if (event === "listening") {
		this.fd = a0;
		debug("UServer listening on " + this.fd);
		this.emit('listening');
		this.listening = true;
		if (!this.paused)
			this._wrap.resume();
	}

	if (event === "error") {
		debug("UServer error", a0);
		this._wrap.close();
		this._wrap = null;
		this.emit("error", a0);
	}

	if (event === "accept") {
		debug("UServer accepted socket " + a0);
		var n = new USocket({ fd: a0 });
		this.emit('connection', n);
	}
};
<|endoftext|>


<commit_before>var _ = require('lodash');
var postcss = require('postcss');

// Properties
var mapProperties = {
    'background-color': 'hintergrund-farbe',
    'background-image': 'hintergrund-bild',
    'background-position': 'hintergrund-position',
    'background-repeat': 'hintergrund-wiederholung',
    'background': 'hintergrund',
    'border-bottom-color': 'rahmen-unten-farbe',
    'border-bottom-style': 'rahmen-unten-stil',
    'border-bottom-width': 'rahmen-unten-breite',
    'border-bottom': 'rahmen-unten',
    'border-collapse': 'rahmen-kollaps',
    'border-color': 'rahmen-farbe',
    'border-left-color': 'rahmen-links-farbe',
    'border-left-style': 'rahmen-links-stil',
    'border-left-width': 'rahmen-links-breite',
    'border-left': 'rahmen-links',
    'border-right-color': 'rahmen-rechts-farbe',
    'border-right-style': 'rahmen-rechts-stil',
    'border-right-width': 'rahmen-rechts-breite',
    'border-right': 'rahmen-rechts',
    'border-spacing': 'rahmen-abstand',
    'border-style': 'rahmen-stil',
    'border-top-color': 'rahmen-oben-farbe',
    'border-top-style': 'rahmen-oben-stil',
    'border-top-width': 'rahmen-oben-breite',
    'border-top': 'rahmen-oben',
    'border-width': 'rahmen-breite',
    'border': 'rahmen',
    'bottom': 'unten',
    'color': 'farbe',
    'content': 'inhalt',
    'cursor': 'zeiger',
    'display': 'anzeige',
    'float': 'umlaufen',
    'font-family': 'schrift-familie',
    'font-size': 'schrift-größe',
    'font-style': 'schrift-stil',
    'font-variant': 'schrift-variante',
    'font-weight': 'schrift-gewicht',
    'font': 'schrift',
    'line-height': 'zeilen-höhe',
    'height': 'höhe',
    'left': 'links',
    'letter-spacing': 'zeichen-abstand',
    'list-style': 'listen-stil',
    'margin-bottom': 'außenabstand-unten',
    'margin-left': 'außenabstand-links',
    'margin-right': 'außenabstand-rechts',
    'margin-top': 'außenabstand-oben',
    'margin': 'außenabstand',
    'max-height': 'max-höhe',
    'max-width': 'max-breite',
    'min-height': 'min-höhe',
    'min-width': 'min-breite',
    'outline-color': 'kontur-farbe',
    'outline-style': 'kontur-stil',
    'outline-width': 'kontur-breite',
    'outline': 'kontur',
    'overflow': 'überlauf',
    'overflow-x': 'überlauf-x',
    'overflow-y': 'überlauf-y',
    'padding-bottom': 'innenabstand-unten',
    'padding-left': 'innenabstand-left',
    'padding-right': 'innenabstand-rechts',
    'padding-top': 'innenabstand-oben',
    'padding': 'innenabstand',
    'position': 'position',
    'right': 'rechts',
    'text-shadow': 'text-schatten',
    'transition': 'übergang',
    'vertical-align': 'vertikale-ausrichtung',
    'visibility': 'sichtbarkeit',
    'white-space': 'weißraum',
    'width': 'breite',
    'word-spacing': 'wort-abstand',
    'z-index': 'ebene'
};

// Values
var mapValues = {
    'absolute': 'absolut',
    'auto': 'automatisch',
    'bold': 'dick',
    'fixed': 'fixiert',
    'hidden': 'versteckt',
    'inherit': 'erben',
    'initial': 'initial',
    'italic': 'kursiv',
    'left': 'links',
    'no-repeat': 'nicht-wiederholen',
    'none': 'keines',
    'relative': 'relativ',
    'repeat-x': 'wiederholen-x',
    'repeat-y': 'wiederholen-y',
    'repeat': 'wiederholen',
    'right': 'rechts',
    'solid': 'durchgezogen',
    'static': 'statisch',
    'unset': 'aufheben',
    // Colors
    'black': 'schwarz',
    'blue': 'blau',
    'cyan': 'cyan',
    'gray': 'grau',
    'green': 'grün',
    'orange': 'orange',
    'red': 'rot',
    'white': 'weiß',
    'yellow': 'gelb'
};

module.exports = postcss.plugin('postcss-german-stylesheets', function (opts) {
    opts = opts || {};

    return function (css) {
        css.walkDecls(function transformDecl(decl) {
            // Properties
            _.forEach(mapProperties, function (value, key) {
                decl.prop = decl.prop.replace(value, key);
            });

            // Values
            _.forEach(mapValues, function (value, key) {
                decl.value = decl.value.replace(value, key);
            });

            // Important
            if (decl.value.indexOf('!wichtig') >= 0) {
                decl.value = decl.value.replace(/\s*!wichtig\s*/, '');
                decl.important = true;
            }
        });
    };
});

// Export Properties and Values for testing
module.exports.mapProperties = mapProperties;
module.exports.mapValues = mapValues;
<commit_msg>added new colors<commit_after>var _ = require('lodash');
var postcss = require('postcss');

// Properties
var mapProperties = {
    'background-color': 'hintergrund-farbe',
    'background-image': 'hintergrund-bild',
    'background-position': 'hintergrund-position',
    'background-repeat': 'hintergrund-wiederholung',
    'background': 'hintergrund',
    'border-bottom-color': 'rahmen-unten-farbe',
    'border-bottom-style': 'rahmen-unten-stil',
    'border-bottom-width': 'rahmen-unten-breite',
    'border-bottom': 'rahmen-unten',
    'border-collapse': 'rahmen-kollaps',
    'border-color': 'rahmen-farbe',
    'border-left-color': 'rahmen-links-farbe',
    'border-left-style': 'rahmen-links-stil',
    'border-left-width': 'rahmen-links-breite',
    'border-left': 'rahmen-links',
    'border-right-color': 'rahmen-rechts-farbe',
    'border-right-style': 'rahmen-rechts-stil',
    'border-right-width': 'rahmen-rechts-breite',
    'border-right': 'rahmen-rechts',
    'border-spacing': 'rahmen-abstand',
    'border-style': 'rahmen-stil',
    'border-top-color': 'rahmen-oben-farbe',
    'border-top-style': 'rahmen-oben-stil',
    'border-top-width': 'rahmen-oben-breite',
    'border-top': 'rahmen-oben',
    'border-width': 'rahmen-breite',
    'border': 'rahmen',
    'bottom': 'unten',
    'color': 'farbe',
    'content': 'inhalt',
    'cursor': 'zeiger',
    'display': 'anzeige',
    'float': 'umlaufen',
    'font-family': 'schrift-familie',
    'font-size': 'schrift-größe',
    'font-style': 'schrift-stil',
    'font-variant': 'schrift-variante',
    'font-weight': 'schrift-gewicht',
    'font': 'schrift',
    'line-height': 'zeilen-höhe',
    'height': 'höhe',
    'left': 'links',
    'letter-spacing': 'zeichen-abstand',
    'list-style': 'listen-stil',
    'margin-bottom': 'außenabstand-unten',
    'margin-left': 'außenabstand-links',
    'margin-right': 'außenabstand-rechts',
    'margin-top': 'außenabstand-oben',
    'margin': 'außenabstand',
    'max-height': 'max-höhe',
    'max-width': 'max-breite',
    'min-height': 'min-höhe',
    'min-width': 'min-breite',
    'outline-color': 'kontur-farbe',
    'outline-style': 'kontur-stil',
    'outline-width': 'kontur-breite',
    'outline': 'kontur',
    'overflow': 'überlauf',
    'overflow-x': 'überlauf-x',
    'overflow-y': 'überlauf-y',
    'padding-bottom': 'innenabstand-unten',
    'padding-left': 'innenabstand-left',
    'padding-right': 'innenabstand-rechts',
    'padding-top': 'innenabstand-oben',
    'padding': 'innenabstand',
    'position': 'position',
    'right': 'rechts',
    'text-shadow': 'text-schatten',
    'transition': 'übergang',
    'vertical-align': 'vertikale-ausrichtung',
    'visibility': 'sichtbarkeit',
    'white-space': 'weißraum',
    'width': 'breite',
    'word-spacing': 'wort-abstand',
    'z-index': 'ebene'
};

// Values
var mapValues = {
    'absolute': 'absolut',
    'auto': 'automatisch',
    'bold': 'dick',
    'fixed': 'fixiert',
    'hidden': 'versteckt',
    'inherit': 'erben',
    'initial': 'initial',
    'italic': 'kursiv',
    'left': 'links',
    'no-repeat': 'nicht-wiederholen',
    'none': 'keines',
    'relative': 'relativ',
    'repeat-x': 'wiederholen-x',
    'repeat-y': 'wiederholen-y',
    'repeat': 'wiederholen',
    'right': 'rechts',
    'solid': 'durchgezogen',
    'static': 'statisch',
    'unset': 'aufheben',
    // Colors
    'black': 'schwarz',
    'blue': 'blau',
    'cyan': 'cyan',
    'gray': 'grau',
    'green': 'grün',
    'orange': 'orange',
    'red': 'rot',
    'white': 'weiß',
    'yellow': 'gelb',
    'aliceblue': 'eisfarben',
    'antiquewhite': 'antikweiß',
    'aqua': 'wasser',
    'aquamarine': 'aquamarinblau',
    'azure': 'himmelblau',
    'beige': 'beige',
    'bisque': 'biskuit',
    'blanchedalmond': 'mandelweiß',
    'blueviolet': 'blauviolett',
    'burlywood': 'geldbraun',
    'cadetblue': 'kadettenblau',
    'chartreuse': 'hellgrün',
    'chocolate': 'schokolade',
    'coral': 'koralle',
    'cornflowerblue': 'kornblumenblau',
    'cornsilk': 'mais',
    'crimson': 'karmesinrot',
    'cyan': 'türkis',
    'darkblue': 'dunkelblau',
    'darkcyan': 'dunkeltürkis',
    'darkgoldenrod': 'dunklegoldrunenfarbe',
    'darkgreen': 'dunkelgrün',
    'darkgray': 'dunkelgrau',
    'darkkhaki': 'dunkelkhaki',
    'darkmagenta': 'dunkelmagenta',
    'darkolivegreen': 'dunkelgrünoliv',
    'darkorange': 'dunkelorange',
    'darkorchid': 'dunkleorchidee',
    'darkred': 'dunkelrot',
    'darksalmon': 'dunklelachsfarbe',
    'darkseagreen': 'dunkleseegrün',
    'darkslateblue': 'dunkleschieferblau',
    'darkviolet': 'dunkelviolett',
    'deeppink': 'tiefrosa',
    'deepskyblue': 'tiefeshimmelblau',
    'dimgrey': 'gedimmtesgrau',
    'dodgerblue': 'persinningblau',
    'firebrick': 'backstein',
    'floralwhite': 'blütenweiß',
    'forestgreen': 'waldgrün',
    'ghostwhite': 'geisterweiß',
    'greenyellow': 'grüngelb',
    'honeydew': 'honigmelone',
    'hotpink': 'leuchtendrosa',
    'indianred': 'indischrot',
    'ivory': 'elfenbein',
    'khaki': 'staubfarbend',
    'lavender': 'lavendel',
    'lavenderblush': 'lavendelrosa',
    'lawngreen': 'grasgrün',
    'lemonchiffon': 'chiffongelb',
    'lightblue': 'hellblau',
    'lightcoral': 'helleskorallenrot',
    'lightcyan': 'helltürkis',
    'lightgray': 'hellgrau',
    'lightgreen': 'hellgrün',
    'lightpink': 'hellrosa',
    'lightsalmon': 'hellelachsfarbe',
    'lightseagreen': 'hellesseegrün',
    'lightskyblue': 'helleshimmelblau',
    'lightslategray': 'hellesschiefergrau',
    'lightsteelblue': 'hellesstahlblau',
    'lightyellow': 'hellgelb',
    'lime': 'limone',
    'limegreen': 'limonengrün',
    'linen': 'leinen',
    'maroon': 'kastanie',
    'midnightblue': 'mitternachtsblau',
    'mintcream': 'cremigeminze',
    'mistyrose': 'altrosa',
    'moccasin': 'mokassin',
    'navajowhite': 'navajoweiß',
    'navy': 'marineblau',
    'oldlace': 'altespitze',
    'olive': 'olivgrün',
    'olivedrab': 'olivgrünbraun',
    'orangered': 'orangerot',
    'orchid': 'orchidee',
    'palegoldenrod': 'blassegoldrunenfarbe',
    'palegreen': 'blassgrün',
    'paleturquoise': 'blasstürkis',
    'papayawhip': 'papayacreme',
    'peachpuff': 'pfirsich',
    'pink': 'rosa',
    'plum': 'pflaume',
    'powderblue': 'taubenblau',
    'purple': 'violett',
    'rosybrown': 'rosigesbraun',
    'royalblue': 'royalblau',
    'saddlebrown': 'sattelbraun',
    'salmon': 'lachsfarben',
    'sandybrown': 'sandbraun',
    'seagreen': 'seegrün',
    'seashell': 'muschel',
    'sienna': 'siennaerde',
    'silver': 'silber',
    'skyblue': 'himmelblau',
    'slateblue': 'schieferblau',
    'slategray': 'schiefergrau',
    'snow': 'schneeweiß',
    'springgreen': 'frühlingsgrün',
    'steelblue': 'stahlblau',
    'tan': 'hautfarben',
    'teal': 'krickentengrün',
    'thistle': 'distel',
    'tomato': 'tomate',
    'turquoise': 'türkis',
    'violet': 'veilchen',
    'wheat': 'weizen',
    'whitesmoke': 'rauchfarben',
    'yellowgreen': 'gelbgrün'
};

module.exports = postcss.plugin('postcss-german-stylesheets', function (opts) {
    opts = opts || {};

    return function (css) {
        css.walkDecls(function transformDecl(decl) {
            // Properties
            _.forEach(mapProperties, function (value, key) {
                decl.prop = decl.prop.replace(value, key);
            });

            // Values
            _.forEach(mapValues, function (value, key) {
                decl.value = decl.value.replace(value, key);
            });

            // Important
            if (decl.value.indexOf('!wichtig') >= 0) {
                decl.value = decl.value.replace(/\s*!wichtig\s*/, '');
                decl.important = true;
            }
        });
    };
});

// Export Properties and Values for testing
module.exports.mapProperties = mapProperties;
module.exports.mapValues = mapValues;
<|endoftext|>