Launch Week Day 5: Introducing Reachability for PHP.Learn More
Socket
Book a DemoSign in
Socket

create-servers

Package Overview
Dependencies
Maintainers
6
Versions
25
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

create-servers - npm Package Compare versions

Comparing version
3.2.0
to
3.2.1
+102
-94
index.js

@@ -10,3 +10,4 @@ 'use strict';

var fs = require('fs'),
const
fs = require('fs').promises,
tls = require('tls'),

@@ -19,5 +20,5 @@ path = require('path'),

var pemFormat = /-----BEGIN/;
const pemFormat = /-----BEGIN/;
var CIPHERS = [
const CIPHERS = [
'ECDHE-RSA-AES256-SHA384',

@@ -41,3 +42,3 @@ 'DHE-RSA-AES256-SHA384',

var secureOptions = constants.SSL_OP_NO_SSLv3;
const secureOptions = constants.SSL_OP_NO_SSLv3;

@@ -55,18 +56,15 @@ /**

const [
[httpErr, http],
[httpsErr, https],
[http2Err, http2]] = await Promise.all([
const [httpResult, httpsResult, http2Result] = await Promise.allSettled([
createHttp(options.http, options.log),
createHttps(options.https, options.log),
createHttps(options.http2, options.log, true)
]);
])
const servers = {};
if (http) servers.http = http;
if (https) servers.https = https;
if (http2) servers.http2 = http2;
if (httpResult.value) servers.http = httpResult.value;
if (httpsResult.value) servers.https = httpsResult.value;
if (http2Result.value) servers.http2 = http2Result.value;
if (httpErr || httpsErr || http2Err) {
let errorSource = http2Err || httpsErr || httpErr;
const errorSource = httpResult.reason || httpsResult.reason || http2Result.reason;
if (errorSource) {
if (Array.isArray(errorSource)) {

@@ -78,5 +76,5 @@ errorSource = errorSource[0];

message: errorSource && errorSource.message,
http2: http2Err,
https: httpsErr,
http: httpErr
http2: http2Result.reason,
https: httpsResult.reason,
http: httpResult.reason
}),

@@ -180,13 +178,13 @@ servers

return Array.isArray(data)
? data.map(function(item) {
? Promise.all(data.map(function(item) {
return normalizeCertChain(root, item);
})
}))
: normalizePEMContent(root, data);
}
function normalizeCertChain(root, data) {
async function normalizeCertChain(root, data) {
// A chain can be an array, which we concatenate together into one PEM,
// an already-concatenated chain, or a single PEM
const content = normalizePEMContent(root, data);
const content = await normalizePEMContent(root, data);
return Array.isArray(content) ? content.join('\n') : content;

@@ -199,3 +197,3 @@ }

}
return ca && ca.map(normalizePEMContent.bind(null, root));
return ca && Promise.all(ca.map(normalizePEMContent.bind(null, root)));
}

@@ -211,5 +209,5 @@

if (Array.isArray(file))
return file.map(function map(item) {
return Promise.all(file.map(function map(item) {
return normalizePEMContent(root, item);
});
}));

@@ -223,3 +221,3 @@ //

return fs.readFileSync(path.resolve(root, file));
return fs.readFile(path.resolve(root, file));
}

@@ -238,7 +236,7 @@

function getSNIHandler(sslOpts) {
var sniHosts = Object.keys(sslOpts.sni);
async function getSNIHandler(sslOpts) {
const sniHosts = Object.keys(sslOpts.sni);
// Pre-compile regexps for the hostname
var hostRegexps = sniHosts.map(function(host) {
const hostRegexps = sniHosts.map(function(host) {
return host === '*' ? /.*/ : new RegExp(

@@ -255,3 +253,3 @@ '^' +

// Prepare secure contexts ahead-of-time
var hostSecureContexts = sniHosts.map(function(host) {
const hostSecureContexts = await Promise.all(sniHosts.map(async function(host) {
var hostOpts = sslOpts.sni[host];

@@ -261,7 +259,13 @@

const [key, cert, ca] = await Promise.all([
normalizePEMContent(root, hostOpts.key),
normalizeCertContent(root, hostOpts.cert),
normalizeCA(root, hostOpts.ca || sslOpts.ca)
])
return tls.createSecureContext(
assign({}, sslOpts, hostOpts, {
key: normalizePEMContent(root, hostOpts.key),
cert: normalizeCertContent(root, hostOpts.cert),
ca: normalizeCA(root, hostOpts.ca || sslOpts.ca),
key,
cert,
ca,
ciphers: normalizeCiphers(hostOpts.ciphers || sslOpts.ciphers),

@@ -275,3 +279,3 @@ honorCipherOrder: !!(

);
});
}));

@@ -298,3 +302,3 @@ return function(hostname, cb) {

log('http | no options.http; no server');
return [null, null];
return null;
}

@@ -306,18 +310,19 @@

return await new Promise(resolve => {
var server = require('http').createServer(httpConfig.handler),
timeout = httpConfig.timeout,
port = httpConfig.port,
args;
const
server = require('http').createServer(httpConfig.handler),
timeout = httpConfig.timeout,
port = httpConfig.port;
if (typeof timeout === 'number') server.setTimeout(timeout);
if (typeof timeout === 'number') server.setTimeout(timeout);
args = [server, port];
if (httpConfig.host) {
args.push(httpConfig.host);
}
const args = [server, port];
if (httpConfig.host) {
args.push(httpConfig.host);
}
log('http | try listen ' + port);
log('http | try listen ' + port);
return new Promise((resolve, reject) => {
args.push(function listener(err) {
resolve([err, server]);
err ? reject(err) : resolve(server);
});

@@ -335,3 +340,3 @@ connected.apply(null, args);

log('https | no options.https; no server');
return [null, null];
return null;
}

@@ -343,48 +348,46 @@

return await new Promise(resolve => {
var port = ssl.port,
timeout = ssl.timeout,
server,
args;
const [key, cert, ca] = await Promise.all([
normalizePEMContent(ssl.root, ssl.key),
normalizeCertContent(ssl.root, ssl.cert, ssl.key),
normalizeCA(ssl.root, ssl.ca)
]);
var finalHttpsOptions = assign({}, ssl, {
//
// Load default SSL key, cert and ca(s).
//
key: normalizePEMContent(ssl.root, ssl.key),
cert: normalizeCertContent(ssl.root, ssl.cert, ssl.key),
ca: normalizeCA(ssl.root, ssl.ca),
//
// Properly expose ciphers for an A+ SSL rating:
// https://certsimple.com/blog/a-plus-node-js-ssl
//
ciphers: normalizeCiphers(ssl.ciphers),
honorCipherOrder: !!ssl.honorCipherOrder,
//
// Protect against the POODLE attack by disabling SSLv3
// @see http://googleonlinesecurity.blogspot.nl/2014/10/this-poodle-bites-exploiting-ssl-30.html
//
secureProtocol: 'SSLv23_method',
secureOptions: secureOptions
});
const finalHttpsOptions = assign({}, ssl, {
key,
cert,
ca,
//
// Properly expose ciphers for an A+ SSL rating:
// https://certsimple.com/blog/a-plus-node-js-ssl
//
ciphers: normalizeCiphers(ssl.ciphers),
honorCipherOrder: !!ssl.honorCipherOrder,
//
// Protect against the POODLE attack by disabling SSLv3
// @see http://googleonlinesecurity.blogspot.nl/2014/10/this-poodle-bites-exploiting-ssl-30.html
//
secureProtocol: 'SSLv23_method',
secureOptions: secureOptions
});
if (ssl.sni && !finalHttpsOptions.SNICallback) {
finalHttpsOptions.SNICallback = getSNIHandler(ssl);
}
if (ssl.sni && !finalHttpsOptions.SNICallback) {
finalHttpsOptions.SNICallback = await getSNIHandler(ssl);
}
log('https | listening on %d', port);
if(h2) {
server = require('http2').createSecureServer(finalHttpsOptions, ssl.handler)
} else {
server = require('https').createServer(finalHttpsOptions, ssl.handler);
}
const port = ssl.port;
log('https | listening on %d', port);
const server = h2
? require('http2').createSecureServer(finalHttpsOptions, ssl.handler)
: require('https').createServer(finalHttpsOptions, ssl.handler);
if (typeof timeout === 'number') server.setTimeout(timeout);
args = [server, port];
if (ssl.host) {
args.push(ssl.host);
}
const timeout = ssl.timeout;
if (typeof timeout === 'number') server.setTimeout(timeout);
const args = [server, port];
if (ssl.host) {
args.push(ssl.host);
}
return new Promise((resolve, reject) => {
args.push(function listener(err) {
resolve([err, server]);
err ? reject(err) : resolve(server);
});

@@ -396,12 +399,17 @@ connected.apply(null, args);

async function createMultiple(createFn, configArray, log) {
const errorsOrServers = await Promise.all(
const errorsOrServers = await Promise.allSettled(
configArray.map(cfg => createFn(cfg, log))
);
const errors = [],
servers = [];
for (const [error, server] of errorsOrServers) {
error && errors.push(error);
server && servers.push(server);
const errors = [], servers = [];
for (const result of errorsOrServers) {
result.reason && errors.push(result.reason);
result.value && servers.push(result.value);
}
return [errors.length ? errors : null, servers];
if (errors.length) {
throw errors;
} else {
return servers;
}
}
{
"name": "create-servers",
"version": "3.2.0",
"version": "3.2.1",
"description": "Create an http AND/OR an https server and call the same request handler.",
"main": "index.js",
"files": [
"./index.js"
],
"scripts": {

@@ -7,0 +10,0 @@ "test": "node test/create-servers-test.js"

package-lock.json binary
language: node_js
node_js:
- "0.12"
- "0.10"
- "0.8"
- "iojs"
before_install:
- "npm install -g npm@1.4.x"
# CHANGELOG
## 3.2.0
- [#37] Support HTTP2
## 3.1.0
- [#23], @DullReferenceException Support "*" for SNI host pattern
## 3.0.1
- [#22] Return value compatibility. Do no return `null` valued keys.
## 3.0.0
- [#21], @DullReferenceException Support creating multiple HTTP or HTTPS servers.
- [BREAKING] Introduces `async` functions.
{
"platform": "github",
"autodiscover": false,
"requireConfig": true,
"ignoreNpmrcFile": true,
"rangeStrategy": "replace",
"packageRules": [
{
"packagePatterns": [
"*"
],
"minor": {
"groupName": "all non-major dependencies",
"groupSlug": "all-minor-patch"
}
}
],
"commitMessagePrefix": "[dist]"
}
/*
* create-servers-test.js: Make sure creating both works
*
* (C) 2013, Charlie Robbins.
*
*/
var path = require('path'),
fs = require('fs'),
url = require('url'),
http = require('http'),
https = require('https'),
http2 = require('http2'),
{ promisify } = require('util'),
test = require('tape'),
sinon = require('sinon'),
evilDNS = require('evil-dns'),
createServers = require('../');
const createServersAsync = promisify(createServers);
const { HTTP2_HEADER_PATH } = http2.constants;
const ca = fs.readFileSync(path.join(__dirname, './fixtures/example-ca-cert.pem'));
//
// Immediately end a response.
//
function fend(req, res) {
res.end();
}
//
// Request and download response from a URL
//
async function download(httpsURL) {
return new Promise((resolve, reject) => {
const req = https.get({
...url.parse(httpsURL),
ca
}, res => {
const chunks = [];
res
.on('data', chunk => chunks.push(chunk))
.once('end', () => {
resolve(chunks.map(chunk => chunk.toString('utf8')).join(''));
})
.once('aborted', reject)
.once('close', reject)
.once('error', reject);
});
req.once('error', reject);
});
}
//
// Request and download response from a URL using HTTP/2
//
async function download2(httpsURL) {
return new Promise((resolve, reject) => {
const clientSession = http2.connect(httpsURL);
const fail = results => {
clientSession.close();
reject(results);
};
const req = clientSession.request({ [HTTP2_HEADER_PATH]: '/' });
req.on('response', () => {
const chunks = [];
req
.on('data', chunk => chunks.push(chunk))
.once('end', () => {
resolve(chunks.map(chunk => chunk.toString('utf8')).join(''));
clientSession.close();
});
})
.once('aborted', fail)
.once('close', fail)
.once('error', fail);
});
}
/**
* Helper to start a server with HTTP/2 support.
* Returns stop function to handle server and dns cleanup after tests.
*
* Tests requests can be made to foo.example.org:3456
*
* @param {object} options - Additional http2 server options.
* @returns {Promise<(function(): void)|*>} callback
*/
async function startHttp2Server(options = {}) {
// disabling to avoid UNABLE_TO_VERIFY_LEAF_SIGNATURE for tests
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
const servers = await createServersAsync({
http2: {
port: 3456,
root: path.join(__dirname, 'fixtures'),
key: 'example-org-key.pem',
cert: 'example-org-cert.pem',
...options
},
handler: (req, res) => {
const { httpVersion } = req;
const { socket: { alpnProtocol } } = httpVersion === '2.0' ? req.stream.session : req;
res.writeHead(200, { 'content-type': 'application/json' });
res.end(JSON.stringify({
alpnProtocol,
httpVersion
}));
}
});
evilDNS.add('foo.example.org', '0.0.0.0');
return function stop() {
servers && servers.http2 && servers.http2.close();
evilDNS.clear();
delete process.env.NODE_TLS_REJECT_UNAUTHORIZED;
};
}
test('only http', function (t) {
t.plan(5);
createServers({
log: console.log,
http: 9876,
handler: fend
}, function (err, servers) {
console.dir(err);
t.error(err);
t.equals(typeof servers, 'object');
t.equals(typeof servers.http, 'object');
t.equals(servers.http instanceof Array, false);
t.equals(servers.https, undefined);
servers.http.close();
});
});
test('only http, port 0', function (t) {
t.plan(4);
createServers({
log: console.log,
http: 0,
handler: fend
}, function (err, servers) {
console.dir(err);
t.error(err);
t.equals(typeof servers, 'object');
t.equals(typeof servers.http, 'object');
t.equals(typeof servers.http.address().port, 'number');
servers.http.close();
});
});
test('only http, timeout', function (t) {
t.plan(5);
var time = 3000000;
createServers({
log: console.log,
timeout: time,
http: 0,
handler: fend
}, function (err, servers) {
console.dir(err);
t.error(err);
t.equals(typeof servers, 'object');
t.equals(typeof servers.http, 'object');
t.equals(typeof servers.http.address().port, 'number');
t.equals(servers.http.timeout, time);
servers.http.close();
});
});
test('only https', function (t) {
t.plan(5);
createServers({
log: console.log,
https: {
port: 3456,
root: path.join(__dirname, 'fixtures'),
key: 'example-org-key.pem',
cert: 'example-org-cert.pem'
},
handler: fend
}, function (err, servers) {
t.error(err);
t.equals(typeof servers, 'object');
t.equals(typeof servers.https, 'object');
t.equals(servers.https instanceof Array, false);
t.equals(servers.http, undefined);
servers.https.close();
});
});
test('only https', function (t) {
t.plan(4);
var time = 4000000;
createServers({
log: console.log,
https: {
timeout: time,
port: 3456,
root: path.join(__dirname, 'fixtures'),
key: 'example-org-key.pem',
cert: 'example-org-cert.pem'
},
handler: fend
}, function (err, servers) {
t.error(err);
t.equals(typeof servers, 'object');
t.equals(typeof servers.https, 'object');
t.equals(servers.https.timeout, time);
servers.https.close();
});
});
test('only http2', function (t) {
t.plan(4);
var time = 4000000;
createServers({
log: console.log,
http2: {
timeout: time,
port: 3456,
root: path.join(__dirname, 'fixtures'),
key: 'example-org-key.pem',
cert: 'example-org-cert.pem'
},
handler: fend
}, function (err, servers) {
t.error(err);
t.equals(typeof servers, 'object');
t.equals(typeof servers.http2, 'object');
t.equals(servers.http2.timeout, time);
servers.http2.close();
});
});
test('absolute cert path resolution', function (t) {
t.plan(3);
createServers({
log: console.log,
https: {
port: 3456,
root: '/',
cert: path.resolve(__dirname, 'fixtures', 'example-org-cert.pem'),
key: path.resolve(__dirname, 'fixtures', 'example-org-key.pem')
},
handler: fend
}, function (err, servers) {
t.error(err);
t.equals(typeof servers, 'object');
t.equals(typeof servers.https, 'object');
servers.https.close();
});
});
test('http && https', function (t) {
t.plan(4);
createServers({
log: console.log,
http: 8765,
https: {
port: 3456,
root: path.join(__dirname, 'fixtures'),
key: 'example-org-key.pem',
cert: 'example-org-cert.pem'
},
handler: fend
}, function (err, servers) {
t.error(err);
t.equals(typeof servers, 'object');
t.equals(typeof servers.http, 'object');
t.equals(typeof servers.https, 'object');
servers.http.close();
servers.https.close();
});
});
test('provides useful debug information', async function (t) {
t.plan(4);
const config = {
log: console.log,
https: {
port: 3456,
root: path.join(__dirname, 'fixtures'),
key: 'example-org-key.pem',
cert: 'example-org-cert.pem'
},
handler: fend
};
// Simulate a "port in use" error
const { https: server1 } = await createServersAsync(config);
try {
await createServersAsync(config);
} catch (err) {
t.equals(typeof err, 'object');
t.equals(typeof err.https, 'object');
t.equals(typeof err.message, 'string');
t.notEqual(err.message, 'Unspecified error');
} finally {
server1.close();
}
});
test('http && https with different handlers', function (t) {
t.plan(4);
createServers({
log: console.log,
http: {
handler: function (req, res) {
res.end('http');
},
port: 8765
},
https: {
handler: function (req, res) {
res.end('https');
},
port: 3456,
root: path.join(__dirname, 'fixtures'),
key: 'example-org-key.pem',
cert: 'example-org-cert.pem'
}
}, function (err, servers) {
t.error(err);
t.equals(typeof servers, 'object');
t.equals(typeof servers.http, 'object');
t.equals(typeof servers.https, 'object');
servers.http.close();
servers.https.close();
});
test('only http with string type input for http port', function (t) {
t.plan(3);
createServers({
log: console.log,
http: '9876',
handler: fend
}, function (err, servers) {
t.error(err);
t.equals(typeof servers, 'object');
t.equals(typeof servers.http, 'object');
servers.http.close();
});
});
test('host can be provided to the server', function (t) {
t.plan(4);
createServers({
log: console.log,
http: {
port: 9877,
host: '127.0.0.1'
},
handler: fend
}, function (err, servers) {
t.error(err);
t.equals(typeof servers, 'object');
t.equals(typeof servers.http, 'object');
t.equals(servers.http.address().address, '127.0.0.1');
servers.http.close();
});
});
});
test('supports cert contents instead of cert paths', function (t) {
t.plan(3);
var root = path.join(__dirname, 'fixtures');
createServers({
log: console.log,
https: {
port: 3456,
root: root,
cert: fs.readFileSync(path.resolve(root, 'example-org-cert.pem')),
key: fs.readFileSync(path.resolve(root, 'example-org-key.pem'))
},
handler: fend
}, function (err, servers) {
t.error(err);
t.equals(typeof servers, 'object');
t.equals(typeof servers.https, 'object');
servers.https.close();
});
});
test('supports cert array instead of strings', function (t) {
t.plan(3);
var root = path.join(__dirname, 'fixtures');
createServers({
log: console.log,
https: {
port: 3456,
root: root,
key: 'example-org-key.pem',
cert: 'example-org-cert.pem'
},
handler: fend
}, function (err, servers) {
t.error(err);
t.equals(typeof servers, 'object');
t.equals(typeof servers.https, 'object');
servers.https.close();
});
});
test('supports creating certificate chains', function (t) {
t.plan(2);
var root = path.join(__dirname, 'fixtures');
var agent3Cert = fs.readFileSync(path.resolve(root, 'agent3-cert.pem'));
var intermediate = fs.readFileSync(
path.resolve(root, 'intermediate-cert.pem')
);
var spy = sinon.spy(https, 'createServer');
createServers({
log: console.log,
https: {
port: 3456,
root: root,
cert: ['agent3-cert.pem', 'intermediate-cert.pem'],
key: 'agent3-key.pem'
},
handler: fend
}, function (err, servers) {
t.error(err);
const expectedBundle = [agent3Cert, intermediate].join('\n');
const cert = spy.lastCall.args[0].cert;
t.equals(cert, expectedBundle, 'should create a cert chain');
servers.https.close();
spy.restore();
});
});
test('supports requestCert https option', function (t) {
t.plan(2);
var spy = sinon.spy(https, 'createServer');
createServers({
log: console.log,
https: {
port: 3456,
root: path.join(__dirname, 'fixtures'),
key: 'example-org-key.pem',
cert: 'example-org-cert.pem',
requestCert: true
},
handler: fend
}, function (err, servers) {
t.error(err);
t.equals(
spy.lastCall.args[0].requestCert,
true,
'should preserve the requestCert option'
);
servers.https.close();
spy.restore();
});
});
test('supports SNI', async t => {
await testSni(t, {
'example.com': {
key: 'example-com-key.pem',
cert: 'example-com-cert.pem'
},
'example.net': {
key: 'example-net-key.pem',
cert: 'example-net-cert.pem'
},
'*.example.org': {
key: 'example-org-key.pem',
cert: 'example-org-cert.pem'
}
}, ['example.com', 'example.net', 'foo.example.org']);
});
test('supports catch-all * for SNI', async t => {
await testSni(t, {
'example.com': {
key: 'example-com-key.pem',
cert: 'example-com-cert.pem'
},
'*': {
key: 'example-org-key.pem',
cert: 'example-org-cert.pem'
}
}, ['example.com', 'foo.example.org']);
});
test('multiple https servers', async function (t) {
t.plan(2);
evilDNS.add('foo.example.org', '0.0.0.0');
const servers = await createServersAsync({
log: console.log,
https: [
{
port: 3456,
root: path.join(__dirname, 'fixtures'),
key: 'example-org-key.pem',
cert: 'example-org-cert.pem'
},
{
port: 6543,
root: path.join(__dirname, 'fixtures'),
key: 'example-org-key.pem',
cert: 'example-org-cert.pem'
}
],
handler: (req, res) => {
res.end('Hello');
}
});
try {
t.equals(servers.https.length, 2, 'two servers were created');
const responses = await Promise.all([
download('https://foo.example.org:3456/'),
download('https://foo.example.org:6543/')
]);
t.equals(
responses.every(str => str === 'Hello'),
true,
'responses are as expected'
);
} finally {
let toClose =
servers.https instanceof Array ? servers.https : [servers.https];
toClose.forEach(server => server.close());
evilDNS.clear();
}
});
test('supports http2-only requests', async function (t) {
t.plan(2);
const url = 'https://foo.example.org:3456/';
let stopServer;
try {
stopServer = await startHttp2Server({});
const httpsResponse = await download(url);
t.ok(httpsResponse.includes('Unknown ALPN Protocol'));
const response = JSON.parse(await download2(url));
t.equals(response.httpVersion, '2.0');
} catch (err) {
t.error(err);
} finally {
stopServer && stopServer();
}
});
test('supports http2 and https requests', async function (t) {
t.plan(2);
const url = 'https://foo.example.org:3456/';
let stopServer;
try {
stopServer = await startHttp2Server({
allowHTTP1: true
});
const httpsResponse = JSON.parse(await download(url));
t.equals(httpsResponse.httpVersion, '1.1');
const response = JSON.parse(await download2(url));
t.equals(response.httpVersion, '2.0');
} catch (err) {
t.error(err);
} finally {
stopServer && stopServer();
}
});
async function testSni(t, sniConfig, hostNames) {
t.plan(1);
let httpsServer;
try {
const servers = await createServersAsync({
https: {
port: 3456,
root: path.join(__dirname, 'fixtures'),
sni: sniConfig
},
handler: (req, res) => {
res.write('Hello');
res.end();
}
});
httpsServer = servers.https;
hostNames.forEach(host => evilDNS.add(host, '0.0.0.0'));
const responses = await Promise.all(
hostNames.map(hostname => download(`https://${hostname}:3456/`))
);
t.equals(
responses.every(str => str === 'Hello'),
true,
'responses are as expected'
);
} catch (err) {
return void t.error(err);
} finally {
httpsServer && httpsServer.close();
evilDNS.clear();
}
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet