Commit f6b305e7 by Kornkitt Poolsup

Initial commit

parents
var rest = require('restler');
var ms = require('ms');
var sc = require('./status_code');
var out = require('outliers');
var kairos_usr = 'tsdbadmin';
var kairos_pwd = 'RzuCqG14NrWXMfbj*s6m8v';
var kairos_prt = '32222';
var kairos_url = 'http://' + kairos_usr + ":" + kairos_pwd +
'@nxn1.kube.nexpie.com:' +
kairos_prt + '/';
var range_input = ['raw', '1h', '1d', '1w', '1m', '1y'];
var randval = Math.random();
function timeRoundDown(t, scale='1h') {
return t - (t % ms(scale));
}
function timeRoundUp(t, scale = '1h') {
return t + (ms(scale) - (t % ms(scale)));
}
/**
* Decrease a rwange of timeframe for one step back
* to make a summary of an updated data query
* @param {string} range - a timeframe range
*/
function decrease_range_for_shown(range) {
if (range == '1h') return 'raw';
else if (range == '1d') return 'raw';
else if (range == '1w') return '1h';
else if (range == '1m') return '1h';
else if (range == '1y') return '1d';
else return 'raw';
}
/**
* Decrease a range of timeframe for one step back
* to make a summary of an updated data query
* @param {string} range - a timeframe range
*/
function decrease_range(range) {
var index = range_input.indexOf(range);
if (index > 0) return range_input[index - 1];
else return range_input[0];
}
function query_generator(device_id, range, qtype, endtime) {
var mls = ms('1s');
var now = endtime ? endtime : new Date().getTime()
var q_data = {
start_absolute:
timeRoundDown(now - ms('1w'), range),
end_absoulte: timeRoundDown(now, range),
metrics: [{
name: device_id,
group_by: [{
name: "tag",
tags: ["attr"]
}],
tags: { attr: ["a12"] },
aggregators: [{
name: 'avg',
sampling: {
value: mls,
unit: "milliseconds"
}
}]
}]
}
console.log(' | ' + q_data.metrics[0].metrics);
return q_data;
}
/**
* To check if the range is validate or not
* since 1m in ms package means 1 minute, not one month
* So it should convert 1m to 4w (4 weeks) instead to represent one month
* @param {string} range - a value for validatation
*/
function validateRange(range) {
if (range_input.indexOf(range) == -1) return 'raw';
else if (range == '1m') return '4w';
else return range;
}
function filterOutliers(someArray) {
if (someArray.length < 4)
return someArray;
let values, q1, q3, iqr, maxValue, minValue;
values = someArray.slice().sort((a, b) => a - b); //copy array fast and sort
if ((values.length / 4) % 1 === 0) { //find quartiles
q1 = 1 / 2 * (values[(values.length / 4)] + values[(values.length / 4) + 1]);
q3 = 1 / 2 * (values[(values.length * (3 / 4))] + values[(values.length * (3 / 4)) + 1]);
} else {
q1 = values[Math.floor(values.length / 4 + 1)];
q3 = values[Math.ceil(values.length * (3 / 4) + 1)];
}
iqr = q3 - q1;
maxValue = q3 + iqr * 1.5;
minValue = q1 - iqr * 1.5;
return values.filter((x) => (x < minValue) && (x > maxValue));
}
function median(arr) {
var arry = arr.sort();
// arr.sort();
// console.log(arry.length);
// console.log("val: " + arry.length + " | " + (arry.length % 2 == 0 ?
// arry[arry.length / 2] + " & " + arry[arry.length / 2 + 1] :
// arry[arry.length / 2 + 0.5]));
med = arry.length % 2 == 0 ?
(arry[arry.length / 2] +
arry[arry.length / 2 + 1]) / 2 :
arry[arry.length / 2 + 0.5];
// console.log(med);
return med;
}
function quartile(data, q) {
data = data.sort((a, b) => a - b);
// console.log(data);
var pos = ((data.length) - 1) * q;
var base = Math.floor(pos);
var rest = pos - base;
if ((data[base + 1] !== undefined)) {
return data[base] + rest * (data[base + 1] - data[base]);
} else {
return data[base];
}
}
function filterQuartile(data, range) {
var quart = quartile(data, range);
// console.log("quart: " + quart);
var res = [];
for (var i = 0; i < data.length; i++) {
if (data[i] > quart) res.push(data[i]);
}
console.log(quart + " _ " + res.sort((a, b) => a - b));
return res;
}
function multiply(data, multiplier) {
for(var i = 0; i < data.length; i++) {
data[i] *= multiplier;
data[i] = Math.round(data[i]);
}
return data;
}
function maxCount(data) {
var tendata = multiply(data, 10);
// console.log("ten: " + tendata);
data = filterQuartile(tendata, 0.3);
var count = 0, max = 0;
var temp = data[0];
var res;
for (var i = 0; i < data.length; i++) {
if (data[i] == temp) count++;
else if (count > max) {
max = count;
res = data[i - 1] / 10;
count = 1;
temp = data[i];
} else {
count = 1;
temp = data[i];
}
}
// console.log("maxcount: " + res);
return res;
}
function getLowerBound(data, range) {
var maxC = maxCount(data);
console.log("maxC: " + maxC + " * lb: " + (maxC - maxC * range));
return maxC - maxC * range;
}
function removeLowerBound(data, range) {
var lower = getLowerBound(data, range);
var res = [];
for (var i = 0; i < data.length; i++) {
if (i % 20 == 0) console.log("data: " + data[i] / 10 + " # lower: " + lower + " # size: " + res.length);
if (data[i] / 10 > lower) res.push(data[i] / 10);
}
// console.log("RemoveLB - befor: " + data.length + " ++ after: " + res.length);
return res;
}
function average(data, range) {
var eachWeight = maxCount(data) / 10;
// console.log("w: " + data);
var estimateMaxWeight = eachWeight + eachWeight * range;
// console.log("eachW: " + eachWeight + " | estW: " + estimateMaxWeight);
var sum = 0, count = 0;
for(var i = 0; i < data.length; i++) {
if ((data[i] / 100) > estimateMaxWeight) {
count += Math.round((data[i] / 100) / eachWeight);
}
sum += data[i] / 100;
// if (i % 20 == 0) {
// console.log("ave ^ data: " + data[i] / 100 + " _ est: " + estimateMaxWeight);
// console.log("curr sum: " + sum + " / curr cnt: " + count + "curr ave: " + sum / (i + count));
// }
}
// console.log(count + data.length);
return sum / (data.length + count);
}
/**
* Query the data from KairosDB
* @param {string} device_id - a device name
* @param {string} range - the specify range for query the result,
* can be chosen between 'raw', '1d', '1w', '1m', and '1y'
*/
function getfeed(device_id, range) {
var q_data = query_generator(device_id, range);
// console.log(q_data);
rest.get(kairos_url +
'api/v1/datapoints/query?query=' +
JSON.stringify(q_data)
).on('complete', function (qres, response) {
console.log('status code (qres): ' +
sc.http_codeToStatus(response.statusCode));
var res = qres.queries[0].results;
for(var i = 0; i < res.length; i++) {
var datas = res[i].values; // value from query
var base_time = timeRoundDown(res[i].values[0][0], '1d'); // first midnight time
var data = []; // final data
var data_in_bt = []; // data in base time
var datavg = [];
var databt = [];
for(var j = 0; j < datas.length; j++) {
if (datas[j][1] == 0) continue;
this_time = timeRoundDown(datas[j][0], '1d');
if (this_time == base_time) {
data_in_bt.push(datas[j][1]);
} else {
// console.log("bt: " + base_time);
var range = 0.6;
data_in_bt = data_in_bt.sort((a, b) => a - b);
data_in_bt = removeLowerBound(data_in_bt, range);
var avg = average(data_in_bt, range);
// Push average and data base time (midnight of each day)
datavg.push(avg);
databt.push(base_time);
data.push(data_in_bt);
data_in_bt = [datas[j][1]];
base_time = this_time;
}
}
console.log(device_id);
console.log(databt);
console.log(datavg);
}
});
}
/**
* For testing and debugging in sequence
*/
function run_all() {
var dev = ['4c988381-2cd9-4334-914d-971241bcf3c2',
'f592b419-380d-4875-9c99-354a4579d03c'];
for(var i = 0; i < dev.length; i++){
// console.log(dev[i]);
getfeed(dev[i], '1d');
}
}
run_all();
\ No newline at end of file
var rest = require('restler');
var ms = require('ms');
var sc = require('./status_code');
var kairos_usr = 'tsdbadmin';
var kairos_pwd = 'RzuCqG14NrWXMfbj*s6m8v';
var kairos_prt = '32222';
var kairos_url = 'http://' + kairos_usr + ":" + kairos_pwd +
'@nxn1.kube.nexpie.com:' +
kairos_prt + '/';
function timeRoundDown(t, scale = '1h', gmt = '7h') {
return t - (t % ms(scale)) - ms(gmt);
}
function query_generator(device_id, range, qtype, endtime) {
var mls = ms('1s');
var now = endtime ? endtime : new Date().getTime()
var q_data = {
start_absolute: timeRoundDown(now - ms('1w'), range),
end_absoulte: timeRoundDown(now, range),
metrics: [{
name: device_id,
group_by: [{
name: "tag",
tags: ["attr"]
}],
tags: {
attr: ["a12"]
},
aggregators: [{
name: 'avg',
sampling: {
value: mls,
unit: "milliseconds"
}
}]
}]
}
console.log(' | ' + q_data.metrics[0].metrics);
return q_data;
}
// return the first value with max count
function firstMaxCount(data) {
var count = 0, max = 0;
var temp = data[0], res = 0;
for (var i = 0; i < data.length; i++) {
if (data[i] == temp) count++;
else {
if (count > max) {
res = data[i - 1];
max = count;
}
temp = data[i];
count = 1;
}
}
return res;
}
// find the value at percentile 'range' (0 to 1)
function percentile (data, range) {
var p = (data.length + 1) * range
var index = Math.floor(p) - 1;
var val = data[index] + (p - index) * (data[index + 1] - data[index]);
return val;
}
// remove if data is less than or equal to that range
function removeLowerBound(data, range) {
if (range == 0) return data;
var p = percentile(data, range);
var res = [];
for (var i = 0; i < data.length; i++) {
if (data[i] > p) res.push(data[i]);
}
// console.log(p + " | " + res);
return res;
}
// get data that happen to be the most max count
function getGeneralData(data) {
var dt = [];
// multiply data with 10 and round to get an integr number
for (var i = 0; i < data.length; i++)
dt.push(Math.round(data[i] * 10));
var max = firstMaxCount(dt);
// console.log(max);
return max / 10;
}
function average(data, noiseRange) {
if (data.length == 0) return 0;
data = data.sort((a, b) => a - b);
data = removeLowerBound(data, noiseRange);
var generalWeight = getGeneralData(data);
var sum = 0, count = 0;
for (var i = 0; i < data.length; i++) {
if (data[i] < (generalWeight * 0.5)) continue;
sum += data[i];
count++;
if (data[i] > (generalWeight * 1.5)) {
// console.log(data[i] + " | " + generalWeight + " | " + sum + " | " + count);
count += Math.round(data[i] / generalWeight) - 1;
}
}
return sum / count;
}
function getWeight(device_id, res, range, noiseFilter, lowest=0) {
let final = [];
for (var i = 0; i < res.length; i++) {
var datas = res[i].values; // value from query
var base_time = timeRoundDown(res[i].values[0][0], range); // first midnight time
var data = []; // final data
var data_in_bt = []; // data in base time
var datavg = [];
var databt = [];
for (var j = 0; j < datas.length; j++) {
if (datas[j][1] == 0) continue;
this_time = timeRoundDown(datas[j][0], range);
if (this_time == base_time && datas[j][1] < lowest) {
continue;
} else if (this_time == base_time) {
data_in_bt.push(datas[j][1]);
} else {
var avg = average(data_in_bt, noiseFilter);
// Push average and data base time (midnight of each day)
// datavg.push(avg);
// databt.push(base_time);
final.push([base_time, avg]);
data.push(data_in_bt);
data_in_bt = [datas[j][1]];
base_time = this_time;
}
}
console.log(device_id);
// console.log(databt);
// console.log(datavg);
}
return final;
}
// function dayAve (device_id, res, lowest=0) {
// getWeight(device_id, res, '1d', 0, lowest);
// }
// function eightHrsAve(device_id, res, lowest = 0) {
// getWeight(device_id, res, '8h', 0, lowest);
// }
/**
* Query the data from KairosDB
* @param {string} device_id - a device name
* @param {string} range - the specify range for query the result,
* can be chosen between 'raw', '1d', '1w', '1m', and '1y'
*/
function getfeed(device_id, range) {
var q_data = query_generator(device_id, range);
// console.log(q_data);
rest.get(kairos_url +
'api/v1/datapoints/query?query=' +
JSON.stringify(q_data)
).on('complete', function (qres, response) {
console.log('status code (qres): ' +
sc.http_codeToStatus(response.statusCode));
var res = qres.queries[0].results;
var f = getWeight(device_id, res, range, 0, 0.1);
console.log(f);
// dayAve(device_id, res, 0.1);
// eightHrsAve(device_id, res, 0.1)
});
}
/**
* For testing and debugging in sequence
*/
function run_all() {
var dev = [
'4c988381-2cd9-4334-914d-971241bcf3c2',
'f592b419-380d-4875-9c99-354a4579d03c'
];
for (var i = 0; i < dev.length; i++) {
// console.log(dev[i]);
getfeed(dev[i], '6h');
}
}
run_all();
\ No newline at end of file
var rest = require('restler');
var ms = require('ms');
var sc = require('./status_code');
var kairos_usr = 'tsdbadmin';
var kairos_pwd = 'RzuCqG14NrWXMfbj*s6m8v';
var kairos_prt = '32223';
var kairos_url = 'http://' + kairos_usr + ":" + kairos_pwd +
'@nxn1.kube.nexpie.com:' +
kairos_prt + '/';
function query_generator(device_id, range, qtype, endtime) {
var mls = ms('1s');
var now = endtime ? endtime : new Date().getTime()
var q_data = {
start_absolute: now - ms(range),
end_absoulte: now,
metrics: [{
name: device_id,
group_by: [{
name: "tag",
tags: ["attr"]
}],
tags: {
attr: ["a12"]
},
aggregators: [{
name: 'avg',
sampling: {
value: mls,
unit: "milliseconds"
}
}]
}]
}
return q_data;
}
// check skewed of data
function skewed(data) {
data = data.sort((a, b) => a - b); // sort data increasing
var q1 = percentile(data, 0.25);
var q2 = percentile(data, 0.5);
var q3 = percentile(data, 0.75);
var lower_range = q2 - q1;
var upper_range = q3 - q2;
var ratio = lower_range / upper_range;
if (ratio < 0.5) return 'right';
else if (ratio > 1.5) return 'left';
return 'normal';
}
// find the outlier and whether clear it or not - left skewed
function skew_remove_out(data) {
if (data.length <= 0) return [0];
data = data.sort((a, b) => a - b); // sort data increasing
var skew = skewed(data);
var q1 = percentile(data, 0.25);
var q2 = percentile(data, 0.5);
var q3 = percentile(data, 0.75);
var iqr = q3 - q1;
var bound, lower, upper;
if (skew == 'normal') {
bound = iqr;
lower = q1 - bound;
upper = q3 + bound;
} else if (skew == 'right') {
bound = q2 - q1;
lower = q1 - bound;
upper = q2 + bound;
} else {
bound = q3 - q2;
lower = q2 - bound;
upper = q3 + bound;
}
var outs = []; // outlier
var not_outs = []; // data without outlier
data.map(x => {
if (x < lower || x > upper) outs.push(x);
else not_outs.push(x);
});
return not_outs;
}
// find the value at percentile 'range' (0 to 1)
function percentile(data, range) {
var p = (data.length + 1) * range;
var index = Math.floor(p) - 1;
var val = data[index] +
(p - index) * (data[index + 1] - data[index]);
return val;
}
function average(data) {
if (data.length == 0) return 0;
var sum = 0;
data.map(x => sum += x);
return sum / data.length;
}
function getWeight(device_id, response, remove_zero = false) {
let final = [];
response.map(res => {
var data = res.values; // value from
var data_bf_out = []; // data in base time
data.map(x => {
if (!remove_zero && x[1] >= 0 || remove_zero && x[1] > 0)
data_bf_out.push(x[1]);
});
var out = skew_remove_out(data_bf_out);
var avg = average(out);
final.push([device_id, avg]);
});
return final;
}
function currentWeight(device_id, traceback = '1d', remove_zero = false) {
var q_data = query_generator(device_id, traceback);
rest.get(kairos_url +
'api/v1/datapoints/query?query=' +
JSON.stringify(q_data)
).on('complete', function (qres, response) {
console.log('status code (qres): ' +
sc.http_codeToStatus(response.statusCode));
var res = qres.queries[0].results;
var f = getWeight(device_id, res, remove_zero);
console.log(f);
});
}
/**
* For testing and debugging in sequence
*/
function run_all() {
var dev = [
'4c988381-2cd9-4334-914d-971241bcf3c2',
'f592b419-380d-4875-9c99-354a4579d03c'
];
dev.map(x => currentWeight(x, '1w', false));
}
run_all();
var rest = require('restler');
var ms = require('ms');
var sc = require('./status_code');
var kairos_usr = 'tsdbadmin';
var kairos_pwd = 'RzuCqG14NrWXMfbj*s6m8v';
var kairos_prt = '32223';
var kairos_url = 'http://' + kairos_usr + ":" + kairos_pwd +
'@nxn1.kube.nexpie.com:' +
kairos_prt + '/';
function timeRoundDown(t, scale = '1h', gmt = '7h') {
return t - (t % ms(scale)) - ms(gmt);
}
function query_generator(device_id, range, endtime) {
var mls = ms('1s');
var now = endtime ? endtime : new Date().getTime()
var q_data = {
start_absolute: now - ms(range),
end_absoulte: now,
metrics: [{
name: device_id,
group_by: [{
name: "tag",
tags: ["attr"]
}],
tags: {
attr: ["a12"]
},
aggregators: [{
name: 'avg',
sampling: {
value: mls,
unit: "milliseconds"
}
}]
}]
}
return q_data;
}
function lie_in_range(x, base, range = 0.5) {
var upper = base + (1.5 * base * range);
var lower = base - (base * range);
if (x < upper && x > lower) return true;
return false;
}
function average(data) {
if (data.length <= 0) return 0;
var sum = 0;
data.map(x => sum += x);
return sum / data.length;
}
function getWeight(device_id, response) {
var final = [];
response.map(res => {
var data = res.values;
var base_time = timeRoundDown(data[0][0], '1d');
var data_in_bt = [];
var base_avg = 0;
data.map(x => {
var data_bt = timeRoundDown(x[0], '1d');
if (data_bt === base_time) {
if (base_avg === 0 || lie_in_range(x[1], base_avg))
data_in_bt.push(x[1]);
} else {
var avg = average(data_in_bt);
if (avg >= base_avg) base_avg = avg;
console.log(base_time + " | " + base_avg + " | " +
x[1] + " | " + lie_in_range(x[1], base_avg));
base_time = data_bt;
if (lie_in_range(x[1], base_avg)) {
data_in_bt = [x[1]];
} else data_in_bt = [];
}
});
var avg = average(data_in_bt);
if (avg >= base_avg) base_avg = avg;
console.log(base_time + " | " + base_avg);
final.push([device_id, base_avg]);
});
return final;
}
function currentWeight(device_id, traceback = '4w') {
var q_data = query_generator(device_id, traceback);
rest.get(kairos_url +
'api/v1/datapoints/query?query=' +
JSON.stringify(q_data)
).on('complete', function (qres, response) {
console.log('status code (qres): ' +
sc.http_codeToStatus(response.statusCode));
var res = qres.queries[0].results;
var f = getWeight(device_id, res);
console.log(f);
});
}
/**
* For testing and debugging in sequence
*/
function run_all() {
var dev = [
'4c988381-2cd9-4334-914d-971241bcf3c2',
'f592b419-380d-4875-9c99-354a4579d03c'
];
dev.map(x => currentWeight(x));
}
run_all();
node_modules
*~
*sublime-*
language: node_js
node_js:
- 0.4
- 0.6
- 0.8
Copyright (c) 2011 Alexander Shtuchkin
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
iconv-lite - pure javascript character encoding conversion
======================================================================
[![Build Status](https://secure.travis-ci.org/ashtuchkin/iconv-lite.png?branch=master)](http://travis-ci.org/ashtuchkin/iconv-lite)
## Features
* Pure javascript. Doesn't need native code compilation.
* Easy API.
* Works on Windows and in sandboxed environments like [Cloud9](http://c9.io).
* Encoding is much faster than node-iconv (see below for performance comparison).
## Usage
var iconv = require('iconv-lite');
// Convert from an encoded buffer to string.
str = iconv.decode(buf, 'win1251');
// Convert from string to an encoded buffer.
buf = iconv.encode("Sample input string", 'win1251');
// Check if encoding is supported
iconv.encodingExists("us-ascii")
## Supported encodings
* All node.js native encodings: 'utf8', 'ucs2', 'ascii', 'binary', 'base64'
* All widespread single byte encodings: Windows 125x family, ISO-8859 family,
IBM/DOS codepages, Macintosh family, KOI8 family.
Aliases like 'latin1', 'us-ascii' also supported.
* Multibyte encodings: 'gbk', 'gb2313', 'Big5', 'cp950'.
Others are easy to add, see the source. Please, participate.
Most encodings are generated from node-iconv. Thank you Ben Noordhuis and iconv authors!
Not supported yet: EUC family, Shift_JIS.
## Encoding/decoding speed
Comparison with node-iconv module (1000x256kb, on Ubuntu 12.04, Core i5/2.5 GHz, Node v0.8.7).
Note: your results may vary, so please always check on your hardware.
operation iconv@1.2.4 iconv-lite@0.2.4
----------------------------------------------------------
encode('win1251') ~115 Mb/s ~230 Mb/s
decode('win1251') ~95 Mb/s ~130 Mb/s
## Notes
When decoding, a 'binary'-encoded string can be used as a source buffer.
Untranslatable characters are set to � or ?. No transliteration is currently supported, pull requests are welcome.
## Testing
git clone git@github.com:ashtuchkin/iconv-lite.git
cd iconv-lite
npm install
npm test
# To view performance:
node test/performance.js
## TODO
* Support streaming character conversion, something like util.pipe(req, iconv.fromEncodingStream('latin1')).
* Add more encodings.
* Add transliteration (best fit char).
* Add tests and correct support of variable-byte encodings (currently work is delegated to node).
iconv-lite - native javascript conversion between character encodings.
======================================================================
## Usage
var iconv = require('iconv-lite');
// Convert from an encoded buffer to string.
str = iconv.fromEncoding(buf, 'win-1251');
// Or
str = iconv.decode(buf, 'win-1251');
// Convert from string to an encoded buffer.
buf = iconv.toEncoding("Sample input string", 'win-1251');
// Or
buf = iconv.encode("Sample input string", 'win-1251');
## Supported encodings
Currently only a small part of encodings supported:
* All node.js native encodings: 'utf8', 'ucs2', 'ascii', 'binary', 'base64'.
* 'latin1'
* Cyrillic encodings: 'windows-1251', 'koi8-r', 'iso 8859-5'.
Other encodings are easy to add, see the source. Please, participate.
## Encoding/decoding speed
Comparison with iconv module (1000 times 256kb, on Core i5/2.5 GHz).
Operation\module iconv iconv-lite (this)
toEncoding('win1251') 19.57 mb/s 49.04 mb/s
fromEncoding('win1251') 16.39 mb/s 24.11 mb/s
## Notes
This module is JavaScript-only, thus can be used in a sandboxed environment like [Cloud9](http://c9.io).
Untranslatable characters are set to '?'. No transliteration is currently supported, pull requests are welcome.
## Testing
npm install --dev iconv-lite
vows
## TODO
* Support streaming character conversion, something like util.pipe(req, iconv.fromEncodingStream('latin1')).
* Add more encodings.
* Add transliteration (best fit char).
* Add tests and correct support of variable-byte encodings (currently work is delegated to node).
var big5Table = require('./table/big5.js');
module.exports = {
'windows950': 'big5',
'cp950': 'big5',
'big5': {
type: 'table',
table: big5Table
}
}
var gbkTable = require('./table/gbk.js');
module.exports = {
'windows936': 'gbk',
'gb2312': 'gbk',
'gbk': {
type: 'table',
table: gbkTable
}
}
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
var http = require('http');
var fs = require('fs');
// BIG5
var cp950_b2u = {host:'moztw.org',path:'/docs/big5/table/cp950-b2u.txt'},
cp950_u2b = {host:'moztw.org',path:'/docs/big5/table/cp950-u2b.txt'},
cp950_moz18_b2u = {host:'moztw.org',path:'/docs/big5/table/moz18-b2u.txt'};
http.get(cp950_moz18_b2u, function(res) {
var data = '';
res.on('data', function(chunk) {
data += chunk;
});
res.on('end', function() {
var table = {};
data = data.split('\n').slice(1);
data.forEach(function(line, idx) {
var pair = line.split(' ');
var key = parseInt(pair[0]);
var val = parseInt(pair[1]);
table[key] = val;
});
fs.createWriteSync('encodings/table/big5.js',
'module.exports = ' + JSON.stringify(table) + ';');
});
});
var fs = require("fs");
var Iconv = require("iconv").Iconv;
var encodingFamilies = [
{
// Windows code pages
encodings: [1250, 1251, 1252, 1253, 1254, 1255, 1256, 1257, 1258],
convert: function(cp) {
return {
name: "windows-"+cp,
aliases: ["win"+cp, "cp"+cp, ""+cp],
}
}
},
{
// ISO-8859 code pages
encodings: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, 15, 16],
convert: function(i) {
return {
name: "iso-8859-"+i,
aliases: ["cp"+(28590+i), (28590+i)],
}
}
},
{
// IBM/DOS code pages
encodings: [437, 737, 775, 850, 852, 855, 857, 858, 860, 861, 862, 863, 864, 865, 866, 869],
convert: function(cp) {
return {
name: "CP"+cp,
aliases: ["ibm"+cp, ""+cp],
}
}
},
{
// Macintosh code pages
encodings: ["macCroatian", "macCyrillic", "macGreek",
"macIceland", "macRoman", "macRomania",
"macThai", "macTurkish", "macUkraine"],
},
{
// KOI8 code pages
encodings: ["KOI8-R", "KOI8-U"],
},
];
var encodings = {
// Aliases.
"ascii8bit": "ascii",
"usascii": "ascii",
"latin1": "iso88591",
"latin2": "iso88592",
"latin3": "iso88593",
"latin4": "iso88594",
"latin6": "iso885910",
"latin7": "iso885913",
"latin8": "iso885914",
"latin9": "iso885915",
"latin10": "iso885916",
"cp819": "iso88951",
"arabic": "iso88596",
"arabic8": "iso88596",
"greek" : "iso88597",
"greek8" : "iso88597",
"hebrew": "iso88598",
"hebrew8": "iso88598",
"turkish": "iso88599",
"turkish8": "iso88599",
"thai": "iso885911",
"thai8": "iso885911",
"tis620": "iso885911",
"windows874": "iso885911",
"win874": "iso885911",
"cp874": "iso885911",
"874": "iso885911",
"celtic": "iso885914",
"celtic8": "iso885914",
"cp20866": "koi8r",
"20866": "koi8r",
"ibm878": "koi8r",
"cp21866": "koi8u",
"21866": "koi8u",
"ibm1168": "koi8u",
};
// Add all encodings from encodingFamilies.
encodingFamilies.forEach(function(family){
family.encodings.forEach(function(encoding){
if (family.convert)
encoding = family.convert(encoding);
var encodingIconvName = encoding.name ? encoding.name : encoding;
var encodingName = encodingIconvName.replace(/[-_]/g, "").toLowerCase();
encodings[encodingName] = {
type: "singlebyte",
chars: generateCharsString(encodingIconvName)
};
if (encoding.aliases)
encoding.aliases.forEach(function(alias){
encodings[alias] = encodingName;
});
});
});
// Write encodings.
fs.writeFileSync("encodings/singlebyte.js",
"module.exports = " + JSON.stringify(encodings, undefined, " ") + ";");
function generateCharsString(encoding) {
console.log("Generate encoding for " + encoding);
var iconvToUtf8 = new Iconv(encoding, "UTF-8");
var chars = "";
for (var b = 0x80; b < 0x100; b++) {
try {
var convertedChar = iconvToUtf8.convert(new Buffer([b])).toString();
if (convertedChar.length != 1)
throw new Error("Single-byte encoding error: Must return single char.");
} catch (exception) {
if (exception.code === "EILSEQ") {
convertedChar = "\ufffd";
} else {
throw exception;
}
}
chars += convertedChar;
}
return chars;
}
var RE_SPACEDASH = /[- ]/g;
// Module exports
var iconv = module.exports = {
toEncoding: function(str, encoding) {
return iconv.getCodec(encoding).toEncoding(str);
},
fromEncoding: function(buf, encoding) {
return iconv.getCodec(encoding).fromEncoding(buf);
},
encodingExists: function(enc) {
loadEncodings();
enc = enc.replace(RE_SPACEDASH, "").toLowerCase();
return (iconv.encodings[enc] !== undefined);
},
defaultCharUnicode: '�',
defaultCharSingleByte: '?',
encodingsLoaded: false,
// Get correct codec for given encoding.
getCodec: function(encoding) {
loadEncodings();
var enc = encoding || "utf8";
var codecOptions = undefined;
while (1) {
if (getType(enc) === "String")
enc = enc.replace(RE_SPACEDASH, "").toLowerCase();
var codec = iconv.encodings[enc];
var type = getType(codec);
if (type === "String") {
// Link to other encoding.
codecOptions = {originalEncoding: enc};
enc = codec;
}
else if (type === "Object" && codec.type != undefined) {
// Options for other encoding.
codecOptions = codec;
enc = codec.type;
}
else if (type === "Function")
// Codec itself.
return codec(codecOptions);
else
throw new Error("Encoding not recognized: '" + encoding + "' (searched as: '"+enc+"')");
}
},
// Define basic encodings
encodings: {
internal: function(options) {
return {
toEncoding: toInternalEncoding,
fromEncoding: fromInternalEncoding,
options: options
};
},
utf8: "internal",
ucs2: "internal",
binary: "internal",
ascii: "internal",
base64: "internal",
// Codepage single-byte encodings.
singlebyte: function(options) {
// Prepare chars if needed
if (!options.charsBuf) {
if (!options.chars || (options.chars.length !== 128 && options.chars.length !== 256))
throw new Error("Encoding '"+options.type+"' has incorrect 'chars' (must be of len 128 or 256)");
if (options.chars.length === 128)
options.chars = asciiString + options.chars;
options.charsBuf = new Buffer(options.chars, 'ucs2');
}
if (!options.revCharsBuf) {
options.revCharsBuf = new Buffer(65536);
var defChar = iconv.defaultCharSingleByte.charCodeAt(0);
for (var i = 0; i < options.revCharsBuf.length; i++)
options.revCharsBuf[i] = defChar;
for (var i = 0; i < options.chars.length; i++)
options.revCharsBuf[options.chars.charCodeAt(i)] = i;
}
return {
toEncoding: toSingleByteEncoding,
fromEncoding: fromSingleByteEncoding,
options: options,
};
},
// Codepage double-byte encodings.
table: function(options) {
if (!options.table) {
throw new Error("Encoding '" + options.type + "' has incorect 'table' option");
}
if (!options.revCharsTable) {
var revCharsTable = options.revCharsTable = {};
for (var i = 0; i <= 0xFFFF; i++) {
revCharsTable[i] = 0;
}
var table = options.table;
for (var key in table) {
revCharsTable[table[key]] = +key;
}
}
return {
toEncoding: toTableEncoding,
fromEncoding: fromTableEncoding,
options: options,
};
}
}
};
function toInternalEncoding(str) {
return new Buffer(ensureString(str), this.options.originalEncoding);
}
function fromInternalEncoding(buf) {
return ensureBuffer(buf).toString(this.options.originalEncoding);
}
function toTableEncoding(str) {
str = ensureString(str);
var strLen = str.length;
var revCharsTable = this.options.revCharsTable;
var newBuf = new Buffer(strLen*2), gbkcode, unicode,
defaultChar = revCharsTable[iconv.defaultCharUnicode.charCodeAt(0)];
for (var i = 0, j = 0; i < strLen; i++) {
unicode = str.charCodeAt(i);
if (unicode >> 7) {
gbkcode = revCharsTable[unicode] || defaultChar;
newBuf[j++] = gbkcode >> 8; //high byte;
newBuf[j++] = gbkcode & 0xFF; //low byte
} else {//ascii
newBuf[j++] = unicode;
}
}
return newBuf.slice(0, j);
}
function fromTableEncoding(buf) {
buf = ensureBuffer(buf);
var bufLen = buf.length;
var table = this.options.table;
var newBuf = new Buffer(bufLen*2), unicode, gbkcode,
defaultChar = iconv.defaultCharUnicode.charCodeAt(0);
for (var i = 0, j = 0; i < bufLen; i++, j+=2) {
gbkcode = buf[i];
if (gbkcode & 0x80) {
gbkcode = (gbkcode << 8) + buf[++i];
unicode = table[gbkcode] || defaultChar;
} else {
unicode = gbkcode;
}
newBuf[j] = unicode & 0xFF; //low byte
newBuf[j+1] = unicode >> 8; //high byte
}
return newBuf.slice(0, j).toString('ucs2');
}
function toSingleByteEncoding(str) {
str = ensureString(str);
var buf = new Buffer(str.length);
var revCharsBuf = this.options.revCharsBuf;
for (var i = 0; i < str.length; i++)
buf[i] = revCharsBuf[str.charCodeAt(i)];
return buf;
}
function fromSingleByteEncoding(buf) {
buf = ensureBuffer(buf);
// Strings are immutable in JS -> we use ucs2 buffer to speed up computations.
var charsBuf = this.options.charsBuf;
var newBuf = new Buffer(buf.length*2);
var idx1 = 0, idx2 = 0;
for (var i = 0, _len = buf.length; i < _len; i++) {
idx1 = buf[i]*2; idx2 = i*2;
newBuf[idx2] = charsBuf[idx1];
newBuf[idx2+1] = charsBuf[idx1+1];
}
return newBuf.toString('ucs2');
}
// Add aliases to convert functions
iconv.encode = iconv.toEncoding;
iconv.decode = iconv.fromEncoding;
// Load other encodings manually from files in /encodings dir.
function loadEncodings() {
if (!iconv.encodingsLoaded) {
[ require('./encodings/singlebyte'),
require('./encodings/gbk'),
require('./encodings/big5')
].forEach(function(encodings) {
for (var key in encodings)
iconv.encodings[key] = encodings[key]
});
iconv.encodingsLoaded = true;
}
}
// Utilities
var asciiString = '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f'+
' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f';
var ensureBuffer = function(buf) {
buf = buf || new Buffer(0);
return (buf instanceof Buffer) ? buf : new Buffer(""+buf, "binary");
}
var ensureString = function(str) {
str = str || "";
return (str instanceof Buffer) ? str.toString('utf8') : (""+str);
}
var getType = function(obj) {
return Object.prototype.toString.call(obj).slice(8, -1);
}
{
"_from": "iconv-lite@0.2.11",
"_id": "iconv-lite@0.2.11",
"_inBundle": false,
"_integrity": "sha1-HOYKOleGSiktEyH/RgnKS7llrcg=",
"_location": "/iconv-lite",
"_phantomChildren": {},
"_requested": {
"type": "version",
"registry": true,
"raw": "iconv-lite@0.2.11",
"name": "iconv-lite",
"escapedName": "iconv-lite",
"rawSpec": "0.2.11",
"saveSpec": null,
"fetchSpec": "0.2.11"
},
"_requiredBy": [
"/restler"
],
"_resolved": "http://registry.npmjs.org/iconv-lite/-/iconv-lite-0.2.11.tgz",
"_shasum": "1ce60a3a57864a292d1321ff4609ca4bb965adc8",
"_spec": "iconv-lite@0.2.11",
"_where": "D:\\My Jobs\\Job 18\\chicweight\\node_modules\\restler",
"author": {
"name": "Alexander Shtuchkin",
"email": "ashtuchkin@gmail.com"
},
"bugs": {
"url": "https://github.com/ashtuchkin/iconv-lite/issues"
},
"bundleDependencies": false,
"contributors": [
{
"name": "Jinwu Zhan",
"url": "https://github.com/jenkinv"
},
{
"name": "Adamansky Anton",
"url": "https://github.com/adamansky"
},
{
"name": "George Stagas",
"url": "https://github.com/stagas"
},
{
"name": "Mike D Pilsbury",
"url": "https://github.com/pekim"
},
{
"name": "Niggler",
"url": "https://github.com/Niggler"
},
{
"name": "wychi",
"url": "https://github.com/wychi"
},
{
"name": "David Kuo",
"url": "https://github.com/david50407"
},
{
"name": "ChangZhuo Chen",
"url": "https://github.com/czchen"
},
{
"name": "Lee Treveil",
"url": "https://github.com/leetreveil"
},
{
"name": "Brian White",
"url": "https://github.com/mscdex"
}
],
"deprecated": false,
"description": "Convert character encodings in pure javascript.",
"devDependencies": {
"iconv": ">=1.1",
"vows": ""
},
"engines": {
"node": ">=0.4.0"
},
"homepage": "https://github.com/ashtuchkin/iconv-lite",
"keywords": [
"iconv",
"convert",
"charset"
],
"license": "MIT",
"main": "index.js",
"name": "iconv-lite",
"repository": {
"type": "git",
"url": "git://github.com/ashtuchkin/iconv-lite.git"
},
"scripts": {
"test": "vows --spec"
},
"version": "0.2.11"
}
var vows = require('vows'),
fs = require('fs'),
assert = require('assert'),
iconv = require(__dirname + '/../');
var testString = "中文abc", //unicode contains Big5-code and ascii
testStringBig5Buffer = new Buffer([0xa4,0xa4,0xa4,0xe5,0x61,0x62,0x63]),
testString2 = '測試',
testStringBig5Buffer2 = new Buffer([0xb4, 0xfa, 0xb8, 0xd5]);
vows.describe("Big5 tests").addBatch({
"Big5 correctly encoded/decoded": function() {
assert.strictEqual(iconv.toEncoding(testString, "big5").toString('binary'), testStringBig5Buffer.toString('binary'));
assert.strictEqual(iconv.fromEncoding(testStringBig5Buffer, "big5"), testString);
assert.strictEqual(iconv.toEncoding(testString2, 'big5').toString('binary'), testStringBig5Buffer2.toString('binary'));
assert.strictEqual(iconv.fromEncoding(testStringBig5Buffer2, 'big5'), testString2);
},
"cp950 correctly encoded/decoded": function() {
assert.strictEqual(iconv.toEncoding(testString, "cp950").toString('binary'), testStringBig5Buffer.toString('binary'));
assert.strictEqual(iconv.fromEncoding(testStringBig5Buffer, "cp950"), testString);
},
"Big5 file read decoded,compare with iconv result": function() {
var contentBuffer = fs.readFileSync(__dirname+"/big5File.txt");
var str = iconv.fromEncoding(contentBuffer, "big5");
var iconvc = new (require('iconv').Iconv)('big5','utf8');
assert.strictEqual(iconvc.convert(contentBuffer).toString(), str);
},
"Big5 correctly decodes and encodes characters · and ×": function() {
// https://github.com/ashtuchkin/iconv-lite/issues/13
// Reference: http://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP950.TXT
var chars = "·×";
var big5Chars = new Buffer([0xA1, 0x50, 0xA1, 0xD1]);
assert.strictEqual(iconv.toEncoding(chars, "big5").toString('binary'), big5Chars.toString('binary'));
assert.strictEqual(iconv.fromEncoding(big5Chars, "big5"), chars)
},
}).export(module)
<HTML>
<HEAD>
<TITLE> meta 標籤的使用:中文網頁 </TITLE>
<meta HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=big5">
</HEAD>
<BODY>
這是一個繁體中文網頁!<br>
(This page uses big5 character set.)<br>
charset=big5
</BODY>
</HTML>
\ No newline at end of file
var vows = require('vows'),
assert = require('assert'),
iconv = require(__dirname+'/../');
var baseStrings = {
empty: "",
hi: "Привет!",
ascii: '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f'+
' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f',
rus: "АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюя",
additional1: "ЂЃ‚ѓ„…†‡€‰Љ‹ЊЌЋЏђ‘’“”•–—™љ›њќћџ ЎўЈ¤Ґ¦§Ё©Є«¬\xAD®Ї°±Ііґµ¶·ё№є»јЅѕї",
additional2: "─│┌┐└┘├┤┬┴┼▀▄█▌▐░▒▓⌠■∙√≈≤≥ ⌡°²·÷═║╒ё╓╔╕╖╗╘╙╚╛╜╝╞╟╠╡Ё╢╣╤╥╦╧╨╩╪╫╬©",
additional3: " ЁЂЃЄЅІЇЈЉЊЋЌ­ЎЏ№ёђѓєѕіїјљњћќ§ўџ",
untranslatable: "£Åçþÿ¿",
};
var encodings = [{
name: "Win-1251",
variations: ['win1251', 'Windows-1251', 'windows1251', 'CP1251', 1251],
encodedStrings: {
empty: new Buffer(''),
hi: new Buffer('\xcf\xf0\xe8\xe2\xe5\xf2!', 'binary'),
ascii: new Buffer(baseStrings.ascii, 'binary'),
rus: new Buffer('\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff', 'binary'),
additional1: new Buffer('\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf','binary'),
}
}, {
name: "Koi8-R",
variations: ['koi8r', 'KOI8-R', 'cp20866', 20866],
encodedStrings: {
empty: new Buffer(''),
hi: new Buffer('\xf0\xd2\xc9\xd7\xc5\xd4!', 'binary'),
ascii: new Buffer(baseStrings.ascii, 'binary'),
rus: new Buffer('\xe1\xe2\xf7\xe7\xe4\xe5\xf6\xfa\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf2\xf3\xf4\xf5\xe6\xe8\xe3\xfe\xfb\xfd\xff\xf9\xf8\xfc\xe0\xf1\xc1\xc2\xd7\xc7\xc4\xc5\xd6\xda\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd2\xd3\xd4\xd5\xc6\xc8\xc3\xde\xdb\xdd\xdf\xd9\xd8\xdc\xc0\xd1', 'binary'),
additional2: new Buffer('\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf', 'binary'),
}
}, {
name: "ISO 8859-5",
variations: ['iso88595', 'ISO-8859-5', 'ISO 8859-5', 'cp28595', 28595],
encodedStrings: {
empty: new Buffer(''),
hi: new Buffer('\xbf\xe0\xd8\xd2\xd5\xe2!', 'binary'),
ascii: new Buffer(baseStrings.ascii, 'binary'),
rus: new Buffer('\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef', 'binary'),
additional3: new Buffer('\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff', 'binary'),
}
}];
var testsBatch = {};
encodings.forEach(function(encoding) {
var enc = encoding.variations[0];
var key = "hi";
var tests = {
"Convert to empty buffer": function() {
assert.strictEqual(iconv.toEncoding("", enc).toString('binary'), new Buffer('').toString('binary'));
},
"Convert from empty buffer": function() {
assert.strictEqual(iconv.fromEncoding(new Buffer(''), enc), "");
},
"Convert from buffer": function() {
for (var key in encoding.encodedStrings)
assert.strictEqual(iconv.fromEncoding(encoding.encodedStrings[key], enc),
baseStrings[key]);
},
"Convert to buffer": function() {
for (var key in encoding.encodedStrings)
assert.strictEqual(iconv.toEncoding(baseStrings[key], enc).toString('binary'),
encoding.encodedStrings[key].toString('binary'));
},
"Try different variations of encoding": function() {
encoding.variations.forEach(function(enc) {
assert.strictEqual(iconv.fromEncoding(encoding.encodedStrings[key], enc), baseStrings[key]);
assert.strictEqual(iconv.toEncoding(baseStrings[key], enc).toString('binary'), encoding.encodedStrings[key].toString('binary'));
});
},
"Untranslatable chars are converted to defaultCharSingleByte": function() {
var expected = baseStrings.untranslatable.split('').map(function(c) {return iconv.defaultCharSingleByte; }).join('');
assert.strictEqual(iconv.toEncoding(baseStrings.untranslatable, enc).toString('binary'), expected); // Only '?' characters.
}
};
testsBatch[encoding.name+":"] = tests;
});
vows.describe("Test Cyrillic encodings").addBatch(testsBatch).export(module);
var vows = require('vows'),
fs = require('fs'),
assert = require('assert'),
iconv = require(__dirname+'/../');
var testString = "中国abc",//unicode contains GBK-code and ascii
testStringGBKBuffer = new Buffer([0xd6,0xd0,0xb9,0xfa,0x61,0x62,0x63]);
vows.describe("GBK tests").addBatch({
"Vows is working": function() {},
"Return values are of correct types": function() {
assert.ok(iconv.toEncoding(testString, "utf8") instanceof Buffer);
var s = iconv.fromEncoding(new Buffer(testString), "utf8");
assert.strictEqual(Object.prototype.toString.call(s), "[object String]");
},
"GBK correctly encoded/decoded": function() {
assert.strictEqual(iconv.toEncoding(testString, "GBK").toString('binary'), testStringGBKBuffer.toString('binary'));
assert.strictEqual(iconv.fromEncoding(testStringGBKBuffer, "GBK"), testString);
},
"GB2312 correctly encoded/decoded": function() {
assert.strictEqual(iconv.toEncoding(testString, "GB2312").toString('binary'), testStringGBKBuffer.toString('binary'));
assert.strictEqual(iconv.fromEncoding(testStringGBKBuffer, "GB2312"), testString);
},
"GBK file read decoded,compare with iconv result": function() {
var contentBuffer = fs.readFileSync(__dirname+"/gbkFile.txt");
var str = iconv.fromEncoding(contentBuffer, "GBK");
var iconvc = new (require('iconv').Iconv)('GBK','utf8');
assert.strictEqual(iconvc.convert(contentBuffer).toString(), str);
},
"GBK correctly decodes and encodes characters · and ×": function() {
// https://github.com/ashtuchkin/iconv-lite/issues/13
// Reference: http://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP936.TXT
var chars = "·×";
var gbkChars = new Buffer([0xA1, 0xA4, 0xA1, 0xC1]);
assert.strictEqual(iconv.toEncoding(chars, "GBK").toString('binary'), gbkChars.toString('binary'));
assert.strictEqual(iconv.fromEncoding(gbkChars, "GBK"), chars)
},
}).export(module)
<!doctype html><html><head><meta http-equiv="Content-Type" content="text/html;charset=gb2312"><title>百度一下,你就知道 </title><style>html{overflow-y:auto}body{font:12px arial;text-align:center;background:#fff}body,p,form,ul,li{margin:0;padding:0;list-style:none}body,form,#fm{position:relative}td{text-align:left}img{border:0}a{color:#00c}a:active{color:#f60}#u{padding:7px 10px 3px 0;text-align:right}#m{width:680px;margin:0 auto}#nv{font-size:16px;margin:0 0 4px;text-align:left;text-indent:117px}#nv a,#nv b,.btn,#lk{font-size:14px}#fm{padding-left:90px;text-align:left}#kw{width:404px;height:22px;padding:4px 7px;padding:6px 7px 2px\9;font:16px arial;background:url(http://www.baidu.com/img/i-1.0.0.png) no-repeat -304px 0;_background-attachment:fixed;border:1px solid #cdcdcd;border-color:#9a9a9a #cdcdcd #cdcdcd #9a9a9a;vertical-align:top}.btn{width:95px;height:32px;padding:0;padding-top:2px\9;border:0;background:#ddd url(http://www.baidu.com/img/i-1.0.0.png) no-repeat;cursor:pointer}.btn_h{background-position:-100px 0}#kw,.btn_wr{margin:0 5px 0 0}.btn_wr{width:97px;height:34px;display:inline-block;background:url(http://www.baidu.com/img/i-1.0.0.png) no-repeat -202px 0;_top:1px;*position:relative}#lk{margin:33px 0}#lk span{font:14px "宋体"}#lm{height:60px}#lh{margin:16px 0 5px;word-spacing:3px}.tools{position:absolute;top:-4px;*top:10px;right:-13px;}#mHolder{width:62px;position:relative;z-index:296;display:none}#mCon{height:18px;line-height:18px;position:absolute;cursor:pointer;padding:0 18px 0 0;background:url(http://www.baidu.com/img/bg-1.0.0.gif) no-repeat right -134px;background-position:right -136px\9}#mCon span{color:#00c;cursor:default;display:block}#mCon .hw{text-decoration:underline;cursor:pointer}#mMenu{width:56px;border:1px solid #9a99ff;list-style:none;position:absolute;right:7px;top:28px;display:none;background:#fff}#mMenu a{width:100%;height:100%;display:block;line-height:22px;text-indent:6px;text-decoration:none}#mMenu a:hover{background:#d9e1f6}#mMenu .ln{height:1px;background:#ccf;overflow:hidden;margin:2px;font-size:1px;line-height:1px}#cp,#cp a{color:#77c}#seth{display:none;behavior:url(#default#homepage)}#setf{display:none}</style>
</head>
<body><div id="u"><a href="http://www.baidu.com/gaoji/preferences.html" name="tj_setting">搜索设置</a>&nbsp;|&nbsp;<a href="http://passport.baidu.com/?login&tpl=mn" name="tj_login">登录</a></div>
<div id="m"><p id="lg"><img src="http://www.baidu.com/img/baidu_sylogo1.gif" width="270" height="129" usemap="#mp"><map name="mp"><area shape="rect" coords="40,25,230,95" href="http://hi.baidu.com/baidu/" target="_blank" title="点此进入 百度的空间" ></map></p><p id="nv"><a href="http://news.baidu.com">新&nbsp;闻</a> <b>网&nbsp;页</b> <a href="http://tieba.baidu.com">贴&nbsp;吧</a> <a href="http://zhidao.baidu.com">知&nbsp;道</a> <a href="http://mp3.baidu.com">MP3</a> <a href="http://image.baidu.com">图&nbsp;片</a> <a href="http://video.baidu.com">视&nbsp;频</a> <a href="http://map.baidu.com">地&nbsp;图</a></p><div id="fm"><form name="f" action="/s"><input type="text" name="wd" id="kw" maxlength="100"><input type="hidden" name="rsv_bp" value="0"><input type="hidden" name="rsv_spt" value="3"><span class="btn_wr"><input type="submit" value="百度一下" id="su" class="btn" onmousedown="this.className='btn btn_h'" onmouseout="this.className='btn'"></span></form><span class="tools"><span id="mHolder"><div id="mCon"><span>输入法</span></div></span></span><ul id="mMenu"><li><a href="#" name="ime_hw">手写</a></li><li><a href="#" name="ime_py">拼音</a></li><li class="ln"></li><li><a href="#" name="ime_cl">关闭</a></li></ul></div>
<p id="lk"><a href="http://hi.baidu.com">空间</a> <a href="http://baike.baidu.com">百科</a> <a href="http://www.hao123.com">hao123</a><span> | <a href="/more/">更多&gt;&gt;</a></span></p><p id="lm"></p><p><a id="seth" onClick="this.setHomePage('http://www.baidu.com')" href="http://utility.baidu.com/traf/click.php?id=215&url=http://www.baidu.com" onmousedown="return ns_c({'fm':'behs','tab':'homepage','pos':0})">把百度设为主页</a><a id="setf" onClick="fa(this)" href="javascript:void(0)" onmousedown="return ns_c({'fm':'behs','tab':'favorites','pos':0})">把百度加入收藏夹</a></p>
<p id="lh"><a href="http://e.baidu.com/?refer=888">加入百度推广</a> | <a href="http://top.baidu.com">搜索风云榜</a> | <a href="http://home.baidu.com">关于百度</a> | <a href="http://ir.baidu.com">About Baidu</a></p><p id="cp">&copy;2011 Baidu <a href="/duty/">使用百度前必读</a> <a href="http://www.miibeian.gov.cn" target="_blank">京ICP证030173号</a> <img src="http://gimg.baidu.com/img/gs.gif"></p></div></body>
<script>var w=window,d=document,n=navigator,k=d.f.wd,a=d.getElementById("nv").getElementsByTagName("a"),isIE=n.userAgent.indexOf("MSIE")!=-1&&!window.opera;for(var i=0;i<a.length;i++){a[i].onclick=function(){if(k.value.length>0){var C=this,A=C.href,B=encodeURIComponent(k.value);if(A.indexOf("q=")!=-1){C.href=A.replace(/q=[^&\x24]*/,"q="+B)}else{this.href+="?q="+B}}}}(function(){if(/q=([^&]+)/.test(location.search)){k.value=decodeURIComponent(RegExp["\x241"])}})();if(n.cookieEnabled&&!/sug?=0/.test(d.cookie)){d.write("<script src=http://www.baidu.com/js/bdsug.js?v=1.0.3.0><\/script>")}function addEV(C,B,A){if(w.attachEvent){C.attachEvent("on"+B,A)}else{if(w.addEventListener){C.addEventListener(B,A,false)}}}function G(A){return d.getElementById(A)}function ns_c(E){var F=encodeURIComponent(window.document.location.href),D="",A="",B="",C=window["BD_PS_C"+(new Date()).getTime()]=new Image();for(v in E){A=E[v];D+=v+"="+A+"&"}B="&mu="+F;C.src="http://nsclick.baidu.com/v.gif?pid=201&pj=www&"+D+"path="+F+"&t="+new Date().getTime();return true}if(/\bbdime=[12]/.test(d.cookie)){document.write("<script src=http://www.baidu.com/cache/ime/js/openime-1.0.0.js><\/script>")}(function(){var B=G("user"),A=G("userMenu");if(B&&A){addEV(B,"click",function(C){A.style.display=A.style.display=="block"?"none":"block";window.event?C.cancelBubble=true:C.stopPropagation()});addEV(document,"click",function(){A.style.display="none"})}})();(function(){var E=G("u").getElementsByTagName("a"),C=G("nv").getElementsByTagName("a"),I=G("lk").getElementsByTagName("a"),B="";var A=["news","tieba","zhidao","mp3","img","video","map"];var H=["hi","baike","hao123","more"];if(G("un")&&G("un").innerHTML!=""){B=G("un").innerHTML}function D(J){addEV(J,"mousedown",function(L){var L=L||window.event;var K=L.target||L.srcElement;ns_c({fm:"behs",tab:K.name||"tj_user",un:encodeURIComponent(B)})})}for(var F=0;F<E.length;F++){D(E[F])}for(var F=0;F<C.length;F++){C[F].name="tj_"+A[F];D(C[F])}for(var F=0;F<I.length;F++){I[F].name="tj_"+H[F];D(I[F])}})();addEV(w,"load",function(){k.focus()});w.onunload=function(){};</script>
<script type="text/javascript" src="http://www.baidu.com/cache/hps/js/hps-1.2.js"></script>
</html><!--b762345d979562e8-->
\ No newline at end of file
var vows = require('vows'),
assert = require('assert'),
iconv = require(__dirname+'/../');
var baseStrings = {
empty: "",
hi: "Γειά!",
ascii: '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f'+
' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f',
greek: "αβγδεζηθικλμνξοπρστυφχψωΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩάέήίόύώΆΈΉΊΌΎΏϊϋΪΫ",
untranslatable: "Åçþÿ¿"
};
var encodings = [{
name: "windows1253",
variations: ['windows-1253', 'win-1253', 'win1253', 'cp1253', 'cp-1253', 1253],
encodedStrings: {
empty: new Buffer(''),
hi: new Buffer('\xc3\xe5\xe9\xdc!', 'binary'),
ascii: new Buffer(baseStrings.ascii, 'binary'),
greek: new Buffer('\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xdc\xdd\xde\xdf\xfc\xfd\xfe\xa2\xb8\xb9\xba\xbc\xbe\xbf\xfa\xfb\xda\xdb', 'binary'),
}
}, {
name: "iso88597",
variations: ['iso-8859-7', 'greek', 'greek8', 'cp28597', 'cp-28597', 28597],
encodedStrings: {
empty: new Buffer(''),
hi: new Buffer('\xc3\xe5\xe9\xdc!', 'binary'),
ascii: new Buffer(baseStrings.ascii, 'binary'),
greek: new Buffer('\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xdc\xdd\xde\xdf\xfc\xfd\xfe\xb6\xb8\xb9\xba\xbc\xbe\xbf\xfa\xfb\xda\xdb', 'binary'),
}
}, {
name: "cp737",
variations: ['cp-737', 737],
encodedStrings: {
empty: new Buffer(''),
hi: new Buffer('\x82\x9c\xa0\xe1!', 'binary'),
ascii: new Buffer(baseStrings.ascii, 'binary'),
greek: new Buffer('\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xab\xac\xad\xae\xaf\xe0\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\xe1\xe2\xe3\xe5\xe6\xe7\xe9\xea\xeb\xec\xed\xee\xef\xf0\xe4\xe8\xf4\xf5', 'binary'),
}
}];
var testsBatch = {};
encodings.forEach(function(encoding) {
var enc = encoding.variations[0];
var key = "hi";
var tests = {
"Convert to empty buffer": function() {
assert.strictEqual(iconv.toEncoding("", enc).toString('binary'), new Buffer('').toString('binary'));
},
"Convert from empty buffer": function() {
assert.strictEqual(iconv.fromEncoding(new Buffer(''), enc), "");
},
"Convert from buffer": function() {
for (var key in encoding.encodedStrings)
assert.strictEqual(iconv.fromEncoding(encoding.encodedStrings[key], enc),
baseStrings[key]);
},
"Convert to buffer": function() {
for (var key in encoding.encodedStrings)
assert.strictEqual(iconv.toEncoding(baseStrings[key], enc).toString('binary'),
encoding.encodedStrings[key].toString('binary'));
},
"Try different variations of encoding": function() {
encoding.variations.forEach(function(enc) {
assert.strictEqual(iconv.fromEncoding(encoding.encodedStrings[key], enc), baseStrings[key]);
assert.strictEqual(iconv.toEncoding(baseStrings[key], enc).toString('binary'), encoding.encodedStrings[key].toString('binary'));
});
},
"Untranslatable chars are converted to defaultCharSingleByte": function() {
var expected = baseStrings.untranslatable.split('').map(function(c) {return iconv.defaultCharSingleByte; }).join('');
assert.strictEqual(iconv.toEncoding(baseStrings.untranslatable, enc).toString('binary'), expected); // Only '?' characters.
}
};
testsBatch[encoding.name+":"] = tests;
});
vows.describe("Test Greek encodings").addBatch(testsBatch).export(module);
var vows = require('vows'),
assert = require('assert'),
iconv = require(__dirname+'/../');
var testString = "Hello123!";
var testStringLatin1 = "Hello123!£Å÷×çþÿ¿®";
var testStringBase64 = "SGVsbG8xMjMh";
vows.describe("Generic UTF8-UCS2 tests").addBatch({
"Vows is working": function() {},
"Return values are of correct types": function() {
assert.ok(iconv.toEncoding(testString, "utf8") instanceof Buffer);
var s = iconv.fromEncoding(new Buffer(testString), "utf8");
assert.strictEqual(Object.prototype.toString.call(s), "[object String]");
},
"Internal encodings all correctly encoded/decoded": function() {
['utf8', "UTF-8", "UCS2", "binary", ""].forEach(function(enc) {
assert.strictEqual(iconv.toEncoding(testStringLatin1, enc).toString(enc), testStringLatin1);
assert.strictEqual(iconv.fromEncoding(new Buffer(testStringLatin1, enc), enc), testStringLatin1);
});
},
"Base64 correctly encoded/decoded": function() {
assert.strictEqual(iconv.toEncoding(testStringBase64, "base64").toString("binary"), testString);
assert.strictEqual(iconv.fromEncoding(new Buffer(testString, "binary"), "base64"), testStringBase64);
},
"Latin1 correctly encoded/decoded": function() {
assert.strictEqual(iconv.toEncoding(testStringLatin1, "latin1").toString("binary"), testStringLatin1);
assert.strictEqual(iconv.fromEncoding(new Buffer(testStringLatin1, "binary"), "latin1"), testStringLatin1);
},
"Convert from string, not buffer (binary encoding used)": function() {
assert.strictEqual(iconv.fromEncoding(testStringLatin1, "binary"), testStringLatin1);
},
"Convert to string, not buffer (utf8 used)": function() {
var res = iconv.toEncoding(new Buffer(testStringLatin1, "utf8"));
assert.ok(res instanceof Buffer);
assert.strictEqual(res.toString("utf8"), testStringLatin1);
},
"Throws on unknown encodings": function() {
assert.throws(function() { iconv.toEncoding("a", "xxx"); });
assert.throws(function() { iconv.fromEncoding("a", "xxx"); });
},
"Convert non-strings and non-buffers": function() {
assert.strictEqual(iconv.toEncoding({}, "utf8").toString(), "[object Object]");
assert.strictEqual(iconv.toEncoding(10, "utf8").toString(), "10");
assert.strictEqual(iconv.toEncoding(undefined, "utf8").toString(), "");
assert.strictEqual(iconv.fromEncoding({}, "utf8"), "[object Object]");
assert.strictEqual(iconv.fromEncoding(10, "utf8"), "10");
assert.strictEqual(iconv.fromEncoding(undefined, "utf8"), "");
},
"Aliases encode and decode work the same as toEncoding and fromEncoding": function() {
assert.strictEqual(iconv.toEncoding(testString, "latin1").toString("binary"), iconv.encode(testString, "latin1").toString("binary"));
assert.strictEqual(iconv.fromEncoding(testStringLatin1, "latin1"), iconv.decode(testStringLatin1, "latin1"));
},
}).export(module)
var iconv = require('iconv');
var iconv_lite = require("../index");
var encoding = process.argv[2] || "windows-1251";
var convertTimes = 10000;
var encodingStrings = {
'windows-1251': 'This is a test string 32 chars..',
'gbk': '这是中文字符测试。。!@¥%12',
'utf8': '这是中文字符测试。。!@¥%12This is a test string 48 chars..',
};
// Test encoding.
var str = encodingStrings[encoding];
if (!str) {
throw new Error('Don\'t support ' + encoding + ' performance test.');
}
for (var i = 0; i < 13; i++) {
str = str + str;
}
console.log('\n' + encoding + ' charset performance test:');
console.log("\nEncoding "+str.length+" chars "+convertTimes+" times:");
var start = Date.now();
var converter = new iconv.Iconv("utf8", encoding);
for (var i = 0; i < convertTimes; i++) {
var b = converter.convert(str);
}
var duration = Date.now() - start;
var mbs = convertTimes*b.length/duration/1024;
console.log("iconv: "+duration+"ms, "+mbs.toFixed(2)+" Mb/s.");
var start = Date.now();
for (var i = 0; i < convertTimes; i++) {
var b = iconv_lite.encode(str, encoding);
}
var duration = Date.now() - start;
var mbs = convertTimes*b.length/duration/1024;
console.log("iconv-lite: "+duration+"ms, "+mbs.toFixed(2)+" Mb/s.");
// Test decoding.
var buf = iconv_lite.encode(str, encoding);
console.log("\nDecoding "+buf.length+" bytes "+convertTimes+" times:");
var start = Date.now();
var converter = new iconv.Iconv(encoding, "utf8");
for (var i = 0; i < convertTimes; i++) {
var s = converter.convert(buf).toString();
}
var duration = Date.now() - start;
var mbs = convertTimes*buf.length/duration/1024;
console.log("iconv: "+duration+"ms, "+mbs.toFixed(2)+" Mb/s.");
var start = Date.now();
for (var i = 0; i < convertTimes; i++) {
var s = iconv_lite.decode(buf, encoding);
}
var duration = Date.now() - start;
var mbs = convertTimes*buf.length/duration/1024;
console.log("iconv-lite: "+duration+"ms, "+mbs.toFixed(2)+" Mb/s.");
var vows = require('vows'),
assert = require('assert'),
iconv = require(__dirname+'/../');
var ascii = '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f'+
' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f';
var encodings = [{
name: "windows1254",
variations: ['windows-1254', 'win-1254', 'win1254', 'cp1254', 'cp-1254', 1254],
strings: {
empty: "",
ascii: ascii,
turkish: "€‚ƒ„…†‡ˆ‰Š‹Œ‘’“”•–—˜™š›œŸ¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏĞÑÒÓÔÕÖ×ØÙÚÛÜİŞßàáâãäåæçèéêëìíîïğñòóôõö÷øùúûüışÿ",
untranslatable: "\x81\x8d\x8e\x8f\x90\x9d\x9e"
},
encodedStrings: {
empty: new Buffer(''),
ascii: new Buffer(ascii, 'binary'),
turkish: new Buffer(
'\x80\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c' +
'\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9f' +
'\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xae\xaf' +
'\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf' +
'\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf' +
'\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf' +
'\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef' +
'\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff',
'binary'),
}
}, {
name: "iso88599",
variations: ['iso-8859-9', 'turkish', 'turkish8', 'cp28599', 'cp-28599', 28599],
strings: {
empty: "",
ascii: ascii,
turkish: "\xa0¡¢£¤¥¦§¨©ª«¬\xad®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏĞÑÒÓÔÕÖ×ØÙÚÛÜİŞßàáâãäåæçèéêëìíîïğñòóôõö÷øùúûüışÿ",
untranslatable: ''
},
encodedStrings: {
empty: new Buffer(''),
ascii: new Buffer(ascii, 'binary'),
turkish: new Buffer(
'\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf' +
'\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf' +
'\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf' +
'\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf' +
'\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef' +
'\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff',
'binary')
}
}];
var testsBatch = {};
encodings.forEach(function(encoding) {
var enc = encoding.variations[0];
var key = "turkish";
var tests = {
"Convert to empty buffer": function() {
assert.strictEqual(iconv.toEncoding("", enc).toString('binary'), new Buffer('').toString('binary'));
},
"Convert from empty buffer": function() {
assert.strictEqual(iconv.fromEncoding(new Buffer(''), enc), "");
},
"Convert from buffer": function() {
for (var key in encoding.encodedStrings)
assert.strictEqual(iconv.fromEncoding(encoding.encodedStrings[key], enc),
encoding.strings[key]);
},
"Convert to buffer": function() {
for (var key in encoding.encodedStrings)
assert.strictEqual(iconv.toEncoding(encoding.strings[key], enc).toString('binary'),
encoding.encodedStrings[key].toString('binary'));
},
"Try different variations of encoding": function() {
encoding.variations.forEach(function(enc) {
assert.strictEqual(iconv.fromEncoding(encoding.encodedStrings[key], enc), encoding.strings[key]);
assert.strictEqual(iconv.toEncoding(encoding.strings[key], enc).toString('binary'), encoding.encodedStrings[key].toString('binary'));
});
},
"Untranslatable chars are converted to defaultCharSingleByte": function() {
var expected = encoding.strings.untranslatable.split('').map(function(c) {return iconv.defaultCharSingleByte; }).join('');
assert.strictEqual(iconv.toEncoding(encoding.strings.untranslatable, enc).toString('binary'), expected); // Only '?' characters.
}
};
testsBatch[encoding.name+":"] = tests;
});
vows.describe("Test Turkish encodings").addBatch(testsBatch).export(module);
/**
* Helpers.
*/
var s = 1000;
var m = s * 60;
var h = m * 60;
var d = h * 24;
var w = d * 7;
var y = d * 365.25;
/**
* Parse or format the given `val`.
*
* Options:
*
* - `long` verbose formatting [false]
*
* @param {String|Number} val
* @param {Object} [options]
* @throws {Error} throw an error if val is not a non-empty string or a number
* @return {String|Number}
* @api public
*/
module.exports = function(val, options) {
options = options || {};
var type = typeof val;
if (type === 'string' && val.length > 0) {
return parse(val);
} else if (type === 'number' && isNaN(val) === false) {
return options.long ? fmtLong(val) : fmtShort(val);
}
throw new Error(
'val is not a non-empty string or a valid number. val=' +
JSON.stringify(val)
);
};
/**
* Parse the given `str` and return milliseconds.
*
* @param {String} str
* @return {Number}
* @api private
*/
function parse(str) {
str = String(str);
if (str.length > 100) {
return;
}
var match = /^((?:\d+)?\-?\d?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(
str
);
if (!match) {
return;
}
var n = parseFloat(match[1]);
var type = (match[2] || 'ms').toLowerCase();
switch (type) {
case 'years':
case 'year':
case 'yrs':
case 'yr':
case 'y':
return n * y;
case 'weeks':
case 'week':
case 'w':
return n * w;
case 'days':
case 'day':
case 'd':
return n * d;
case 'hours':
case 'hour':
case 'hrs':
case 'hr':
case 'h':
return n * h;
case 'minutes':
case 'minute':
case 'mins':
case 'min':
case 'm':
return n * m;
case 'seconds':
case 'second':
case 'secs':
case 'sec':
case 's':
return n * s;
case 'milliseconds':
case 'millisecond':
case 'msecs':
case 'msec':
case 'ms':
return n;
default:
return undefined;
}
}
/**
* Short format for `ms`.
*
* @param {Number} ms
* @return {String}
* @api private
*/
function fmtShort(ms) {
var msAbs = Math.abs(ms);
if (msAbs >= d) {
return Math.round(ms / d) + 'd';
}
if (msAbs >= h) {
return Math.round(ms / h) + 'h';
}
if (msAbs >= m) {
return Math.round(ms / m) + 'm';
}
if (msAbs >= s) {
return Math.round(ms / s) + 's';
}
return ms + 'ms';
}
/**
* Long format for `ms`.
*
* @param {Number} ms
* @return {String}
* @api private
*/
function fmtLong(ms) {
var msAbs = Math.abs(ms);
if (msAbs >= d) {
return plural(ms, msAbs, d, 'day');
}
if (msAbs >= h) {
return plural(ms, msAbs, h, 'hour');
}
if (msAbs >= m) {
return plural(ms, msAbs, m, 'minute');
}
if (msAbs >= s) {
return plural(ms, msAbs, s, 'second');
}
return ms + ' ms';
}
/**
* Pluralization helper.
*/
function plural(ms, msAbs, n, name) {
var isPlural = msAbs >= n * 1.5;
return Math.round(ms / n) + ' ' + name + (isPlural ? 's' : '');
}
The MIT License (MIT)
Copyright (c) 2016 Zeit, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
{
"_from": "ms",
"_id": "ms@2.1.1",
"_inBundle": false,
"_integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==",
"_location": "/ms",
"_phantomChildren": {},
"_requested": {
"type": "tag",
"registry": true,
"raw": "ms",
"name": "ms",
"escapedName": "ms",
"rawSpec": "",
"saveSpec": null,
"fetchSpec": "latest"
},
"_requiredBy": [
"#USER",
"/"
],
"_resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
"_shasum": "30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a",
"_spec": "ms",
"_where": "D:\\My Jobs\\Job 18\\chicweight",
"bugs": {
"url": "https://github.com/zeit/ms/issues"
},
"bundleDependencies": false,
"deprecated": false,
"description": "Tiny millisecond conversion utility",
"devDependencies": {
"eslint": "4.12.1",
"expect.js": "0.3.1",
"husky": "0.14.3",
"lint-staged": "5.0.0",
"mocha": "4.0.1"
},
"eslintConfig": {
"extends": "eslint:recommended",
"env": {
"node": true,
"es6": true
}
},
"files": [
"index.js"
],
"homepage": "https://github.com/zeit/ms#readme",
"license": "MIT",
"lint-staged": {
"*.js": [
"npm run lint",
"prettier --single-quote --write",
"git add"
]
},
"main": "./index",
"name": "ms",
"repository": {
"type": "git",
"url": "git+https://github.com/zeit/ms.git"
},
"scripts": {
"lint": "eslint lib/* bin/*",
"precommit": "lint-staged",
"test": "mocha tests.js"
},
"version": "2.1.1"
}
# ms
[![Build Status](https://travis-ci.org/zeit/ms.svg?branch=master)](https://travis-ci.org/zeit/ms)
[![Slack Channel](http://zeit-slackin.now.sh/badge.svg)](https://zeit.chat/)
Use this package to easily convert various time formats to milliseconds.
## Examples
```js
ms('2 days') // 172800000
ms('1d') // 86400000
ms('10h') // 36000000
ms('2.5 hrs') // 9000000
ms('2h') // 7200000
ms('1m') // 60000
ms('5s') // 5000
ms('1y') // 31557600000
ms('100') // 100
ms('-3 days') // -259200000
ms('-1h') // -3600000
ms('-200') // -200
```
### Convert from Milliseconds
```js
ms(60000) // "1m"
ms(2 * 60000) // "2m"
ms(-3 * 60000) // "-3m"
ms(ms('10 hours')) // "10h"
```
### Time Format Written-Out
```js
ms(60000, { long: true }) // "1 minute"
ms(2 * 60000, { long: true }) // "2 minutes"
ms(-3 * 60000, { long: true }) // "-3 minutes"
ms(ms('10 hours'), { long: true }) // "10 hours"
```
## Features
- Works both in [Node.js](https://nodejs.org) and in the browser
- If a number is supplied to `ms`, a string with a unit is returned
- If a string that contains the number is supplied, it returns it as a number (e.g.: it returns `100` for `'100'`)
- If you pass a string with a number and a valid unit, the number of equivalent milliseconds is returned
## Related Packages
- [ms.macro](https://github.com/knpwrs/ms.macro) - Run `ms` as a macro at build-time.
## Caught a Bug?
1. [Fork](https://help.github.com/articles/fork-a-repo/) this repository to your own GitHub account and then [clone](https://help.github.com/articles/cloning-a-repository/) it to your local device
2. Link the package to the global module directory: `npm link`
3. Within the module you want to test your local development instance of ms, just link it to the dependencies: `npm link ms`. Instead of the default one from npm, Node.js will now use your clone of ms!
As always, you can run the tests using: `npm test`
support
test
examples
*.sock
0.0.3 / 2015-04-06
==================
* add: filter key
0.0.2 / 2015-04-06
==================
* add: filter
0.0.1 / 2010-01-03
==================
* Initial release
test:
@./node_modules/.bin/mocha \
--require should \
--reporter spec
.PHONY: test
\ No newline at end of file
# outliers
Find outliers in a dataset.
## Install
```
npm install outliers
```
## Examples
### Pass an array
```js
outliers([12, 14, 51, 12, 10, 9, 16, 1]) // [1, 51]
```
### Filter out outliers
```js
[12, 14, 51, 12, 10, 9, 16, 1].filter(outliers()); // [12, 14, 12, 10, 9, 16]
```
### Filter out outliers from an array of objects
```js
var arr = [{ n: 12 },{ n: 14 },{ n: 51 },{ n: 12 },{ n: 10 },{ n: 9 },{ n: 16 },{ n: 1 }]
arr.filter(outliers('n')); // [{ n: 12 },{ n: 14 },{ n: 12 },{ n: 10 },{ n: 9 },{ n: 16 }]
```
## Credits
- Based on: http://en.wikipedia.org/wiki/Interquartile_range#Interquartile_range_and_outliers
- Basically the non-OOP version of: https://github.com/pablodenadai/outlier
## License
(The MIT License)
Copyright (c) 2015 Matthew Mueller &lt;mattmuelle@gmail.com&gt;
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
/**
* Module Dependencies
*/
var isArray = Array.isArray;
/**
* Export `outliers`
*/
module.exports = outliers;
/**
* Initialize the outliers
*
* @param {Array|String|undefined}
* @return {Array|Function}
*/
function outliers(arr) {
if (isArray(arr)) return calc(arr);
var o = null;
var k = 'string' == typeof arr && arr;
return function(v, i, a) {
if (!o) o = calc(a, k);
v = k ? v[k] : v;
return !~o.indexOf(v);
}
}
/**
* Calculate the outliers
*
* @param {Array} arr
* @param {String} key (optional)
* @return {Array} outliers
*/
function calc(arr, key) {
arr = arr.slice(0);
if (key) arr = arr.map(function(v) { return v[key]; });
arr = arr.sort(function(a, b) {
return a - b;
});
var len = arr.length;
var middle = median(arr);
var range = iqr(arr);
var outliers = [];
for (var i = 0; i < len; i++) {
Math.abs(arr[i] - middle) > range && outliers.push(arr[i]);
}
return outliers;
}
/**
* Find the median
*
* @param {Array} arr
* @return {Number}
*/
function median(arr) {
var len = arr.length;
var half = ~~(len / 2);
return len % 2
? arr[half]
: (arr[half - 1] + arr[half]) / 2;
}
/**
* Find the range
*
* @param {Array} arr
* @return {Number}
*/
function iqr(arr) {
var len = arr.length;
var q1 = median(arr.slice(0, ~~(len / 2)));
var q3 = median(arr.slice(Math.ceil(len / 2)));
var g = 1.5;
return (q3 - q1) * g;
}
{
"_from": "outliers@0.0.3",
"_id": "outliers@0.0.3",
"_inBundle": false,
"_integrity": "sha1-TYMpvyU0BJW2KNOZcBZSXQl91bg=",
"_location": "/outliers",
"_phantomChildren": {},
"_requested": {
"type": "version",
"registry": true,
"raw": "outliers@0.0.3",
"name": "outliers",
"escapedName": "outliers",
"rawSpec": "0.0.3",
"saveSpec": null,
"fetchSpec": "0.0.3"
},
"_requiredBy": [
"#USER",
"/"
],
"_resolved": "https://registry.npmjs.org/outliers/-/outliers-0.0.3.tgz",
"_shasum": "4d8329bf25340495b628d3997016525d097dd5b8",
"_spec": "outliers@0.0.3",
"_where": "D:\\My Jobs\\Job 18\\chicweight",
"author": {
"name": "Matthew Mueller",
"email": "mattmuelle@gmail.com"
},
"bugs": {
"url": "https://github.com/MatthewMueller/outliers/issues"
},
"bundleDependencies": false,
"dependencies": {},
"deprecated": false,
"description": "find outliers in a dataset",
"devDependencies": {
"mocha": "*",
"should": "*"
},
"homepage": "https://github.com/MatthewMueller/outliers#readme",
"keywords": [],
"main": "index",
"name": "outliers",
"repository": {
"type": "git",
"url": "git://github.com/MatthewMueller/outliers.git"
},
"version": "0.0.3"
}
var outliers = require('./index.js');
var arr = [12, 14, 51, 12, 10, 9, 16, 1];
var arr_obj = [{ n: 12 },{ n: 14 },{ n: 51 },{ n: 12 },{ n: 10 },{ n: 9 },{ n: 16 },{ n: 1 }]
console.log(outliers(arr));
console.log(arr.filter(outliers()));
console.log(arr_obj.filter(outliers('n')));
{
"node": true,
"curly": true,
"latedef": true,
"quotmark": true,
"undef": true,
"unused": true,
"trailing": true
}
.idea
*.iml
npm-debug.log
dump.rdb
node_modules
results.tap
results.xml
npm-shrinkwrap.json
config.json
.DS_Store
*/.DS_Store
*/*/.DS_Store
._*
*/._*
*/*/._*
coverage.*
lib-cov
complexity.md
language: node_js
node_js:
- 0.10
\ No newline at end of file
Copyright (c) 2014 Nathan LaFreniere and other contributors.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* The names of any contributors may not be used to endorse or promote
products derived from this software without specific prior written
permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* * *
The complete list of contributors can be found at: https://github.com/hapijs/qs/graphs/contributors
test:
@node node_modules/lab/bin/lab
test-cov:
@node node_modules/lab/bin/lab -t 100
test-cov-html:
@node node_modules/lab/bin/lab -r html -o coverage.html
.PHONY: test test-cov test-cov-html
\ No newline at end of file
# qs
A querystring parsing and stringifying library with some added security.
[![Build Status](https://secure.travis-ci.org/hapijs/qs.svg)](http://travis-ci.org/hapijs/qs)
Lead Maintainer: [Nathan LaFreniere](https://github.com/nlf)
The **qs** module was originally created and maintained by [TJ Holowaychuk](https://github.com/visionmedia/node-querystring).
## Usage
```javascript
var Qs = require('qs');
var obj = Qs.parse('a=c'); // { a: 'c' }
var str = Qs.stringify(obj); // 'a=c'
```
### Parsing Objects
```javascript
Qs.parse(string, [depth], [delimiter]);
```
**qs** allows you to create nested objects within your query strings, by surrounding the name of sub-keys with square brackets `[]`.
For example, the string `'foo[bar]=baz'` converts to:
```javascript
{
foo: {
bar: 'baz'
}
}
```
URI encoded strings work too:
```javascript
Qs.parse('a%5Bb%5D=c');
// { a: { b: 'c' } }
```
You can also nest your objects, like `'foo[bar][baz]=foobarbaz'`:
```javascript
{
foo: {
bar: {
baz: 'foobarbaz'
}
}
}
```
By default, when nesting objects **qs** will only parse up to 5 children deep. This means if you attempt to parse a string like
`'a[b][c][d][e][f][g][h][i]=j'` your resulting object will be:
```javascript
{
a: {
b: {
c: {
d: {
e: {
f: {
'[g][h][i]': 'j'
}
}
}
}
}
}
}
```
This depth can be overridden by passing a `depth` option to `Qs.parse(string, depth)`:
```javascript
Qs.parse('a[b][c][d][e][f][g][h][i]=j', 1);
// { a: { b: { '[c][d][e][f][g][h][i]': 'j' } } }
```
The depth limit mitigate abuse when **qs** is used to parse user input, and it is recommended to keep it a reasonably small number.
An optional delimiter can also be passed:
```javascript
Qs.parse('a=b;c=d', ';');
// { a: 'b', c: 'd' }
```
### Parsing Arrays
**qs** can also parse arrays using a similar `[]` notation:
```javascript
Qs.parse('a[]=b&a[]=c');
// { a: ['b', 'c'] }
```
You may specify an index as well:
```javascript
Qs.parse('a[1]=c&a[0]=b');
// { a: ['b', 'c'] }
```
Note that the only difference between an index in an array and a key in an object is that the value between the brackets must be a number
to create an array. When creating arrays with specific indices, **qs** will compact a sparse array to only the existing values preserving
their order:
```javascript
Qs.parse('a[1]=b&a[15]=c');
// { a: ['b', 'c'] }
```
Note that an empty string is also a value, and will be preserved:
```javascript
Qs.parse('a[]=&a[]=b');
// { a: ['', 'b'] }
Qs.parse('a[0]=b&a[1]=&a[2]=c');
// { a: ['b', '', 'c'] }
```
**qs** will also limit specifying indices in an array to a maximum index of `20`. Any array members with an index of greater than `20` will
instead be converted to an object with the index as the key:
```javascript
Qs.parse('a[100]=b');
// { a: { '100': 'b' } }
```
If you mix notations, **qs** will merge the two items into an object:
```javascript
Qs.parse('a[0]=b&a[b]=c');
// { a: { '0': 'b', b: 'c' } }
```
You can also create arrays of objects:
```javascript
Qs.parse('a[][b]=c');
// { a: [{ b: 'c' }] }
```
### Stringifying
```javascript
Qs.stringify(object, [delimiter]);
```
When stringifying, **qs** always URI encodes output. Objects are stringified as you would expect:
```javascript
Qs.stringify({ a: 'b' });
// 'a=b'
Qs.stringify({ a: { b: 'c' } });
// 'a%5Bb%5D=c'
```
Examples beyond this point will be shown as though the output is not URI encoded for clarity. Please note that the return values in these cases *will* be URI encoded during real usage.
When arrays are stringified, they are always given explicit indices:
```javascript
Qs.stringify({ a: ['b', 'c', 'd'] });
// 'a[0]=b&a[1]=c&a[2]=d'
```
Empty strings and null values will omit the value, but the equals sign (=) remains in place:
```javascript
Qs.stringify({ a: '' });
// 'a='
```
Properties that are set to `undefined` will be omitted entirely:
```javascript
Qs.stringify({ a: null, b: undefined });
// 'a='
```
The delimiter may be overridden with stringify as well:
```javascript
Qs.stringify({ a: 'b', c: 'd' }, ';');
// 'a=b;c=d'
module.exports = require('./lib');
// Load modules
var Stringify = require('./stringify');
var Parse = require('./parse');
// Declare internals
var internals = {};
module.exports = {
stringify: Stringify,
parse: Parse
};
// Load modules
var Utils = require('./utils');
// Declare internals
var internals = {
delimiter: '&',
depth: 5,
arrayLimit: 20,
parametersLimit: 1000
};
internals.parseValues = function (str, delimiter) {
delimiter = typeof delimiter === 'undefined' ? internals.delimiter : delimiter;
var obj = {};
var parts = str.split(delimiter, internals.parametersLimit);
for (var i = 0, il = parts.length; i < il; ++i) {
var part = parts[i];
var pos = part.indexOf(']=') === -1 ? part.indexOf('=') : part.indexOf(']=') + 1;
if (pos === -1) {
obj[Utils.decode(part)] = '';
}
else {
var key = Utils.decode(part.slice(0, pos));
var val = Utils.decode(part.slice(pos + 1));
if (!obj[key]) {
obj[key] = val;
}
else {
obj[key] = [].concat(obj[key]).concat(val);
}
}
}
return obj;
};
internals.parseObject = function (chain, val) {
if (!chain.length) {
return val;
}
var root = chain.shift();
var obj = {};
if (root === '[]') {
obj = [];
obj = obj.concat(internals.parseObject(chain, val));
}
else {
var cleanRoot = root[0] === '[' && root[root.length - 1] === ']' ? root.slice(1, root.length - 1) : root;
var index = parseInt(cleanRoot, 10);
if (!isNaN(index) &&
root !== cleanRoot &&
index <= internals.arrayLimit) {
obj = [];
obj[index] = internals.parseObject(chain, val);
}
else {
obj[cleanRoot] = internals.parseObject(chain, val);
}
}
return obj;
};
internals.parseKeys = function (key, val, depth) {
if (!key) {
return;
}
// The regex chunks
var parent = /^([^\[\]]*)/;
var child = /(\[[^\[\]]*\])/g;
// Get the parent
var segment = parent.exec(key);
// Don't allow them to overwrite object prototype properties
if (Object.prototype.hasOwnProperty(segment[1])) {
return;
}
// Stash the parent if it exists
var keys = [];
if (segment[1]) {
keys.push(segment[1]);
}
// Loop through children appending to the array until we hit depth
var i = 0;
while ((segment = child.exec(key)) !== null && i < depth) {
++i;
if (!Object.prototype.hasOwnProperty(segment[1].replace(/\[|\]/g, ''))) {
keys.push(segment[1]);
}
}
// If there's a remainder, just add whatever is left
if (segment) {
keys.push('[' + key.slice(segment.index) + ']');
}
return internals.parseObject(keys, val);
};
module.exports = function (str, depth, delimiter) {
if (str === '' ||
str === null ||
typeof str === 'undefined') {
return {};
}
if (typeof depth !== 'number') {
delimiter = depth;
depth = internals.depth;
}
var tempObj = typeof str === 'string' ? internals.parseValues(str, delimiter) : Utils.clone(str);
var obj = {};
// Iterate over the keys and setup the new object
//
for (var key in tempObj) {
if (tempObj.hasOwnProperty(key)) {
var newObj = internals.parseKeys(key, tempObj[key], depth);
obj = Utils.merge(obj, newObj);
}
}
return Utils.compact(obj);
};
// Load modules
// Declare internals
var internals = {
delimiter: '&'
};
internals.stringify = function (obj, prefix) {
if (Buffer.isBuffer(obj)) {
obj = obj.toString();
}
else if (obj instanceof Date) {
obj = obj.toISOString();
}
else if (obj === null) {
obj = '';
}
if (typeof obj === 'string' ||
typeof obj === 'number' ||
typeof obj === 'boolean') {
return [encodeURIComponent(prefix) + '=' + encodeURIComponent(obj)];
}
var values = [];
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
values = values.concat(internals.stringify(obj[key], prefix + '[' + key + ']'));
}
}
return values;
};
module.exports = function (obj, delimiter) {
delimiter = typeof delimiter === 'undefined' ? internals.delimiter : delimiter;
var keys = [];
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
keys = keys.concat(internals.stringify(obj[key], key));
}
}
return keys.join(delimiter);
};
// Load modules
// Declare internals
var internals = {};
exports.arrayToObject = function (source) {
var obj = {};
for (var i = 0, il = source.length; i < il; ++i) {
if (typeof source[i] !== 'undefined') {
obj[i] = source[i];
}
}
return obj;
};
exports.clone = function (source) {
if (typeof source !== 'object' ||
source === null) {
return source;
}
if (Buffer.isBuffer(source)) {
return source.toString();
}
var obj = Array.isArray(source) ? [] : {};
for (var i in source) {
if (source.hasOwnProperty(i)) {
obj[i] = exports.clone(source[i]);
}
}
return obj;
};
exports.merge = function (target, source) {
if (!source) {
return target;
}
var obj = exports.clone(target);
if (Array.isArray(source)) {
for (var i = 0, il = source.length; i < il; ++i) {
if (typeof source[i] !== 'undefined') {
if (typeof obj[i] === 'object') {
obj[i] = exports.merge(obj[i], source[i]);
}
else {
obj[i] = source[i];
}
}
}
return obj;
}
if (Array.isArray(obj)) {
obj = exports.arrayToObject(obj);
}
var keys = Object.keys(source);
for (var k = 0, kl = keys.length; k < kl; ++k) {
var key = keys[k];
var value = source[key];
if (value &&
typeof value === 'object') {
if (!obj[key]) {
obj[key] = exports.clone(value);
}
else {
obj[key] = exports.merge(obj[key], value);
}
}
else {
obj[key] = value;
}
}
return obj;
};
exports.decode = function (str) {
try {
return decodeURIComponent(str.replace(/\+/g, ' '));
} catch (e) {
return str;
}
};
exports.compact = function (obj) {
if (typeof obj !== 'object') {
return obj;
}
var compacted = {};
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
if (Array.isArray(obj[key])) {
compacted[key] = [];
for (var i = 0, l = obj[key].length; i < l; i++) {
if (typeof obj[key][i] !== 'undefined') {
compacted[key].push(obj[key][i]);
}
}
}
else {
compacted[key] = exports.compact(obj[key]);
}
}
}
return compacted;
};
{
"_from": "qs@1.2.0",
"_id": "qs@1.2.0",
"_inBundle": false,
"_integrity": "sha1-7Qeb4oaCFH5v2aNMwrDB4OxkU+4=",
"_location": "/qs",
"_phantomChildren": {},
"_requested": {
"type": "version",
"registry": true,
"raw": "qs@1.2.0",
"name": "qs",
"escapedName": "qs",
"rawSpec": "1.2.0",
"saveSpec": null,
"fetchSpec": "1.2.0"
},
"_requiredBy": [
"/restler"
],
"_resolved": "http://registry.npmjs.org/qs/-/qs-1.2.0.tgz",
"_shasum": "ed079be28682147e6fd9a34cc2b0c1e0ec6453ee",
"_spec": "qs@1.2.0",
"_where": "D:\\My Jobs\\Job 18\\chicweight\\node_modules\\restler",
"author": {
"name": "Nathan LaFreniere",
"email": "quitlahok@gmail.com"
},
"bugs": {
"url": "https://github.com/hapijs/qs/issues"
},
"bundleDependencies": false,
"dependencies": {},
"deprecated": false,
"description": "A querystring parser that supports nesting and arrays, with a depth limit",
"devDependencies": {
"lab": "3.x.x"
},
"homepage": "https://github.com/hapijs/qs",
"keywords": [
"querystring",
"qs"
],
"licenses": [
{
"type": "BSD",
"url": "http://github.com/hapijs/qs/raw/master/LICENSE"
}
],
"main": "index.js",
"name": "qs",
"repository": {
"type": "git",
"url": "git+https://github.com/hapijs/qs.git"
},
"scripts": {
"test": "make test-cov"
},
"version": "1.2.0"
}
// Load modules
var Lab = require('lab');
var Qs = require('../');
// Declare internals
var internals = {};
// Test shortcuts
var expect = Lab.expect;
var before = Lab.before;
var after = Lab.after;
var describe = Lab.experiment;
var it = Lab.test;
describe('#parse', function () {
it('parses a simple string', function (done) {
expect(Qs.parse('0=foo')).to.deep.equal({ '0': 'foo' });
expect(Qs.parse('foo=c++')).to.deep.equal({ foo: 'c ' });
expect(Qs.parse('a[>=]=23')).to.deep.equal({ a: { '>=': '23' } });
expect(Qs.parse('a[<=>]==23')).to.deep.equal({ a: { '<=>': '=23' } });
expect(Qs.parse('a[==]=23')).to.deep.equal({ a: { '==': '23' } });
expect(Qs.parse('foo')).to.deep.equal({ foo: '' });
expect(Qs.parse('foo=bar')).to.deep.equal({ foo: 'bar' });
expect(Qs.parse(' foo = bar = baz ')).to.deep.equal({ ' foo ': ' bar = baz ' });
expect(Qs.parse('foo=bar=baz')).to.deep.equal({ foo: 'bar=baz' });
expect(Qs.parse('foo=bar&bar=baz')).to.deep.equal({ foo: 'bar', bar: 'baz' });
expect(Qs.parse('foo=bar&baz')).to.deep.equal({ foo: 'bar', baz: '' });
expect(Qs.parse('cht=p3&chd=t:60,40&chs=250x100&chl=Hello|World')).to.deep.equal({
cht: 'p3',
chd: 't:60,40',
chs: '250x100',
chl: 'Hello|World'
});
done();
});
it('parses a single nested string', function (done) {
expect(Qs.parse('a[b]=c')).to.deep.equal({ a: { b: 'c' } });
done();
});
it('parses a double nested string', function (done) {
expect(Qs.parse('a[b][c]=d')).to.deep.equal({ a: { b: { c: 'd' } } });
done();
});
it('defaults to a depth of 5', function (done) {
expect(Qs.parse('a[b][c][d][e][f][g][h]=i')).to.deep.equal({ a: { b: { c: { d: { e: { f: { '[g][h]': 'i' } } } } } } });
done();
});
it('only parses one level when depth = 1', function (done) {
expect(Qs.parse('a[b][c]=d', 1)).to.deep.equal({ a: { b: { '[c]': 'd' } } });
expect(Qs.parse('a[b][c][d]=e', 1)).to.deep.equal({ a: { b: { '[c][d]': 'e' } } });
done();
});
it('parses a simple array', function (done) {
expect(Qs.parse('a=b&a=c')).to.deep.equal({ a: ['b', 'c'] });
done();
});
it('parses an explicit array', function (done) {
expect(Qs.parse('a[]=b')).to.deep.equal({ a: ['b'] });
expect(Qs.parse('a[]=b&a[]=c')).to.deep.equal({ a: ['b', 'c'] });
expect(Qs.parse('a[]=b&a[]=c&a[]=d')).to.deep.equal({ a: ['b', 'c', 'd'] });
done();
});
it('parses a nested array', function (done) {
expect(Qs.parse('a[b][]=c&a[b][]=d')).to.deep.equal({ a: { b: ['c', 'd'] } });
expect(Qs.parse('a[>=]=25')).to.deep.equal({ a: { '>=': '25' } });
done();
});
it('allows to specify array indices', function (done) {
expect(Qs.parse('a[1]=c&a[0]=b&a[2]=d')).to.deep.equal({ a: ['b', 'c', 'd'] });
expect(Qs.parse('a[1]=c&a[0]=b')).to.deep.equal({ a: ['b', 'c'] });
expect(Qs.parse('a[1]=c')).to.deep.equal({ a: ['c'] });
done();
});
it('limits specific array indices to 20', function (done) {
expect(Qs.parse('a[20]=a')).to.deep.equal({ a: ['a'] });
expect(Qs.parse('a[21]=a')).to.deep.equal({ a: { '21': 'a' } });
done();
});
it('supports encoded = signs', function (done) {
expect(Qs.parse('he%3Dllo=th%3Dere')).to.deep.equal({ 'he=llo': 'th=ere' });
done();
});
it('is ok with url encoded strings', function (done) {
expect(Qs.parse('a[b%20c]=d')).to.deep.equal({ a: { 'b c': 'd' } });
expect(Qs.parse('a[b]=c%20d')).to.deep.equal({ a: { b: 'c d' } });
done();
});
it('allows brackets in the value', function (done) {
expect(Qs.parse('pets=["tobi"]')).to.deep.equal({ pets: '["tobi"]' });
expect(Qs.parse('operators=[">=", "<="]')).to.deep.equal({ operators: '[">=", "<="]' });
done();
});
it('allows empty values', function (done) {
expect(Qs.parse('')).to.deep.equal({});
expect(Qs.parse(null)).to.deep.equal({});
expect(Qs.parse(undefined)).to.deep.equal({});
done();
});
it('transforms arrays to objects', function (done) {
expect(Qs.parse('foo[0]=bar&foo[bad]=baz')).to.deep.equal({ foo: { '0': 'bar', bad: 'baz' } });
expect(Qs.parse('foo[bad]=baz&foo[0]=bar')).to.deep.equal({ foo: { bad: 'baz', '0': 'bar' } });
expect(Qs.parse('foo[bad]=baz&foo[]=bar')).to.deep.equal({ foo: { bad: 'baz', '0': 'bar' } });
expect(Qs.parse('foo[]=bar&foo[bad]=baz')).to.deep.equal({ foo: { '0': 'bar', bad: 'baz' } });
expect(Qs.parse('foo[bad]=baz&foo[]=bar&foo[]=foo')).to.deep.equal({ foo: { bad: 'baz', '0': 'bar', '1': 'foo' } });
expect(Qs.parse('foo[0][a]=a&foo[0][b]=b&foo[1][a]=aa&foo[1][b]=bb')).to.deep.equal({foo: [ {a: 'a', b: 'b'}, {a: 'aa', b: 'bb'} ]});
done();
});
it('correctly prunes undefined values when converting an array to an object', function (done) {
expect(Qs.parse('a[2]=b&a[99999999]=c')).to.deep.equal({ a: { '2': 'b', '99999999': 'c' } });
done();
});
it('supports malformed uri characters', function (done) {
expect(Qs.parse('{%:%}')).to.deep.equal({ '{%:%}': '' });
expect(Qs.parse('foo=%:%}')).to.deep.equal({ foo: '%:%}' });
done();
});
it('doesn\'t produce empty keys', function (done) {
expect(Qs.parse('_r=1&')).to.deep.equal({ '_r': '1' });
done();
});
it('cannot override prototypes', function (done) {
var obj = Qs.parse('toString=bad&bad[toString]=bad&constructor=bad');
expect(typeof obj.toString).to.equal('function');
expect(typeof obj.bad.toString).to.equal('function');
expect(typeof obj.constructor).to.equal('function');
done();
});
it('cannot access Object prototype', function (done) {
Qs.parse('constructor[prototype][bad]=bad');
Qs.parse('bad[constructor][prototype][bad]=bad');
expect(typeof Object.prototype.bad).to.equal('undefined');
done();
});
it('parses arrays of objects', function (done) {
expect(Qs.parse('a[][b]=c')).to.deep.equal({ a: [{ b: 'c' }] });
expect(Qs.parse('a[0][b]=c')).to.deep.equal({ a: [{ b: 'c' }] });
done();
});
it('allows for empty strings in arrays', function (done) {
expect(Qs.parse('a[]=b&a[]=&a[]=c')).to.deep.equal({ a: ['b', '', 'c'] });
expect(Qs.parse('a[0]=b&a[1]=&a[2]=c&a[19]=')).to.deep.equal({ a: ['b', '', 'c', ''] });
done();
});
it('should compact sparse arrays', function (done) {
expect(Qs.parse('a[10]=1&a[2]=2')).to.deep.equal({ a: ['2', '1'] });
done();
});
it('parses semi-parsed strings', function (done) {
expect(Qs.parse({ 'a[b]': 'c' })).to.deep.equal({ a: { b: 'c' } });
expect(Qs.parse({ 'a[b]': 'c', 'a[d]': 'e' })).to.deep.equal({ a: { b: 'c', d: 'e' } });
done();
});
it('parses buffers to strings', function (done) {
var b = new Buffer('test');
expect(Qs.parse({ a: b })).to.deep.equal({ a: b.toString() });
done();
});
it('continues parsing when no parent is found', function (done) {
expect(Qs.parse('[]&a=b')).to.deep.equal({ '0': '', a: 'b' });
expect(Qs.parse('[foo]=bar')).to.deep.equal({ foo: 'bar' });
done();
});
it('does not error when parsing a very long array', function (done) {
var str = 'a[]=a';
while (Buffer.byteLength(str) < 128 * 1024) {
str += '&' + str;
}
expect(function () {
Qs.parse(str);
}).to.not.throw();
done();
});
it('should not throw when a native prototype has an enumerable property', { parallel: false }, function (done) {
Object.prototype.crash = '';
Array.prototype.crash = '';
expect(Qs.parse.bind(null, 'a=b')).to.not.throw();
expect(Qs.parse('a=b')).to.deep.equal({ a: 'b' });
expect(Qs.parse.bind(null, 'a[][b]=c')).to.not.throw();
expect(Qs.parse('a[][b]=c')).to.deep.equal({ a: [{ b: 'c' }] });
delete Object.prototype.crash;
delete Array.prototype.crash;
done();
});
it('parses a string with an alternative delimiter', function (done) {
expect(Qs.parse('a=b;c=d', ';')).to.deep.equal({ a: 'b', c: 'd' });
done();
});
});
// Load modules
var Lab = require('lab');
var Qs = require('../');
// Declare internals
var internals = {};
// Test shortcuts
var expect = Lab.expect;
var before = Lab.before;
var after = Lab.after;
var describe = Lab.experiment;
var it = Lab.test;
describe('#stringify', function () {
it('stringifies a querystring object', function (done) {
expect(Qs.stringify({ a: 'b' })).to.equal('a=b');
expect(Qs.stringify({ a: 1 })).to.equal('a=1');
expect(Qs.stringify({ a: 1, b: 2 })).to.equal('a=1&b=2');
done();
});
it('stringifies a nested object', function (done) {
expect(Qs.stringify({ a: { b: 'c' } })).to.equal('a%5Bb%5D=c');
expect(Qs.stringify({ a: { b: { c: { d: 'e' } } } })).to.equal('a%5Bb%5D%5Bc%5D%5Bd%5D=e');
done();
});
it('stringifies an array value', function (done) {
expect(Qs.stringify({ a: ['b', 'c', 'd'] })).to.equal('a%5B0%5D=b&a%5B1%5D=c&a%5B2%5D=d');
done();
});
it('stringifies a nested array value', function (done) {
expect(Qs.stringify({ a: { b: ['c', 'd'] } })).to.equal('a%5Bb%5D%5B0%5D=c&a%5Bb%5D%5B1%5D=d');
done();
});
it('stringifies an object inside an array', function (done) {
expect(Qs.stringify({ a: [{ b: 'c' }] })).to.equal('a%5B0%5D%5Bb%5D=c');
expect(Qs.stringify({ a: [{ b: { c: [1] } }] })).to.equal('a%5B0%5D%5Bb%5D%5Bc%5D%5B0%5D=1');
done();
});
it('stringifies a complicated object', function (done) {
expect(Qs.stringify({ a: { b: 'c', d: 'e' } })).to.equal('a%5Bb%5D=c&a%5Bd%5D=e');
done();
});
it('stringifies an empty value', function (done) {
expect(Qs.stringify({ a: '' })).to.equal('a=');
expect(Qs.stringify({ a: '', b: '' })).to.equal('a=&b=');
expect(Qs.stringify({ a: null })).to.equal('a=');
expect(Qs.stringify({ a: { b: null } })).to.equal('a%5Bb%5D=');
done();
});
it('drops keys with a value of undefined', function (done) {
expect(Qs.stringify({ a: undefined })).to.equal('');
expect(Qs.stringify({ a: { b: undefined, c: null } })).to.equal('a%5Bc%5D=');
done();
});
it('url encodes values', function (done) {
expect(Qs.stringify({ a: 'b c' })).to.equal('a=b%20c');
done();
});
it('stringifies a date', function (done) {
var now = new Date();
var str = 'a=' + encodeURIComponent(now.toISOString());
expect(Qs.stringify({ a: now })).to.equal(str);
done();
});
it('stringifies the weird object from qs', function (done) {
expect(Qs.stringify({ 'my weird field': 'q1!2"\'w$5&7/z8)?' })).to.equal('my%20weird%20field=q1!2%22\'w%245%267%2Fz8)%3F');
done();
});
it('skips properties that are part of the object prototype', function (done) {
Object.prototype.crash = 'test';
expect(Qs.stringify({ a: 'b'})).to.equal('a=b');
expect(Qs.stringify({ a: { b: 'c' } })).to.equal('a%5Bb%5D=c');
delete Object.prototype.crash;
done();
});
it('stringifies boolean values', function (done) {
expect(Qs.stringify({ a: true })).to.equal('a=true');
expect(Qs.stringify({ a: { b: true } })).to.equal('a%5Bb%5D=true');
expect(Qs.stringify({ b: false })).to.equal('b=false');
expect(Qs.stringify({ b: { c: false } })).to.equal('b%5Bc%5D=false');
done();
});
it('stringifies buffer values', function (done) {
expect(Qs.stringify({ a: new Buffer('test') })).to.equal('a=test');
expect(Qs.stringify({ a: { b: new Buffer('test') } })).to.equal('a%5Bb%5D=test');
done();
});
it('stringifies an object using an alternative delimiter', function (done) {
expect(Qs.stringify({ a: 'b', c: 'd' }, ';')).to.equal('a=b;c=d');
done();
});
});
{
"presets": ["es2015", "stage-0"],
"plugins": ["transform-es2015-modules-umd"]
}
root = true
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false
{
"extends": "airbnb-base",
"rules": {
"import/prefer-default-export": 0,
"no-plusplus": 0
},
}
.git*
example/
.DS_Store
env:
global:
- CC_TEST_REPORTER_ID=1937cd951ca5a26580a65f98a7b627eb92126bdd2b272e3dec71f8396062d210
- GIT_COMMITTED_AT=$(if [ "$TRAVIS_PULL_REQUEST" == "false" ]; then git log -1 --pretty=format:%ct; else git log -1 --skip 1 --pretty=format:%ct; fi)
language: node_js
node_js:
- "6.1"
before_script:
- curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
- chmod +x ./cc-test-reporter
script:
- npm test
- if [ "$TRAVIS_PULL_REQUEST" == "false" ]; then ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT; fi
# 2.0.0
- Replaces the build system with just babel
- Rewritten in es6 syntax
- Improvements to test coverage
- Fixes null value bug
- Improvements to documentation
- Removes lastvalue
- Removes linearThroughOrigin. This is now handled by the linear model.
- Changes model access
- Adds predict function
# 2.0.1
- Fix broken minified distribution
The MIT License (MIT)
Copyright (c) Tom Alexander <me@tomalexander.co.nz>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
<div align="center">
<h1>regression-js</h1>
<a href="https://travis-ci.org/Tom-Alexander/regression-js">
<img src="https://travis-ci.org/Tom-Alexander/regression-js.svg?branch=master"/>
</a>
<a href="https://npmjs.com/package/regression">
<img src="https://img.shields.io/npm/v/regression.svg" alt="npm version" />
</a>
<a href="https://npmjs.com/package/regression">
<img src="https://img.shields.io/npm/dt/regression.svg" alt="npm downloads" />
</a>
<a href="https://codeclimate.com/github/Tom-Alexander/regression-js/coverage"><img src="https://codeclimate.com/github/Tom-Alexander/regression-js/badges/coverage.svg" /></a>
<br/>
<br/>
<p>
regression-js is a JavaScript module containing a collection of linear least-squares fitting methods for simple data analysis.
</p>
</div>
## Installation
This module works on node and in the browser. It is available as the 'regression' package on [npm](https://www.npmjs.com/package/regression). It is also available on a [CDN](https://cdnjs.com/libraries/regression).
### npm
```
npm install --save regression
```
## Usage
```javascript
import regression from 'regression';
const result = regression.linear([[0, 1], [32, 67], [12, 79]]);
const gradient = result.equation[0];
const yIntercept = result.equation[1];
```
Data is passed into the model as an array. A second parameter can be used to configure the model. The configuration parameter is optional. `null` values are ignored. The precision option will set the number of significant figures the output is rounded to.
### Configuration options
Below are the default values for the configuration parameter.
```javascript
{
order: 2,
precision: 2,
}
```
### Properties
- `equation`: an array containing the coefficients of the equation
- `string`: A string representation of the equation
- `points`: an array containing the predicted data in the domain of the input
- `r2`: the coefficient of determination (<i>R</i><sup>2</sup>)
- `predict(x)`: This function will return the predicted value
## API
### `regression.linear(data[, options])`
Fits the input data to a straight line with the equation ![y = mx + c](http://mathurl.com/ycqyhets.png). It returns the coefficients in the form `[m, c]`.
### `regression.exponential(data[, options])`
Fits the input data to a exponential curve with the equation ![y = ae^bx](http://mathurl.com/zuys53z.png). It returns the coefficients in the form `[a, b]`.
### `regression.logarithmic(data[, options])`
Fits the input data to a logarithmic curve with the equation ![y = a + b ln x](http://mathurl.com/zye394m.png). It returns the coefficients in the form `[a, b]`.
### `regression.power(data[, options])`
Fits the input data to a power law curve with the equation ![y = ax^b](http://mathurl.com/gojkazs.png). It returns the coefficients in the form `[a, b]`.
### `regression.polynomial(data[, options])`
Fits the input data to a polynomial curve with the equation ![anx^n ... + a1x + a0](http://mathurl.com/hxz543o.png). It returns the coefficients in the form `[an..., a1, a0]`. The order can be configure with the `order` option.
#### Example
```javascript
const data = [[0,1],[32, 67] .... [12, 79]];
const result = regression.polynomial(data, { order: 3 });
```
## Development
- Install the dependencies with `npm install`
- To build the assets in the `dist` directory, use `npm run build`
- You can run the tests with: `npm run test`.
{
"name": "regression-js",
"version": "2.0.0",
"homepage": "https://github.com/Tom-Alexander/regression-js",
"authors": [
"Tom-Alexander <me@tomalexander.co.nz>"
],
"description": "Javascript least squares data fitting",
"license": "MIT",
"ignore": [
"node_modules",
"bower_components",
"example/*"
],
"main": "./dist/regression.js"
}
(function(global,factory){if(typeof define==="function"&&define.amd){define(["module"],factory)}else if(typeof exports!=="undefined"){factory(module)}else{var mod={exports:{}};factory(mod);global.regression=mod.exports}})(this,function(module){"use strict";function _defineProperty(obj,key,value){if(key in obj){Object.defineProperty(obj,key,{value:value,enumerable:true,configurable:true,writable:true})}else{obj[key]=value}return obj}var _extends=Object.assign||function(target){for(var i=1;i<arguments.length;i++){var source=arguments[i];for(var key in source){if(Object.prototype.hasOwnProperty.call(source,key)){target[key]=source[key]}}}return target};function _toConsumableArray(arr){if(Array.isArray(arr)){for(var i=0,arr2=Array(arr.length);i<arr.length;i++){arr2[i]=arr[i]}return arr2}else{return Array.from(arr)}}var DEFAULT_OPTIONS={order:2,precision:2,period:null};function determinationCoefficient(data,results){var predictions=[];var observations=[];data.forEach(function(d,i){if(d[1]!==null){observations.push(d);predictions.push(results[i])}});var sum=observations.reduce(function(a,observation){return a+observation[1]},0);var mean=sum/observations.length;var ssyy=observations.reduce(function(a,observation){var difference=observation[1]-mean;return a+difference*difference},0);var sse=observations.reduce(function(accum,observation,index){var prediction=predictions[index];var residual=observation[1]-prediction[1];return accum+residual*residual},0);return 1-sse/ssyy}function gaussianElimination(input,order){var matrix=input;var n=input.length-1;var coefficients=[order];for(var i=0;i<n;i++){var maxrow=i;for(var j=i+1;j<n;j++){if(Math.abs(matrix[i][j])>Math.abs(matrix[i][maxrow])){maxrow=j}}for(var k=i;k<n+1;k++){var tmp=matrix[k][i];matrix[k][i]=matrix[k][maxrow];matrix[k][maxrow]=tmp}for(var _j=i+1;_j<n;_j++){for(var _k=n;_k>=i;_k--){matrix[_k][_j]-=matrix[_k][i]*matrix[i][_j]/matrix[i][i]}}}for(var _j2=n-1;_j2>=0;_j2--){var total=0;for(var _k2=_j2+1;_k2<n;_k2++){total+=matrix[_k2][_j2]*coefficients[_k2]}coefficients[_j2]=(matrix[n][_j2]-total)/matrix[_j2][_j2]}return coefficients}function round(number,precision){var factor=Math.pow(10,precision);return Math.round(number*factor)/factor}var methods={linear:function linear(data,options){var sum=[0,0,0,0,0];var len=0;for(var n=0;n<data.length;n++){if(data[n][1]!==null){len++;sum[0]+=data[n][0];sum[1]+=data[n][1];sum[2]+=data[n][0]*data[n][0];sum[3]+=data[n][0]*data[n][1];sum[4]+=data[n][1]*data[n][1]}}var run=len*sum[2]-sum[0]*sum[0];var rise=len*sum[3]-sum[0]*sum[1];var gradient=run===0?0:round(rise/run,options.precision);var intercept=round(sum[1]/len-gradient*sum[0]/len,options.precision);var predict=function predict(x){return[round(x,options.precision),round(gradient*x+intercept,options.precision)]};var points=data.map(function(point){return predict(point[0])});return{points:points,predict:predict,equation:[gradient,intercept],r2:round(determinationCoefficient(data,points),options.precision),string:intercept===0?"y = "+gradient+"x":"y = "+gradient+"x + "+intercept}},exponential:function exponential(data,options){var sum=[0,0,0,0,0,0];for(var n=0;n<data.length;n++){if(data[n][1]!==null){sum[0]+=data[n][0];sum[1]+=data[n][1];sum[2]+=data[n][0]*data[n][0]*data[n][1];sum[3]+=data[n][1]*Math.log(data[n][1]);sum[4]+=data[n][0]*data[n][1]*Math.log(data[n][1]);sum[5]+=data[n][0]*data[n][1]}}var denominator=sum[1]*sum[2]-sum[5]*sum[5];var a=Math.exp((sum[2]*sum[3]-sum[5]*sum[4])/denominator);var b=(sum[1]*sum[4]-sum[5]*sum[3])/denominator;var coeffA=round(a,options.precision);var coeffB=round(b,options.precision);var predict=function predict(x){return[round(x,options.precision),round(coeffA*Math.exp(coeffB*x),options.precision)]};var points=data.map(function(point){return predict(point[0])});return{points:points,predict:predict,equation:[coeffA,coeffB],string:"y = "+coeffA+"e^("+coeffB+"x)",r2:round(determinationCoefficient(data,points),options.precision)}},logarithmic:function logarithmic(data,options){var sum=[0,0,0,0];var len=data.length;for(var n=0;n<len;n++){if(data[n][1]!==null){sum[0]+=Math.log(data[n][0]);sum[1]+=data[n][1]*Math.log(data[n][0]);sum[2]+=data[n][1];sum[3]+=Math.pow(Math.log(data[n][0]),2)}}var a=(len*sum[1]-sum[2]*sum[0])/(len*sum[3]-sum[0]*sum[0]);var coeffB=round(a,options.precision);var coeffA=round((sum[2]-coeffB*sum[0])/len,options.precision);var predict=function predict(x){return[round(x,options.precision),round(round(coeffA+coeffB*Math.log(x),options.precision),options.precision)]};var points=data.map(function(point){return predict(point[0])});return{points:points,predict:predict,equation:[coeffA,coeffB],string:"y = "+coeffA+" + "+coeffB+" ln(x)",r2:round(determinationCoefficient(data,points),options.precision)}},power:function power(data,options){var sum=[0,0,0,0,0];var len=data.length;for(var n=0;n<len;n++){if(data[n][1]!==null){sum[0]+=Math.log(data[n][0]);sum[1]+=Math.log(data[n][1])*Math.log(data[n][0]);sum[2]+=Math.log(data[n][1]);sum[3]+=Math.pow(Math.log(data[n][0]),2)}}var b=(len*sum[1]-sum[0]*sum[2])/(len*sum[3]-Math.pow(sum[0],2));var a=(sum[2]-b*sum[0])/len;var coeffA=round(Math.exp(a),options.precision);var coeffB=round(b,options.precision);var predict=function predict(x){return[round(x,options.precision),round(round(coeffA*Math.pow(x,coeffB),options.precision),options.precision)]};var points=data.map(function(point){return predict(point[0])});return{points:points,predict:predict,equation:[coeffA,coeffB],string:"y = "+coeffA+"x^"+coeffB,r2:round(determinationCoefficient(data,points),options.precision)}},polynomial:function polynomial(data,options){var lhs=[];var rhs=[];var a=0;var b=0;var len=data.length;var k=options.order+1;for(var i=0;i<k;i++){for(var l=0;l<len;l++){if(data[l][1]!==null){a+=Math.pow(data[l][0],i)*data[l][1]}}lhs.push(a);a=0;var c=[];for(var j=0;j<k;j++){for(var _l=0;_l<len;_l++){if(data[_l][1]!==null){b+=Math.pow(data[_l][0],i+j)}}c.push(b);b=0}rhs.push(c)}rhs.push(lhs);var coefficients=gaussianElimination(rhs,k).map(function(v){return round(v,options.precision)});var predict=function predict(x){return[round(x,options.precision),round(coefficients.reduce(function(sum,coeff,power){return sum+coeff*Math.pow(x,power)},0),options.precision)]};var points=data.map(function(point){return predict(point[0])});var string="y = ";for(var _i=coefficients.length-1;_i>=0;_i--){if(_i>1){string+=coefficients[_i]+"x^"+_i+" + "}else if(_i===1){string+=coefficients[_i]+"x + "}else{string+=coefficients[_i]}}return{string:string,points:points,predict:predict,equation:[].concat(_toConsumableArray(coefficients)).reverse(),r2:round(determinationCoefficient(data,points),options.precision)}}};function createWrapper(){var reduce=function reduce(accumulator,name){return _extends({_round:round},accumulator,_defineProperty({},name,function(data,supplied){return methods[name](data,_extends({},DEFAULT_OPTIONS,supplied))}))};return Object.keys(methods).reduce(reduce,{})}module.exports=createWrapper()});
\ No newline at end of file
{
"_from": "regression",
"_id": "regression@2.0.1",
"_inBundle": false,
"_integrity": "sha1-jSnD6CJKEIUMNeM36FqLL6w7DIc=",
"_location": "/regression",
"_phantomChildren": {},
"_requested": {
"type": "tag",
"registry": true,
"raw": "regression",
"name": "regression",
"escapedName": "regression",
"rawSpec": "",
"saveSpec": null,
"fetchSpec": "latest"
},
"_requiredBy": [
"#USER",
"/"
],
"_resolved": "https://registry.npmjs.org/regression/-/regression-2.0.1.tgz",
"_shasum": "8d29c3e8224a10850c35e337e85a8b2fac3b0c87",
"_spec": "regression",
"_where": "D:\\My Jobs\\Job 18\\chicweight",
"author": {
"name": "Tom Alexander",
"email": "me@tomalexander.co.nz"
},
"bugs": {
"url": "https://github.com/Tom-Alexander/regression-js/issues"
},
"bundleDependencies": false,
"contributors": [
{
"name": "Tom Alexander",
"email": "me@tomalexander.co.nz"
},
{
"name": "Misha Wolfson",
"email": "misha@ginkgobioworks.com"
}
],
"deprecated": false,
"description": "Javascript least squares data fitting methods",
"devDependencies": {
"babel-cli": "^6.24.1",
"babel-core": "^6.25.0",
"babel-plugin-transform-es2015-modules-umd": "^6.24.1",
"babel-preset-es2015": "^6.24.1",
"babel-preset-stage-0": "^6.24.1",
"chai": "^3.5.0",
"eslint": "^3.19.0",
"eslint-config-airbnb-base": "^11.2.0",
"eslint-plugin-import": "^2.7.0",
"mocha": "^3.2.0",
"nyc": "^11.0.3",
"uglify-js": "3"
},
"homepage": "https://github.com/Tom-Alexander/regression-js#readme",
"keywords": [
"regression",
"data",
"fiting",
"modeling",
"analysis"
],
"license": "MIT",
"main": "./dist/regression.js",
"name": "regression",
"repository": {
"type": "git",
"url": "git+https://github.com/Tom-Alexander/regression-js.git"
},
"scripts": {
"build": "npm run clean && npm run build-regression-js && npm run build-regression-min-js",
"build-regression-js": "BABEL_ENV=production ./node_modules/.bin/babel src/regression.js --out-file dist/regression.js",
"build-regression-min-js": " ./node_modules/.bin/uglifyjs dist/regression.js --output dist/regression.min.js",
"clean": "rm -rf dist && mkdir dist",
"lint": "eslint src/** tests/**",
"test": "npm run lint && ./node_modules/.bin/nyc --reporter=lcov ./node_modules/.bin/mocha --compilers js:babel-core/register"
},
"version": "2.0.1"
}
const DEFAULT_OPTIONS = { order: 2, precision: 2, period: null };
/**
* Determine the coefficient of determination (r^2) of a fit from the observations
* and predictions.
*
* @param {Array<Array<number>>} data - Pairs of observed x-y values
* @param {Array<Array<number>>} results - Pairs of observed predicted x-y values
*
* @return {number} - The r^2 value, or NaN if one cannot be calculated.
*/
function determinationCoefficient(data, results) {
const predictions = [];
const observations = [];
data.forEach((d, i) => {
if (d[1] !== null) {
observations.push(d);
predictions.push(results[i]);
}
});
const sum = observations.reduce((a, observation) => a + observation[1], 0);
const mean = sum / observations.length;
const ssyy = observations.reduce((a, observation) => {
const difference = observation[1] - mean;
return a + (difference * difference);
}, 0);
const sse = observations.reduce((accum, observation, index) => {
const prediction = predictions[index];
const residual = observation[1] - prediction[1];
return accum + (residual * residual);
}, 0);
return 1 - (sse / ssyy);
}
/**
* Determine the solution of a system of linear equations A * x = b using
* Gaussian elimination.
*
* @param {Array<Array<number>>} input - A 2-d matrix of data in row-major form [ A | b ]
* @param {number} order - How many degrees to solve for
*
* @return {Array<number>} - Vector of normalized solution coefficients matrix (x)
*/
function gaussianElimination(input, order) {
const matrix = input;
const n = input.length - 1;
const coefficients = [order];
for (let i = 0; i < n; i++) {
let maxrow = i;
for (let j = i + 1; j < n; j++) {
if (Math.abs(matrix[i][j]) > Math.abs(matrix[i][maxrow])) {
maxrow = j;
}
}
for (let k = i; k < n + 1; k++) {
const tmp = matrix[k][i];
matrix[k][i] = matrix[k][maxrow];
matrix[k][maxrow] = tmp;
}
for (let j = i + 1; j < n; j++) {
for (let k = n; k >= i; k--) {
matrix[k][j] -= (matrix[k][i] * matrix[i][j]) / matrix[i][i];
}
}
}
for (let j = n - 1; j >= 0; j--) {
let total = 0;
for (let k = j + 1; k < n; k++) {
total += matrix[k][j] * coefficients[k];
}
coefficients[j] = (matrix[n][j] - total) / matrix[j][j];
}
return coefficients;
}
/**
* Round a number to a precision, specificed in number of decimal places
*
* @param {number} number - The number to round
* @param {number} precision - The number of decimal places to round to:
* > 0 means decimals, < 0 means powers of 10
*
*
* @return {numbr} - The number, rounded
*/
function round(number, precision) {
const factor = 10 ** precision;
return Math.round(number * factor) / factor;
}
/**
* The set of all fitting methods
*
* @namespace
*/
const methods = {
linear(data, options) {
const sum = [0, 0, 0, 0, 0];
let len = 0;
for (let n = 0; n < data.length; n++) {
if (data[n][1] !== null) {
len++;
sum[0] += data[n][0];
sum[1] += data[n][1];
sum[2] += data[n][0] * data[n][0];
sum[3] += data[n][0] * data[n][1];
sum[4] += data[n][1] * data[n][1];
}
}
const run = ((len * sum[2]) - (sum[0] * sum[0]));
const rise = ((len * sum[3]) - (sum[0] * sum[1]));
const gradient = run === 0 ? 0 : round(rise / run, options.precision);
const intercept = round((sum[1] / len) - ((gradient * sum[0]) / len), options.precision);
const predict = x => ([
round(x, options.precision),
round((gradient * x) + intercept, options.precision)]
);
const points = data.map(point => predict(point[0]));
return {
points,
predict,
equation: [gradient, intercept],
r2: round(determinationCoefficient(data, points), options.precision),
string: intercept === 0 ? `y = ${gradient}x` : `y = ${gradient}x + ${intercept}`,
};
},
exponential(data, options) {
const sum = [0, 0, 0, 0, 0, 0];
for (let n = 0; n < data.length; n++) {
if (data[n][1] !== null) {
sum[0] += data[n][0];
sum[1] += data[n][1];
sum[2] += data[n][0] * data[n][0] * data[n][1];
sum[3] += data[n][1] * Math.log(data[n][1]);
sum[4] += data[n][0] * data[n][1] * Math.log(data[n][1]);
sum[5] += data[n][0] * data[n][1];
}
}
const denominator = ((sum[1] * sum[2]) - (sum[5] * sum[5]));
const a = Math.exp(((sum[2] * sum[3]) - (sum[5] * sum[4])) / denominator);
const b = ((sum[1] * sum[4]) - (sum[5] * sum[3])) / denominator;
const coeffA = round(a, options.precision);
const coeffB = round(b, options.precision);
const predict = x => ([
round(x, options.precision),
round(coeffA * Math.exp(coeffB * x), options.precision),
]);
const points = data.map(point => predict(point[0]));
return {
points,
predict,
equation: [coeffA, coeffB],
string: `y = ${coeffA}e^(${coeffB}x)`,
r2: round(determinationCoefficient(data, points), options.precision),
};
},
logarithmic(data, options) {
const sum = [0, 0, 0, 0];
const len = data.length;
for (let n = 0; n < len; n++) {
if (data[n][1] !== null) {
sum[0] += Math.log(data[n][0]);
sum[1] += data[n][1] * Math.log(data[n][0]);
sum[2] += data[n][1];
sum[3] += (Math.log(data[n][0]) ** 2);
}
}
const a = ((len * sum[1]) - (sum[2] * sum[0])) / ((len * sum[3]) - (sum[0] * sum[0]));
const coeffB = round(a, options.precision);
const coeffA = round((sum[2] - (coeffB * sum[0])) / len, options.precision);
const predict = x => ([
round(x, options.precision),
round(round(coeffA + (coeffB * Math.log(x)), options.precision), options.precision),
]);
const points = data.map(point => predict(point[0]));
return {
points,
predict,
equation: [coeffA, coeffB],
string: `y = ${coeffA} + ${coeffB} ln(x)`,
r2: round(determinationCoefficient(data, points), options.precision),
};
},
power(data, options) {
const sum = [0, 0, 0, 0, 0];
const len = data.length;
for (let n = 0; n < len; n++) {
if (data[n][1] !== null) {
sum[0] += Math.log(data[n][0]);
sum[1] += Math.log(data[n][1]) * Math.log(data[n][0]);
sum[2] += Math.log(data[n][1]);
sum[3] += (Math.log(data[n][0]) ** 2);
}
}
const b = ((len * sum[1]) - (sum[0] * sum[2])) / ((len * sum[3]) - (sum[0] ** 2));
const a = ((sum[2] - (b * sum[0])) / len);
const coeffA = round(Math.exp(a), options.precision);
const coeffB = round(b, options.precision);
const predict = x => ([
round(x, options.precision),
round(round(coeffA * (x ** coeffB), options.precision), options.precision),
]);
const points = data.map(point => predict(point[0]));
return {
points,
predict,
equation: [coeffA, coeffB],
string: `y = ${coeffA}x^${coeffB}`,
r2: round(determinationCoefficient(data, points), options.precision),
};
},
polynomial(data, options) {
const lhs = [];
const rhs = [];
let a = 0;
let b = 0;
const len = data.length;
const k = options.order + 1;
for (let i = 0; i < k; i++) {
for (let l = 0; l < len; l++) {
if (data[l][1] !== null) {
a += (data[l][0] ** i) * data[l][1];
}
}
lhs.push(a);
a = 0;
const c = [];
for (let j = 0; j < k; j++) {
for (let l = 0; l < len; l++) {
if (data[l][1] !== null) {
b += data[l][0] ** (i + j);
}
}
c.push(b);
b = 0;
}
rhs.push(c);
}
rhs.push(lhs);
const coefficients = gaussianElimination(rhs, k).map(v => round(v, options.precision));
const predict = x => ([
round(x, options.precision),
round(
coefficients.reduce((sum, coeff, power) => sum + (coeff * (x ** power)), 0),
options.precision,
),
]);
const points = data.map(point => predict(point[0]));
let string = 'y = ';
for (let i = coefficients.length - 1; i >= 0; i--) {
if (i > 1) {
string += `${coefficients[i]}x^${i} + `;
} else if (i === 1) {
string += `${coefficients[i]}x + `;
} else {
string += coefficients[i];
}
}
return {
string,
points,
predict,
equation: [...coefficients].reverse(),
r2: round(determinationCoefficient(data, points), options.precision),
};
},
};
function createWrapper() {
const reduce = (accumulator, name) => ({
_round: round,
...accumulator,
[name](data, supplied) {
return methods[name](data, {
...DEFAULT_OPTIONS,
...supplied,
});
},
});
return Object.keys(methods).reduce(reduce, {});
}
module.exports = createWrapper();
export const linear = {
zeroGradient: {
r2: NaN,
equation: [0, 10],
predicted: [10, 10],
string: 'y = 0x + 10',
data: [[10, 10], [10, 10], [10, 10]],
points: [[10, 10], [10, 10], [10, 10]],
},
zeroIntercept: {
r2: 1,
equation: [2, 0],
string: 'y = 2x',
predicted: [10, 20],
data: [[0, 0], [1, 2], [2, 4], [3, 6]],
points: [[0, 0], [1, 2], [2, 4], [3, 6]],
},
positiveGradient: {
r2: 1,
equation: [2, 1],
predicted: [20, 41],
string: 'y = 2x + 1',
data: [[10, 21], [100, 201], [1000, 2001], [10000, 20001]],
points: [[10, 21], [100, 201], [1000, 2001], [10000, 20001]],
},
negativeGradient: {
r2: 1,
predicted: [3, -7],
equation: [-2, -1],
string: 'y = -2x + -1',
data: [[10, -21], [100, -201], [1000, -2001], [10000, -20001]],
points: [[10, -21], [100, -201], [1000, -2001], [10000, -20001]],
},
positiveGradientWithEmpty: {
r2: 1,
equation: [2, 1],
predicted: [20, 41],
string: 'y = 2x + 1',
data: [[10, 21], [100, null], [1000, 2001], [10000, null]],
points: [[10, 21], [100, 201], [1000, 2001], [10000, 20001]],
},
};
export const exponential = {
growthGreaterThanZero: {
r2: 1,
equation: [2, 2],
predicted: [2, 109.2],
string: 'y = 2e^(2x)',
points: [[0, 2], [0.69, 8], [1.1, 18], [1.39, 32]],
data: [[0, 2], [0.6931471806, 8], [1.098612289, 18], [1.386294361, 32]],
},
decayGreaterThanZero: {
r2: 1,
equation: [2, -2],
predicted: [2, 0.04],
string: 'y = 2e^(-2x)',
points: [[0, 2], [0.69, 0.5], [1.1, 0.22], [1.39, 0.13]],
data: [[0, 2], [0.6931471806, 0.5], [1.098612289, 0.2222222222], [1.386294361, 0.125]],
},
growthGreaterThanZeroWithEmpty: {
r2: 1,
equation: [2, 2],
predicted: [2, 109.2],
string: 'y = 2e^(2x)',
points: [[0, 2], [0.69, 8], [1.1, 18], [1.39, 32]],
data: [[0, 2], [0.6931471806, null], [1.098612289, 18], [1.386294361, null]],
},
};
export const logarithmic = {
greaterThanOne: {
r2: 1,
equation: [0, 10],
predicted: [5, 16.09],
string: 'y = 0 + 10 ln(x)',
points: [[1, 0], [2, 6.93], [3, 10.99], [4, 13.86]],
data: [[1, 0], [2, 6.931471806], [3, 10.98612289], [4, 13.86294361]],
},
greaterThanOneWithEmpty: {
r2: 1,
equation: [0, 10],
predicted: [5, 16.09],
string: 'y = 0 + 10 ln(x)',
points: [[1, 0], [2, 6.93], [3, 10.99], [4, 13.86]],
data: [[1, 0], [2, null], [3, 10.98612289], [4, null]],
},
};
export const power = {
coefficientsEqualToOne: {
r2: 1,
equation: [1, 1],
predicted: [7, 7],
string: 'y = 1x^1',
points: [[1, 1], [2, 2], [3, 3], [4, 4], [5, 5], [6, 6]],
data: [[1, 1], [2, 2], [3, 3], [4, 4], [5, 5], [6, 6]],
},
coefficientsEqualToOneWithEmpty: {
r2: 1,
equation: [1, 1],
predicted: [7, 7],
string: 'y = 1x^1',
points: [[1, 1], [2, 2], [3, 3], [4, 4], [5, 5], [6, 6]],
data: [[1, 1], [2, null], [3, 3], [4, 4], [5, 5], [6, null]],
},
};
export const polynomial = {
positiveLinearGradient: {
config: { order: 1 },
r2: 1,
equation: [2, 0],
string: 'y = 2x + 0',
predicted: [4, 8],
data: [[10, 20], [100, 200], [1000, 2000], [10000, 20000]],
points: [[10, 20], [100, 200], [1000, 2000], [10000, 20000]],
},
negativeLinearGradient: {
config: { order: 1 },
r2: 1,
equation: [-2, 0],
string: 'y = -2x + 0',
predicted: [4, -8],
data: [[10, -20], [100, -200], [1000, -2000], [10000, -20000]],
points: [[10, -20], [100, -200], [1000, -2000], [10000, -20000]],
},
parabolaPositiveCoefficients: {
config: { order: 2 },
r2: 1,
equation: [1, 2, 3],
predicted: [4, 27],
string: 'y = 1x^2 + 2x + 3',
data: [[0, 3], [1, 6], [2, 11], [3, 18]],
points: [[0, 3], [1, 6], [2, 11], [3, 18]],
},
parabolaNegativeCoefficients: {
config: { order: 2 },
r2: 1,
equation: [-1, -2, -3],
predicted: [4, -27],
string: 'y = -1x^2 + -2x + -3',
data: [[0, -3], [1, -6], [2, -11], [3, -18]],
points: [[0, -3], [1, -6], [2, -11], [3, -18]],
},
cubicPositiveCoefficients: {
config: { order: 3 },
r2: 1,
equation: [2, 2, 2, 2],
predicted: [4, 170],
string: 'y = 2x^3 + 2x^2 + 2x + 2',
data: [[0, 2], [1, 8], [2, 30], [3, 80]],
points: [[0, 2], [1, 8], [2, 30], [3, 80]],
},
cubicNegativeCoefficients: {
config: { order: 3 },
r2: 1,
equation: [-2, -2, -2, -2],
predicted: [4, -170],
string: 'y = -2x^3 + -2x^2 + -2x + -2',
data: [[0, -2], [1, -8], [2, -30], [3, -80]],
points: [[0, -2], [1, -8], [2, -30], [3, -80]],
},
cubicPositiveCoefficientsWithEmpty: {
config: { order: 3 },
r2: 1,
equation: [2, 2, 2, 2],
predicted: [4, 170],
string: 'y = 2x^3 + 2x^2 + 2x + 2',
data: [[0, 2], [1, null], [2, 30], [3, 80], [4, 170], [5, 312]],
points: [[0, 2], [1, 8], [2, 30], [3, 80], [4, 170], [5, 312]],
},
zeroYValueCubic: {
r2: 1,
config: { order: 3 },
equation: [1, 2, 3, -6],
predicted: [7, 456],
string: 'y = 1x^3 + 2x^2 + 3x + -6',
data: [[1, 0], [2, 16], [3, 48], [4, 102], [5, 184], [6, 300]],
points: [[1, 0], [2, 16], [3, 48], [4, 102], [5, 184], [6, 300]],
},
zeroYCoefficientCubic: {
r2: 1,
config: { order: 3 },
equation: [0, 1, 2, 3],
predicted: [7, 66],
string: 'y = 0x^3 + 1x^2 + 2x + 3',
data: [[1, 6], [2, 11], [3, 18], [4, 27], [5, 38], [6, 51]],
points: [[1, 6], [2, 11], [3, 18], [4, 27], [5, 38], [6, 51]],
},
};
/* eslint-env node, mocha */
import { expect } from 'chai';
import * as models from './data';
import regression from '../src/regression';
const { _round } = regression;
describe('round', () => {
it('rounds to the correct precision', () => {
expect(_round(0.33333333333333333333, 9)).to.equal(0.333333333);
});
});
describe('models', () => {
Object.keys(models).forEach((model) => {
describe(model, () => {
Object.keys(models[model]).forEach((name) => {
const example = models[model][name];
describe(name, () => {
it(`correctly predicts ${name}`, () => {
let result = regression[model](example.data, example.config);
delete result.predict;
expect(result).to.deep.equal({
r2: example.r2,
string: example.string,
points: example.points,
equation: example.equation,
});
});
it('should correctly forecast data points', () => {
const result = regression[model](example.data, example.config);
expect(result.predict(example.predicted[0])).to.deep.equal(example.predicted);
});
it('should take precision options', () => {
const notSpecified = regression[model](example.data, example.config);
const specified = regression[model](example.data, { ...example.config, precision: 4 });
expect(specified.equation).to.deep.equal(example.equation.map(v => _round(v, 4)));
expect(notSpecified.equation).to.deep.equal(example.equation.map(v => _round(v, 2)));
});
});
});
});
});
});
This source diff could not be displayed because it is too large. You can view the blob instead.
*.swp
.[Dd][Ss]_store
node_modules
.idea
Copyright (c) 2009 Dan Webb
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
Restler [![NPM Version](https://img.shields.io/npm/v/restler.svg?style=flat)](https://www.npmjs.com/package/restler) ![Node Version](https://img.shields.io/node/v/restler.svg?style=flat) ![Downloads](https://img.shields.io/npm/dm/restler.svg?style=flat)
=======
(C) Dan Webb (dan@danwebb.net/@danwrong) 2011, Licensed under the MIT-LICENSE
An HTTP client library for node.js. Hides most of the complexity of creating and using http.Client.
See [Version History](https://github.com/danwrong/restler/wiki/Version-History) for changes
Installing
----------
```
npm install restler
```
Running the tests
-----------------
```
npm test
```
Features
--------
* Easy interface for common operations via http.request
* Automatic serialization of post data
* Automatic serialization of query string data
* Automatic deserialization of XML, JSON and YAML responses to JavaScript objects
* Provide your own deserialization functions for other datatypes
* Automatic following of redirects
* Send files with multipart requests
* Transparently handle SSL (just specify https in the URL)
* Deals with basic auth for you, just provide username and password options
* Simple service wrapper that allows you to easily put together REST API libraries
* Transparently handle content-encoded responses (gzip, deflate)
* Transparently handle different content charsets via [iconv-lite](https://github.com/ashtuchkin/iconv-lite)
API
---
### request(url, options)
Basic method to make a request of any type. The function returns a RestRequest object that emits events:
#### events
* `complete: function(result, response)` - emitted when the request has finished whether it was successful or not. Gets passed the response result and the response object as arguments. If some error has occurred, `result` is always instance of `Error`, otherwise it contains response data.
* `success: function(data, response)` - emitted when the request was successful. Gets passed the response data and the response object as arguments.
* `fail: function(data, response)` - emitted when the request was successful, but 4XX or 5XX status code returned. Gets passed the response data and the response object as arguments.
* `error: function(err, response)` - emitted when some errors have occurred (eg. connection aborted, parse, encoding, decoding failed or some other unhandled errors). Gets passed the `Error` object and the response object (when available) as arguments.
* `abort: function()` - emitted when `request.abort()` is called.
* `timeout: function(ms)` - when a request takes more than the timeout option eg: {timeout:5000}, the request will be aborted. error and abort events will not be called, instead timeout will be emitted.
* `2XX`, `3XX`, `4XX`, `5XX: function(data, response)` - emitted for all requests with response codes in the range (eg. `2XX` emitted for 200, 201, 203).
* <code><i>actual response code</i>: function(data, response)</code> - emitted for every single response code (eg. 404, 201, etc).
#### members
* `abort([error])` Cancels request. `abort` event is emitted. `request.aborted` is set to `true`. If non-falsy `error` is passed, then `error` will be additionally emitted (with `error` passed as a param and `error.type` is set to `"abort"`). Otherwise only `complete` event will raise.
* `retry([timeout])` Re-sends request after `timeout` ms. Pending request is aborted.
* `aborted` Determines if request was aborted.
### get(url, options)
Create a GET request.
### post(url, options)
Create a POST request.
### put(url, options)
Create a PUT request.
### del(url, options)
Create a DELETE request.
### head(url, options)
Create a HEAD request.
### patch(url, options)
Create a PATCH request.
### json(url, data, options)
Send json `data` via GET method.
### postJson(url, data, options)
Send json `data` via POST method.
### putJson(url, data, options)
Send json `data` via PUT method.
### patchJson(url, data, options)
Send json `data` via PATCH method.
### Parsers
You can give any of these to the parsers option to specify how the response data is deserialized.
In case of malformed content, parsers emit `error` event. Original data returned by server is stored in `response.raw`.
#### parsers.auto
Checks the content-type and then uses parsers.xml, parsers.json or parsers.yaml.
If the content type isn't recognised it just returns the data untouched.
#### parsers.json, parsers.xml, parsers.yaml
All of these attempt to turn the response into a JavaScript object. In order to use the YAML and XML parsers you must have yaml and/or xml2js installed.
### Options
* `method` Request method, can be get, post, put, delete. Defaults to `"get"`.
* `query` Query string variables as a javascript object, will override the querystring in the URL. Defaults to empty.
* `data` The data to be added to the body of the request. Can be a string or any object.
Note that if you want your request body to be JSON with the `Content-Type: application/json`, you need to
`JSON.stringify` your object first. Otherwise, it will be sent as `application/x-www-form-urlencoded` and encoded accordingly.
Also you can use `json()` and `postJson()` methods.
* `parser` A function that will be called on the returned data. Use any of predefined `restler.parsers`. See parsers section below. Defaults to `restler.parsers.auto`.
* `xml2js` [Options](https://github.com/Leonidas-from-XIV/node-xml2js#options) for xml2js
* `encoding` The encoding of the request body. Defaults to `"utf8"`.
* `decoding` The encoding of the response body. For a list of supported values see [Buffers](http://nodejs.org/api/buffer.html#buffer_buffer). Additionally accepts `"buffer"` - returns response as `Buffer`. Defaults to `"utf8"`.
* `headers` A hash of HTTP headers to be sent. Defaults to `{ 'Accept': '*/*', 'User-Agent': 'Restler for node.js' }`.
* `username` Basic auth username. Defaults to empty.
* `password` Basic auth password. Defaults to empty.
* `accessToken` OAuth Bearer Token. Defaults to empty.
* `multipart` If set the data passed will be formatted as `multipart/form-encoded`. See multipart example below. Defaults to `false`.
* `client` A http.Client instance if you want to reuse or implement some kind of connection pooling. Defaults to empty.
* `followRedirects` If set will recursively follow redirects. Defaults to `true`.
* `timeout` If set, will emit the timeout event when the response does not return within the said value (in ms)
* `rejectUnauthorized` If true, the server certificate is verified against the list of supplied CAs. An 'error' event is emitted if verification fails. Verification happens at the connection level, before the HTTP request is sent. Default true.
* `agent` [HTTP Agent][http-agent-doc] instance to use. If not defined [globalAgent][http-global-agent-doc] will be used. If false opts out of connection pooling with an Agent, defaults request to Connection: close.
Example usage
-------------
```javascript
var rest = require('./restler');
rest.get('http://google.com').on('complete', function(result) {
if (result instanceof Error) {
console.log('Error:', result.message);
this.retry(5000); // try again after 5 sec
} else {
console.log(result);
}
});
rest.get('http://twaud.io/api/v1/users/danwrong.json').on('complete', function(data) {
console.log(data[0].message); // auto convert to object
});
rest.get('http://twaud.io/api/v1/users/danwrong.xml').on('complete', function(data) {
console.log(data[0].sounds[0].sound[0].message); // auto convert to object
});
rest.get('http://someslowdomain.com',{timeout: 10000}).on('timeout', function(ms){
console.log('did not return within '+ms+' ms');
}).on('complete',function(data,response){
console.log('did not time out');
});
rest.post('http://user:pass@service.com/action', {
data: { id: 334 },
}).on('complete', function(data, response) {
if (response.statusCode == 201) {
// you can get at the raw response like this...
}
});
// multipart request sending a 321567 byte long file using https
rest.post('https://twaud.io/api/v1/upload.json', {
multipart: true,
username: 'danwrong',
password: 'wouldntyouliketoknow',
data: {
'sound[message]': 'hello from restler!',
'sound[file]': rest.file('doug-e-fresh_the-show.mp3', null, 321567, null, 'audio/mpeg')
}
}).on('complete', function(data) {
console.log(data.audio_url);
});
// create a service constructor for very easy API wrappers a la HTTParty...
Twitter = rest.service(function(u, p) {
this.defaults.username = u;
this.defaults.password = p;
}, {
baseURL: 'http://twitter.com'
}, {
update: function(message) {
return this.post('/statuses/update.json', { data: { status: message } });
}
});
var client = new Twitter('danwrong', 'password');
client.update('Tweeting using a Restler service thingy').on('complete', function(data) {
console.log(data);
});
// post JSON
var jsonData = { id: 334 };
rest.postJson('http://example.com/action', jsonData).on('complete', function(data, response) {
// handle response
});
// put JSON
var jsonData = { id: 334 };
rest.putJson('http://example.com/action', jsonData).on('complete', function(data, response) {
// handle response
});
```
TODO
----
* What do you need? Let me know or fork.
[http-agent-doc]: https://nodejs.org/api/http.html#http_class_http_agent
[http-global-agent-doc]: https://nodejs.org/api/http.html#http_http_globalagent
\ No newline at end of file
#!/usr/bin/env node
require.paths.push(process.cwd());
var sys = require('util'),
rest = require('../lib/restler'),
repl = require('repl');
var replServer = repl.start();
var exportMethods = {
sys: sys,
rest: rest
}
Object.keys(exportMethods).forEach(function(exportMethod) {
replServer.context[exportMethod] = exportMethods[exportMethod];
});
rest.get('http://twaud.io/api/v1/7.json').on('complete', function(data, response) {
console.log(response.headers);
replServer.context.data = data;
});
\ No newline at end of file
module.exports = require('./lib/restler');
\ No newline at end of file
var fs = require('fs');
var sys = require('util')
exports.defaultBoundary = '48940923NODERESLTER3890457293';
// This little object allows us hijack the write method via duck-typing
// and write to strings or regular streams that support the write method.
function Stream(stream) {
//If the user pases a string for stream,we initalize one to write to
if (this._isString(stream)) {
this.string = "";
}
this.stream = stream;
}
Stream.prototype = {
//write to an internal String or to the Stream
write: function(data) {
if (this.string != undefined) {
this.string += data;
} else {
this.stream.write(data, "binary");
}
},
//stolen from underscore.js
_isString: function(obj) {
return !!(obj === '' || (obj && obj.charCodeAt && obj.substr));
}
}
function File(path, filename, fileSize, encoding, contentType) {
this.path = path;
this.filename = filename || this._basename(path);
this.fileSize = fileSize;
this.encoding = encoding || "binary";
this.contentType = contentType || 'application/octet-stream';
}
File.prototype = {
_basename: function(path) {
var parts = path.split(/\/|\\/);
return parts[parts.length - 1];
}
};
function Data(filename, contentType, data) {
this.filename = filename;
this.contentType = contentType || 'application/octet-stream';
this.data = data;
}
function Part(name, value, boundary) {
this.name = name;
this.value = value;
this.boundary = boundary;
}
Part.prototype = {
//returns the Content-Disposition header
header: function() {
var header;
if (this.value.data) {
header = "Content-Disposition: form-data; name=\"" + this.name +
"\"; filename=\"" + this.value.filename + "\"\r\n" +
"Content-Length: " + this.value.data.length + "\r\n" +
"Content-Type: " + this.value.contentType;
} else if (this.value instanceof File) {
header = "Content-Disposition: form-data; name=\"" + this.name +
"\"; filename=\"" + this.value.filename + "\"\r\n" +
"Content-Length: " + this.value.fileSize + "\r\n" +
"Content-Type: " + this.value.contentType;
} else {
header = "Content-Disposition: form-data; name=\"" + this.name + "\"";
}
return "--" + this.boundary + "\r\n" + header + "\r\n\r\n";
},
//calculates the size of the Part
sizeOf: function() {
var valueSize;
if (this.value instanceof File) {
valueSize = this.value.fileSize;
} else if (this.value.data) {
valueSize = this.value.data.length;
} else if (typeof this.value === 'number') {
valueSize = this.value.toString().length;
} else {
valueSize = this.value.length;
}
return valueSize + this.header().length + 2;
},
// Writes the Part out to a writable stream that supports the write(data) method
// You can also pass in a String and a String will be returned to the callback
// with the whole Part
// Calls the callback when complete
write: function(stream, callback) {
var self = this;
//first write the Content-Disposition
stream.write(this.header());
//Now write out the body of the Part
if (this.value instanceof File) {
fs.open(this.value.path, "r", 0666, function (err, fd) {
if (err) throw err;
var position = 0;
(function reader () {
fs.read(fd, 1024 * 4, position, "binary", function (er, chunk) {
if (er) callback(err);
stream.write(chunk);
position += 1024 * 4;
if (chunk) reader();
else {
stream.write("\r\n")
callback();
fs.close(fd);
}
});
})(); // reader()
});
} else if (this.value instanceof Data) {
stream.write(this.value.data);
stream.write("\r\n");
callback();
} else {
stream.write(this.value + "\r\n");
callback();
}
}
}
//Renamed to MultiPartRequest from Request
function MultiPartRequest(data, boundary) {
this.encoding = 'binary';
this.boundary = boundary || exports.defaultBoundary;
this.data = data;
this.partNames = this._partNames();
}
MultiPartRequest.prototype = {
_partNames: function() {
var partNames = [];
for (var name in this.data) {
partNames.push(name)
}
return partNames;
},
write: function(stream, callback) {
var partCount = 0, self = this;
// wrap the stream in our own Stream object
// See the Stream function above for the benefits of this
var stream = new Stream(stream);
// Let each part write itself out to the stream
(function writePart() {
var partName = self.partNames[partCount];
var part = new Part(partName, self.data[partName], self.boundary);
part.write(stream, function (err) {
if (err) {
callback(err);
return;
}
partCount += 1;
if (partCount < self.partNames.length)
writePart();
else {
stream.write('--' + self.boundary + '--' + "\r\n");
if (callback) callback(stream.string || "");
}
});
})();
}
}
var exportMethods = {
file: function(path, filename, fileSize, encoding, contentType) {
return new File(path, filename, fileSize, encoding, contentType)
},
data: function(filename, contentType, data) {
return new Data(filename, contentType, data);
},
sizeOf: function(parts, boundary) {
var totalSize = 0;
boundary = boundary || exports.defaultBoundary;
for (var name in parts) totalSize += new Part(name, parts[name], boundary).sizeOf();
return totalSize + boundary.length + 6;
},
write: function(stream, data, callback, boundary) {
var r = new MultiPartRequest(data, boundary);
r.write(stream, callback);
return r;
}
}
Object.keys(exportMethods).forEach(function(exportMethod) {
exports[exportMethod] = exportMethods[exportMethod]
})
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment