Explorar el Código

it works togather!

Ivan Valkou hace 5 años
padre
commit
2a1ce667dc

+ 0 - 4
FreeAPS.xcodeproj/project.pbxproj

@@ -7,7 +7,6 @@
 	objects = {
 	objects = {
 
 
 /* Begin PBXBuildFile section */
 /* Begin PBXBuildFile section */
-		3811DDFF25C9593400A708ED /* MealInputs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3811DDFE25C9593400A708ED /* MealInputs.swift */; };
 		384E803425C385E60086DB71 /* JavaScriptWorker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 384E803325C385E60086DB71 /* JavaScriptWorker.swift */; };
 		384E803425C385E60086DB71 /* JavaScriptWorker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 384E803325C385E60086DB71 /* JavaScriptWorker.swift */; };
 		384E803825C388640086DB71 /* Script.swift in Sources */ = {isa = PBXBuildFile; fileRef = 384E803725C388640086DB71 /* Script.swift */; };
 		384E803825C388640086DB71 /* Script.swift in Sources */ = {isa = PBXBuildFile; fileRef = 384E803725C388640086DB71 /* Script.swift */; };
 		388E595C25AD948C0019842D /* FreeAPSApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 388E595B25AD948C0019842D /* FreeAPSApp.swift */; };
 		388E595C25AD948C0019842D /* FreeAPSApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 388E595B25AD948C0019842D /* FreeAPSApp.swift */; };
@@ -23,7 +22,6 @@
 /* End PBXBuildFile section */
 /* End PBXBuildFile section */
 
 
 /* Begin PBXFileReference section */
 /* Begin PBXFileReference section */
-		3811DDFE25C9593400A708ED /* MealInputs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MealInputs.swift; sourceTree = "<group>"; };
 		384E803325C385E60086DB71 /* JavaScriptWorker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JavaScriptWorker.swift; sourceTree = "<group>"; };
 		384E803325C385E60086DB71 /* JavaScriptWorker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JavaScriptWorker.swift; sourceTree = "<group>"; };
 		384E803725C388640086DB71 /* Script.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Script.swift; sourceTree = "<group>"; };
 		384E803725C388640086DB71 /* Script.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Script.swift; sourceTree = "<group>"; };
 		388E595825AD948C0019842D /* FreeAPS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = FreeAPS.app; sourceTree = BUILT_PRODUCTS_DIR; };
 		388E595825AD948C0019842D /* FreeAPS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = FreeAPS.app; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -107,7 +105,6 @@
 			children = (
 			children = (
 				388E5A5F25B6F2310019842D /* Autosens.swift */,
 				388E5A5F25B6F2310019842D /* Autosens.swift */,
 				3895E4C525B9E00D00214B37 /* Profile.swift */,
 				3895E4C525B9E00D00214B37 /* Profile.swift */,
-				3811DDFE25C9593400A708ED /* MealInputs.swift */,
 			);
 			);
 			path = Models;
 			path = Models;
 			sourceTree = "<group>";
 			sourceTree = "<group>";
@@ -192,7 +189,6 @@
 			buildActionMask = 2147483647;
 			buildActionMask = 2147483647;
 			files = (
 			files = (
 				388E5A6025B6F2310019842D /* Autosens.swift in Sources */,
 				388E5A6025B6F2310019842D /* Autosens.swift in Sources */,
-				3811DDFF25C9593400A708ED /* MealInputs.swift in Sources */,
 				3895E4C625B9E00D00214B37 /* Profile.swift in Sources */,
 				3895E4C625B9E00D00214B37 /* Profile.swift in Sources */,
 				388E596C25AD95110019842D /* OpenAPS.swift in Sources */,
 				388E596C25AD95110019842D /* OpenAPS.swift in Sources */,
 				388E595E25AD948C0019842D /* ContentView.swift in Sources */,
 				388E595E25AD948C0019842D /* ContentView.swift in Sources */,

+ 1 - 2
FreeAPS/ContentView.swift

@@ -12,8 +12,7 @@ struct ContentView: View {
         Text("Hello, world!")
         Text("Hello, world!")
             .padding()
             .padding()
             .onAppear {
             .onAppear {
-                OpenAPS().meal()
-//                OpenAPS().determineBasal()
+                OpenAPS().test()
             }
             }
     }
     }
 }
 }

+ 0 - 4
FreeAPS/Helpers/JSON.swift

@@ -37,7 +37,3 @@ extension Double: JSON {}
 extension Int: JSON {}
 extension Int: JSON {}
 
 
 extension Bool: JSON {}
 extension Bool: JSON {}
-
-extension OpenAPSName: JSON {
-    var string: String { rawValue }
-}

+ 0 - 17
FreeAPS/Models/MealInputs.swift

@@ -1,17 +0,0 @@
-//
-//  MealInputs.swift
-//  FreeAPS
-//
-//  Created by Ivan Valkou on 02.02.2021.
-//
-
-import Foundation
-
-struct MealInputs: JSON {
-    let history: String
-    let profile: String
-    let basalprofile: String
-    let clock: String
-    let carbs: String
-    let glucose: String
-}

+ 8 - 32
FreeAPS/OpenAPS/JavaScriptWorker.swift

@@ -21,22 +21,6 @@ final class JavaScriptWorker {
                 print(error)
                 print(error)
             }
             }
         }
         }
-
-        context.setObject(require, forKeyedSubscript: "require" as NSString)
-
-    }
-
-    private lazy var require: @convention(block) (String) -> (JSValue?) = { path in
-        switch path {
-        case "../round-basal", "./round-basal":
-            self.evaluate(script: Script(name: "oref0/lib/round-basal"))
-        case "lodash/endsWith":
-            self.evaluate(script: Script(name: "lodash"))
-        default:
-            return nil
-        }
-
-        return self.context.objectForKeyedSubscript("module")?.objectForKeyedSubscript("exports")
     }
     }
 
 
     @discardableResult
     @discardableResult
@@ -50,9 +34,15 @@ final class JavaScriptWorker {
     }
     }
 
 
     subscript(key: String) -> JSValue! {
     subscript(key: String) -> JSValue! {
-        context.objectForKeyedSubscript(key)
+        get {
+            context.objectForKeyedSubscript(key)
+        }
+        set(newValue) {
+            context.setObject(newValue, forKeyedSubscript: key as NSString)
+        }
     }
     }
 
 
+
     func json(for string: String) -> JSON {
     func json(for string: String) -> JSON {
         evaluate(string: "JSON.stringify(\(string));")!.toString()!
         evaluate(string: "JSON.stringify(\(string));")!.toString()!
     }
     }
@@ -67,20 +57,6 @@ final class JavaScriptWorker {
     }
     }
 
 
     var log: String {
     var log: String {
-        context.objectForKeyedSubscript("freeaps")!.objectForKeyedSubscript("log")!.toString()!
+        context.objectForKeyedSubscript("freeapsLog")!.toString()!
     }
     }
-
-//    func recursivePathsForResources(type: String, in directoryPath: String) -> [String] {
-//        // Enumerators are recursive
-//        let enumerator = FileManager.default.enumerator(atPath: directoryPath)
-//        var filePaths: [String] = []
-//
-//        while let filePath = enumerator?.nextObject() as? String {
-//
-//            if URL(fileURLWithPath: filePath).pathExtension == type {
-//                filePaths.append(directoryPath.byAppending(pathComponent: filePath))
-//            }
-//        }
-//        return filePaths
-//    }
 }
 }

+ 97 - 55
FreeAPS/OpenAPS/OpenAPS.swift

@@ -9,84 +9,126 @@ import Foundation
 import JavaScriptCore
 import JavaScriptCore
 
 
 final class OpenAPS {
 final class OpenAPS {
-    private let vmQueue = DispatchQueue(label: "DispatchQueue.JSVirtualMachine")
+    func test() {
+        let pumphistory = loadJSON(name: "pumphistory")
+        let profile = loadJSON(name: "profile")
+        let basalProfile = loadJSON(name: "basal_profile")
+        let clock = loadJSON(name: "clock")
+        let carbs = loadJSON(name: "carbhistory")
+        let glucose = loadJSON(name: "glucose")
+        let currentTemp = loadJSON(name: "temp_basal")
+        let autosens = Autosens(ratio: 1)
+        let reservoir = 100
+        let tsMilliseconds: Double = 1527924300000
 
 
-//    func iob() {
-//
-//    }
-//
-    func meal() {
+
+        let iobResult = iob(
+            pumphistory: pumphistory,
+            profile: profile,
+            clock: clock,
+            autosens: autosens,
+            pumphistory24: "null"
+        )
+        print("IOB: \(iobResult)")
+
+        let mealResult = meal(
+            pumphistory: pumphistory,
+            profile: profile,
+            basalProfile: basalProfile,
+            clock: clock,
+            carbs: carbs,
+            glucose: glucose
+        )
+
+        print("MEAL: \(mealResult)")
+
+        let glucoseStatus = glucoseGetLast(glucose: glucose)
+        print("GLUCOSE STATUS: \(glucoseStatus)")
+
+        let suggested = determineBasal(
+            glucoseStatus: glucoseStatus,
+            currentTemp: currentTemp,
+            iob: iobResult,
+            profile: profile,
+            aurosens: autosens,
+            meal: mealResult,
+            microBolusAllowed: true,
+            reservoir: reservoir,
+            tsMilliseconds: tsMilliseconds
+        )
+
+        print("SUGGESTED: \(suggested)")
+    }
+
+    func iob(pumphistory: JSON, profile: JSON, clock: JSON, autosens: JSON, pumphistory24: JSON) -> JSON {
         let jsWorker = JavaScriptWorker()
         let jsWorker = JavaScriptWorker()
+        jsWorker.evaluate(script: Script(name:"iob-bundle"))
+        jsWorker.evaluate(script: Script(name:"prepare-iob"))
+        return jsWorker.call(function: "generate", with: [
+            pumphistory,
+            profile,
+            clock,
+            autosens,
+            pumphistory24
+        ])
+    }
 
 
-        jsWorker.evaluate(script: Script(name:"lib-meal-bundle"))
+    func meal(pumphistory: JSON, profile: JSON, basalProfile: JSON, clock: JSON, carbs: JSON, glucose: JSON) -> JSON {
+        let jsWorker = JavaScriptWorker()
+        jsWorker.evaluate(script: Script(name:"meal-bundle"))
         jsWorker.evaluate(script: Script(name:"prepare-meal"))
         jsWorker.evaluate(script: Script(name:"prepare-meal"))
-        let result = jsWorker.call(function: "generate", with: [
-            loadJSON(name: "pumphistory"),
-            loadJSON(name: "profile"),
-            loadJSON(name: "basal_profile"),
-            loadJSON(name: "clock"),
-            loadJSON(name: "carbhistory"),
-            loadJSON(name: "glucose")
+        return jsWorker.call(function: "generate", with: [
+            pumphistory,
+            profile,
+            basalProfile,
+            clock,
+            carbs,
+            glucose
         ])
         ])
-        print(result)
     }
     }
 
 
-    func determineBasal() {
+    func glucoseGetLast(glucose: JSON) -> JSON {
         let jsWorker = JavaScriptWorker()
         let jsWorker = JavaScriptWorker()
+        jsWorker.evaluate(script: Script(name:"glucose-get-last-bundle"))
+        return jsWorker.call(function: "freeaps", with: [glucose])
+    }
 
 
-        let scripts = [
-            Script(name: "prepare"),
-            Script(name: "basal-set-temp"),
-            Script(name: "determine-basal"),
-            Script(name: "glucose-get-last")
-        ]
-
-        scripts.forEach { jsWorker.evaluate(script: $0) }
+    func determineBasal(
+        glucoseStatus: JSON,
+        currentTemp: JSON,
+        iob: JSON,
+        profile: JSON,
+        aurosens: JSON,
+        meal: JSON,
+        microBolusAllowed: Bool,
+        reservoir: Int,
+        tsMilliseconds: Double
+    ) -> JSON {
+        let jsWorker = JavaScriptWorker()
 
 
-        let glucose = loadJSON(name: "glucose")
-        let currentTemp = loadJSON(name: "temp_basal")
-        let iobData = loadJSON(name: "iob")
-        let profile = loadJSON(name: "profile")
-        let autosensData = Autosens(ratio: 1.0)
-        let mealData = loadJSON(name: "meal")
-        let tempBasalFunctions: OpenAPSName = .tempBasalFunctions
-        let microBolusAllowed = true
-        let reservoir = 100
-        let tsMilliseconds = 1527924300000
+        jsWorker.evaluate(script: Script(name:"basal-set-temp-bundle"))
+        jsWorker.evaluate(script: Script(name:"prepare-determine-basal"))
+        let funcKey = "tempBasalFunctions"
+        jsWorker.evaluate(script: Script(name:"determine-basal-bundle"))
 
 
-        let glucoseStatus = jsWorker.call(function: .getLastGlucose, with: [glucose])
-        let result = jsWorker.call(
-            function: .determineBasal,
+        return jsWorker.call(
+            function: "freeaps",
             with: [
             with: [
                 glucoseStatus,
                 glucoseStatus,
                 currentTemp,
                 currentTemp,
-                iobData,
+                iob,
                 profile,
                 profile,
-                autosensData,
-                mealData,
-                tempBasalFunctions,
+                aurosens,
+                meal,
+                funcKey,
                 microBolusAllowed,
                 microBolusAllowed,
                 reservoir,
                 reservoir,
                 tsMilliseconds
                 tsMilliseconds
             ]
             ]
         )
         )
-        print(jsWorker.log)
-        print(result)
     }
     }
 
 
     private func loadJSON(name: String) -> String {
     private func loadJSON(name: String) -> String {
         try! String(contentsOf: Bundle.main.url(forResource: "json/\(name)", withExtension: "json")!)
         try! String(contentsOf: Bundle.main.url(forResource: "json/\(name)", withExtension: "json")!)
     }
     }
 }
 }
-
-enum OpenAPSName: String {
-    case tempBasalFunctions
-    case getLastGlucose
-    case determineBasal = "determine_basal"
-}
-
-extension JavaScriptWorker {
-    func call(function: OpenAPSName, with arguments: [JSON]) -> JSON {
-        call(function: function.string, with: arguments)
-    }
-}

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1 - 0
javascript/basal-set-temp-bundle.js


+ 0 - 60
javascript/basal-set-temp.js

@@ -1,60 +0,0 @@
-'use strict';
-
-function reason(rT, msg) {
-  rT.reason = (rT.reason ? rT.reason + '. ' : '') + msg;
-  console.error(msg);
-}
-
-var tempBasalFunctions = {};
-
-tempBasalFunctions.getMaxSafeBasal = function getMaxSafeBasal(profile) {
-
-    var max_daily_safety_multiplier = (isNaN(profile.max_daily_safety_multiplier) || profile.max_daily_safety_multiplier === null) ? 3 : profile.max_daily_safety_multiplier;
-    var current_basal_safety_multiplier = (isNaN(profile.current_basal_safety_multiplier) || profile.current_basal_safety_multiplier === null) ? 4 : profile.current_basal_safety_multiplier;
-
-    return Math.min(profile.max_basal, max_daily_safety_multiplier * profile.max_daily_basal, current_basal_safety_multiplier * profile.current_basal);
-};
-
-tempBasalFunctions.setTempBasal = function setTempBasal(rate, duration, profile, rT, currenttemp) {
-    //var maxSafeBasal = Math.min(profile.max_basal, 3 * profile.max_daily_basal, 4 * profile.current_basal);
-
-    var maxSafeBasal = tempBasalFunctions.getMaxSafeBasal(profile);
-    var round_basal = require('./round-basal');
-
-    if (rate < 0) {
-        rate = 0;
-    } else if (rate > maxSafeBasal) {
-        rate = maxSafeBasal;
-    }
-
-    var suggestedRate = round_basal(rate, profile);
-    if (typeof(currenttemp) !== 'undefined' && typeof(currenttemp.duration) !== 'undefined' && typeof(currenttemp.rate) !== 'undefined' && currenttemp.duration > (duration-10) && currenttemp.duration <= 120 && suggestedRate <= currenttemp.rate * 1.2 && suggestedRate >= currenttemp.rate * 0.8 && duration > 0 ) {
-        rT.reason += " "+currenttemp.duration+"m left and " + currenttemp.rate + " ~ req " + suggestedRate + "U/hr: no temp required";
-        return rT;
-    }
-
-    if (suggestedRate === profile.current_basal) {
-      if (profile.skip_neutral_temps === true) {
-        if (typeof(currenttemp) !== 'undefined' && typeof(currenttemp.duration) !== 'undefined' && currenttemp.duration > 0) {
-          reason(rT, 'Suggested rate is same as profile rate, a temp basal is active, canceling current temp');
-          rT.duration = 0;
-          rT.rate = 0;
-          return rT;
-        } else {
-          reason(rT, 'Suggested rate is same as profile rate, no temp basal is active, doing nothing');
-          return rT;
-        }
-      } else {
-        reason(rT, 'Setting neutral temp basal of ' + profile.current_basal + 'U/hr');
-        rT.duration = duration;
-        rT.rate = suggestedRate;
-        return rT;
-      }
-    } else {
-      rT.duration = duration;
-      rT.rate = suggestedRate;
-      return rT;
-    }
-};
-
-module.exports = tempBasalFunctions;

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1 - 0
javascript/determine-basal-bundle.js


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 1162
javascript/determine-basal.js


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1 - 0
javascript/glucose-get-last-bundle.js


