<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/*
 * This file implements the /api/csv route. This route accepts csv data for
 * meter and readings data.
 *
 */

const escapeHtml = require('core-js/fn/string/escape-html');
const express = require('express');
const fs = require('fs').promises;
const { getConnection } = require('../db');
const loadCsvInput = require('../services/pipeline-in-progress/loadCsvInput');
const { log } = require('../log');
const Meter = require('../models/Meter');
const multer = require('multer');
const streamBuffers = require('stream-buffers');
const zlib = require('zlib');

// The upload here ensures that the file is saved to server RAM rather than disk; TODO: Think about large uploads
const upload = multer({ storage: multer.memoryStorage() });
const router = express.Router();

/**
 * Inform the client of a failure (406 Not Acceptable), and log it.
 *
 * @param {express.Request} req The Express request object
 * @param {express.Response} res The Express response object
 * @param {string} reason The reason for the failure.
 *
 */
function failure(req, res, reason = '') {
	const ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
	log.error(`Csv protocol request from ${ip} failed due to ${reason}`);

	res.status(400)
		.send(`<pre>\n${escapeHtml(reason)}\n</pre>\n`);
}

/**
 * Inform the client of a success (200 OK).
 *
 * @param {express.Request} req The Express request object
 * @param {express.Response} res The Express response object
 * @param {string} comment Any additional data to be returned to the client.
 *
 */
function success(req, res, comment = '') {
	res.status(200) // 200 OK
		.send(`<pre>\nSUCCESS\n${escapeHtml(comment)}</pre>\n`);
}

function streamToWriteBuffer(stream) {
	const writableStreamBuffer = new streamBuffers.WritableStreamBuffer({
		frequency: 10,
		chunkSize: 2048
	});
	writableStreamBuffer.write(stream);
	return writableStreamBuffer;
}

router.get('/', (req, res) => {
	success(req, res, "Lookie here you accessed the route file");
});

router.post('/', upload.single('csvfile'), async (req, res) => {
	// we need to sanitize req query params, res

	// We do readings for meters first then meter data later
	// since the pipeline only supports readings atm.

	const { createmeter: createMeter, cumulative, cumulativereset: cumulativeReset, duplications, length, meter: meterName,
		mode, password, timesort: timeSort, update } = req.body; // extract query parameters

	if (!req.file) {
		failure(req, res, 'No file uploaded.');
		return;
	}// TODO: Validate file upload

	switch (mode) {
		case 'readings':
			// Invalidate unimplemented time sort.
			if (timeSort !== 'increasing') {
				failure(req, res, `Time sort '${timeSort}' is invalid. Only 'increasing' is currently implemented.`);
				return;
			}

			// create buffer to save into file; will need to gunzip file
			const myWritableStreamBuffer = streamToWriteBuffer(req.file.buffer);
			// save this buffer into a file
			const randomFileName = `${meterName}-willBeRandom`; // TODO: use a unique name and use that name in the new meter creation
			const filePath = `./${randomFileName}.csv`;
			await fs.writeFile(filePath, myWritableStreamBuffer.getContents())
				.then(() => log.info(`The file ${filePath} was created to upload csv data`))
				.catch(reason => log.error(`Failed to write the file: ${filePath}`, reason));

			const conn = getConnection();

			let meter;
			await Meter.getByName(meterName, conn)
				.then(row => meter = row) // retrieve meter by name
				.catch(async err => {
					meter = new Meter(undefined, meterName, undefined, false, false, Meter.type.MAMAC, meterName);
					log.warn(`Creating the meter ${meterName} for readings since it did not exist.`);
					await meter.insert(conn); // does not seem to actually return a promise
				}) // if no meter is found an error is thrown and we create the meter and log it. TODO: there may be other reasons for error; QueryResultError may be a type to switch on

			const mapRowToModel = (row) => { return row; }; // stub func to satisfy param
			await loadCsvInput(filePath, meter.id, mapRowToModel, false, cumulative, cumulativeReset, duplications, undefined, conn); // load csv data
			// Problem here is that we will not know if csv was loaded successfully.
			success(req, res, `It looks like success.`); // TODO: need try catch for all these awaits
			return;
		case 'meter':
			failure(req, res, `Mode meter has not been implemented`);
			return;
		default:
			failure(req, res, `Mode ${mode} is invalid. Mode can either be 'readings' or 'meter'.`)
			return;
	}
});

module.exports = router;
<commit_msg>Remove file generated<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/*
 * This file implements the /api/csv route. This route accepts csv data for
 * meter and readings data.
 *
 */

const escapeHtml = require('core-js/fn/string/escape-html');
const express = require('express');
const fs = require('fs').promises;
const { getConnection } = require('../db');
const loadCsvInput = require('../services/pipeline-in-progress/loadCsvInput');
const { log } = require('../log');
const Meter = require('../models/Meter');
const multer = require('multer');
const streamBuffers = require('stream-buffers');
const zlib = require('zlib');

// The upload here ensures that the file is saved to server RAM rather than disk; TODO: Think about large uploads
const upload = multer({ storage: multer.memoryStorage() });
const router = express.Router();

/**
 * Inform the client of a failure (406 Not Acceptable), and log it.
 *
 * @param {express.Request} req The Express request object
 * @param {express.Response} res The Express response object
 * @param {string} reason The reason for the failure.
 *
 */
function failure(req, res, reason = '') {
	const ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
	log.error(`Csv protocol request from ${ip} failed due to ${reason}`);

	res.status(400)
		.send(`<pre>\n${escapeHtml(reason)}\n</pre>\n`);
}

/**
 * Inform the client of a success (200 OK).
 *
 * @param {express.Request} req The Express request object
 * @param {express.Response} res The Express response object
 * @param {string} comment Any additional data to be returned to the client.
 *
 */
function success(req, res, comment = '') {
	res.status(200) // 200 OK
		.send(`<pre>\nSUCCESS\n${escapeHtml(comment)}</pre>\n`);
}

function streamToWriteBuffer(stream) {
	const writableStreamBuffer = new streamBuffers.WritableStreamBuffer({
		frequency: 10,
		chunkSize: 2048
	});
	writableStreamBuffer.write(stream);
	return writableStreamBuffer;
}

router.get('/', (req, res) => {
	success(req, res, "Lookie here you accessed the route file");
});

router.post('/', upload.single('csvfile'), async (req, res) => {
	// we need to sanitize req query params, res

	// We do readings for meters first then meter data later
	// since the pipeline only supports readings atm.

	const { createmeter: createMeter, cumulative, cumulativereset: cumulativeReset, duplications, length, meter: meterName,
		mode, password, timesort: timeSort, update } = req.body; // extract query parameters

	if (!req.file) {
		failure(req, res, 'No file uploaded.');
		return;
	}// TODO: Validate file upload

	switch (mode) {
		case 'readings':
			// Invalidate unimplemented time sort.
			if (timeSort !== 'increasing') {
				failure(req, res, `Time sort '${timeSort}' is invalid. Only 'increasing' is currently implemented.`);
				return;
			}

			// create buffer to save into file; will need to gunzip file
			const myWritableStreamBuffer = streamToWriteBuffer(req.file.buffer);
			// save this buffer into a file
			const randomFileName = `${meterName}-willBeRandom`; // TODO: use a unique name and use that name in the new meter creation
			const filePath = `./${randomFileName}.csv`;
			await fs.writeFile(filePath, myWritableStreamBuffer.getContents())
				.then(() => log.info(`The file ${filePath} was created to upload csv data`))
				.catch(reason => log.error(`Failed to write the file: ${filePath}`, reason));

			const conn = getConnection();

			let meter;
			await Meter.getByName(meterName, conn)
				.then(row => meter = row) // retrieve meter by name
				.catch(async err => {
					meter = new Meter(undefined, meterName, undefined, false, false, Meter.type.MAMAC, meterName);
					log.warn(`Creating the meter ${meterName} for readings since it did not exist.`);
					await meter.insert(conn); // does not seem to actually return a promise
				}) // if no meter is found an error is thrown and we create the meter and log it. TODO: there may be other reasons for error; QueryResultError may be a type to switch on

			const mapRowToModel = (row) => { return row; }; // stub func to satisfy param
			await loadCsvInput(filePath, meter.id, mapRowToModel, false, cumulative, cumulativeReset, duplications, undefined, conn); // load csv data
			// Problem here is that we will not know if csv was loaded successfully.
			await fs.unlink(filePath); // TODO: do we really need this to complete before sending back a response and should this file be removed on an unsuccessful upload?
			success(req, res, `It looks like success.`); // TODO: need try catch for all these awaits
			return;
		case 'meter':
			failure(req, res, `Mode meter has not been implemented`);
			return;
		default:
			failure(req, res, `Mode ${mode} is invalid. Mode can either be 'readings' or 'meter'.`)
			return;
	}
});

module.exports = router;
<|endoftext|>


<commit_before>uv.util = {};

uv.util.extend = function (f) {
	function G() {}
	G.prototype = f.prototype || f;
	return new G();
};

uv.util.getUniqueId = function () {
	return new Date().getTime();
};

uv.util.getMaxValue = function (graphdef) {
	return d3.max(graphdef.categories.map(function (d) {
		return d3.max(graphdef.dataset[d].map(function (d) {
			return d.value;
		}));
	}));
};

uv.util.getStepMaxValue = function (graphdef) {
	var sumMap = graphdef.dataset[graphdef.categories[0]].map(function () {return 0; });
	graphdef.categories.map(function (d) {
		graphdef.dataset[d].map(function (d, i) {
			sumMap[i] += d.value;
		});
	});

	return d3.max(sumMap);
};

uv.util.getWaterfallMaxValue = function(graphdef) {
	var sumMap = graphdef.categories.map(function() {return 0;});
	graphdef.categories.map(function (d, i) {
		var localMax = 0;
		graphdef.dataset[d].map(function(d) {
			localMax += d.value;
			if(sumMap[i] < localMax) {
				sumMap[i] = localMax;
			}
		});
	});

	return d3.max(sumMap);
};

uv.util.getSumUpArray = function (graphdef) {
	var sumMap = graphdef.dataset[graphdef.categories[0]].map(function () {return 0; });
	graphdef.categories.map(function (d) {
		graphdef.dataset[d].map(function (d, i) {
			sumMap[i] += d.value;
		});
	});

	return sumMap;
};

uv.util.getPercentage = function (value, total) {
	return value * 100 / total;
};

uv.util.getDataArray = function (graphdef) {
	return graphdef.categories.map(function (d) { return graphdef.dataset[d]; });
};

uv.util.getTabularArray = function (graphdef) {
	var table = [], i, j, catlen, len, arr = [];
	for (i = 0, len = graphdef.dataset[graphdef.categories[0]].length; i < len; i = i + 1) {
		arr = [];
		arr.push(graphdef.dataset[graphdef.categories[0]][i].name);
		for (j = 0, catlen = graphdef.categories.length; j < catlen; j = j + 1) {
			arr.push(graphdef.dataset[graphdef.categories[j]][i].value);
		}
		table.push(arr);
	}
	return table;
};

uv.util.getLabelArray = function (graphdef) {
	return graphdef.dataset[graphdef.categories[0]].map(function (d) { return d.name; });
};

uv.util.getCategoryArray = function (graphdef) {
	return graphdef.categories.map(function (d) { return d; });
};

uv.util.getCategoryData = function (graphdef, categories) {
	return categories.map(function (d) {
		return graphdef.dataset[d].map(function (d) {
			return d.value;
		});
	});
};

uv.util.transposeData = function (graphdef) {
	var dataset = {}, i, j, length, jlength,
		name, label, value, categories = graphdef.dataset[graphdef.categories[0]].map(function (d) { return d.name; });

	for (i = 0, length = categories.length; i < length; i = i + 1) { dataset[categories[i]] = []; }

	for (i = 0, length = graphdef.categories.length; i < length; i = i + 1) {
		name = graphdef.categories[i];
		for (j = 0, jlength = graphdef.dataset[name].length; j < jlength; j = j + 1) {
			label = graphdef.dataset[name][j].name;
			value = graphdef.dataset[name][j].value;
			dataset[label].push({ 'name' : name, 'value' : value });
		}
	}

	graphdef.categories = categories;
	graphdef.dataset = dataset;
};

uv.util.getPascalCasedName = function (name) {
	return name.substring(0, 1).toUpperCase() + name.substring(1);
};

uv.util.getColorBand = function (config, index) {
	var len = uv.palette[config.graph.palette].length;
	return uv.palette[config.graph.palette][index % len];
};

/**
 * This function finds regular expressions other than Alphabets, Numbers,
 * "_" and "-" and replaces it with "_".
 * @param  {string} name The string which needs to be formatted
 * @return {string}      Returns the formatted String
 */
uv.util.formatClassName = function(name){
	var returnName = name.trim().replace(/[^A-Za-z0-9_\-]/g,"-");
	return returnName;
}

/**
 * This function waits till the end of the transition and then call the callback
 * function which is passed as an argument
 * @param  {transition}   transition It's the current transition
 * @param  {Function} callback   function which is called at the end of
 *                               transition
 */
uv.util.endAll = function (transition, callback){
	var n = 0;
    transition
        .each(function() { ++n; })
        .each("end", function() {
        	if (!--n) {
        		callback.apply(this, arguments);
        	}
         });
}
<commit_msg>Added jsdocs for few functions, and aligned few<commit_after>uv.util = {};

/**
 * Utility method to extend prototype for JavaScript classes, to act like inheritance
 * @param  {Class} f Original class which is being extended
 * @return {Prototype}   Prototype containing the functions from the super class
 */
uv.util.extend = function (f) {
	function G() {}
	G.prototype = f.prototype || f;
	return new G();
};

/**
 * Utility method to return a unique identification id
 * @return {number} Timestamp in ms is returned as a unique id
 */
uv.util.getUniqueId = function () {
	return new Date().getTime();
};

/**
 *
 */
uv.util.getMaxValue = function (graphdef) {
	return d3.max(graphdef.categories.map(function (d) {
		return d3.max(graphdef.dataset[d].map(function (d) {
			return d.value;
		}));
	}));
};

uv.util.getStepMaxValue = function (graphdef) {
	var sumMap = graphdef.dataset[graphdef.categories[0]].map(function () {return 0; });
	graphdef.categories.map(function (d) {
		graphdef.dataset[d].map(function (d, i) {
			sumMap[i] += d.value;
		});
	});

	return d3.max(sumMap);
};

uv.util.getWaterfallMaxValue = function(graphdef) {
	var sumMap = graphdef.categories.map(function() {return 0;});
	graphdef.categories.map(function (d, i) {
		var localMax = 0;
		graphdef.dataset[d].map(function(d) {
			localMax += d.value;
			if(sumMap[i] < localMax) {
				sumMap[i] = localMax;
			}
		});
	});

	return d3.max(sumMap);
};

uv.util.getSumUpArray = function (graphdef) {
	var sumMap = graphdef.dataset[graphdef.categories[0]].map(function () {return 0; });
	graphdef.categories.map(function (d) {
		graphdef.dataset[d].map(function (d, i) {
			sumMap[i] += d.value;
		});
	});

	return sumMap;
};

uv.util.getPercentage = function (value, total) {
	return value * 100 / total;
};

uv.util.getDataArray = function (graphdef) {
	return graphdef.categories.map(function (d) { return graphdef.dataset[d]; });
};

uv.util.getTabularArray = function (graphdef) {
	var table = [], i, j, catlen, len, arr = [];
	for (i = 0, len = graphdef.dataset[graphdef.categories[0]].length; i < len; i = i + 1) {
		arr = [];
		arr.push(graphdef.dataset[graphdef.categories[0]][i].name);
		for (j = 0, catlen = graphdef.categories.length; j < catlen; j = j + 1) {
			arr.push(graphdef.dataset[graphdef.categories[j]][i].value);
		}
		table.push(arr);
	}
	return table;
};

uv.util.getLabelArray = function (graphdef) {
	return graphdef.dataset[graphdef.categories[0]].map(function (d) { return d.name; });
};

uv.util.getCategoryArray = function (graphdef) {
	return graphdef.categories.map(function (d) { return d; });
};

uv.util.getCategoryData = function (graphdef, categories) {
	return categories.map(function (d) {
		return graphdef.dataset[d].map(function (d) {
			return d.value;
		});
	});
};

uv.util.transposeData = function (graphdef) {
	var dataset = {}, i, j, length, jlength,
		name, label, value, categories = graphdef.dataset[graphdef.categories[0]].map(function (d) { return d.name; });

	for (i = 0, length = categories.length; i < length; i = i + 1) { dataset[categories[i]] = []; }

	for (i = 0, length = graphdef.categories.length; i < length; i = i + 1) {
		name = graphdef.categories[i];
		for (j = 0, jlength = graphdef.dataset[name].length; j < jlength; j = j + 1) {
			label = graphdef.dataset[name][j].name;
			value = graphdef.dataset[name][j].value;
			dataset[label].push({ 'name' : name, 'value' : value });
		}
	}

	graphdef.categories = categories;
	graphdef.dataset = dataset;
};

uv.util.getPascalCasedName = function (name) {
	return name.substring(0, 1).toUpperCase() + name.substring(1);
};

uv.util.getColorBand = function (config, index) {
	var len = uv.palette[config.graph.palette].length;
	return uv.palette[config.graph.palette][index % len];
};

/**
 * This function finds regular expressions other than Alphabets, Numbers,
 * "_" and "-" and replaces it with "_".
 * @param  {string} name The string which needs to be formatted
 * @return {string}      Returns the formatted String
 */
uv.util.formatClassName = function(name){
	var returnName = name.trim().replace(/[^A-Za-z0-9_\-]/g,"-");
	return returnName;
};

/**
 * This function waits till the end of the transition and then call the callback
 * function which is passed as an argument
 * @param  {transition}   transition It's the current transition
 * @param  {Function} callback   function which is called at the end of
 *                               transition
 */
uv.util.endAll = function (transition, callback){
	var n = 0;

  transition.each(function() { ++n; })
    .each("end", function() {
      if (!--n) {
        callback.apply(this, arguments);
       }
    });
};
<|endoftext|>


<commit_before>import express from 'express'
import path from 'path'
import passport from 'passport'
import configurePassport from 'server/routes/configurePassport'
import session from 'express-session'
import connectRedis from 'connect-redis'
import config from 'config'
import graphqlMiddleware from 'server/graphql/middleware'
import rendering from 'server/middlewares/rendering'

const router = new express.Router()
const RedisStore = connectRedis(session)

// Public directory
router.use(express.static(path.join(__dirname, '../../../server/public'), {
  etag: true,
  lastModified: false,
  setHeaders: (res) => {
    res.set('Cache-Control', 'no-cache')
  },
}))

// Static directory
router.use('/static', express.static(path.join(__dirname, '../../../server/static'), {
  etag: true,
  lastModified: false,
  maxAge: '1 year',
  index: false,
}))

// GraphQL
router.use('/graphql', graphqlMiddleware())

router.use(session({
  secret: config.get('server.sessionSecret'),
  store: new RedisStore({
    url: config.get('redis.url'),
  }),
  cookie: {
    secure: false, // To activate once we do HTTPS.
  },
  // Touch is supported by the Redis store.
  // No need to resave, we can avoid concurrency issues.
  resave: false,
  saveUninitialized: false,
}))
router.use(passport.initialize())
router.use(passport.session())

configurePassport(passport)

// GraphQL
router.use('/graphql', graphqlMiddleware())

router.get('/auth/github',
  passport.authenticate('github'),
  () => {
    // The request will be redirected to GitHub for authentication.
  },
)

router.get('/auth/github/callback',
  passport.authenticate('github', {
    failureRedirect: '/login',
  }),
  (req, res) => {
    // Successful authentication, redirect home.
    res.redirect('/')
  },
)

router.get('/auth/logout', (req, res) => {
  req.logout()
  res.redirect('/')
})

router.get('*', rendering)

export default router
<commit_msg>fix(review): disable github access until we handle permissions<commit_after>import express from 'express'
import path from 'path'
import passport from 'passport'
import configurePassport from 'server/routes/configurePassport'
import session from 'express-session'
import connectRedis from 'connect-redis'
import config from 'config'
import graphqlMiddleware from 'server/graphql/middleware'
import rendering from 'server/middlewares/rendering'

const router = new express.Router()
const RedisStore = connectRedis(session)

// Public directory
router.use(express.static(path.join(__dirname, '../../../server/public'), {
  etag: true,
  lastModified: false,
  setHeaders: (res) => {
    res.set('Cache-Control', 'no-cache')
  },
}))

// Static directory
router.use('/static', express.static(path.join(__dirname, '../../../server/static'), {
  etag: true,
  lastModified: false,
  maxAge: '1 year',
  index: false,
}))

// GraphQL
router.use('/graphql', graphqlMiddleware())

router.use(session({
  secret: config.get('server.sessionSecret'),
  store: new RedisStore({
    url: config.get('redis.url'),
  }),
  cookie: {
    secure: false, // To activate once we do HTTPS.
  },
  // Touch is supported by the Redis store.
  // No need to resave, we can avoid concurrency issues.
  resave: false,
  saveUninitialized: false,
}))
// router.use(passport.initialize())
// router.use(passport.session())

// configurePassport(passport)

// GraphQL
router.use('/graphql', graphqlMiddleware())

router.get('/auth/github',
  passport.authenticate('github'),
  () => {
    // The request will be redirected to GitHub for authentication.
  },
)

router.get('/auth/github/callback',
  passport.authenticate('github', {
    failureRedirect: '/login',
  }),
  (req, res) => {
    // Successful authentication, redirect home.
    res.redirect('/')
  },
)

router.get('/auth/logout', (req, res) => {
  req.logout()
  res.redirect('/')
})

router.get('*', rendering)

export default router
<|endoftext|>


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

var fs = require('fs');
var ini = require('ini');
var iconv = require('iconv-lite');
var sqlite3 = require('sqlite3');
var argv = require('yargs').argv;
var cheerio = require('cheerio'), $;

var config = ini.parse(fs.readFileSync('./config.ini', 'utf-8'));

if (argv.file) {
    // Getting file from fs if it exists
    if (fs.existsSync(argv.file)) {
        console.log('Reading "' + argv.file + '"');
        fs.readFile(argv.file, function(err, data) {
            if (err) throw err;
            parseOverclockersPage(data);
        });
    } else {
        console.log('File "' + argv.file + '" not found');
        process.exit(1);
    }
} else {
    // Otherwise downloading the whole db
    var http = require('http');
    console.log('Downloading from ' + config.url);
    callback = function(response) {
        var len = parseInt(response.headers['content-length'], 10);
        var bytesReceived = 0;
        var responseText = ''
        response.on('data', function (chunk) {
            bytesReceived += chunk.length;
            process.stdout.write("\r" + Math.round(bytesReceived / 1048576) + " Mb received");
            responseText += chunk;
        });
        response.on('end', function () {
            console.log();
            console.log('Download complete');
            parseOverclockersPage(responseText);
        });
    }
    var req = http.get(config.url, callback);
    req.end();
}

function initDb(db) {
    // Creating db and indexes
    var queryCreate = 'CREATE TABLE IF NOT EXISTS results (\
"author-name" VARCHAR(100), \
"author-mail" VARCHAR(100), \
"core" VARCHAR(100), \
"batch" VARCHAR(100), \
"reference-frequency" INT, \
"reference-fsb" INT, \
"oc-fsb" INT, \
"oc-multiplier" REAL, \
"screenshot-id" INT, \
"vcore" REAL, \
"date" INT, \
"motherboard" VARCHAR(100), \
"bios-version" VARCHAR(100), \
"cooler" VARCHAR(100), \
"max-temperature" REAL, \
"id" INT PRIMARY KEY, \
"comment" TEXT\
)';
    db.exec(queryCreate);
    db.exec('CREATE INDEX IF NOT EXISTS index_author_name ON results ("author-name")');
    db.exec('CREATE INDEX IF NOT EXISTS index_core ON results ("core")');
    db.exec('CREATE INDEX IF NOT EXISTS index_date ON results ("date")');
    db.exec('PRAGMA journal_mode=OFF');
}

function parseOverclockersPage(html) {
    console.log('Initializing db');
    var db = new sqlite3.Database(config.dbFile);
    initDb(db);

    console.log('Converting to utf-8');
    var utf8String = iconv.decode(html, 'win1251');

    console.log('Parsing');
    $ = cheerio.load(utf8String);

    console.log('Getting raw results');
    var resultNodes = $('#hypercontext').find('table');
    var resultCount = resultNodes.length;

    console.log('Filtering results');
    var realResultNodes = [];
    for (var i = 0; i < resultCount; i++) {
        if ($(resultNodes[i]).hasClass('tsmall')
            || $(resultNodes[i]).attr('cellpadding') == '2'
            || resultNodes[i].parentNode.tagName == 'b'
        ) {
            continue;
        }
        realResultNodes.push(resultNodes[i]);
    }

    var realResultCount = realResultNodes.length;
    var queryInsert = 'REPLACE INTO results VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)';
    var stmt = db.prepare(queryInsert);

    console.log('Walking ' + realResultCount + ' result tables and inserting');
    var time1 = new Date().getTime(), time2 = 0, done = 0;
    for (var i = 0; i < realResultCount; i++) {
        stmt.run(parseResult(realResultNodes[i]), function() {
            done++;
            time2 = new Date().getTime();
            if (time2 - time1 > 500) {
                time1 = time2;
                var percent = Math.round(done / realResultCount * 100);
                process.stdout.write("\rExecuting transaction... " + percent + "%");
            }
            if (done == realResultCount) {
                process.stdout.write("\r");
                console.log('Executing transaction... Done');
            }
        });
        time2 = new Date().getTime();
        if (time2 - time1 > 500) {
            time1 = time2;
            var percent = Math.round(i / realResultCount * 100);
            process.stdout.write("\rPreparing transaction... " + percent + "%");
        }
    }
    process.stdout.write("\r");
    console.log('Preparing transaction... Done');

    stmt.finalize();
    db.close(function() { console.log('All done'); });
}

function parseResult(resultTable) {
    // Parsing one result and filling the array to be inserted into db
    var resultObject = {
        'author-name': '',
        'author-mail': '',
        'core': '',
        'batch': '',
        'reference-frequency': 0,
        'reference-fsb': 0,
        'oc-fsb': 0,
        'oc-multiplier': 0,
        'screenshot-id': 0,
        'vcore': 0,
        'date': 0,
        'motherboard': '',
        'bios-version': '',
        'cooler': '',
        'max-temperature': 0,
        'id': 0,
        'comment': ''
    };
    var count = 0;
    var trNodes = $(resultTable).find('tr').get(), trCount = trNodes.length;
    for (var i = 0; i < trCount; i++) {
        var trNode = trNodes[i];
        if ($(trNode).hasClass('th2')) {
            continue;
        }
        var tdNodes = $(trNode).find('td').get(), tdCount = tdNodes.length;
        for (var j = 0; j < tdCount; j++) {
            var tdNode = $(tdNodes[j]);
            switch (count) {
                case 0:
                    resultObject = getAuthor(tdNode, resultObject);
                    break;
                case 1:
                    resultObject = getCore(tdNode, resultObject);
                    break;
                case 2:
                    resultObject = getBatch(tdNode, resultObject);
                    break;
                case 3:
                    resultObject = getReferenceFrequency(tdNode, resultObject);
                    break;
                case 4:
                    resultObject = getOcFrequency(tdNode, resultObject);
                    break;
                case 8:
                    resultObject = getVcore(tdNode, resultObject);
                    break;
                case 12:
                    resultObject = getSubmitDate(tdNode, resultObject);
                    break;
                case 13:
                    resultObject = getMotherboard(tdNode, resultObject);
                    break;
                case 14:
                    resultObject = getBiosVersion(tdNode, resultObject);
                    break;
                case 15:
                    resultObject = getCooler(tdNode, resultObject);
                    break;
                case 16:
                    resultObject = getTemperature(tdNode, resultObject);
                    break;
                case 17:
                    resultObject = getId(tdNode, resultObject);
                    break;
                case 19:
                    resultObject = getComment(tdNode, resultObject);
                    break;
            }
            count++;
        }
    }
    var bind = [];
    for (var key in resultObject) {
        bind.push(resultObject[key]);
    }
    return bind;
}

function getAuthor(node, result) {
    var aNodes = node.find('a').get();
    if (aNodes.length == 0) {
        result['author-name'] = node.text().trim();
    } else {
        var a = $(aNodes[0]);
        result['author-name'] = a.text().trim();
        var mail = a.attr('href');
        var mailto = 'mailto:';
        result['author-mail'] = mail.indexOf(mailto) >= 0
            ? mail.substr(mailto.length)
            : mail
        ;
    }
    return result;
}

function getCore(node, result) {
    result['core'] = node.text()
    return result;
}

function getBatch(node, result) {
    result['batch'] = node.text();
    return result;
}

function getReferenceFrequency(node, result) {
    var parts = node.text().split(' ');
    result['reference-frequency'] = parseInt(parts[0].trim());
    result['reference-fsb'] = parseInt(parts[1].trim().substr(1));
    return result;
}

function getOcFrequency(node, result) {
    var parts = node.text().split(' ');
    result['oc-fsb'] = parseInt(parts[1].trim().substr(1));
    result['oc-multiplier'] = parseFloat(parts[3].trim().match(/[0-9\.]*/)[0]);
    var tdNodes = node.find('td').get(), tdCount = tdNodes.length;
    if (tdCount > 1) {
        var aNodes = $(tdNodes[1]).find('a');
        if (aNodes.length > 0) {
            var aNode = $(aNodes.get(0));
            var href = aNode.attr('href');
            result['screenshot-id'] = parseInt(href.match(/([0-9]+)/)[0]);
        }
    }
    return result;
}

function getVcore(node, result) {
    result['vcore'] = parseFloat(node.text());
    return result;
}

function getSubmitDate(node, result) {
    var parts = node.text().split('.');
    var date = new Date(parseInt(parts[2]), parseInt(parts[1]) - 1, parseInt(parts[0]), 0, 0, 0, 0);
    result['date'] = date.getTime();
    return result;
}

function getMotherboard(node, result) {
    result['motherboard'] = node.text();
    return result;
}

function getBiosVersion(node, result) {
    result['bios-version'] = node.text();
    return result;
}

function getCooler(node, result) {
    result['cooler'] = node.text();
    return result;
}

function getTemperature(node, result) {
    result['max-temperature'] = parseInt(node.text());
    return result;
}

function getId(node, result) {
    result['id'] = parseInt(node.text());
    return result;
}

function getComment(node, result) {
    result['comment'] = node.text();
    return result;
}
<commit_msg>Added a console argument to download only n latest results. Also added a usage message<commit_after>#!/usr/bin/env node

var fs = require('fs');
var ini = require('ini');
var iconv = require('iconv-lite');
var sqlite3 = require('sqlite3');
var argv = require('yargs')
    .usage("Usage: $0 [-file filename] [-resultlimit number]");
var cheerio = require('cheerio'), $;

var config = ini.parse(fs.readFileSync('./config.ini', 'utf-8'));

console.log(argv.help());
argv = argv.argv;
if (argv.file) {
    // Getting file from fs if it exists
    if (fs.existsSync(argv.file)) {
        console.log('Reading "' + argv.file + '"');
        fs.readFile(argv.file, function(err, data) {
            if (err) throw err;
            parseOverclockersPage(data);
        });
    } else {
        console.log('File "' + argv.file + '" not found');
        process.exit(1);
    }
} else {
    // Otherwise downloading the whole db
    var http = require('http');
    var url = require('url');
    var resultsUrl = config.url;
    if (argv.resultlimit && parseInt(argv.resultlimit) > 0) {
        urlObject = url.parse(resultsUrl, true);
        urlObject.query.items = parseInt(argv.resultlimit);
        urlObject.search = null;
        resultsUrl = url.format(urlObject);
    }
    console.log('Downloading from ' + resultsUrl);
    callback = function(response) {
        var len = parseInt(response.headers['content-length'], 10);
        var bytesReceived = 0;
        var responseText = ''
        response.on('data', function (chunk) {
            bytesReceived += chunk.length;
            process.stdout.write("\r" + Math.round(bytesReceived / 1048576) + " Mb received");
            responseText += chunk;
        });
        response.on('end', function () {
            console.log();
            console.log('Download complete');
            parseOverclockersPage(responseText);
        });
    }
    var req = http.get(resultsUrl, callback);
    req.end();
}

function initDb(db) {
    // Creating db and indexes
    var queryCreate = 'CREATE TABLE IF NOT EXISTS results (\
"author-name" VARCHAR(100), \
"author-mail" VARCHAR(100), \
"core" VARCHAR(100), \
"batch" VARCHAR(100), \
"reference-frequency" INT, \
"reference-fsb" INT, \
"oc-fsb" INT, \
"oc-multiplier" REAL, \
"screenshot-id" INT, \
"vcore" REAL, \
"date" INT, \
"motherboard" VARCHAR(100), \
"bios-version" VARCHAR(100), \
"cooler" VARCHAR(100), \
"max-temperature" REAL, \
"id" INT PRIMARY KEY, \
"comment" TEXT\
)';
    db.exec(queryCreate);
    db.exec('CREATE INDEX IF NOT EXISTS index_author_name ON results ("author-name")');
    db.exec('CREATE INDEX IF NOT EXISTS index_core ON results ("core")');
    db.exec('CREATE INDEX IF NOT EXISTS index_date ON results ("date")');
    db.exec('PRAGMA journal_mode=OFF');
}

function parseOverclockersPage(html) {
    console.log('Initializing db');
    var db = new sqlite3.Database(config.dbFile);
    initDb(db);

    console.log('Converting to utf-8');
    var utf8String = iconv.decode(html, 'win1251');

    console.log('Parsing');
    $ = cheerio.load(utf8String);

    console.log('Getting raw results');
    var resultNodes = $('#hypercontext').find('table');
    var resultCount = resultNodes.length;

    console.log('Filtering results');
    var realResultNodes = [];
    for (var i = 0; i < resultCount; i++) {
        if ($(resultNodes[i]).hasClass('tsmall')
            || $(resultNodes[i]).attr('cellpadding') == '2'
            || resultNodes[i].parentNode.tagName == 'b'
        ) {
            continue;
        }
        realResultNodes.push(resultNodes[i]);
    }

    var realResultCount = realResultNodes.length;
    var queryInsert = 'REPLACE INTO results VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)';
    var stmt = db.prepare(queryInsert);

    console.log('Walking ' + realResultCount + ' result tables and inserting');
    var time1 = new Date().getTime(), time2 = 0, done = 0;
    for (var i = 0; i < realResultCount; i++) {
        stmt.run(parseResult(realResultNodes[i]), function() {
            done++;
            time2 = new Date().getTime();
            if (time2 - time1 > 500) {
                time1 = time2;
                var percent = Math.round(done / realResultCount * 100);
                process.stdout.write("\rExecuting transaction... " + percent + "%");
            }
            if (done == realResultCount) {
                process.stdout.write("\r");
                console.log('Executing transaction... Done');
            }
        });
        time2 = new Date().getTime();
        if (time2 - time1 > 500) {
            time1 = time2;
            var percent = Math.round(i / realResultCount * 100);
            process.stdout.write("\rPreparing transaction... " + percent + "%");
        }
    }
    process.stdout.write("\r");
    console.log('Preparing transaction... Done');

    stmt.finalize();
    db.close(function() { console.log('All done'); });
}

