feat: add components

This commit is contained in:
2025-04-04 17:19:07 +08:00
parent 6f494ec9ca
commit c37b9f0ab2
40 changed files with 2088 additions and 0 deletions

View File

@@ -0,0 +1,82 @@
var parseARGS = (kvKeys) => {
return exports.parse($ARGS, kvKeys);
};
var parse = (args, kvKeys) => {
var newArgs = [];
var keyValueMap = {};
var keyFlagMap = {};
keyValueMap.vals = () => {
var ret = [];
for (var i = 0; i < arguments.length; i++) {
var v = keyValueMap[arguments[i]];
if (v) { v.forEach((x) => { ret.push(x) } ); }
}
return ret;
};
keyValueMap.val = () => {
for (var i = 0; i < arguments.length; i++) {
var v = keyValueMap[arguments[i]] && keyValueMap[arguments[i]][0];
if (v) { return v; }
}
return null;
};
keyFlagMap.flg = () => {
for (var i = 0; i < arguments.length; i++) {
var v = keyFlagMap[arguments[i]];
if (v) { return true; }
}
return false;
};
var kvKeyMap = {}; (kvKeys || []).forEach((k) => { kvKeyMap[k] = 1; });
for (var i = 0; i < args.length; i++) {
var arg = args[i];
var key = null;
if (arg.startsWith('--')) {
key = arg.substring(2);
} else if (arg.startsWith('-')) {
key = arg.substring(1);
if (key.length > 1) {
for (var x = 0; x < key.length; x++) {
var k = key.substring(x, 1);
kvKeyMap[k] = 1;
keyFlagMap[k] = 1;
}
continue;
}
}
if ((key != null) && ((i + 1) < args.length) || kvKeyMap[key]) {
if (kvKeyMap[key]) {
keyFlagMap[key] = 1;
} else {
keyValueMap[key] = keyValueMap[key] || [];
keyValueMap[key].push(args[++i]);
}
} else {
newArgs.push(arg);
}
}
return {
args: newArgs,
flags: keyFlagMap,
values: keyValueMap
};
};
var parseDefARGs = (kvKeys) => {
var args = parseARGS(kvKeys);
var newArgs = args.args;
newArgs.flg = args.flags.flg;
newArgs.val = args.values.val;
newArgs.vals = args.values.vals;
return newArgs;
};
if (typeof exports == 'object') {
exports.parse = parse;
exports.parseARGS = parseARGS;
exports.parseDefARGs = parseDefARGs;
}

View File

@@ -0,0 +1,17 @@
var UNITS = ['bytes', 'KB', 'MB', 'GB', 'TB'];
var UNITS_BYTES = [0, Math.pow(1024, 1), Math.pow(1024, 2), Math.pow(1024, 3), Math.pow(1024, 4)];
exports.showBytes = (bytes) => {
for (var i = 0; i < (UNITS.length - 1); i++) {
if ((bytes >= UNITS_BYTES[i]) && bytes < UNITS_BYTES[i + 1]) {
if (i == 0) {
return bytes + ((bytes <= 1) ? ' byte' : ' bytes');
} else {
return (parseInt(bytes * 100 / UNITS_BYTES[i]) / 100) + ' ' + UNITS[i];
}
}
}
return (parseInt(bytes * 100 / UNITS_BYTES[i]) / 100) + ' ' + UNITS[i]; // i == UNITS.length - 1
};

View File

@@ -0,0 +1,41 @@
var HEADER = '\033[95m';
var OKBLUE = '\033[94m';
var OKGREEN = '\033[92m';
var WARNING = '\033[93m';
var FAIL = '\033[91m';
var BOLD = '\033[1m';
var UNDERLINE = '\033[4m';
var ENDC = '\033[0m';
var colorMapping = {
"header": HEADER,
"okblue": OKBLUE,
"okgreen": OKGREEN,
"warning": WARNING,
"fail": FAIL,
"bold": BOLD,
"underline": UNDERLINE,
"none": null // nothing special
};
var colorPrint = exports;
for (var k in colorMapping) {
colorPrint[k] = {};
colorPrint[k].render = ((k) => {
return (x) => {
return colorMapping[k] ? (colorMapping[k] + x + ENDC) : x;
};
})(k);
colorPrint[k].print = ((k) => {
return (x) => {
print(colorPrint[k].render(x));
};
})(k);
colorPrint[k].println = ((k) => {
return (x) => {
println(colorPrint[k].render(x));
};
})(k);
}

View File

@@ -0,0 +1,3 @@
(() => {
colorPrint = require('component-colorprint-ex.js');
})();

View File

@@ -0,0 +1,61 @@
var System = java.lang.System;
var readLineEx = (prompt) => {
var ret = null;
while ((ret == null) || $STR(ret).trim() == '') {
ret = readLine(prompt);
}
return ret;
};
var readLine = (prompt) => {
print(prompt);
return System.console().readLine();
};
var readYNEx = (prompt) => {
var ret = null;
while (ret == null) {
ret = readYN(prompt);
}
return ret;
};
var readYN = (prompt) => {
print(prompt);
var read = readLine();
if ($STR(read).toLowerCase() == 'y') {
return true;
}
if ($STR(read).toLowerCase() == 'n') {
return false;
}
return null;
};
var readListToMark = (prompt, mark) => {
if (!(mark)) { throw 'Mark cannot be null or empty.'; }
print(prompt);
var list = [];
while (true) {
var ln = System.console().readLine();
if ($STR(ln) == $STR(mark)) {
return list;
}
list.push(ln);
}
};
var readListToCustomMark = (prompt) => {
var mark = readLineEx(prompt);
return readListToMark('', mark);
};
if (typeof exports == 'object') {
exports.readYN = readYN;
exports.readYNEx = readYNEx;
exports.readLine = readLine;
exports.readLineEx = readLineEx;
exports.readListToMark = readListToMark;
exports.readListToCustomMark = readListToCustomMark;
}

View File

@@ -0,0 +1,137 @@
// https://github.com/wandergis/coordtransform/blob/master/index.js
(() => {
/**
* Created by Wandergis on 2015/7/8.
* 提供了百度坐标BD09、国测局坐标火星坐标GCJ02、和WGS84坐标系之间的转换
*/
//定义一些常量
var x_PI = 3.14159265358979324 * 3000.0 / 180.0;
var PI = 3.1415926535897932384626;
var a = 6378245.0;
var ee = 0.00669342162296594323;
/**
* 百度坐标系 (BD-09) 与 火星坐标系 (GCJ-02)的转换
* 即 百度 转 谷歌、高德
* @param bd_lon
* @param bd_lat
* @returns {*[]}
*/
var bd09togcj02 = function bd09togcj02(bd_lon, bd_lat) {
var bd_lon = +bd_lon;
var bd_lat = +bd_lat;
var x = bd_lon - 0.0065;
var y = bd_lat - 0.006;
var z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * x_PI);
var theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * x_PI);
var gg_lng = z * Math.cos(theta);
var gg_lat = z * Math.sin(theta);
return [gg_lng, gg_lat]
};
/**
* 火星坐标系 (GCJ-02) 与百度坐标系 (BD-09) 的转换
* 即谷歌、高德 转 百度
* @param lng
* @param lat
* @returns {*[]}
*/
var gcj02tobd09 = function gcj02tobd09(lng, lat) {
var lat = +lat;
var lng = +lng;
var z = Math.sqrt(lng * lng + lat * lat) + 0.00002 * Math.sin(lat * x_PI);
var theta = Math.atan2(lat, lng) + 0.000003 * Math.cos(lng * x_PI);
var bd_lng = z * Math.cos(theta) + 0.0065;
var bd_lat = z * Math.sin(theta) + 0.006;
return [bd_lng, bd_lat]
};
/**
* WGS84转GCj02
* @param lng
* @param lat
* @returns {*[]}
*/
var wgs84togcj02 = function wgs84togcj02(lng, lat) {
var lat = +lat;
var lng = +lng;
if (out_of_china(lng, lat)) {
return [lng, lat]
} else {
var dlat = transformlat(lng - 105.0, lat - 35.0);
var dlng = transformlng(lng - 105.0, lat - 35.0);
var radlat = lat / 180.0 * PI;
var magic = Math.sin(radlat);
magic = 1 - ee * magic * magic;
var sqrtmagic = Math.sqrt(magic);
dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * PI);
dlng = (dlng * 180.0) / (a / sqrtmagic * Math.cos(radlat) * PI);
var mglat = lat + dlat;
var mglng = lng + dlng;
return [mglng, mglat]
}
};
/**
* GCJ02 转换为 WGS84
* @param lng
* @param lat
* @returns {*[]}
*/
var gcj02towgs84 = function gcj02towgs84(lng, lat) {
var lat = +lat;
var lng = +lng;
if (out_of_china(lng, lat)) {
return [lng, lat]
} else {
var dlat = transformlat(lng - 105.0, lat - 35.0);
var dlng = transformlng(lng - 105.0, lat - 35.0);
var radlat = lat / 180.0 * PI;
var magic = Math.sin(radlat);
magic = 1 - ee * magic * magic;
var sqrtmagic = Math.sqrt(magic);
dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * PI);
dlng = (dlng * 180.0) / (a / sqrtmagic * Math.cos(radlat) * PI);
var mglat = lat + dlat;
var mglng = lng + dlng;
return [lng * 2 - mglng, lat * 2 - mglat]
}
};
var transformlat = function transformlat(lng, lat) {
var lat = +lat;
var lng = +lng;
var ret = -100.0 + 2.0 * lng + 3.0 * lat + 0.2 * lat * lat + 0.1 * lng * lat + 0.2 * Math.sqrt(Math.abs(lng));
ret += (20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0 / 3.0;
ret += (20.0 * Math.sin(lat * PI) + 40.0 * Math.sin(lat / 3.0 * PI)) * 2.0 / 3.0;
ret += (160.0 * Math.sin(lat / 12.0 * PI) + 320 * Math.sin(lat * PI / 30.0)) * 2.0 / 3.0;
return ret
};
var transformlng = function transformlng(lng, lat) {
var lat = +lat;
var lng = +lng;
var ret = 300.0 + lng + 2.0 * lat + 0.1 * lng * lng + 0.1 * lng * lat + 0.1 * Math.sqrt(Math.abs(lng));
ret += (20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0 / 3.0;
ret += (20.0 * Math.sin(lng * PI) + 40.0 * Math.sin(lng / 3.0 * PI)) * 2.0 / 3.0;
ret += (150.0 * Math.sin(lng / 12.0 * PI) + 300.0 * Math.sin(lng / 30.0 * PI)) * 2.0 / 3.0;
return ret
};
/**
* 判断是否在国内,不在国内则不做偏移
* @param lng
* @param lat
* @returns {boolean}
*/
var out_of_china = function out_of_china(lng, lat) {
var lat = +lat;
var lng = +lng;
// 纬度3.86~53.55,经度73.66~135.05
return !(lng > 73.66 && lng < 135.05 && lat > 3.86 && lat < 53.55);
};
exports.bd09togcj02 = bd09togcj02;
exports.gcj02tobd09 = gcj02tobd09;
exports.wgs84togcj02 = wgs84togcj02;
exports.gcj02towgs84 = gcj02towgs84;
})();

View File

@@ -0,0 +1,68 @@
var counter = require('component-counter.js');
var requireJARs = () => {
$ONCE('component-cos-requireJARS').run(() => {
requireJAR('cos_api-5.2.2.jar');
requireJAR('httpcore-4.4.6.jar');
requireJAR('commons-codec-1.10.jar');
requireJAR('commons-logging-1.2.jar');
requireJAR('httpclient-4.5.3.jar');
requireJAR('httpmime-4.5.2.jar');
requireJAR('slf4j-api-1.7.21.jar');
requireJAR('log4j-1.2.17.jar');
requireJAR('slf4j-log4j12-1.7.21.jar');
requireJAR('joda-time-2.9.6.jar');
requireJAR('jackson-core-2.8.5.jar');
requireJAR('jackson-annotations-2.8.0.jar');
requireJAR('jackson-databind-2.8.5.jar');
});
};
var createCounterIS = (file) => {
var CounterInputStream = Packages.me.hatter.tools.commons.io.CounterInputStream;
var uploadFile = (file instanceof java.io.File) ? file : new java.io.File(file);
var uploadIS = new java.io.FileInputStream(uploadFile);
var counterIS = new CounterInputStream(uploadIS, counter.getCounterBar(uploadFile.length()));
return counterIS;
};
var putObject = (client, bucket, key, file) => {
var f = $$.file(file);
var objectMetadata = new Packages.com.qcloud.cos.model.ObjectMetadata();
objectMetadata.setContentLength(f.length());
var result = client.putObject(bucket, key, createCounterIS(f), objectMetadata);
return result;
};
// client -> https://cloud.tencent.com/document/product/436/10199
// region -> https://cloud.tencent.com/document/product/436/6224
var newClient = (region, appId, accessKey, secretKey) => {
requireJARs();
var COSClient = Packages.com.qcloud.cos.COSClient;
var Region = Packages.com.qcloud.cos.region.Region;
var ClientConfig = Packages.com.qcloud.cos.ClientConfig;
var BasicCOSCredentials = Packages.com.qcloud.cos.auth.BasicCOSCredentials;
var cred = new BasicCOSCredentials(appId, accessKey, secretKey);
var clientConfig = new ClientConfig(new Region(region));
var client = new COSClient(cred, clientConfig);
return {
runWith: (runFunc) => {
try {
runFunc(client);
} catch (e) {
println('COS Error: ' + e);
} finally {
client.shutdown();
}
}
};
};
if (typeof exports == 'object') {
exports.requireJARs = requireJARs;
exports.createCounterIS = createCounterIS;
exports.putObject = putObject;
exports.newClient = newClient;
}

View File

@@ -0,0 +1,77 @@
var bytesjs = require('component-bytes.js');
exports.getCounter = (fileLength, dotStep) => {
var total = 0;
var step = dotStep || (1024 * 64);
var percentPrintFlag = {};
var percentN = (fileLength > (60 * 1024 * 1024)) ? 100 : 10;
return (len) => {
var t = total;
total += len;
var n = parseInt(total / step) - parseInt(t / step);
if (n > 0) { n.times(() => { print('.') }); }
if (fileLength) {
var updatePercentN = parseInt((total * percentN) / fileLength);
if (updatePercentN && (!(percentPrintFlag[updatePercentN]))) {
percentPrintFlag[updatePercentN] = 1;
print('[' + parseInt((total * 100) / fileLength) + '%]');
}
}
};
};
exports.getCounter2 = (dotStep) => {
var total = 0;
var step = dotStep || (1024 * 64);
var percentPrintFlag = {};
return (len, fileLength) => {
var t = total;
total += len;
var n = parseInt(total / step) - parseInt(t / step);
if (n > 0) { n.times(() => { print('.') }); }
if (fileLength > 0) {
var updatePercent10 = parseInt((total * 10) / fileLength);
if (updatePercent10 && (!(percentPrintFlag[updatePercent10]))) {
percentPrintFlag[updatePercent10] = 1;
print('[' + parseInt((total * 100) / fileLength) + '%]');
}
}
};
};
exports.getCounter2Bar = (dotStep) => {
Packages.me.hatter.tools.jssp.main.StandaloneMainInteractive.initJLine(); // require jline
var total = 0;
var start = $$.date().millis();
var step = dotStep || (1024 * 64);
var percentPrintFlag = {};
return (len, fileLength) => {
var t = total; total += len;
var diff = $$.date().millis() - start;
var download = bytesjs.showBytes(total);
var speed = 'unknown';
if (diff > 0) {
speed = bytesjs.showBytes(parseInt(total * 1000 / diff)) + '/s';
}
if (fileLength > 0) {
var width = Packages.jline.TerminalFactory.get().getWidth();
var per = ' ' + $$.num(total).mul(100).divr(fileLength, 2, null) + '% [' + download + ' - ' + speed + ']';
var w = $$.num(total).divr((fileLength), 10, null).mul(width - 2 - per.length).floor().aint();
reprint(repeat('>', w) + per);
} else {
reprint('Downloaded: ' + download + ', speed: ' + speed);
}
};
};
exports.getCounterBar = (fileLength) => {
Packages.me.hatter.tools.jssp.main.StandaloneMainInteractive.initJLine(); // require jline
var total = 0;
return (len) => {
var width = Packages.jline.TerminalFactory.get().getWidth();
total += len;
var per = ' ' + $$.num(total).mul(100).divr(fileLength, 2, null) + '%';
var w = $$.num(total).divr((fileLength), 10, null).mul(width - 1 - per.length).floor().aint();
print('\r' + repeat('>', w) + per + '\033[K');
};
};

View File

@@ -0,0 +1,26 @@
requireJAR('dataaccess-1.0.jar');
var InMemoryCompiler = Packages.me.hatter.tools.commons.classloader.compile.InMemoryCompiler;
var EntityJavaSourceCodeGenerateTool = Packages.me.hatter.tools.dataaccess.entity.EntityJavaSourceCodeGenerateTool;
var systemInMemoryCompiler = InMemoryCompiler.systemInstance().updateClassPath();
var allCompiledEntityClassMap = {};
var generateClass = (json) => {
var sourceCode = EntityJavaSourceCodeGenerateTool.instance().config(json).generate();
var clazz = systemInMemoryCompiler.compile(sourceCode);
return clazz;
};
var getClass = (json) => {
var jsonSha256Hex = $$.digests().sha256().digest(json.getBytes('UTF-8')).asHex();
if (allCompiledEntityClassMap[jsonSha256Hex]) {
return allCompiledEntityClassMap[jsonSha256Hex];
}
var clazz = generateClass(json);
allCompiledEntityClassMap[jsonSha256Hex] = clazz;
return clazz;
};
exports.getClass = getClass;
exports.generateClass = generateClass;

View File

@@ -0,0 +1,38 @@
requireJAR('diffutils-1.3.0.jar');
var DiffUtils = Packages.difflib.DiffUtils;
var DeleteDelta = Packages.difflib.DeleteDelta;
var ChangeDelta = Packages.difflib.ChangeDelta;
var InsertDelta = Packages.difflib.InsertDelta;
exports.diff2List = (left, right) => {
var patch = DiffUtils.diff(left, right);
var result = [];
$EACH(patch.getDeltas(), (delta) => {
if (delta instanceof DeleteDelta) {
result.push("@@deleted @" + delta.getOriginal().getPosition()
+ " #" + delta.getOriginal().getLines().size());
$EACH(delta.getOriginal().getLines(), (line) => {
result.push("-- " + line);
})
}
if (delta instanceof ChangeDelta) {
result.push("@@modified @" + delta.getOriginal().getPosition()
+ " #" + delta.getOriginal().getLines().size() + '-' + delta.getRevised().getLines().size());
$EACH(delta.getOriginal().getLines(), (line) => {
result.push("-- " + line);
});
$EACH(delta.getRevised().getLines(), (line) => {
result.push("++ " + line);
});
}
if (delta instanceof InsertDelta) {
result.push("@@inserted @" + delta.getOriginal().getPosition()
+ " #" + delta.getRevised().getLines().size());
$EACH(delta.getRevised().getLines(), (line) => {
result.push("++ " + line);
});
}
});
return result;
};

View File

@@ -0,0 +1,9 @@
requireJAR('diffutils-1.3.0.jar');
(() => {
var diff = require('component-diffutil-ex.js');
diff2List = (left, right) => {
return diff.diff2List(left, right);
};
})();

View File

@@ -0,0 +1,24 @@
exports.sendText = (token, message) => {
var dingTalkRobotURL = 'https://oapi.dingtalk.com/robot/send?access_token=' + token;
var postResult = $$.httpRequest()
.url(dingTalkRobotURL)
.addHeader('Content-Type', 'application/json')
.post(JSON.stringify({
"msgtype": "text",
"text": {
"content": $STR(message)
}
}));
return postResult;
};
exports.sendTextDefault = (message) => {
var tokenFile = $$.file($$.prop('user.home'), '.component-dingtalkrobot.js.token');
if (!tokenFile.exists()) {
println('DingTalk token file not exists: ' + tokenFile);
return;
}
var token = $$.rFile(tokenFile).string().trim();
sendDingTalkRobotTextMessage(token, message);
};

View File

@@ -0,0 +1,11 @@
(() => {
var dingtalkrobot = require('component-dingtalkrobot-ex.js');
sendDingTalkRobotTextMessage = (token, message) => {
return dingtalkrobot.sendText(token, message);
};
sendDingTalkRobotTextMessageDefault = (message) => {
return dingtalkrobot.sendTextDefault(message);
};
})();

View File

@@ -0,0 +1,26 @@
var Proxy = java.lang.reflect.Proxy;
var Toolkit = java.awt.Toolkit;
var FileFilter = javax.swing.filechooser.FileFilter;
var JFileChooser = javax.swing.JFileChooser;
exports.showDialog = (filter, filterName) => {
var fileFilter = new FileFilter({
"getDescription": () => {
return filterName || 'Default Filter';
},
"accept": (f) => {
return filter(f);
}
});
var chooser = new JFileChooser();
if (filter != null) {
chooser.setFileFilter(fileFilter);
}
var ret = chooser.showOpenDialog(null);
if (ret == JFileChooser.APPROVE_OPTION) {
return chooser.getSelectedFile();
}
return null;
};

View File

@@ -0,0 +1,7 @@
(() => {
var filechooser = require('component-filechooser-ex.js');
showFileOpenDialog = (filter, filterName) => {
return filechooser.showDialog(filter, filterName);
};
})();

View File

@@ -0,0 +1,14 @@
var Files = java.nio.file.Files;
var PosixFilePermission = java.nio.file.attribute.PosixFilePermission;
var chmodAddExec = (file) => {
file = $$.file(file);
var perms = $$.set();
perms.addAll(Files.getPosixFilePermissions(file.toPath()));
perms.add(PosixFilePermission.OWNER_EXECUTE);
Files.setPosixFilePermissions(file.toPath(), perms);
};
if (typeof exports == 'object') {
exports.chmodAddExec = chmodAddExec;
}

View File

@@ -0,0 +1,243 @@
// https://github.com/chrisveness/latlon-geohash/blob/master/latlon-geohash.js
(() => {
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* Geohash encoding/decoding and associated functions (c) Chris Veness 2014-2016 / MIT Licence */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
'use strict';
/**
* Geohash encode, decode, bounds, neighbours.
*
* @namespace
*/
var Geohash = {};
/* (Geohash-specific) Base32 map */
Geohash.base32 = '0123456789bcdefghjkmnpqrstuvwxyz';
/**
* Encodes latitude/longitude to geohash, either to specified precision or to automatically
* evaluated precision.
*
* @param {number} lat - Latitude in degrees.
* @param {number} lon - Longitude in degrees.
* @param {number} [precision] - Number of characters in resulting geohash.
* @returns {string} Geohash of supplied latitude/longitude.
* @throws Invalid geohash.
*
* @example
* var geohash = Geohash.encode(52.205, 0.119, 7); // geohash: 'u120fxw'
*/
exports.encode = Geohash.encode = function (lat, lon, precision) {
// infer precision?
if (typeof precision == 'undefined') {
// refine geohash until it matches precision of supplied lat/lon
for (var p = 1; p <= 12; p++) {
var hash = Geohash.encode(lat, lon, p);
var posn = Geohash.decode(hash);
if (posn.lat == lat && posn.lon == lon) return hash;
}
precision = 12; // set to maximum
}
lat = Number(lat);
lon = Number(lon);
precision = Number(precision);
if (isNaN(lat) || isNaN(lon) || isNaN(precision)) throw new Error('Invalid geohash');
var idx = 0; // index into base32 map
var bit = 0; // each char holds 5 bits
var evenBit = true;
var geohash = '';
var latMin = -90, latMax = 90;
var lonMin = -180, lonMax = 180;
while (geohash.length < precision) {
if (evenBit) {
// bisect E-W longitude
var lonMid = (lonMin + lonMax) / 2;
if (lon >= lonMid) {
idx = idx * 2 + 1;
lonMin = lonMid;
} else {
idx = idx * 2;
lonMax = lonMid;
}
} else {
// bisect N-S latitude
var latMid = (latMin + latMax) / 2;
if (lat >= latMid) {
idx = idx * 2 + 1;
latMin = latMid;
} else {
idx = idx * 2;
latMax = latMid;
}
}
evenBit = !evenBit;
if (++bit == 5) {
// 5 bits gives us a character: append it and start over
geohash += Geohash.base32.charAt(idx);
bit = 0;
idx = 0;
}
}
return geohash;
};
/**
* Decode geohash to latitude/longitude (location is approximate centre of geohash cell,
* to reasonable precision).
*
* @param {string} geohash - Geohash string to be converted to latitude/longitude.
* @returns {{lat:number, lon:number}} (Center of) geohashed location.
* @throws Invalid geohash.
*
* @example
* var latlon = Geohash.decode('u120fxw'); // latlon: { lat: 52.205, lon: 0.1188 }
*/
exports.decode = Geohash.decode = function (geohash) {
var bounds = Geohash.bounds(geohash); // <-- the hard work
// now just determine the centre of the cell...
var latMin = bounds.sw.lat, lonMin = bounds.sw.lon;
var latMax = bounds.ne.lat, lonMax = bounds.ne.lon;
// cell centre
var lat = (latMin + latMax) / 2;
var lon = (lonMin + lonMax) / 2;
// round to close to centre without excessive precision: ⌊2-log10(Δ°)⌋ decimal places
lat = lat.toFixed(Math.floor(2 - Math.log(latMax - latMin) / Math.LN10));
lon = lon.toFixed(Math.floor(2 - Math.log(lonMax - lonMin) / Math.LN10));
return { lat: Number(lat), lon: Number(lon) };
};
/**
* Returns SW/NE latitude/longitude bounds of specified geohash.
*
* @param {string} geohash - Cell that bounds are required of.
* @returns {{sw: {lat: number, lon: number}, ne: {lat: number, lon: number}}}
* @throws Invalid geohash.
*/
exports.bounds = Geohash.bounds = function (geohash) {
if (geohash.length === 0) throw new Error('Invalid geohash');
geohash = geohash.toLowerCase();
var evenBit = true;
var latMin = -90, latMax = 90;
var lonMin = -180, lonMax = 180;
for (var i = 0; i < geohash.length; i++) {
var chr = geohash.charAt(i);
var idx = Geohash.base32.indexOf(chr);
if (idx == -1) throw new Error('Invalid geohash');
for (var n = 4; n >= 0; n--) {
var bitN = idx >> n & 1;
if (evenBit) {
// longitude
var lonMid = (lonMin + lonMax) / 2;
if (bitN == 1) {
lonMin = lonMid;
} else {
lonMax = lonMid;
}
} else {
// latitude
var latMid = (latMin + latMax) / 2;
if (bitN == 1) {
latMin = latMid;
} else {
latMax = latMid;
}
}
evenBit = !evenBit;
}
}
var bounds = {
sw: { lat: latMin, lon: lonMin },
ne: { lat: latMax, lon: lonMax },
};
return bounds;
};
/**
* Determines adjacent cell in given direction.
*
* @param geohash - Cell to which adjacent cell is required.
* @param direction - Direction from geohash (N/S/E/W).
* @returns {string} Geocode of adjacent cell.
* @throws Invalid geohash.
*/
exports.adjacent = Geohash.adjacent = function (geohash, direction) {
// based on github.com/davetroy/geohash-js
geohash = geohash.toLowerCase();
direction = direction.toLowerCase();
if (geohash.length === 0) throw new Error('Invalid geohash');
if ('nsew'.indexOf(direction) == -1) throw new Error('Invalid direction');
var neighbour = {
n: ['p0r21436x8zb9dcf5h7kjnmqesgutwvy', 'bc01fg45238967deuvhjyznpkmstqrwx'],
s: ['14365h7k9dcfesgujnmqp0r2twvyx8zb', '238967debc01fg45kmstqrwxuvhjyznp'],
e: ['bc01fg45238967deuvhjyznpkmstqrwx', 'p0r21436x8zb9dcf5h7kjnmqesgutwvy'],
w: ['238967debc01fg45kmstqrwxuvhjyznp', '14365h7k9dcfesgujnmqp0r2twvyx8zb'],
};
var border = {
n: ['prxz', 'bcfguvyz'],
s: ['028b', '0145hjnp'],
e: ['bcfguvyz', 'prxz'],
w: ['0145hjnp', '028b'],
};
var lastCh = geohash.slice(-1); // last character of hash
var parent = geohash.slice(0, -1); // hash without last character
var type = geohash.length % 2;
// check for edge-cases which don't share common prefix
if (border[direction][type].indexOf(lastCh) != -1 && parent !== '') {
parent = Geohash.adjacent(parent, direction);
}
// append letter for direction to parent
return parent + Geohash.base32.charAt(neighbour[direction][type].indexOf(lastCh));
};
/**
* Returns all 8 adjacent cells to specified geohash.
*
* @param {string} geohash - Geohash neighbours are required of.
* @returns {{n,ne,e,se,s,sw,w,nw: string}}
* @throws Invalid geohash.
*/
exports.neighbours = Geohash.neighbours = function (geohash) {
return {
'n': Geohash.adjacent(geohash, 'n'),
'ne': Geohash.adjacent(Geohash.adjacent(geohash, 'n'), 'e'),
'e': Geohash.adjacent(geohash, 'e'),
'se': Geohash.adjacent(Geohash.adjacent(geohash, 's'), 'e'),
's': Geohash.adjacent(geohash, 's'),
'sw': Geohash.adjacent(Geohash.adjacent(geohash, 's'), 'w'),
'w': Geohash.adjacent(geohash, 'w'),
'nw': Geohash.adjacent(Geohash.adjacent(geohash, 'n'), 'w'),
};
};
})();