+ 0 - 82
javascript/glucose-get-last.js

@@ -1,82 +0,0 @@
-var getLastGlucose = function (data) {
-    data = data.map(function prepGlucose (obj) {
-        //Support the NS sgv field to avoid having to convert in a custom way
-        obj.glucose = obj.glucose || obj.sgv;
-        return obj;
-    });
-
-    var now = data[0];
-    var now_date = now.date || Date.parse(now.display_time) || Date.parse(then.dateString);
-    var change;
-    var last_deltas = [];
-    var short_deltas = [];
-    var long_deltas = [];
-    var last_cal = 0;
-
-    //console.error(now.glucose);
-    for (var i=1; i < data.length; i++) {
-        // if we come across a cal record, don't process any older SGVs
-        if (typeof data[i] !== 'undefined' && data[i].type === "cal") {
-            last_cal = i;
-            break;
-        }
-        // only use data from the same device as the most recent BG data point
-        if (typeof data[i] !== 'undefined' && data[i].glucose > 38 && data[i].device === now.device) {
-            var then = data[i];
-            var then_date = then.date || Date.parse(then.display_time) || Date.parse(then.dateString);
-            var avgdelta = 0;
-            var minutesago;
-            if (typeof then_date !== 'undefined' && typeof now_date !== 'undefined') {
-                minutesago = Math.round( (now_date - then_date) / (1000 * 60) );
-                // multiply by 5 to get the same units as delta, i.e. mg/dL/5m
-                change = now.glucose - then.glucose;
-                avgdelta = change/minutesago * 5;
-            } else { console.error("Error: date field not found: cannot calculate avgdelta"); }
-            //if (i < 5) {
-                //console.error(then.glucose, minutesago, avgdelta);
-            //}
-            // use the average of all data points in the last 2.5m for all further "now" calculations
-            if (-2 < minutesago && minutesago < 2.5) {
-                now.glucose = ( now.glucose + then.glucose ) / 2;
-                now_date = ( now_date + then_date ) / 2;
-                //console.error(then.glucose, now.glucose);
-            // short_deltas are calculated from everything ~5-15 minutes ago
-            } else if (2.5 < minutesago && minutesago < 17.5) {
-                //console.error(minutesago, avgdelta);
-                short_deltas.push(avgdelta);
-                // last_deltas are calculated from everything ~5 minutes ago
-                if (2.5 < minutesago && minutesago < 7.5) {
-                    last_deltas.push(avgdelta);
-                }
-                //console.error(then.glucose, minutesago, avgdelta, last_deltas, short_deltas);
-            // long_deltas are calculated from everything ~20-40 minutes ago
-            } else if (17.5 < minutesago && minutesago < 42.5) {
-                long_deltas.push(avgdelta);
-            }
-        }
-    }
-    var last_delta = 0;
-    var short_avgdelta = 0;
-    var long_avgdelta = 0;
-    if (last_deltas.length > 0) {
-        last_delta = last_deltas.reduce(function(a, b) { return a + b; }) / last_deltas.length;
-    }
-    if (short_deltas.length > 0) {
-        short_avgdelta = short_deltas.reduce(function(a, b) { return a + b; }) / short_deltas.length;
-    }
-    if (long_deltas.length > 0) {
-        long_avgdelta = long_deltas.reduce(function(a, b) { return a + b; }) / long_deltas.length;
-    }
-
-    return {
-        delta: Math.round( last_delta * 100 ) / 100
-        , glucose: Math.round( now.glucose * 100 ) / 100
-        , noise: Math.round(now.noise)
-        , short_avgdelta: Math.round( short_avgdelta * 100 ) / 100
-        , long_avgdelta: Math.round( long_avgdelta * 100 ) / 100
-        , date: now_date
-        , last_cal: last_cal
-    };
-};
-
-module.exports = getLastGlucose;

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 2 - 0
javascript/iob-bundle.js


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 39717
javascript/lib-iob-bundle.js


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 40303
javascript/lib-meal-bundle.js


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 17112
javascript/lodash.js


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 2 - 0
javascript/meal-bundle.js


+ 10 - 0
javascript/prepare-determine-basal.js

@@ -0,0 +1,10 @@
+var freeapsLog = ""
+var printLog = function(...args) {
+    args.forEach(element => freeapsLog.log += JSON.stringify(element) + " ");
+    freeapsLog += "\n";
+}
+
+tempBasalFunctions = freeaps;
+
+var process = { stderr: { write: printLog } };
+var console = { log: freeaps.print, error: printLog };

+ 14 - 0
javascript/prepare-iob.js

@@ -0,0 +1,14 @@
+function generate(pumphistory_data, profile_data, clock_data, autosens_data, pumphistory_24_data) {
+    var inputs = {
+        history: pumphistory_data,
+        history24: pumphistory_24_data,
+        profile: profile_data,
+        clock: clock_data
+    };
+    if (autosens_data)  {
+        inputs.autosens = autosens_data;
+    }
+
+    return freeaps(inputs);
+}
+

+ 6 - 6
javascript/prepare-meal.js

@@ -1,11 +1,11 @@
 function generate(pumphistory_data, profile_data, basalprofile_data, clock_data, carb_data, glucose_data) {
 function generate(pumphistory_data, profile_data, basalprofile_data, clock_data, carb_data, glucose_data) {
     var inputs = {
     var inputs = {
-        history: pumphistory_data
-    , profile: profile_data
-    , basalprofile: basalprofile_data
-    , clock: clock_data
-    , carbs: carb_data
-    , glucose: glucose_data
+        history: pumphistory_data,
+        profile: profile_data,
+        basalprofile: basalprofile_data,
+        clock: clock_data,
+        carbs: carb_data,
+        glucose: glucose_data
     };
     };
 
 
     var recentCarbs = freeaps(inputs);
     var recentCarbs = freeaps(inputs);

+ 0 - 15
javascript/prepare.js

@@ -1,15 +0,0 @@
-var exports = {};
-var module = {
-    exports: {}
-};
-var freeaps = {
-    log: ""
-};
-
-freeaps.print = function(...args) {
-    args.forEach(element => freeaps.log += JSON.stringify(element) + " ");
-    freeaps.log += "\n";
-}
-
-var process = { stderr: { write: freeaps.print } };
-var console = { log: freeaps.print, error: freeaps.print };