function parseResult(resultTable) {
    // Parsing one result and filling the array to be inserted into db
    var resultObject = {
        'author-name': '',
        'author-mail': '',
        'core': '',
        'batch': '',
        'reference-frequency': 0,
        'reference-fsb': 0,
        'oc-fsb': 0,
        'oc-multiplier': 0,
        'screenshot-id': 0,
        'vcore': 0,
        'date': 0,
        'motherboard': '',
        'bios-version': '',
        'cooler': '',
        'max-temperature': 0,
        'id': 0,
        'comment': ''
    };
    var count = 0;
    var trNodes = $(resultTable).find('tr').get(), trCount = trNodes.length;
    for (var i = 0; i < trCount; i++) {
        var trNode = trNodes[i];
        if ($(trNode).hasClass('th2')) {
            continue;
        }
        var tdNodes = $(trNode).find('td').get(), tdCount = tdNodes.length;
        for (var j = 0; j < tdCount; j++) {
            var tdNode = $(tdNodes[j]);
            switch (count) {
                case 0:
                    resultObject = getAuthor(tdNode, resultObject);
                    break;
                case 1:
                    resultObject = getCore(tdNode, resultObject);
                    break;
                case 2:
                    resultObject = getBatch(tdNode, resultObject);
                    break;
                case 3:
                    resultObject = getReferenceFrequency(tdNode, resultObject);
                    break;
                case 4:
                    resultObject = getOcFrequency(tdNode, resultObject);
                    break;
                case 8:
                    resultObject = getVcore(tdNode, resultObject);
                    break;
                case 12:
                    resultObject = getSubmitDate(tdNode, resultObject);
                    break;
                case 13:
                    resultObject = getMotherboard(tdNode, resultObject);
                    break;
                case 14:
                    resultObject = getBiosVersion(tdNode, resultObject);
                    break;
                case 15:
                    resultObject = getCooler(tdNode, resultObject);
                    break;
                case 16:
                    resultObject = getTemperature(tdNode, resultObject);
                    break;
                case 17:
                    resultObject = getId(tdNode, resultObject);
                    break;
                case 19:
                    resultObject = getComment(tdNode, resultObject);
                    break;
            }
            count++;
        }
    }
    var bind = [];
    for (var key in resultObject) {
        bind.push(resultObject[key]);
    }
    return bind;
}

function getAuthor(node, result) {
    var aNodes = node.find('a').get();
    if (aNodes.length == 0) {
        result['author-name'] = node.text().trim();
    } else {
        var a = $(aNodes[0]);
        result['author-name'] = a.text().trim();
        var mail = a.attr('href');
        var mailto = 'mailto:';
        result['author-mail'] = mail.indexOf(mailto) >= 0
            ? mail.substr(mailto.length)
            : mail
        ;
    }
    return result;
}

function getCore(node, result) {
    result['core'] = node.text()
    return result;
}

function getBatch(node, result) {
    result['batch'] = node.text();
    return result;
}

function getReferenceFrequency(node, result) {
    var parts = node.text().split(' ');
    result['reference-frequency'] = parseInt(parts[0].trim());
    result['reference-fsb'] = parseInt(parts[1].trim().substr(1));
    return result;
}

function getOcFrequency(node, result) {
    var parts = node.text().split(' ');
    result['oc-fsb'] = parseInt(parts[1].trim().substr(1));
    result['oc-multiplier'] = parseFloat(parts[3].trim().match(/[0-9\.]*/)[0]);
    var tdNodes = node.find('td').get(), tdCount = tdNodes.length;
    if (tdCount > 1) {
        var aNodes = $(tdNodes[1]).find('a');
        if (aNodes.length > 0) {
            var aNode = $(aNodes.get(0));
            var href = aNode.attr('href');
            result['screenshot-id'] = parseInt(href.match(/([0-9]+)/)[0]);
        }
    }
    return result;
}

function getVcore(node, result) {
    result['vcore'] = parseFloat(node.text());
    return result;
}

function getSubmitDate(node, result) {
    var parts = node.text().split('.');
    var date = new Date(parseInt(parts[2]), parseInt(parts[1]) - 1, parseInt(parts[0]), 0, 0, 0, 0);
    result['date'] = date.getTime();
    return result;
}

function getMotherboard(node, result) {
    result['motherboard'] = node.text();
    return result;
}

function getBiosVersion(node, result) {
    result['bios-version'] = node.text();
    return result;
}

function getCooler(node, result) {
    result['cooler'] = node.text();
    return result;
}

function getTemperature(node, result) {
    result['max-temperature'] = parseInt(node.text());
    return result;
}

function getId(node, result) {
    result['id'] = parseInt(node.text());
    return result;
}

function getComment(node, result) {
    result['comment'] = node.text();
    return result;
}
<|endoftext|>


<commit_before>// @flow weak

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import AppBar from 'material-ui/AppBar';
import IconButton from 'material-ui/IconButton';
import spacing from 'material-ui/styles/spacing';
import getMuiTheme from 'material-ui/styles/getMuiTheme';
import { darkWhite, lightWhite, grey900 } from 'material-ui/styles/colors';
import withWidth, { MEDIUM, LARGE } from 'material-ui/utils/withWidth';
import palette from '../utils/palette';
import AppNavDrawer from './AppNavDrawer';
import FullWidthSection from './FullWidthSection';

class AppFrame extends Component {
  static propTypes = {
    children: PropTypes.node,
    location: PropTypes.object,
    width: PropTypes.number.isRequired,
  };

  static contextTypes = {
    router: PropTypes.object.isRequired,
  };

  static childContextTypes = {
    muiTheme: PropTypes.object,
  };

  state = {
    navDrawerOpen: false,
  };

  getChildContext() {
    return {
      muiTheme: this.state.muiTheme,
    };
  }

  componentWillMount() {
    this.setState({
      muiTheme: getMuiTheme({ palette }),
    });
  }

  componentWillReceiveProps(nextProps, nextContext) {
    const newMuiTheme = nextContext.muiTheme ? nextContext.muiTheme : this.state.muiTheme;
    this.setState({
      muiTheme: newMuiTheme,
    });
  }

  getStyles() {
    const styles = {
      appBar: {
        position: 'fixed',
        zIndex: this.state.muiTheme.zIndex.appBar + 1,
        top: 0,
      },
      root: {
        paddingTop: spacing.desktopKeylineIncrement,
        minHeight: 400,
      },
      content: {
        margin: spacing.desktopGutter,
      },
      contentWhenMedium: {
        margin: `${spacing.desktopGutter}px ${spacing.desktopGutter}px`,
      },
      footer: {
        backgroundColor: '#455a64',
        textAlign: 'center',
      },
      a: {
        color: darkWhite,
      },
      p: {
        margin: '0 auto',
        padding: 0,
        color: lightWhite,
        maxWidth: 356,
      },
      browserstack: {
        display: 'flex',
        alignItems: 'flex-start',
        justifyContent: 'center',
        margin: '25px 15px 0',
        padding: 0,
        color: lightWhite,
        lineHeight: '25px',
        fontSize: 12,
      },
      browserstackLogo: {
        margin: '0 3px',
      },
      iconButton: {
        color: darkWhite,
      },
    };

    if (this.props.width === MEDIUM || this.props.width === LARGE) {
      styles.content = Object.assign(styles.content, styles.contentWhenMedium);
    }

    return styles;
  }

  handleTouchTapLeftIconButton = () => {
    this.setState({
      navDrawerOpen: !this.state.navDrawerOpen,
    });
  };

  handleChangeRequestNavDrawer = (open) => {
    this.setState({
      navDrawerOpen: open,
    });
  };

  handleChangeList = (event, value) => {
    this.context.router.push(value);
    this.setState({
      navDrawerOpen: false,
    });
  };

  render() {
    const {
      location,
      children,
    } = this.props;

    let {
      navDrawerOpen,
    } = this.state;

    const {
      prepareStyles,
    } = this.state.muiTheme;

    // const router = this.context.router;
    const styles = this.getStyles();
    const title = 'Resonance';

    let docked = false;
    let showMenuIconButton = true;

    if (this.props.width === LARGE && title !== '') {
      docked = true;
      navDrawerOpen = true;
      showMenuIconButton = false;

      styles.navDrawer = {
        zIndex: styles.appBar.zIndex - 1,
      };
      styles.root.paddingLeft = 256;
      styles.footer.paddingLeft = 256;
    }

    return (

        <AppBar
          onLeftIconButtonTouchTap={this.handleTouchTapLeftIconButton}
          title={title}
          zDepth={0}
          iconElementRight={
            <IconButton
              iconClassName="muidocs-icon-custom-github"
              href="https://github.com/sghall/resonance"
            />
          }
          style={styles.appBar}
          showMenuIconButton={showMenuIconButton}
        />

            {children}

        <AppNavDrawer
          style={styles.navDrawer}
          location={location}
          docked={docked}
          onRequestChangeNavDrawer={this.handleChangeRequestNavDrawer}
          onChangeList={this.handleChangeList}
          open={navDrawerOpen}
        />
        <FullWidthSection style={styles.footer}>
          <IconButton
            iconStyle={styles.iconButton}
            href="https://github.com/sghall/resonance"
          />

            {'Check out the project on Github '}

              Resonance

        </FullWidthSection>

    );
  }
}

export default withWidth()(AppFrame);
<commit_msg>fix lint issue<commit_after>// @flow weak

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import AppBar from 'material-ui/AppBar';
import IconButton from 'material-ui/IconButton';
import spacing from 'material-ui/styles/spacing';
import getMuiTheme from 'material-ui/styles/getMuiTheme';
import { darkWhite, lightWhite } from 'material-ui/styles/colors';
import withWidth, { MEDIUM, LARGE } from 'material-ui/utils/withWidth';
import palette from '../utils/palette';
import AppNavDrawer from './AppNavDrawer';
import FullWidthSection from './FullWidthSection';

class AppFrame extends Component {
  static propTypes = {
    children: PropTypes.node,
    location: PropTypes.object,
    width: PropTypes.number.isRequired,
  };

  static contextTypes = {
    router: PropTypes.object.isRequired,
  };

  static childContextTypes = {
    muiTheme: PropTypes.object,
  };

  state = {
    navDrawerOpen: false,
  };

  getChildContext() {
    return {
      muiTheme: this.state.muiTheme,
    };
  }

  componentWillMount() {
    this.setState({
      muiTheme: getMuiTheme({ palette }),
    });
  }

  componentWillReceiveProps(nextProps, nextContext) {
    const newMuiTheme = nextContext.muiTheme ? nextContext.muiTheme : this.state.muiTheme;
    this.setState({
      muiTheme: newMuiTheme,
    });
  }

  getStyles() {
    const styles = {
      appBar: {
        position: 'fixed',
        zIndex: this.state.muiTheme.zIndex.appBar + 1,
        top: 0,
      },
      root: {
        paddingTop: spacing.desktopKeylineIncrement,
        minHeight: 400,
      },
      content: {
        margin: spacing.desktopGutter,
      },
      contentWhenMedium: {
        margin: `${spacing.desktopGutter}px ${spacing.desktopGutter}px`,
      },
      footer: {
        backgroundColor: '#455a64',
        textAlign: 'center',
      },
      a: {
        color: darkWhite,
      },
      p: {
        margin: '0 auto',
        padding: 0,
        color: lightWhite,
        maxWidth: 356,
      },
      browserstack: {
        display: 'flex',
        alignItems: 'flex-start',
        justifyContent: 'center',
        margin: '25px 15px 0',
        padding: 0,
        color: lightWhite,
        lineHeight: '25px',
        fontSize: 12,
      },
      browserstackLogo: {
        margin: '0 3px',
      },
      iconButton: {
        color: darkWhite,
      },
    };

    if (this.props.width === MEDIUM || this.props.width === LARGE) {
      styles.content = Object.assign(styles.content, styles.contentWhenMedium);
    }

    return styles;
  }

  handleTouchTapLeftIconButton = () => {
    this.setState({
      navDrawerOpen: !this.state.navDrawerOpen,
    });
  };

  handleChangeRequestNavDrawer = (open) => {
    this.setState({
      navDrawerOpen: open,
    });
  };

  handleChangeList = (event, value) => {
    this.context.router.push(value);
    this.setState({
      navDrawerOpen: false,
    });
  };

  render() {
    const {
      location,
      children,
    } = this.props;

    let {
      navDrawerOpen,
    } = this.state;

    const {
      prepareStyles,
    } = this.state.muiTheme;

    // const router = this.context.router;
    const styles = this.getStyles();
    const title = 'Resonance';

    let docked = false;
    let showMenuIconButton = true;

    if (this.props.width === LARGE && title !== '') {
      docked = true;
      navDrawerOpen = true;
      showMenuIconButton = false;

      styles.navDrawer = {
        zIndex: styles.appBar.zIndex - 1,
      };
      styles.root.paddingLeft = 256;
      styles.footer.paddingLeft = 256;
    }

    return (

        <AppBar
          onLeftIconButtonTouchTap={this.handleTouchTapLeftIconButton}
          title={title}
          zDepth={0}
          iconElementRight={
            <IconButton
              iconClassName="muidocs-icon-custom-github"
              href="https://github.com/sghall/resonance"
            />
          }
          style={styles.appBar}
          showMenuIconButton={showMenuIconButton}
        />

            {children}

        <AppNavDrawer
          style={styles.navDrawer}
          location={location}
          docked={docked}
          onRequestChangeNavDrawer={this.handleChangeRequestNavDrawer}
          onChangeList={this.handleChangeList}
          open={navDrawerOpen}
        />
        <FullWidthSection style={styles.footer}>
          <IconButton
            iconStyle={styles.iconButton}
            href="https://github.com/sghall/resonance"
          />

            {'Check out the project on Github '}

              Resonance

        </FullWidthSection>

    );
  }
}

export default withWidth()(AppFrame);
<|endoftext|>


<commit_before>var drFrankenstyle = require('dr-frankenstyle');
var through2 = require('through2');
var File = require('vinyl');
var gulp = require('gulp');

var gulpDestTransformCode = 'function saveFile(file, enc, cb) {\n    var basePath;\n    if (typeof outFolder === \'string\') {\n      basePath = path.resolve(cwd, outFolder);\n    }\n    if (typeof outFolder === \'function\') {\n      basePath = path.resolve(cwd, outFolder(file));\n    }\n    var writePath = path.resolve(basePath, file.relative);\n    var writeFolder = path.dirname(writePath);\n\n    // wire up new properties\n    file.stat = file.stat ? file.stat : new fs.Stats();\n    file.stat.mode = (options.mode || file.stat.mode);\n    file.cwd = cwd;\n    file.base = basePath;\n    file.path = writePath;\n\n    // mkdirp the folder the file is going in\n    mkdirp(writeFolder, function(err){\n      if (err) {\n        return cb(err);\n      }\n      writeContents(writePath, file, cb);\n    });\n  }';
function wrapStream(stream) { // Evil monkey patch for a vinyl bug in gulp dest: https://github.com/wearefractal/vinyl-fs/issues/19
  var oldPipe = stream.pipe;
  stream.pipe = function(processor) {
    var isGulpDest = processor._transform.toString() === gulpDestTransformCode;
    if (isGulpDest) {
      var gulpDest = oldPipe.call(this, processor);
      var _transform = gulpDest._transform;
      gulpDest._transform = function(file, encoding, callback) {
        return _transform.call(this, file.clone(), encoding, callback);
      };
      return wrapStream(gulpDest);
    } else {
      return wrapStream(oldPipe.call(this, processor))
    }
  };
  return stream;
}

module.exports = function gulpDrFrankenstyle() {
  return wrapStream(
    drFrankenstyle({stream: true})
      .pipe(through2.obj(function(file, encoding, callback) {
        callback(null, Object.setPrototypeOf(file, new File(file)));
      }))
  );
};

gulp.task('assets', function() {
  drFrankenstyle()
    .pipe(thing())
    .pipe(otherThing())
    .pipe(gulp.dest('public'))
});<commit_msg>Remove monkey-patch<commit_after>var drFrankenstyle = require('dr-frankenstyle');
var through2 = require('through2');
var File = require('vinyl');
module.exports = function gulpDrFrankenstyle() {
  return drFrankenstyle({stream: true})
    .pipe(through2.obj(function(file, encoding, callback) {
      callback(null, Object.setPrototypeOf(file, new File(file)));
    }));
};
<|endoftext|>


<commit_before>"use strict";

define(['logManager',
        'clientUtil',
        'nodeAttributeNames',
        'nodeRegistryNames'], function (logManager,
                                    util,
                                    nodeAttributeNames,
                                    nodeRegistryNames) {

    var ModelEditorControl;

    ModelEditorControl = function (myClient, myModelEditor) {
        var self = this;

        this._client = myClient;
        this._modelEditorView = myModelEditor;
        this._modelEditorView._client = myClient;

        this._logger = logManager.create("HTML_ModelEditorControl");
        this._logger.debug("Created");

        //this._territoryId = this._client.addUI(this, true);
        this._selfPatterns = {};

        this._componentStates = { "loading": 0,
                                  "loaded": 1 };

        this._components = {};

        //local variable holding info about the currently opened node
        this._currentNodeInfo = {"id": null, "children" : [], "parentId": null };

        /*OVERRIDE MODEL EDITOR METHODS*/
        this._modelEditorView.onCreateConnection = function (connDesc) {
            self._client.makeConnection({   "parentId": self._currentNodeInfo.id,
                "sourceId": connDesc.sourceId,
                "targetId": connDesc.targetId,
                "directed": true });
        };

        this._modelEditorView.onUpdateConnectionEnd = function (data) {
            self._client.makePointer(data.connectionId, data.endType, data.newValue);
        };

        this._modelEditorView.onDragCopy = function (pasteDesc) {
            var intellyPasteOpts = { "parentId": self._currentNodeInfo.id },
                id;

            for (id in pasteDesc) {
                if (pasteDesc.hasOwnProperty(id)) {
                    intellyPasteOpts[id] = { "attributes": {}, registry: {} };
                    if (pasteDesc[id].hasOwnProperty("x") && pasteDesc[id].hasOwnProperty("y")) {
                        intellyPasteOpts[id].registry[nodeRegistryNames.position] = { "x": pasteDesc[id].x, "y": pasteDesc[id].y };
                    }
                }
            }

            self._client.intellyPaste(intellyPasteOpts);
        };

        this._modelEditorView.onReposition = function (repositionDesc) {
            var id;

            for (id in repositionDesc) {
                if (repositionDesc.hasOwnProperty(id)) {
                    //TODO: bulk somehow
                    self._client.setRegistry(id, nodeRegistryNames.position, { "x": repositionDesc[id].x, "y": repositionDesc[id].y });
                }
            }
        };

        this._modelEditorView.onCopy = function (selectedIds) {
            self._client.copyNodes(selectedIds);
        };

        this._modelEditorView.onPaste = function () {
            if (self._currentNodeInfo.id) {
                self._client.pasteNodes(self._currentNodeInfo.id);
            }
        };

        this._modelEditorView.onDelete = function (ids) {
            self._client.delMoreNodes(ids);
        };

        this._modelEditorView.onSaveConnectionSegmentPoints = function (connId, segmentPointsToSave) {
            self._client.setRegistry(connId, nodeRegistryNames.segmentPoints, segmentPointsToSave);
        };

        this._modelEditorView.onSetLineType = function (connId, type) {
            var reg = {};
            reg[nodeRegistryNames.lineType] = type;
            reg[nodeRegistryNames.segmentPoints] = [];
            self._client.setRegistry(connId, reg);
        };

        this._modelEditorView.onDoubleClick = function (componentId) {
            self._client.setSelectedObjectId(componentId);
        };

        this._modelEditorView.onGotoParent = function () {
            if (self._currentNodeInfo.parentId) {
                self._client.setSelectedObjectId(self._currentNodeInfo.parentId);
            }
        };

        this._modelEditorView.onAutLayout = function (components) {
            var i,
                nodeData;

            //TODO: bulk
            self._client.disableEventToUI(self.territoryId);
            for (i = 0; i < components.length; i += 1) {
                nodeData = components[i];
                self._client.setRegistry(nodeData.id, nodeRegistryNames.position, { "x": nodeData.x, "y": nodeData.y });
            }
            self._client.enableEventToUI(self.territoryId);
        };

        this._modelEditorView.onAutRename = function (components) {
            var i,
                nodeData;

            //TODO: bulk
            self._client.disableEventToUI(self.territoryId);
            for (i = 0; i < components.length; i += 1) {
                nodeData = components[i];
                self._client.setAttributes(nodeData.id, nodeAttributeNames.name, nodeData.title);
            }
            self._client.enableEventToUI(self.territoryId);
        };

        this._modelEditorView.onCreateModels = function (models) {
            var i;

            //TODO: bulk
            self._client.disableEventToUI(self.territoryId);
            for (i = 0; i < models.length; i += 1) {
                self._client.createChild({ "parentId": self._currentNodeInfo.id,
                                           "name": models[i].name });
            }
            self._client.enableEventToUI(self.territoryId);
        };
        /*END OF - OVERRIDE MODEL EDITOR METHODS*/

        this._initialize();
    };

    ModelEditorControl.prototype._initialize = function () {
        var self = this;

        /*this._client.addEventListener(this._client.events.SELECTEDOBJECT_CHANGED, function (__project, nodeId) {
            self._selectedObjectChanged(nodeId);
        });*/
    };

    ModelEditorControl.prototype.selectedObjectChanged = function (nodeId) {
        var desc = this._getObjectDescriptor(nodeId);

        this._logger.debug("SELECTEDOBJECT_CHANGED nodeId '" + nodeId + "'");

        //delete everything from model editor
        this._modelEditorView.clear();

        //clean up local hash map
        this._components = {};

        //remove current territory patterns
        if (this._currentNodeInfo.id) {
            this._client.removeUI(this._territoryId);
        }

        this._currentNodeInfo.id = nodeId;
        this._currentNodeInfo.parentId = desc.parentId;

        //put new node's info into territory rules
        this._selfPatterns = {};
        this._selfPatterns[nodeId] = { "children": 1 };

        this._modelEditorView.updateCanvas(desc);

        this._territoryId = this._client.addUI(this, true);
        //update the territory
        this._client.updateTerritory(this._territoryId, this._selfPatterns);
    };

    ModelEditorControl.prototype._getObjectDescriptor = function (nodeId) {
        var nodeObj = this._client.getNode(nodeId),
            objDescriptor,
            pos;

        if (nodeObj) {
            objDescriptor = {};

            objDescriptor.id = nodeObj.getId();
            objDescriptor.name =  nodeObj.getAttribute(nodeAttributeNames.name);
            objDescriptor.parentId = nodeObj.getParentId();

            //fill the descriptor based on its type
            if (nodeObj.getBaseId() === "connection") {
                objDescriptor.kind = "CONNECTION";
                objDescriptor.source = nodeObj.getPointer("source").to;
                objDescriptor.target = nodeObj.getPointer("target").to;
                if (nodeObj.getAttribute(nodeAttributeNames.directed) === true) {
                    objDescriptor.arrowEnd = "block";
                }
                objDescriptor.lineType =  nodeObj.getRegistry(nodeRegistryNames.lineType) || "L";
                objDescriptor.segmentPoints = nodeObj.getRegistry(nodeRegistryNames.segmentPoints);
            } else {
                objDescriptor.kind = "MODEL";
                pos = nodeObj.getRegistry(nodeRegistryNames.position);

                objDescriptor.position = { "x": pos.x, "y": pos.y};

                if (objDescriptor.position.hasOwnProperty("x")) {
                    objDescriptor.position.x = this._getDefaultValueForNumber(objDescriptor.position.x, 0);
                } else {
                    objDescriptor.position.x = 0;
                }

                if (objDescriptor.position.hasOwnProperty("y")) {
                    objDescriptor.position.y = this._getDefaultValueForNumber(objDescriptor.position.y, 0);
                } else {
                    objDescriptor.position.y = 0;
                }

                objDescriptor.decorator = nodeObj.getRegistry(nodeRegistryNames.decorator) || "SimpleModelDecorator";
            }
        }

        return objDescriptor;
    };

    ModelEditorControl.prototype._getDefaultValueForNumber = function (cValue, defaultValue) {
        if (_.isNumber(cValue)) {
            if (_.isNaN(cValue)) {
                return defaultValue;
            }
        } else {
            return defaultValue;
        }

        //cValue is a number, simply return it
        return cValue;
    };

    // PUBLIC METHODS
    ModelEditorControl.prototype.onOneEvent = function (events) {
        var i;

        this._logger.debug("onOneEvent '" + events.length + "' items");

        if (events && events.length > 0) {
            this._modelEditorView.startLongUpdate();

            for (i = 0; i < events.length; i += 1) {
                this.onEvent(events[i].etype, events[i].eid);
            }

            this._modelEditorView.finishLongUpdate();
        }

        this._logger.debug("onOneEvent '" + events.length + "' items - DONE");
    };

    ModelEditorControl.prototype.onEvent = function (etype, eid) {
        this._logger.debug("onEvent '" + etype + "', '" + eid + "'");
        switch (etype) {
        case "load":
            this._onLoad(eid);
            break;
        case "update":
            this._onUpdate(eid);
            break;
        case "unload":
            this._onUnload(eid);
            break;
        }
    };

    // PUBLIC METHODS
    ModelEditorControl.prototype._onLoad = function (objectId) {
        var desc;

        //component loaded
        //we are interested in the load of subcomponents of the opened component
        if (this._currentNodeInfo.id !== objectId) {
            desc = this._getObjectDescriptor(objectId);

            if (desc) {
                if (desc.kind === "MODEL") {
                    this._modelEditorView.createModelComponent(desc);
                }

                if (desc.kind === "CONNECTION") {
                    this._modelEditorView.createConnectionComponent(desc);
                }
            }
        }
    };

    ModelEditorControl.prototype._onUpdate = function (objectId) {
        //self or child updated
        var desc = this._getObjectDescriptor(objectId);

        //check if the updated object is the opened node
        if (objectId === this._currentNodeInfo.id) {
            //the updated object is the parent whose children are displayed here
            //the interest about the parent is:
            // - name change
            this._modelEditorView.updateCanvas(desc);
        } else {
            if (desc) {
                if (desc.kind === "MODEL") {
                    this._modelEditorView.updateModelComponent(objectId, desc);
                }

                if (desc.kind === "CONNECTION") {
                    this._modelEditorView.updateConnectionComponent(objectId, desc);
                }
            }
        }
    };

    ModelEditorControl.prototype._onUnload = function (objectId) {
        if (objectId === this._currentNodeInfo.id) {
            //the opened model has been deleted....
            this._modelEditorView.updateCanvas({"name": "The currently opened model has beed deleted (TODO)"});
        } else {
            this._modelEditorView.deleteComponent(objectId);
        }
    };

    //TODO: check this here...
    ModelEditorControl.prototype.destroy = function () {
        this._client.removeUI(this._territoryId);
    };

    return ModelEditorControl;
});
<commit_msg>using client.starTransaction and client.CompleteTransaction for some of the bulk edit's (just trying)<commit_after>"use strict";

define(['logManager',
        'clientUtil',
        'nodeAttributeNames',
        'nodeRegistryNames'], function (logManager,
                                    util,
                                    nodeAttributeNames,
                                    nodeRegistryNames) {

    var ModelEditorControl;

    ModelEditorControl = function (myClient, myModelEditor) {
        var self = this;

        this._client = myClient;
        this._modelEditorView = myModelEditor;
        this._modelEditorView._client = myClient;

        this._logger = logManager.create("HTML_ModelEditorControl");
        this._logger.debug("Created");

        //this._territoryId = this._client.addUI(this, true);
        this._selfPatterns = {};

        this._componentStates = { "loading": 0,
                                  "loaded": 1 };

        this._components = {};

        //local variable holding info about the currently opened node
        this._currentNodeInfo = {"id": null, "children" : [], "parentId": null };

        /*OVERRIDE MODEL EDITOR METHODS*/
        this._modelEditorView.onCreateConnection = function (connDesc) {
            self._client.makeConnection({   "parentId": self._currentNodeInfo.id,
                "sourceId": connDesc.sourceId,
                "targetId": connDesc.targetId,
                "directed": true });
        };

        this._modelEditorView.onUpdateConnectionEnd = function (data) {
            self._client.makePointer(data.connectionId, data.endType, data.newValue);
        };

        this._modelEditorView.onDragCopy = function (pasteDesc) {
            var intellyPasteOpts = { "parentId": self._currentNodeInfo.id },
                id;

            for (id in pasteDesc) {
                if (pasteDesc.hasOwnProperty(id)) {
                    intellyPasteOpts[id] = { "attributes": {}, registry: {} };
                    if (pasteDesc[id].hasOwnProperty("x") && pasteDesc[id].hasOwnProperty("y")) {
                        intellyPasteOpts[id].registry[nodeRegistryNames.position] = { "x": pasteDesc[id].x, "y": pasteDesc[id].y };
                    }
                }
            }

            self._client.intellyPaste(intellyPasteOpts);
        };

        this._modelEditorView.onReposition = function (repositionDesc) {
            var id;

            for (id in repositionDesc) {
                if (repositionDesc.hasOwnProperty(id)) {
                    //TODO: bulk somehow
                    self._client.setRegistry(id, nodeRegistryNames.position, { "x": repositionDesc[id].x, "y": repositionDesc[id].y });
                }
            }
        };

        this._modelEditorView.onCopy = function (selectedIds) {
            self._client.copyNodes(selectedIds);
        };

        this._modelEditorView.onPaste = function () {
            if (self._currentNodeInfo.id) {
                self._client.pasteNodes(self._currentNodeInfo.id);
            }
        };

        this._modelEditorView.onDelete = function (ids) {
            self._client.delMoreNodes(ids);
        };

        this._modelEditorView.onSaveConnectionSegmentPoints = function (connId, segmentPointsToSave) {
            self._client.setRegistry(connId, nodeRegistryNames.segmentPoints, segmentPointsToSave);
        };

        this._modelEditorView.onSetLineType = function (connId, type) {
            var reg = {};
            reg[nodeRegistryNames.lineType] = type;
            reg[nodeRegistryNames.segmentPoints] = [];
            self._client.setRegistry(connId, reg);
        };

        this._modelEditorView.onDoubleClick = function (componentId) {
            self._client.setSelectedObjectId(componentId);
        };

        this._modelEditorView.onGotoParent = function () {
            if (self._currentNodeInfo.parentId) {
                self._client.setSelectedObjectId(self._currentNodeInfo.parentId);
            }
        };

        this._modelEditorView.onAutLayout = function (components) {
            var i,
                nodeData;

            //TODO: bulk
            //self._client.disableEventToUI(self.territoryId);
            self._client.startTransaction();
            for (i = 0; i < components.length; i += 1) {
                nodeData = components[i];
                self._client.setRegistry(nodeData.id, nodeRegistryNames.position, { "x": nodeData.x, "y": nodeData.y });
            }
            //self._client.enableEventToUI(self.territoryId);
            self._client.completeTransaction();
        };

        this._modelEditorView.onAutRename = function (components) {
            var i,
                nodeData;

            //TODO: bulk
            //self._client.disableEventToUI(self.territoryId);
            self._client.startTransaction();
            for (i = 0; i < components.length; i += 1) {
                nodeData = components[i];
                self._client.setAttributes(nodeData.id, nodeAttributeNames.name, nodeData.title);
            }
            self._client.completeTransaction();
            //self._client.enableEventToUI(self.territoryId);
        };

        this._modelEditorView.onCreateModels = function (models) {
            var i;

            //TODO: bulk
            //self._client.disableEventToUI(self.territoryId);
            self._client.startTransaction();
            for (i = 0; i < models.length; i += 1) {
                self._client.createChild({ "parentId": self._currentNodeInfo.id,
                                           "name": models[i].name });
            }
            self._client.completeTransaction();
            //self._client.enableEventToUI(self.territoryId);
        };
        /*END OF - OVERRIDE MODEL EDITOR METHODS*/

        this._initialize();
    };

    ModelEditorControl.prototype._initialize = function () {
        var self = this;

        /*this._client.addEventListener(this._client.events.SELECTEDOBJECT_CHANGED, function (__project, nodeId) {
            self._selectedObjectChanged(nodeId);
        });*/
    };

    ModelEditorControl.prototype.selectedObjectChanged = function (nodeId) {
        var desc = this._getObjectDescriptor(nodeId);

        this._logger.debug("SELECTEDOBJECT_CHANGED nodeId '" + nodeId + "'");

        //delete everything from model editor
        this._modelEditorView.clear();

        //clean up local hash map
        this._components = {};

        //remove current territory patterns
        if (this._currentNodeInfo.id) {
            this._client.removeUI(this._territoryId);
        }

        this._currentNodeInfo.id = nodeId;
        this._currentNodeInfo.parentId = desc.parentId;

        //put new node's info into territory rules
        this._selfPatterns = {};
        this._selfPatterns[nodeId] = { "children": 1 };

        this._modelEditorView.updateCanvas(desc);

        this._territoryId = this._client.addUI(this, true);
        //update the territory
        this._client.updateTerritory(this._territoryId, this._selfPatterns);
    };

    ModelEditorControl.prototype._getObjectDescriptor = function (nodeId) {
        var nodeObj = this._client.getNode(nodeId),
            objDescriptor,
            pos;

        if (nodeObj) {
            objDescriptor = {};

            objDescriptor.id = nodeObj.getId();
            objDescriptor.name =  nodeObj.getAttribute(nodeAttributeNames.name);
            objDescriptor.parentId = nodeObj.getParentId();

            //fill the descriptor based on its type
            if (nodeObj.getBaseId() === "connection") {
                objDescriptor.kind = "CONNECTION";
                objDescriptor.source = nodeObj.getPointer("source").to;
                objDescriptor.target = nodeObj.getPointer("target").to;
                if (nodeObj.getAttribute(nodeAttributeNames.directed) === true) {
                    objDescriptor.arrowEnd = "block";
                }
                objDescriptor.lineType =  nodeObj.getRegistry(nodeRegistryNames.lineType) || "L";
                objDescriptor.segmentPoints = nodeObj.getRegistry(nodeRegistryNames.segmentPoints);
            } else {
                objDescriptor.kind = "MODEL";
                pos = nodeObj.getRegistry(nodeRegistryNames.position);

                objDescriptor.position = { "x": pos.x, "y": pos.y};

                if (objDescriptor.position.hasOwnProperty("x")) {
                    objDescriptor.position.x = this._getDefaultValueForNumber(objDescriptor.position.x, 0);
                } else {
                    objDescriptor.position.x = 0;
                }

                if (objDescriptor.position.hasOwnProperty("y")) {
                    objDescriptor.position.y = this._getDefaultValueForNumber(objDescriptor.position.y, 0);
                } else {
                    objDescriptor.position.y = 0;
                }

                objDescriptor.decorator = nodeObj.getRegistry(nodeRegistryNames.decorator) || "SimpleModelDecorator";
            }
        }

        return objDescriptor;
    };

    ModelEditorControl.prototype._getDefaultValueForNumber = function (cValue, defaultValue) {
        if (_.isNumber(cValue)) {
            if (_.isNaN(cValue)) {
                return defaultValue;
            }
        } else {
            return defaultValue;
        }

        //cValue is a number, simply return it
        return cValue;
    };

    // PUBLIC METHODS
    ModelEditorControl.prototype.onOneEvent = function (events) {
        var i;

        this._logger.debug("onOneEvent '" + events.length + "' items");

        if (events && events.length > 0) {
            this._modelEditorView.startLongUpdate();

            for (i = 0; i < events.length; i += 1) {
                this.onEvent(events[i].etype, events[i].eid);
            }

            this._modelEditorView.finishLongUpdate();
        }

        this._logger.debug("onOneEvent '" + events.length + "' items - DONE");
    };

    ModelEditorControl.prototype.onEvent = function (etype, eid) {
        this._logger.debug("onEvent '" + etype + "', '" + eid + "'");
        switch (etype) {
        case "load":
            this._onLoad(eid);
            break;
        case "update":
            this._onUpdate(eid);
            break;
        case "unload":
            this._onUnload(eid);
            break;
        }
    };

    // PUBLIC METHODS
    ModelEditorControl.prototype._onLoad = function (objectId) {
        var desc;

        //component loaded
        //we are interested in the load of subcomponents of the opened component
        if (this._currentNodeInfo.id !== objectId) {
            desc = this._getObjectDescriptor(objectId);

            if (desc) {
                if (desc.kind === "MODEL") {
                    this._modelEditorView.createModelComponent(desc);
                }

                if (desc.kind === "CONNECTION") {
                    this._modelEditorView.createConnectionComponent(desc);
                }
            }
        }
    };

    ModelEditorControl.prototype._onUpdate = function (objectId) {
        //self or child updated
        var desc = this._getObjectDescriptor(objectId);

        //check if the updated object is the opened node
        if (objectId === this._currentNodeInfo.id) {
            //the updated object is the parent whose children are displayed here
            //the interest about the parent is:
            // - name change
            this._modelEditorView.updateCanvas(desc);
        } else {
            if (desc) {
                if (desc.kind === "MODEL") {
                    this._modelEditorView.updateModelComponent(objectId, desc);
                }

                if (desc.kind === "CONNECTION") {
                    this._modelEditorView.updateConnectionComponent(objectId, desc);
                }
            }
        }
    };

    ModelEditorControl.prototype._onUnload = function (objectId) {
        if (objectId === this._currentNodeInfo.id) {
            //the opened model has been deleted....
            this._modelEditorView.updateCanvas({"name": "The currently opened model has beed deleted (TODO)"});
        } else {
            this._modelEditorView.deleteComponent(objectId);
        }
    };

    //TODO: check this here...
    ModelEditorControl.prototype.destroy = function () {
        this._client.removeUI(this._territoryId);
    };

    return ModelEditorControl;
});
<|endoftext|>


<commit_before>/**
 * Created by Șandor Sergiu (micku7zu) on 1/27/2017.
 * Original idea: https://github.com/gijsroge/tilt.js
 * MIT License.
 * Version 1.4.1
 */

export default class VanillaTilt {
  constructor(element, settings = {}) {
    if (!(element instanceof Node)) {
      throw ("Can't initialize VanillaTilt because " + element + " is not a Node.");
    }

    this.width = null;
    this.height = null;
    this.left = null;
    this.top = null;
    this.transitionTimeout = null;
    this.updateCall = null;

    this.updateBind = this.update.bind(this);
    this.resetBind = this.reset.bind(this);

    this.element = element;
    this.settings = this.extendSettings(settings);

    this.reverse = this.settings.reverse ? -1 : 1;

    this.glare = this.isSettingTrue(this.settings.glare);
    this.glarePrerender = this.isSettingTrue(this.settings["glare-prerender"]);

    if (this.glare) {
      this.prepareGlare();
    }

    this.addEventListeners();
  }

  isSettingTrue(setting) {
    return setting === "" || setting === true || setting === 1;
  }

  addEventListeners() {
    this.onMouseEnterBind = this.onMouseEnter.bind(this);
    this.onMouseMoveBind = this.onMouseMove.bind(this);
    this.onMouseLeaveBind = this.onMouseLeave.bind(this);
    this.onWindowResizeBind = this.onWindowResizeBind.bind(this);

    this.element.addEventListener("mouseenter", this.onMouseEnterBind);
    this.element.addEventListener("mousemove", this.onMouseMoveBind);
    this.element.addEventListener("mouseleave", this.onMouseLeaveBind);
    if (this.glare) {
      window.addEventListener("resize", this.onWindowResizeBind);
    }
  }

  removeEventListeners() {
    this.element.removeEventListener("mouseenter", this.onMouseEnterBind);
    this.element.removeEventListener("mousemove", this.onMouseMoveBind);
    this.element.removeEventListener("mouseleave", this.onMouseLeaveBind);
    if (this.glare) {
      window.removeEventListener("resize", this.onWindowResizeBind);
    }
  }

  destroy() {
    clearTimeout(this.transitionTimeout);
    if (this.updateCall !== null) {
      cancelAnimationFrame(this.updateCall);
    }

    this.reset();

    this.removeEventListeners();
    this.element.vanillaTilt = null;
    delete this.element.vanillaTilt;

    this.element = null;
  }

  onMouseEnter() {
    this.updateElementPosition();
    this.element.style.willChange = 'transform';
    this.setTransition();
  }

  onMouseMove(event) {
    if (this.updateCall !== null) {
      cancelAnimationFrame(this.updateCall);
    }

    this.event = event;
    this.updateCall = requestAnimationFrame(this.updateBind);
  }

  onMouseLeave() {
    this.setTransition();

    if (this.settings.reset) {
      requestAnimationFrame(this.resetBind);
    }
  }

  reset() {
    this.event = {
      pageX: this.left + this.width / 2,
      pageY: this.top + this.height / 2
    };

    this.element.style.transform = "perspective(" + this.settings.perspective + "px) " +
      "rotateX(0deg) " +
      "rotateY(0deg) " +
      "scale3d(1, 1, 1)";

    if (this.glare) {
      this.glareElement.style.transform = 'rotate(180deg) translate(-50%, -50%)';
      this.glareElement.style.opacity = '0';
    }
  }

  getValues() {
    let x = (this.event.clientX - this.left) / this.width;
    let y = (this.event.clientY - this.top) / this.height;

    x = Math.min(Math.max(x, 0), 1);
    y = Math.min(Math.max(y, 0), 1);

    let tiltX = (this.reverse * (this.settings.max / 2 - x * this.settings.max)).toFixed(2);
    let tiltY = (this.reverse * (y * this.settings.max - this.settings.max / 2)).toFixed(2);
    let angle = Math.atan2(this.event.clientX - (this.left + this.width / 2), -(this.event.clientY - (this.top + this.height / 2))) * (180 / Math.PI);

    return {
      tiltX: tiltX,
      tiltY: tiltY,
      percentageX: x * 100,
      percentageY: y * 100,
      angle: angle
    };
  }

  updateElementPosition() {
    let rect = this.element.getBoundingClientRect();

    this.width = this.element.offsetWidth;
    this.height = this.element.offsetHeight;
    this.left = rect.left;
    this.top = rect.top;
  }

  update() {
    let values = this.getValues();

    this.element.style.transform = "perspective(" + this.settings.perspective + "px) " +
      "rotateX(" + (this.settings.axis === "x" ? 0 : values.tiltY) + "deg) " +
      "rotateY(" + (this.settings.axis === "y" ? 0 : values.tiltX) + "deg) " +
      "scale3d(" + this.settings.scale + ", " + this.settings.scale + ", " + this.settings.scale + ")";

    if (this.glare) {
      this.glareElement.style.transform = `rotate(${values.angle}deg) translate(-50%, -50%)`;
      this.glareElement.style.opacity = `${values.percentageY * this.settings["max-glare"] / 100}`;
    }

    this.element.dispatchEvent(new CustomEvent("tiltChange", {
      "detail": values
    }));

    this.updateCall = null;
  }

  /**
   * Appends the glare element (if glarePrerender equals false)
   * and sets the default style
   */
  prepareGlare() {
    // If option pre-render is enabled we assume all html/css is present for an optimal glare effect.
    if (!this.glarePrerender) {
      // Create glare element
      const jsTiltGlare = document.createElement("div");
      jsTiltGlare.classList.add("js-tilt-glare");

      const jsTiltGlareInner = document.createElement("div");
      jsTiltGlareInner.classList.add("js-tilt-glare-inner");

      jsTiltGlare.appendChild(jsTiltGlareInner);
      this.element.appendChild(jsTiltGlare);
    }

    this.glareElementWrapper = this.element.querySelector(".js-tilt-glare");
    this.glareElement = this.element.querySelector(".js-tilt-glare-inner");

    if (this.glarePrerender) {
      return;
    }

    Object.assign(this.glareElementWrapper.style, {
      "position": "absolute",
      "top": "0",
      "left": "0",
      "width": "100%",
      "height": "100%",
      "overflow": "hidden"
    });

    Object.assign(this.glareElement.style, {
      'position': 'absolute',
      'top': '50%',
      'left': '50%',
      'pointer-events': 'none',
      'background-image': `linear-gradient(0deg, rgba(255,255,255,0) 0%, rgba(255,255,255,1) 100%)`,
      'width': `${this.element.offsetWidth * 2}px`,
      'height': `${this.element.offsetWidth * 2}px`,
      'transform': 'rotate(180deg) translate(-50%, -50%)',
      'transform-origin': '0% 0%',
      'opacity': '0',
    });
  }

  updateGlareSize() {
    Object.assign(this.glareElement.style, {
      'width': `${this.element.offsetWidth * 2}`,
      'height': `${this.element.offsetWidth * 2}`,
    });
  }

  onWindowResizeBind() {
    this.updateGlareSize();
  }

  setTransition() {
    clearTimeout(this.transitionTimeout);
    this.element.style.transition = this.settings.speed + "ms " + this.settings.easing;
    if (this.glare) this.glareElement.style.transition = `opacity ${this.settings.speed}ms ${this.settings.easing}`;

    this.transitionTimeout = setTimeout(() => {
      this.element.style.transition = "";
      if (this.glare) {
        this.glareElement.style.transition = "";
      }
    }, this.settings.speed);

  }

  extendSettings(settings) {
    let defaultSettings = {
      reverse: false,
      max: 35,
      perspective: 1000,
      easing: "cubic-bezier(.03,.98,.52,.99)",
      scale: "1",
      speed: "300",
      transition: true,
      axis: null,
      glare: false,
      "max-glare": 1,
      "glare-prerender": false,
      reset: true
    };

    let newSettings = {};
    for (var property in defaultSettings) {
      if (property in settings) {
        newSettings[property] = settings[property];
      } else if (this.element.hasAttribute("data-tilt-" + property)) {
        let attribute = this.element.getAttribute("data-tilt-" + property);
        try {
          newSettings[property] = JSON.parse(attribute);
        } catch (e) {
          newSettings[property] = attribute;
        }

      } else {
        newSettings[property] = defaultSettings[property];
      }
    }

    return newSettings;
  }