View File

@@ -0,0 +1,9 @@
exports.isGitUptodate = () => {
var r = $STR($$.shell().commands('git', 'fetch', '--dry-run').mergeError().start()[0]);
if (r.trim().length > 0) {
return false;
}
return true;
};

View File

@@ -0,0 +1,32 @@
exports.encrypt = (keyId, srcFile, destFile) => {
$$.shell().commands('sh', '-c', 'gpg -r ' + keyId + ' -e -o "' + destFile + '" ' + srcFile).start();
};
exports.encryptArmor = (keyId, srcFile, destFile) => {
$$.shell().commands('sh', '-c', 'gpg -r ' + keyId + ' -e -a --no-comment --comment "https://hatter.in/key" -o "' + destFile + '" ' + srcFile).start();
};
exports.decryptArmor = (gpgArmor) => {
var gpgArmorB64 = __.bytes.from(gpgArmor).asBase64();
var result = $$.shell().commands('sh', '-c', "echo '" + gpgArmorB64 + "' | base64 -D | gpg").start();
return __decrypt(result);
};
exports.decrypt = (gpgFile) => {
var result = $$.shell().commands('sh', '-c', 'cat ' + gpgFile + ' | gpg').start();
__decrypt(result);
};
var __decrypt = (result) => {
var out = result[0].string();
var err = result[1].string();
if (err.contains('public key decryption failed')) {
println('+ Decrypt file FAILED: ' + gpgFile);
if (!Packages.me.hatter.tools.jssp.main.StandaloneMain.JSSP_MAIN_MUTE) {
println("ERROR detail:\n" + err);
}
throw 'decrypt file failed: ' + gpgFile;
}
return out;
}

View File

@@ -0,0 +1,15 @@
(() => {
var gpg = require('component-gpg-ex.js');
gpgEncrypt = (keyId, srcFile, destFile) => {
return gpg.encrypt(keyId, srcFile, destFile);
};
gpgEncryptArmor = (keyId, srcFile, destFile) => {
return gpg.encryptArmor(keyId, srcFile, destFile);
};
gpgDecrypt = (gpgFile) => {
return gpg.decrypt(gpgFile);
};
})();

View File

@@ -0,0 +1,48 @@
var COMMENT_HASH_TAG = '//HASH:';
var CollectionUtil = Packages.me.hatter.tools.commons.collection.CollectionUtil;
var __containsCommentHashTag = (list) => {
for (var i = (list.size() - 1); i >= 0; i--) {
var l = list.get(i);
if ($STR(l.trim()) != '') {
return l.startsWith(COMMENT_HASH_TAG);
}
}
return false;
};
var __getDigestJSON = (list) => {
var digestJSON = null;
if (__containsCommentHashTag(list)) {
var last = CollectionUtil.last(list);
while ((list.size() > 0) && ($STR(last.trim()) == '')) { CollectionUtil.removeLast(list); last = CollectionUtil.last(list); }
if (last.startsWith(COMMENT_HASH_TAG)) {
CollectionUtil.removeLast(list);
digestJSON = JSON.parse(last.substring(COMMENT_HASH_TAG.length));
}
}
return digestJSON;
};
var __calcSHA256Hex = (list) => {
return $STR($$.digests().sha256().digest($$.bytes($ARR(list).join('\n'))).asHex());
};
var __checkSHA256 = (list) => {
var digestJSON = __getDigestJSON(list);
return digestJSON && (digestJSON.SHA256 == __calcSHA256Hex(list));
};
var checkBytesSHA256 = (bytes) => {
return __checkSHA256(bytes.list());
};
if (typeof exports == 'object') {
exports.__containsCommentHashTag = __containsCommentHashTag;
exports.__getDigestJSON = __getDigestJSON;
exports.__calcSHA256Hex = __calcSHA256Hex;
exports.__checkSHA256 = __checkSHA256;
exports.COMMENT_HASH_TAG = COMMENT_HASH_TAG;
exports.checkBytesSHA256 = checkBytesSHA256;
}

View File

@@ -0,0 +1,6 @@
(() => {
helloworld = () => {
return 'Hello World!!!';
};
})();

View File

@@ -0,0 +1,5 @@
exports.sayhello = () => {
return 'Say Hello World!';
};

View File

@@ -0,0 +1,415 @@
var bytes = require('component-bytes.js');
var Runtime = java.lang.Runtime;
var InetSocketAddress = java.net.InetSocketAddress;
var Executors = java.util.concurrent.Executors;
var Bytes = Packages.me.hatter.tools.commons.bytes.Bytes;
var IOUtil = Packages.me.hatter.tools.commons.io.IOUtil;
var HttpServer = Packages.com.sun.net.httpserver.HttpServer;
// {
// "status": 200,
// "headers": [[key, value],[key2, value2]],
// "responseJSON": ...,
// "responseBytes": ...,
// "responseText": ...,
// }
var writeResponse = (httpExchange, response) => {
response.status = (response.status == null) ? 200 : response.status;
var resBs;
var resStream = null;
if (response.responseJSON != null) {
resBs = Bytes.from(JSON.stringify(response.responseJSON)).getBytes();
} else if (response.responseText != null) {
resBs = Bytes.from(response.responseText).getBytes();
} else if (response.responseStream != null) {
resBs = null;
resStream = response.responseStream;
} else {
resBs = response.responseBytes;
}
var responseHeaders = httpExchange.getResponseHeaders();
if ((response.headers != null) && (response.headers.length > 0)) {
for (var i = 0; i < response.headers.length; i++) {
var keyValue = response.headers[i];
responseHeaders.set(keyValue[0], keyValue[1]);
}
} else {
responseHeaders.set('Content-Type', 'text/plain;charset=UTF-8');
}
httpExchange.sendResponseHeaders(response.status, (resBs != null) ? resBs.length : 0);
var resBody = httpExchange.getResponseBody();
if (resBs != null) {
resBody.write(resBs);
} else {
IOUtil.copy(response.responseStream, resBody);
IOUtil.closeQuietly(response.responseStream);
}
resBody.close();
};
exports.parseQuery = exports.parseQueryParameterMap = (httpExchange) => {
var queryParameterMap = {};
var rawQuery = $STR(httpExchange.getRequestURI().getRawQuery());
if (rawQuery != null) {
rawQuery.split('&').forEach((kv) => {
var indexOfE = kv.indexOf('=');
var key = '';
var value = '';
if (indexOfE >= 0) {
key = kv.substring(0, indexOfE);
value = kv.substring(indexOfE + 1);
} else {
key = kv;
}
queryParameterMap[key] = queryParameterMap[key] || [];
queryParameterMap[key].push(value);
});
}
return queryParameterMap;
};
var handleDir = (httpExchange, dir, opts) => {
var sb = [];
if (opts.handleDir) {
if (!httpExchange.getRequestURI().getPath().endsWith('/')) {
return {
status: 302,
"headers": [
["Location", httpExchange.getRequestURI().getPath() + '/'],
["Content-Type", 'text/html;charset=UTF-8'],
],
bytes: new java.lang.String('<html>\n'
+ '<head>\n'
+ '<title>Redirecting ...</title>\n'
+ '<meta http-equiv="refresh" content="0; URL=' + httpExchange.getRequestURI().getPath() + '/' + '" />\n'
+ '</head>\n'
+ '<body>\n'
+ 'Redirect to new location: ' + httpExchange.getRequestURI().getPath() + '/' + '\n'
+ '</body>\n'
+ '</html>').getBytes('UTF-8')
};
}
var files = dir.getAbsoluteFile().listFiles();
sb.push('<h1>Directory Listing</h1>\n');
sb.push('<br>\n');
$EACH(files, (f) => {
var isDir = f.isDirectory();
if (isDir) {
sb.push('<a href="' + f.getName() + '/">[' + f.getName() + ']</a>'
+ ' &nbsp; <span style="font-size:12px;"><i>' + new Date(f.lastModified()) + '</i></span>'
+ '<br>\n');
} else {
sb.push('<a href="' + f.getName() + '">' + f.getName() + '</a>'
+ ' &nbsp; <span style="font-size:12px;">'
+ bytes.showBytes(f.length())
+ ' &nbsp; <i>' + new Date(f.lastModified()) + '</i>'
+ '</span>'
+ '<br>\n');
}
});
} else {
sb.push('Directory listing is forbidden.');
}
return { html: sb.join('') };
};
// https://www.freeformatter.com/mime-types-list.html
var mimeTypeList = [
[['txt', 'text'], 'text/plain;charset=UTF-8'],
[['jpg', 'jpeg'], 'image/jpeg'],
[['png'], 'image/png'],
[['swf'], 'application/x-shockwave-flash'],
[['js'], 'text/javascript;charset=UTF-8'],
[['htm', 'html'], 'text/html;charset=UTF-8'],
[['css'], 'text/css;charset=UTF-8'],
[['geojson'], 'application/vnd.geo+json'],
[['svg'], 'image/svg+xml'],
[['7z'], 'application/x-7z-compressed'],
[['ace'], 'application/x-ace-compressed'],
[['acc'], 'application/vnd.americandynamics.acc'],
[['pdf'], 'application/pdf'],
[['aac'], 'audio/x-aac'],
[['apk'], 'application/vnd.android.package-archive'],
[['dmg'], 'application/x-apple-diskimage'],
[['mpkg'], 'application/vnd.apple.installer+xml'],
[['s'], 'text/x-asm'],
[['avi'], 'video/x-msvideo'],
[['bin'], 'application/octet-stream'],
[['bmp'], 'image/bmp'],
[['torrent'], 'application/x-bittorrent'],
[['sh'], 'application/x-sh'],
[['bz'], 'application/x-bzip'],
[['bz2'], 'application/x-bzip2'],
[['csh'], 'application/x-csh'],
[['c'], 'text/x-c'],
[['csv'], ' text/csv'],
[['deb'], 'application/x-debian-package'],
[['dtd'], 'application/xml-dtd'],
[['dwg'], 'image/vnd.dwg'],
[['es'], 'application/ecmascript'],
[['epub'], 'application/epub+zip'],
[['eml'], 'message/rfc822'],
[['f4v'], 'video/x-f4v'],
[['flv'], 'video/x-flv'],
[['gif'], 'image/gif'],
[['h261'], 'video/h261'],
[['h263'], 'video/h263'],
[['h264'], 'video/h264'],
[['ico'], 'image/x-icon'],
[['cer'], 'application/pkix-cert'],
[['pki'], 'application/pkixcmp'],
[['crl'], 'application/pkix-crl'],
[['jad'], 'text/vnd.sun.j2me.app-descriptor'],
[['jar'], 'application/java-archive'],
[['class'], 'application/java-vm'],
[['jnlp'], 'application/x-java-jnlp-file'],
[['ser'], 'application/java-serialized-object'],
[['java'], 'text/x-java-source,java'],
[['json'], 'application/json'],
[['m3u', 'm3u8'], 'audio/x-mpegurl'],
[['mathml'], 'application/mathml+xml'],
[['exe'], 'application/x-msdownload'],
[['cab'], 'application/vnd.ms-cab-compressed'],
[['eot'], 'application/vnd.ms-fontobject'],
[['xls'], 'application/vnd.ms-excel'],
[['ppt'], 'application/vnd.ms-powerpoint'],
[['doc'], 'application/msword'],
[['vsd'], 'application/vnd.visio'],
[['chm'], 'application/vnd.ms-htmlhelp'],
[['pptx'], 'application/vnd.openxmlformats-officedocument.presentationml.presentation'],
[['ppsx'], 'application/vnd.openxmlformats-officedocument.presentationml.slideshow'],
[['xlsx'], 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'],
[['docx'], 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'],
[['dotx'], 'application/vnd.openxmlformats-officedocument.wordprocessingml.template'],
[['vsdx'], 'application/vnd.visio2013'],
[['mpeg'], 'video/mpeg'],
[['mp4a'], 'audio/mp4'],
[['mp4'], 'video/mp4'],
[['psd'], 'image/vnd.adobe.photoshop'],
[['p10'], 'application/pkcs10'],
[['p12'], 'application/x-pkcs12'],
[['p7m'], 'application/pkcs7-mime'],
[['p7s'], 'application/pkcs7-signature'],
[['p7r'], 'application/x-pkcs7-certreqresp'],
[['p7b'], 'application/x-pkcs7-certificates'],
[['p8'], 'application/pkcs8'],
[['pgp'], 'application/pgp-encrypted'],
[['rar'], 'application/x-rar-compressed'],
[['rm'], 'application/vnd.rn-realmedia'],
[['rtf'], 'application/rtf'],
[['movie'], 'video/x-sgi-movie'],
[['tiff'], 'image/tiff'],
[['tar'], 'application/x-tar'],
[['tex'], 'application/x-tex'],
[['ttf'], 'application/x-font-ttf'],
[['vcs'], 'text/x-vcalendar'],
[['vcf'], 'text/x-vcard'],
[['wav'], 'audio/x-wav'],
[['woff'], 'application/x-font-woff'],
[['webp'], 'image/webp'],
[['der'], 'application/x-x509-ca-cert'],
[['xml'], 'application/xml'],
[['zip'], 'application/zip']
];
var mimeTypeMap = {};
mimeTypeList.forEach((m) => {
m[0].forEach((t) => {
mimeTypeMap[t] = m[1];
});
});
var getMimeTypeByExt = (ext) => {
return mimeTypeMap[ext] || 'application/octet-stream';
};
var fileCacheSize = 0;
var fileCacheCount = 0;
var fileCacheMap = {};
var handleFile = (httpExchange, file, opts) => {
var fileAbsPath = file.getAbsolutePath();
if (opts.enableFileCache) {
println('[INFO] ' + getDateYmd() + ' ' + 'File cache hit: ' + fileAbsPath);
var cachedFileContent = fileCacheMap[fileAbsPath];
if (cachedFileContent) { return cachedFileContent; } // cache hit
}
if (file.exists()) {
var path = $STR(httpExchange.getRequestURI().getPath()).toLowerCase();
var lastIndexOfDot = path.lastIndexOf('.');
var ext = '';
if (lastIndexOfDot >= 0) {
ext = path.substring(lastIndexOfDot + 1);
}
var contentType = null;
if (opts.getContentType) {
contentType = opts.getContentType(httpExchange, file, ext);
}
contentType = contentType || getMimeTypeByExt(ext);
if (opts.enableFileCache && (file.length() < (opts.cacheFileLength || (1024 * 1024 * 5)))) { // default cache file length 5MB
if (fileCacheCount < (opts.cacheCount || 1000)) { // default cache size 1000
var fileContent = {
headers: [
['Content-Type', contentType],
['Content-Length', file.length()]
],
bytes: $$.rFile(file).rStream().bytesAndClose()
};
fileCacheCount++;
fileCacheSize += file.length();
println('[INFO] ' + getDateYmd() + ' ' + 'File cached: ' + fileAbsPath + ', size: ' + bytes.showBytes(file.length()) + ', cached count: ' + fileCacheCount + ', cached size: ' + bytes.showBytes(fileCacheSize));
fileCacheMap[fileAbsPath] = fileContent;
return fileContent;
}
}
return {
headers: [
['Content-Type', contentType],
['Content-Length', file.length()]
],
stream: $$.rFile(file).rStream().stream()
};
} else {
return null;
}
};
var getDateYmd = () => {
return new java.text.SimpleDateFormat('yyyy-MM-dd HH:mm:ss').format(new java.util.Date());
};
/**
* @param {*} httpExchange
* @param {*} options
* basePath - base path
* getContentType (httpExchange, file, ext) - get content type
* handleDir - enable dir listing
*/
exports.handleFile = (httpExchange, options) => {
var opts = options || {};
var path = $STR(httpExchange.getRequestURI().getPath());
if (path == '/') {
return handleDir(httpExchange, opts.basePath ? $$.file(opts.basePath) : $$.file(''), opts);
}
var f = path.substring(1);
var file = opts.basePath ? $$.file(opts.basePath, f) : $$.file(f);
if (file.exists()) {
if (file.isDirectory()) {
return handleDir(httpExchange, file, opts);
} else {
return handleFile(httpExchange, file, opts);
}
}
return null;
};
/**
*
* @param {*} port port number
* @param {*} handler process handle
* return {
* text: 'text'
* }
* return {
* html: 'html'
* }
* ...
* @param {*} options
* processors - processor count
* printErrors - print exception detail
*/
exports.serveHTTP = (port, handler, options) => {
var opts = options || {};
var addr = new InetSocketAddress(port);
var httpServer = HttpServer.create(addr, 0);
if (opts.processors) {
httpServer.setExecutor(Executors.newFixedThreadPool(opts.processors));
} else {
httpServer.setExecutor(Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 2));
}
httpServer.createContext("/", (httpExchange) => {
try {
println('[INFO] ' + getDateYmd() + ' ' + httpExchange.getRequestURI());
var response = handler(httpExchange);
if (response != null) {
if (response.text != null) {
responseResult = {
"status": response.status || 200,
"headers": [
["Content-Type", "text/plain;charset=UTF-8"],
],
"responseText": response.text
};
} else if (response.html != null) {
responseResult = {
"status": response.status || 200,
"headers": [
["Content-Type", "text/html;charset=UTF-8"],
],
"responseText": response.html
};
} else if (response.css != null) {
responseResult = {
"status": response.status || 200,
"headers": [
["Content-Type", "text/css;charset=UTF-8"],
],
"responseText": response.css
};
} else if (response.js != null) {
responseResult = {
"status": response.status || 200,
"headers": [
["Content-Type", "text/javascript;charset=UTF-8"],
],
"responseText": response.js
};
} else if (response.json != null) {
responseResult = {
"status": response.status || 200,
"headers": [
["Content-Type", "application/json;charset=UTF-8"],
],
"responseJSON": response.json
};
} else if (response.bytes != null) {
responseResult = {
"status": response.status || 200,
"headers": response.headers,
"responseBytes": response.bytes
};
} else if (response.stream != null) {
responseResult = {
"status": response.status || 200,
"headers": response.headers,
"responseStream": response.stream
};
} else {
responseResult = {
"status": response.status || 200,
"headers": [
["Content-Type", "text/plain;charset=UTF-8"],
],
"responseText": $STR(response)
};
}
writeResponse(httpExchange, responseResult);
}
} catch (e) {
var errMsg = '[ERROR] Request: ' + httpExchange.getRequestURI() + ', exception: ' + e;
println('[ERROR] ' + getDateYmd() + ' ' + errMsg);
if (e.printStackTrace) { e.printStackTrace(); }
writeResponse(httpExchange, {
"status": 500,
"responseText": opts.printErrors ? errMsg : '500 - Server Error'
});
}
});
println('[INFO] ' + getDateYmd() + ' ' + "Start listen at: " + port + ' ...');
httpServer.start();
};

View File

@@ -0,0 +1,12 @@
(() => {
var httpserver = require('component-httpserver-ex.js');
parseQueryParameterMap = (httpExchange) => {
return httpserver.parseQueryParameterMap(httpExchange);
};
serveHTTP = (port, handler) => {
return httpserver.serveHTTP(port, handler);
};
})();

View File

@@ -0,0 +1,67 @@
var OSUtil = Packages.me.hatter.tools.commons.os.OSUtil;
var getJavaHomeFromJdks = (version) => {
var jdksPath = $$.file('~/.jssp/jdks');
if (!(jdksPath.exists() && jdksPath.isDirectory())) {
return null;
}
var jdkVersions = $ARRAY(jdksPath.listFiles()).filter((p) => {
return p.isDirectory();
}).map((p) => {
var jdkVersion = p.getName();
if (jdkVersion.startsWith('jdk-')) {
jdkVersion = jdkVersion.substring('jdk-'.length);
} else if (jdkVersion.startsWith('jdk')) {
jdkVersion = jdkVersion.substring('jdk'.length);
}
return [jdkVersion, p.getAbsolutePath()];
}).sort((a, b) => {
return b[0] - a[0];
});
for (var i = 0; i < jdkVersions.length; i++) {
if (jdkVersions[i][0].startsWith(version)) {
return jdkVersions[i][1];
}
}
return null;
};
var getJavaHomeFromBuildConfig = (version) => {
var buildConfigRFile = __.rfile.from('~/.jssp/config/buildconfig.json');
if (buildConfigRFile.notExists()) {
return null;
}
var buildConfigJSON = JSON.parse(buildConfigRFile.string());
if (buildConfigJSON['java'] && buildConfigJSON['java']['versions']) {
var versions = buildConfigJSON['java']['versions'];
for (var i = 0; i < versions.length; i++) {
if (versions[i].startsWith(version)) {
return buildConfigJSON['java'][versions[i]]['home'];
}
}
}
return null;
}
var getJavaHome = (version) => {
if ((version == null) || ($STR(version) == '')) { return null; }
if (OSUtil.isMacOS()) {
var jversions = $$.shell().commands('/usr/libexec/java_home', '-version', version).start();
if (jversions[1] && $STR(jversions[1].toString()).contains('Unable to find any JVMs matching version')) {
return null;
}
return jversions[0].toString().trim();
} else {
var javaHomeFromJdks = getJavaHomeFromJdks(version);
if (javaHomeFromJdks != null) {
return javaHomeFromJdks;
}
var javaHomeFromBuildConfig = getJavaHomeFromBuildConfig(version);
return javaHomeFromBuildConfig;
}
};
if (typeof exports == 'object') {
exports.getJavaHome = getJavaHome;
}

View File

@@ -0,0 +1,51 @@
$ONCE('component-jose-requireJARS').run(() => {
requireJAR('jose4j-0.5.5.jar');
requireJAR('slf4j-api-1.7.21.jar');
});
var JsonWebKey = Packages.org.jose4j.jwk.JsonWebKey;
var JsonWebEncryption = Packages.org.jose4j.jwe.JsonWebEncryption;
var AlgorithmConstraints = Packages.org.jose4j.jwa.AlgorithmConstraints;
var ConstraintType = Packages.org.jose4j.jwa.AlgorithmConstraints.ConstraintType;
var KeyManagementAlgorithmIdentifiers = Packages.org.jose4j.jwe.KeyManagementAlgorithmIdentifiers;
var ContentEncryptionAlgorithmIdentifiers = Packages.org.jose4j.jwe.ContentEncryptionAlgorithmIdentifiers;
var jwkLoad = (jwkJSONString) => {
return JsonWebKey.Factory.newJwk(jwkJSONString);
}
var jweEnc = (jwk, txt) => {
var jwe = new JsonWebEncryption();
jwe.setPlaintext(txt);
jwe.setAlgorithmHeaderValue(KeyManagementAlgorithmIdentifiers.DIRECT);
jwe.setEncryptionMethodHeaderParameter(ContentEncryptionAlgorithmIdentifiers.AES_128_GCM);
jwe.setKey(jwk.getKey());
return jwe.getCompactSerialization();
};
var jweDec = (jwk, compactSerialization) => {
var jwe = new JsonWebEncryption();
var algConstraints = new AlgorithmConstraints(ConstraintType.WHITELIST, KeyManagementAlgorithmIdentifiers.DIRECT);
jwe.setAlgorithmConstraints(algConstraints);
var encConstraints = new AlgorithmConstraints(ConstraintType.WHITELIST, ContentEncryptionAlgorithmIdentifiers.AES_128_GCM);
jwe.setContentEncryptionAlgorithmConstraints(encConstraints);
jwe.setCompactSerialization(compactSerialization);
jwe.setKey(jwk.getKey());
return receiverJwe.getPlaintextString();
};
var jwk = {
"load": jwkLoad
};
var jwe = {
"enc": jweEnc,
"dec": jweDec
};
if (typeof exports == 'object') {
exports.jwk = jwk;
exports.jwe = jwe;
}

View File

@@ -0,0 +1,13 @@
var FastJSON = Packages.com.alibaba.fastjson.JSON;
var FastJSONSerializerFeature = Packages.com.alibaba.fastjson.serializer.SerializerFeature;
exports.prettyJSON = (obj) => {
return FastJSON.toJSONString(FastJSON.parse(JSON.stringify(obj)), FastJSONSerializerFeature.PrettyFormat);
};
exports.prettyJavaJSON = (obj) => {
return FastJSON.toJSONString(obj, FastJSONSerializerFeature.PrettyFormat);
};

View File

@@ -0,0 +1,7 @@
(() => {
var json = require('component-json-ex.js');
prettyJSON = (obj) => {
return json.prettyJSON(obj);
};
})();

View File

@@ -0,0 +1,8 @@
requireJAR('mysql-connector-java-5.1.44.jar');
requireJAR('dataaccess-1.0.jar');
var DataAccessObjectUtil = Packages.me.hatter.tools.dataaccess.util.DataAccessObjectUtil;
exports.createDAO = (host, sid, userName, password) => {
return DataAccessObjectUtil.createMySQLObject(host, sid, userName, password);
};

View File

@@ -0,0 +1,16 @@
// https://stackoverflow.com/questions/246007/how-to-determine-whether-a-given-linux-is-32-bit-or-64-bit
// https://stackoverflow.com/questions/106387/is-it-possible-to-detect-32-bit-vs-64-bit-in-a-bash-script
var getOS = () => {
var osName = $STR($$.shell().commands('uname').start()[0]).trim();
var arch = $STR($$.shell().commands('uname', '-m').start()[0]).trim(); // OR getconf LONG_BIT
return {
'name': osName,
'arch': arch
};
};
if (typeof exports == 'object') {
exports.getOS = getOS;
}

View File

@@ -0,0 +1,78 @@
var URLEncoder = java.net.URLEncoder;
var Bytes = Packages.me.hatter.tools.commons.bytes.Bytes;
var HMacs = Packages.me.hatter.tools.commons.security.hmac.HMacs;
var counter = require('component-counter.js');
var requireJARs = () => {
$ONCE('component-oss-requireJARS').run(() => {
requireJAR('aliyun-sdk-oss-2.4.1-SNAPSHOT.jar');
requireJAR('commons-beanutils-1.8.0.jar');
requireJAR('commons-codec-1.9.jar');
requireJAR('commons-collections-3.2.1.jar');
requireJAR('commons-lang-2.5.jar');
requireJAR('commons-logging-1.2.jar');
requireJAR('ezmorph-1.0.6.jar');
requireJAR('hamcrest-core-1.1.jar');
requireJAR('httpclient-4.4.1.jar');
requireJAR('httpcore-4.4.1.jar');
requireJAR('jdom-1.1.jar');
requireJAR('json-lib-2.4-jdk15.jar');
});
};
var generateSignedURL = (endpoint, accessKeyId, accessKeySecret, bucketName, key, expiresInSeconds, isHTTP) => {
var sb = [];
sb.push(isHTTP ? 'http://' : 'https://'); // default HTTPS
sb.push(bucketName);
sb.push('.' + endpoint);
sb.push('/' + key);
var expires = parseInt($$.date().millis() / 1000) + expiresInSeconds;
sb.push('?Expires=' + expires);
sb.push('&OSSAccessKeyId=' + URLEncoder.encode(accessKeyId, 'UTF-8'));
sb.push('&Signature=' + URLEncoder.encode(sign(accessKeySecret, expires, bucketName, key), 'UTF-8'));
return sb.join('');
};
var sign = (accessKeySecret, expires, bucketName, key) => {
return HMacs.sha1(Bytes.from(accessKeySecret).getBytes())
.sign(Bytes.from('GET\n\n\n' + expires + '\n/' + bucketName + '/' + key).getBytes())
.asBase64();
};
var createCounterIS = (file) => {
var CounterInputStream = Packages.me.hatter.tools.commons.io.CounterInputStream;
var uploadFile = (file instanceof java.io.File) ? file : new java.io.File(file);
var uploadIS = new java.io.FileInputStream(uploadFile);
var counterIS = new CounterInputStream(uploadIS, counter.getCounter(uploadFile.length()));
return counterIS;
};
var newClient = (endpoint, accessKey, secretKey) => {
requireJARs();
var OSSClient = Packages.com.aliyun.oss.OSSClient;
var client = new OSSClient(endpoint, accessKey, secretKey);
return {
runWith: (runFunc) => {
try {
runFunc(client);
} catch (e) {
println('OSS Error: ' + e);
} finally {
client.shutdown();
}
}
};
};
if (typeof exports == 'object') {
exports.requireJARs = requireJARs;
exports.sign = sign;
exports.generateSignedURL = generateSignedURL;
exports.createCounterIS = createCounterIS;
exports.newClient = newClient;
}

View File

@@ -0,0 +1,55 @@
var counter = require('component-counter.js');
var getLocalPackage = (packageInfo, skipCertCheck) => {
var basePath = $$.file(packageInfo.basePath);
var bin = $$.file(basePath, packageInfo.subPath, packageInfo.bin);
if (!(bin.exists())) {
var packageFn = packageInfo.package.substring(packageInfo.package.lastIndexOf('/') + 1);
xprintln('[INFO] Package bin not exists, downloading...');
var packageFile = $$.file(basePath, packageFn);
packageFile.getAbsoluteFile().getParentFile().mkdirs();
var fos = new java.io.FileOutputStream(packageFile);
$$.httpRequest()
.url(packageInfo.package)
.addHeader('User-Agent', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36')
.skipCertCheck(!! skipCertCheck)
.get(fos, counter.getCounter2());
fos.close();
println();
var sha256 = $$.rFile(packageFile).digest($$.digests().sha256()).asHex();
if ($STR(sha256) == packageInfo.sha256) {
xprintln('[SUCCESS] Check SHA256 success: ' + packageFn);
} else {
xprintln('[ERROR] Check SHA256 failed, actual is: ' + sha256 + ',expected: ' + packageInfo.sha256 + ': ' + packageFn);
f.renameTo($$.file(basePath, packageFn + '.invalid.' + $$.date().millis()));
return null;
}
var installBuilderScripts = [];
installBuilderScripts.push('cd ' + packageInfo.basePath);
if (/.*\.tar\.gz$/.test(packageInfo.package) || /.*\.tgz$/.test(packageInfo.package)) {
installBuilderScripts.push('tar xzvf ' + packageFn);
} else if (/.*\.zip$/.test(packageInfo.package)) {
installBuilderScripts.push('unzip ' + packageFn);
} else {
xprintln('[ERROR] Extract package failed: ' + packageFn);
return;
}
installBuilderScripts.push('');
var builderIntall = $$.file('.builder_install.sh');
$$.rFile(builderIntall).write(installBuilderScripts.join('\n'));
$$.shell().inheritIO().commands('sh', builderIntall.getName()).run();
builderIntall.delete();
}
return {
'packageInfo': packageInfo,
'packageHome': $STR($$.file(packageInfo.basePath, packageInfo.subPath).getAbsolutePath()),
'binFile': bin
};
};
if (typeof exports == 'object') {
exports.getLocalPackage = getLocalPackage;
}

149
components/component-pki.js Normal file
View File

@@ -0,0 +1,149 @@
var gpg = require('component-gpg-ex.js');
var File = java.io.File;
var ECSignatureTool = Packages.me.hatter.tools.commons.security.sign.SignatureTool;
var DEFAULT_SIGN_FILE_EXT = '.sig.txt';
var DEFAULT_PGP_KEY_ID = '6FAFC0E0170985AA71545483C794B1646A886CD6';
var DEFAULT_EC_PRIVATE_KEY_PGP_ENC = '-----BEGIN PGP MESSAGE-----\n' +
'Comment: GPGTools - https://gpgtools.org\n' +
'\n' +
'hQIMA8N6kJ6vG/sAAQ//ef8seBe4daxW1tQg12G6tE2VhA1Y0W/Y3GKCtAxM8PwC\n' +
'j/VjanTqozVwVQp7Qb3hHoBkEJBAEjrNtIhUE7dJBSbrGkK5i8mkQpkc8MFgtx1A\n' +
'LVkhdNkTWenk07l6d56v0+iVjlWJsl9wlpP9eY3GkqkWydCXPEn0rICrB3mBf2BA\n' +
'SRPqucnzSpIjH+KXhUcyVFjU86ZHyzoRP5RwG2MVVSWhwt7Oyd9A6p1hAKHKIjwH\n' +
'K1W4PhxwrjnelcVWC2uwSLWXqgdXQ0EZXMzH5fv3R2EdZopyaC7AF6/jtauEs5RO\n' +
'X4l64jjfajqswSZKW0fGKqJgPVzb3p2fBGBeBFx2sYGU/Xk7QTQlfKOvADzLdEIE\n' +
'hw/i1Huo/xSg4CYiyjlVw82x6cA10UP2d7KRA21NPqWQUKv9p6aWpjkXoM1UE+5D\n' +
'TdyHSnT0Fu+VaBsGZ+3/x+oRlM6PHjk22n8CUEsZecYzGnyXyAEJuCaYOVtfSMTW\n' +
'gdy13gJInaxMawHHyRVFqJClZsXc4LEsSsY4fdTus6mEkD+S5S2gkoFffB6uLWYL\n' +
'pq59IIJ+tp2Y3wxCqUXhu0PYer5No7lU/A53+dtcj7xQYLoOUlB/DkHWfmqAsJi7\n' +
'Zt+SXoy0ksCtXciBZRhuJESbISALjKqOfQIV/8J9GrN/zQl/dzEmrfgqE00hY1bS\n' +
'kQFX26y+2iY7k2xoLg+fNB6LNKmtM4U6115CL+rcX3p02P1f4E6O4gGEg9l/3fe2\n' +
'rz7+2a3WK/MNE1Ak7ImFf6ufU3PHUCQqyEqk7wGeNmRRG3SPJUyBQbpa6I+4xTZ8\n' +
'R6RqgeigqUMDFyyIwYULEwP+dqnHfRBeckh3MKGfrHQUmgrGDOYawxb1G+h2iaVC\n' +
'VtA=\n' +
'=QCYC\n' +
'-----END PGP MESSAGE-----';
var DEFAULT_EC_PUBLIC_KEY = 'MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAESZWG1x7tlv02YF+UZzuZdLquR6Oi3H7QRmaRWzDoupG66dWeKruRUQVj2ozliDKaRQ+5b91u/z9BApIaFs6quw==';
var generateECsecp256r1KeyPair = () => {
var ecSignTool = ECSignatureTool.secp256r1();
ecSignTool.generateKeyPair();
return {
'privKey': ecSignTool.encodePriKey(),
'pubKey': ecSignTool.encodePubKey()
};
};
var __defaultEcPrivateKeyBytes = null;
var getDefaultEcPrivateKeyBytes = () => {
if (__defaultEcPrivateKeyBytes != null) { return __defaultEcPrivateKeyBytes; }
var __defaultEcPrivateKeyLocalFile = $$.file('~/.jssp/config/.defaultecprivatekey.json');
if (__defaultEcPrivateKeyLocalFile.exists()) {
return __.bytes.fromBase64(JSON.parse($$.rFile(__defaultEcPrivateKeyLocalFile).string()).base64Key);
}
var tempPrivKeyFile = File.createTempFile('component-pki', '.temp_key');
$$.rFile(tempPrivKeyFile).write(DEFAULT_EC_PRIVATE_KEY_PGP_ENC);
tempPrivKeyFile.deleteOnExit();
var privKey = gpg.decrypt(tempPrivKeyFile.getAbsolutePath());
__defaultEcPrivateKeyBytes = __.bytes.fromBase64(privKey.trim());
__defaultEcPrivateKeyLocalFile.getParentFile().mkdirs();
$$.rFile(__defaultEcPrivateKeyLocalFile).write(JSON.stringify({
'date': $$.date().fmt('yyyy-MM-dd HH:mm:ss Z').format($$.date().today()),
'base64Key': __defaultEcPrivateKeyBytes.asBase64()
}));
return __defaultEcPrivateKeyBytes;
};
var getDefaultEcPublicKeyBytes = () => {
return __.bytes.fromBase64(DEFAULT_EC_PUBLIC_KEY);
};
var getDefaultEcSignSignature = () => {
return ECSignatureTool.secp256r1().decodePriKey(getDefaultEcPrivateKeyBytes()).signSHA256ECDSA();
};
var getDefaultEcVerifySignature = () => {
return ECSignatureTool.secp256r1().decodePubKey(getDefaultEcPublicKeyBytes()).verifySHA256ECDSA();
};
var defaultSignFile = (file) => {
file = $$.file(file);
if (file.getName().endsWith(DEFAULT_SIGN_FILE_EXT) || !(file.exists()) || !(file.isFile())) {
return false;
}
var signFile = $$.file(file.getAbsoluteFile().getParentFile(), file.getName() + DEFAULT_SIGN_FILE_EXT);
var sigHex = $$.rFile(file).sign(getDefaultEcSignSignature()).asHex();
$$.rFile(signFile).write(JSON.stringify({
'length': $$.str(file.length()),
'lastModified': $$.str(file.lastModified()),
'signature': sigHex
}));
return true;
};
var defaultSignFileV2 = (file) => {
file = $$.file(file);
if (file.getName().endsWith(DEFAULT_SIGN_FILE_EXT) || !(file.exists()) || !(file.isFile())) {
return false;
}
var signFile = $$.file(file.getAbsoluteFile().getParentFile(), file.getName() + DEFAULT_SIGN_FILE_EXT);
var sha256 = $$.rFile(file).digest(__.digests.sha256()).asHex();
var sigHex = __.bytes.fromHex(sha256).sign(getDefaultEcSignSignature()).asHex();
$$.rFile(signFile).write(JSON.stringify({
'version': 2,
'length': $$.str(file.length()),
'lastModified': $$.str(file.lastModified()),
'SHA256': sha256,
'signature': sigHex
}));
return true;
};
var defaultQuickVerifyFile = (file) => {
file = $$.file(file);
if (file.getName().endsWith(DEFAULT_SIGN_FILE_EXT) || !(file.exists()) || !(file.isFile())) {
return null;
}
var signFile = $$.file(file.getAbsoluteFile().getParentFile(), file.getName() + DEFAULT_SIGN_FILE_EXT);
if (!(signFile.exists())) {
return null;
}
var signatureJSON = JSON.parse($$.rFile(signFile).string().trim());
return $$.strEquals(file.length(), signatureJSON.length) && $$.strEquals(file.lastModified(), signatureJSON.lastModified);
};
var defaultVerifyFile = (file) => {
file = $$.file(file);
if (file.getName().endsWith(DEFAULT_SIGN_FILE_EXT) || !(file.exists()) || !(file.isFile())) {
return null;
}
var signFile = $$.file(file.getAbsoluteFile().getParentFile(), file.getName() + DEFAULT_SIGN_FILE_EXT);
if (!(signFile.exists())) {
return null;
}
var signatureJSON = JSON.parse($$.rFile(signFile).string().trim());
if (signatureJSON.version) {
var sha256 = $$.rFile(file).digest(__.digests.sha256());
return $$.strEquals(sha256.asHex(), signatureJSON.SHA256) && sha256.verify(getDefaultEcVerifySignature(), __.bytes.fromHex(signatureJSON.signature));
} else {
return $$.rFile(file).verify(getDefaultEcVerifySignature(), __.bytes.fromHex(signatureJSON.signature));
}
};
if (typeof exports == 'object') {
exports.generateECsecp256r1KeyPair = generateECsecp256r1KeyPair;
exports.getDefaultEcPrivateKeyBytes = getDefaultEcPrivateKeyBytes;
exports.getDefaultEcPublicKeyBytes = getDefaultEcPublicKeyBytes;
exports.getDefaultEcSignSignature = getDefaultEcSignSignature;
exports.getDefaultEcVerifySignature = getDefaultEcVerifySignature;
exports.defaultSignFile = defaultSignFile;
exports.defaultVerifyFile = defaultVerifyFile;
exports.defaultSignFileV2 = defaultSignFileV2;
exports.defaultQuickVerifyFile = defaultQuickVerifyFile;
}

View File

@@ -0,0 +1,33 @@
// http://blog.dkbza.org/2007/05/scanning-data-for-entropy-anomalies.html
// https://github.com/dxa4481/truffleHog/blob/master/truffleHog.py
var Math_log2 = Math.log2 || (x) => {
return Math.log(x) * Math.LOG2E;
};
exports.SHANNON_ENTROPY_BASE64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
exports.SHANNON_ENTROPY_HEX = "1234567890abcdefABCDEF";
exports.shannonEntropy = (data, charRange) => {
if (!data) {
return 0;
}
var lenOfData = data.length;
var charCodeCountMap = {};
for (var i = 0; i < data.length; i++) {
var charCode = data.charCodeAt(i);
charCodeCountMap[charCode] = charCodeCountMap[charCode] || 0;
charCodeCountMap[charCode] += 1;
}
var entropy = 0;
for (var i = 0; i < charRange.length; i++) {
var charCode = charRange.charCodeAt(i);
var charCodeCount = charCodeCountMap[charCode];
if (charCodeCount != null) {
var pCharCode = charCodeCount / lenOfData;
entropy += - pCharCode * Math_log2(pCharCode);
}
}
return entropy;
};

View File

@@ -0,0 +1,10 @@
(() => {
var shannonentropy = require('component-shannonentropy-ex.js');
SHANNON_ENTROPY_BASE64 = shannonentropy.SHANNON_ENTROPY_BASE64;
SHANNON_ENTROPY_HEX = shannonentropy.SHANNON_ENTROPY_HEX;
shannonEntropy = (data, charRange) => {
return shannonentropy.shannonEntropy(data, charRange);
};
})();

View File

@@ -0,0 +1,8 @@
requireJAR('jdbc.sqlite-3.6.7.jar');
requireJAR('dataaccess-1.0.jar');
var DataAccessObjectUtil = Packages.me.hatter.tools.dataaccess.util.DataAccessObjectUtil;
exports.createDAO = (dbFile) => {
return DataAccessObjectUtil.createSqliteObject(dbFile);
};

View File

@@ -0,0 +1,7 @@
(() => {
var sqlitedao = require('component-sqlitedataaccess-ex.js');
createSqliteDataAccessObject = (dbFile) => {
return sqlitedao.createDAO(dbFile);
};
})();

View File

@@ -0,0 +1,94 @@
(() => {
var JFrame = javax.swing.JFrame;
var JLabel = javax.swing.JLabel;
var JPanel = javax.swing.JPanel;
var JButton = javax.swing.JButton;
var JTextArea = javax.swing.JTextArea;
var JScrollPane = javax.swing.JScrollPane;
var Frame = java.awt.Frame;
var Toolkit = java.awt.Toolkit;
var BorderLayout = java.awt.BorderLayout;
var WindowListener = java.awt.event.WindowListener;
var Proxy = java.lang.reflect.Proxy;
var CountDownLatch = java.util.concurrent.CountDownLatch;
try {
//javax.swing.UIManager.setLookAndFeel(javax.swing.UIManager.getCrossPlatformLookAndFeelClassName());
} catch (e) { /* IGNORE */ }
function FutureResult() {
this.result = null;
this.countDown = new CountDownLatch(1);
}
FutureResult.prototype.set = (result) => {
this.result = result;
this.countDown.countDown();
};
FutureResult.prototype.get = () => {
this.countDown.await();
return this.result;
};
showWindow = (title, text, message, editable) => { // GLOBAL
var result = new FutureResult();
var f = new JFrame(title || "Hatter's Frame");
f.addWindowListener(Proxy.newProxyInstance(
Proxy.class.getClassLoader(),
[WindowListener.class],
(proxy, method, args) => {
if (method && method.name == "windowClosing") {
f.setVisible(false);
f.dispose();
result.set(null);
}
}
));
var text = new JTextArea(text || "", 30, 80);
text.setWrapStyleWord(true);
text.setLineWrap(true);
text.setEditable(!!editable);
var textScrollPane = new JScrollPane(text);
var label = new JLabel(message || "This is default message!");
var btnOK = null;
if (editable) {
btnOK = new JButton("OK!");
btnOK.addActionListener(() => {
var t = text.getText();
f.setVisible(false);
f.dispose();
result.set(t);
});
}
var btnCancel = new JButton("Cancel");
btnCancel.addActionListener(() => {
f.setVisible(false);
f.dispose();
result.set(null);
});
var pane = new JPanel();
if (btnOK != null) {
pane.add(btnOK);
}
pane.add(btnCancel);
f.getContentPane().add(label, BorderLayout.NORTH);
f.getContentPane().add(pane, BorderLayout.SOUTH);
f.getContentPane().add(textScrollPane, BorderLayout.CENTER);
f.pack();
var dim = Toolkit.getDefaultToolkit().getScreenSize();
f.setLocation((dim.width / 2) - (f.getSize().width / 2), (dim.height / 2) - (f.getSize().height / 2));
f.setVisible(true);
return result;
};
})();

View File

@@ -0,0 +1,66 @@
var getMillis = (date) => {
if (date == null) { return 0; }
if (date instanceof java.util.Date) {
return date.getTime();
}
return date;
};
var formatDuration = (date) => {
var millis = getMillis(date);
var diffMillis = $$.date().millis() - millis;
if (diffMillis < 3000) {
return 'just now';
}
var secs = $$.num(diffMillis).divr(1000, 0, null).along();
if (secs < 60) {
return secs + 's';
}
var mins = $$.num(secs).divr(60, 0, null).along();
if (mins < 60) {
return mins + 'm';
}
var hours = $$.num(mins).divr(60, 0, null).along();
if (hours < 24) {
return hours + 'h';
}
var days = $$.num(hours).divr(24, 0, null).along();
if (days < 31) {
return days + 'd';
}
return $$.date().fmt('yyyy-MM-dd').format(new java.util.Date(millis));
};
var formatDueInDays = (date) => {
var millis = getMillis(date);
var diffMillis = millis - $$.date().millis();
var isMinus = diffMillis < 0;
if (isMinus) {
diffMillis = -diffMillis;
}
var prefix = isMinus ? '-' : '';
var secs = $$.num(diffMillis).divr(1000, 0, null).along();
if (secs < 60) {
return 'in ' + prefix + secs + 's';
}
var mins = $$.num(secs).divr(60, 0, null).along();
if (mins < 60) {
return 'in ' + prefix + secs + 'm';
}
var hours = $$.num(mins).divr(60, 0, null).along();
if (hours < 24) {
return 'in ' + prefix + hours + 'h';
}
var days = $$.num(hours).divr(24, 0, null).along();
if (days < 31) {
return 'in ' + prefix + days + 'd';
}
return $$.date().fmt('yyyy-MM-dd').format(new java.util.Date(millis));
};
if (typeof exports == 'object') {
exports.getMillis = getMillis;
exports.formatDuration = formatDuration;
exports.formatDueInDays = formatDueInDays;
}