  static init(elements, settings) {
    if (elements instanceof Node) {
      elements = [elements];
    }

    if (elements instanceof NodeList) {
      elements = [].slice.call(elements);
    }

    if (!(elements instanceof Array)) {
      return;
    }

    elements.forEach((element) => {
      if (!("vanillaTilt" in element)) {
        element.vanillaTilt = new VanillaTilt(element, settings);
      }
    });
  }
}

if (typeof document !== "undefined") {
  /* expose the class to window */
  window.VanillaTilt = VanillaTilt;

  /**
   * Auto load
   */
  VanillaTilt.init(document.querySelectorAll("[data-tilt]"));
}
<commit_msg>Adding more flexibility for mouse move events<commit_after>/**
 * Created by Șandor Sergiu (micku7zu) on 1/27/2017.
 * Original idea: https://github.com/gijsroge/tilt.js
 * MIT License.
 * Version 1.4.1
 */

export default class VanillaTilt {
  constructor(element, settings = {}) {
    if (!(element instanceof Node)) {
      throw ("Can't initialize VanillaTilt because " + element + " is not a Node.");
    }

    this.width = null;
    this.height = null;
    this.left = null;
    this.top = null;
    this.transitionTimeout = null;
    this.updateCall = null;

    this.updateBind = this.update.bind(this);
    this.resetBind = this.reset.bind(this);

    this.element = element;
    this.elementListener = this.getElementListener();
    this.settings = this.extendSettings(settings);

    this.reverse = this.settings.reverse ? -1 : 1;

    this.glare = this.isSettingTrue(this.settings.glare);
    this.glarePrerender = this.isSettingTrue(this.settings['glare-prerender']);

    if (this.glare) {
      this.prepareGlare();
    }

    this.addEventListeners();
  }

  isSettingTrue(setting) {
    return setting === "" || setting === true || setting === 1;
  }

  /**
   * Method returns element what will be listen mouse events
   * @return {Node}
   */
  getElementListener() {
    if (!this.settings.mouseEventElement) { return this.element; }

    if (typeof this.settings.mouseEventElement === 'string') {
      const mouseEventElement = document.querySelector(this.settings.mouseEventElement);

      if (mouseEventElement) {
        return mouseEventElement;
      }
    }

    if (this.settings.mouseEventElement instanceof Node && this.settings.mouseEventElement) {
      return this.settings.mouseEventElement;
    }
  }

  /**
   * Method set listen methods for this.elementListener
   * @return {Node}
   */
  addEventListeners() {
    this.onMouseEnterBind = this.onMouseEnter.bind(this);
    this.onMouseMoveBind = this.onMouseMove.bind(this);
    this.onMouseLeaveBind = this.onMouseLeave.bind(this);
    this.onWindowResizeBind = this.onWindowResizeBind.bind(this);

    this.elementListener.addEventListener('mouseenter', this.onMouseEnterBind);
    this.elementListener.addEventListener('mousemove', this.onMouseMoveBind);
    this.elementListener.addEventListener('mouseleave', this.onMouseLeaveBind);

    if (this.glare) {
      window.addEventListener('resize', this.onWindowResizeBind);
    }
  }

  /**
   * Method remove event listeners from current this.elementListener
   */
  removeEventListeners() {
    this.elementListener.removeEventListener('mouseenter', this.onMouseEnterBind);
    this.elementListener.removeEventListener('mousemove', this.onMouseMoveBind);
    this.elementListener.removeEventListener('mouseleave', this.onMouseLeaveBind);

    if (this.glare) {
      window.removeEventListener('resize', this.onWindowResizeBind);
    }
  }

  destroy() {
    clearTimeout(this.transitionTimeout);
    if (this.updateCall !== null) {
      cancelAnimationFrame(this.updateCall);
    }

    this.reset();

    this.removeEventListeners();
    this.element.vanillaTilt = null;
    delete this.element.vanillaTilt;

    this.element = null;
  }

  onMouseEnter() {
    this.updateElementPosition();
    this.element.style.willChange = 'transform';
    this.setTransition();
  }

  onMouseMove(event) {
    if (this.updateCall !== null) {
      cancelAnimationFrame(this.updateCall);
    }

    this.event = event;
    this.updateCall = requestAnimationFrame(this.updateBind);
  }

  onMouseLeave() {
    this.setTransition();

    if (this.settings.reset) {
      requestAnimationFrame(this.resetBind);
    }
  }

  reset() {
    this.event = {
      pageX: this.left + this.width / 2,
      pageY: this.top + this.height / 2
    };

    this.element.style.transform = "perspective(" + this.settings.perspective + "px) " +
      "rotateX(0deg) " +
      "rotateY(0deg) " +
      "scale3d(1, 1, 1)";

    if (this.glare) {
      this.glareElement.style.transform = 'rotate(180deg) translate(-50%, -50%)';
      this.glareElement.style.opacity = '0';
    }
  }

  getValues() {
    let x = (this.event.clientX - this.left) / this.width;
    let y = (this.event.clientY - this.top) / this.height;

    x = Math.min(Math.max(x, 0), 1);
    y = Math.min(Math.max(y, 0), 1);

    let tiltX = (this.reverse * (this.settings.max / 2 - x * this.settings.max)).toFixed(2);
    let tiltY = (this.reverse * (y * this.settings.max - this.settings.max / 2)).toFixed(2);
    let angle = Math.atan2(this.event.clientX - (this.left + this.width / 2), -(this.event.clientY - (this.top + this.height / 2))) * (180 / Math.PI);

    return {
      tiltX: tiltX,
      tiltY: tiltY,
      percentageX: x * 100,
      percentageY: y * 100,
      angle: angle
    };
  }

  updateElementPosition() {
    let rect = this.element.getBoundingClientRect();

    this.width = this.element.offsetWidth;
    this.height = this.element.offsetHeight;
    this.left = rect.left;
    this.top = rect.top;
  }

  update() {
    let values = this.getValues();

    this.element.style.transform = "perspective(" + this.settings.perspective + "px) " +
      "rotateX(" + (this.settings.axis === "x" ? 0 : values.tiltY) + "deg) " +
      "rotateY(" + (this.settings.axis === "y" ? 0 : values.tiltX) + "deg) " +
      "scale3d(" + this.settings.scale + ", " + this.settings.scale + ", " + this.settings.scale + ")";

    if (this.glare) {
      this.glareElement.style.transform = `rotate(${values.angle}deg) translate(-50%, -50%)`;
      this.glareElement.style.opacity = `${values.percentageY * this.settings["max-glare"] / 100}`;
    }

    this.element.dispatchEvent(new CustomEvent("tiltChange", {
      "detail": values
    }));

    this.updateCall = null;
  }

  /**
   * Appends the glare element (if glarePrerender equals false)
   * and sets the default style
   */
  prepareGlare() {
    // If option pre-render is enabled we assume all html/css is present for an optimal glare effect.
    if (!this.glarePrerender) {
      // Create glare element
      const jsTiltGlare = document.createElement("div");
      jsTiltGlare.classList.add("js-tilt-glare");

      const jsTiltGlareInner = document.createElement("div");
      jsTiltGlareInner.classList.add("js-tilt-glare-inner");

      jsTiltGlare.appendChild(jsTiltGlareInner);
      this.element.appendChild(jsTiltGlare);
    }

    this.glareElementWrapper = this.element.querySelector(".js-tilt-glare");
    this.glareElement = this.element.querySelector(".js-tilt-glare-inner");

    if (this.glarePrerender) {
      return;
    }

    Object.assign(this.glareElementWrapper.style, {
      "position": "absolute",
      "top": "0",
      "left": "0",
      "width": "100%",
      "height": "100%",
      "overflow": "hidden"
    });

    Object.assign(this.glareElement.style, {
      'position': 'absolute',
      'top': '50%',
      'left': '50%',
      'pointer-events': 'none',
      'background-image': `linear-gradient(0deg, rgba(255,255,255,0) 0%, rgba(255,255,255,1) 100%)`,
      'width': `${this.element.offsetWidth * 2}px`,
      'height': `${this.element.offsetWidth * 2}px`,
      'transform': 'rotate(180deg) translate(-50%, -50%)',
      'transform-origin': '0% 0%',
      'opacity': '0',
    });
  }

  updateGlareSize() {
    Object.assign(this.glareElement.style, {
      'width': `${this.element.offsetWidth * 2}`,
      'height': `${this.element.offsetWidth * 2}`,
    });
  }

  onWindowResizeBind() {
    this.updateGlareSize();
  }

  setTransition() {
    clearTimeout(this.transitionTimeout);
    this.element.style.transition = this.settings.speed + "ms " + this.settings.easing;
    if (this.glare) this.glareElement.style.transition = `opacity ${this.settings.speed}ms ${this.settings.easing}`;

    this.transitionTimeout = setTimeout(() => {
      this.element.style.transition = "";
      if (this.glare) {
        this.glareElement.style.transition = "";
      }
    }, this.settings.speed);

  }

  /**
   * Method return patched settings of instance
   * @param {boolean} settings.reverse - reverse the tilt direction
   * @param {number} settings.max - max tilt rotation (degrees)
   * @param {number} settings.perspective - Transform perspective, the lower the more extreme the tilt gets
   * @param {string} settings.easing - Easing on enter/exit
   * @param {number} settings.scale - 2 = 200%, 1.5 = 150%, etc..
   * @param {number} settings.speed - Speed of the enter/exit transition
   * @param {boolean} settings.transition - Set a transition on enter/exit
   * @param settings.axis - What axis should be disabled. Can be X or Y
   * @param {boolean} settings.glare - What axis should be disabled. Can be X or Y
   * @param {number} settings.max-glare - the maximum "glare" opacity (1 = 100%, 0.5 = 50%)
   * @param {boolean} settings.glare-prerender - false = VanillaTilt creates the glare elements for you, otherwise
   * @param {boolean} settings.reset - false = If the tilt effect has to be reset on exit
   * @param {boolean} settings.mouseEventElement - String selector or link to HTML-element what will be listen mouse events
   */
  extendSettings(settings) {
    let defaultSettings = {
      reverse: false,
      max: 35,
      perspective: 1000,
      easing: 'cubic-bezier(.03,.98,.52,.99)',
      scale: 1,
      speed: 300,
      transition: true,
      axis: null,
      glare: false,
      'max-glare': 1,
      "glare-prerender": false,
      reset: true,
      mouseEventElement: null,
    };

    let newSettings = {};
    for (var property in defaultSettings) {
      if (property in settings) {
        newSettings[property] = settings[property];
      } else if (this.element.hasAttribute("data-tilt-" + property)) {
        let attribute = this.element.getAttribute("data-tilt-" + property);
        try {
          newSettings[property] = JSON.parse(attribute);
        } catch (e) {
          newSettings[property] = attribute;
        }

      } else {
        newSettings[property] = defaultSettings[property];
      }
    }

    return newSettings;
  }

  static init(elements, settings) {
    if (elements instanceof Node) {
      elements = [elements];
    }

    if (elements instanceof NodeList) {
      elements = [].slice.call(elements);
    }

    if (!(elements instanceof Array)) {
      return;
    }

    elements.forEach((element) => {
      if (!("vanillaTilt" in element)) {
        element.vanillaTilt = new VanillaTilt(element, settings);
      }
    });
  }
}

if (typeof document !== "undefined") {
  /* expose the class to window */
  window.VanillaTilt = VanillaTilt;

  /**
   * Auto load
   */
  VanillaTilt.init(document.querySelectorAll("[data-tilt]"));
}
<|endoftext|>