diff --git a/app/lib/log/index.js b/app/lib/log/index.js
new file mode 100644
index 0000000..08b6e65
--- /dev/null
+++ b/app/lib/log/index.js
@@ -0,0 +1,46 @@
+'use strict';
+const { createLogger, format, transports } = require('winston');
+const { combine, timestamp, label, printf } = format;
+const path = require('path');
+const fs = require('fs-extra');
+const os = require('os');
+const logTime = 'MM/DD/YY-HH:mm:ss';
+let transport;
+async function logFile() {
+ let exists;
+ let logPath = path.join(os.homedir(), `/.config/mcopy-cli/`);
+ if (process.platform === 'darwin') {
+ logPath = path.join(os.homedir(), `/Library/Logs/mcopy-cli/`);
+ }
+ else if (process.platform === 'win32') {
+ logPath = path.join(os.homedir(), `/AppData/Roaming/mcopy-cli/`);
+ }
+ exists = await fs.exists(logPath);
+ if (!exists) {
+ await fs.mkdir(logPath);
+ }
+ return path.join(logPath, 'mcopy-cli.log');
+}
+module.exports = async function (arg) {
+ if (arg.quiet) {
+ transport = {
+ info: function () { },
+ warn: function () { },
+ error: function () { }
+ };
+ }
+ else {
+ transport = createLogger({
+ transports: [
+ new (transports.Console)({
+ format: combine(format.colorize(), format.simple())
+ }),
+ new (transports.File)({
+ filename: await logFile()
+ })
+ ]
+ });
+ }
+ return transport;
+};
+//# sourceMappingURL=index.js.map
\ No newline at end of file
diff --git a/app/lib/log/index.js.map b/app/lib/log/index.js.map
new file mode 100644
index 0000000..c50dde5
--- /dev/null
+++ b/app/lib/log/index.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/log/index.ts"],"names":[],"mappings":"AAAA,YAAY,CAAA;AAEZ,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,SAAS,CAAC,CAAA;AAC/D,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,CAAA;AACpD,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;AAC5B,MAAM,EAAE,GAAG,OAAO,CAAC,UAAU,CAAC,CAAA;AAC9B,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;AAExB,MAAM,OAAO,GAAG,mBAAmB,CAAA;AACnC,IAAI,SAAe,CAAA;AAEnB,KAAK,UAAU,OAAO;IACrB,IAAI,MAAgB,CAAA;IACpB,IAAI,OAAO,GAAY,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,qBAAqB,CAAC,CAAA;IACrE,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ,EAAE;QAClC,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,0BAA0B,CAAC,CAAA;KAC7D;SAAM,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE;QACxC,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,6BAA6B,CAAC,CAAA;KAChE;IACD,MAAM,GAAG,MAAM,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;IACjC,IAAI,CAAC,MAAM,EAAE;QACZ,MAAM,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;KACvB;IACD,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,eAAe,CAAC,CAAA;AAC3C,CAAC;AAED,MAAM,CAAC,OAAO,GAAG,KAAK,WAAW,GAAS;IACzC,IAAI,GAAG,CAAC,KAAK,EAAE;QACd,SAAS,GAAG;YACX,IAAI,EAAG,cAAa,CAAC;YACrB,IAAI,EAAG,cAAa,CAAC;YACrB,KAAK,EAAG,cAAa,CAAC;SACtB,CAAA;KACD;SAAM;QACN,SAAS,GAAG,YAAY,CAAC;YACxB,UAAU,EAAE;gBACX,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;oBACxB,MAAM,EAAE,OAAO,CACd,MAAM,CAAC,QAAQ,EAAE,EACjB,MAAM,CAAC,MAAM,EAAE,CACf;iBACD,CAAC;gBACF,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;oBACrB,QAAQ,EAAE,MAAM,OAAO,EAAE;iBACzB,CAAC;aACF;SACD,CAAC,CAAA;KACF;IACD,OAAO,SAAS,CAAA;AACjB,CAAC,CAAA"}
\ No newline at end of file
diff --git a/app/lib/log/package.json b/app/lib/log/package.json
new file mode 100644
index 0000000..7d7202a
--- /dev/null
+++ b/app/lib/log/package.json
@@ -0,0 +1,11 @@
+{
+ "name": "log",
+ "version": "1.0.0",
+ "description": "",
+ "main": "index.js",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "author": "",
+ "license": "ISC"
+}
diff --git a/cli/lib/arduino/index.js.map b/cli/lib/arduino/index.js.map
new file mode 100644
index 0000000..d999574
--- /dev/null
+++ b/cli/lib/arduino/index.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/arduino/index.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
diff --git a/cli/lib/log/index.js.map b/cli/lib/log/index.js.map
new file mode 100644
index 0000000..c50dde5
--- /dev/null
+++ b/cli/lib/log/index.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/log/index.ts"],"names":[],"mappings":"AAAA,YAAY,CAAA;AAEZ,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,SAAS,CAAC,CAAA;AAC/D,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,CAAA;AACpD,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;AAC5B,MAAM,EAAE,GAAG,OAAO,CAAC,UAAU,CAAC,CAAA;AAC9B,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;AAExB,MAAM,OAAO,GAAG,mBAAmB,CAAA;AACnC,IAAI,SAAe,CAAA;AAEnB,KAAK,UAAU,OAAO;IACrB,IAAI,MAAgB,CAAA;IACpB,IAAI,OAAO,GAAY,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,qBAAqB,CAAC,CAAA;IACrE,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ,EAAE;QAClC,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,0BAA0B,CAAC,CAAA;KAC7D;SAAM,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE;QACxC,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,6BAA6B,CAAC,CAAA;KAChE;IACD,MAAM,GAAG,MAAM,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;IACjC,IAAI,CAAC,MAAM,EAAE;QACZ,MAAM,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;KACvB;IACD,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,eAAe,CAAC,CAAA;AAC3C,CAAC;AAED,MAAM,CAAC,OAAO,GAAG,KAAK,WAAW,GAAS;IACzC,IAAI,GAAG,CAAC,KAAK,EAAE;QACd,SAAS,GAAG;YACX,IAAI,EAAG,cAAa,CAAC;YACrB,IAAI,EAAG,cAAa,CAAC;YACrB,KAAK,EAAG,cAAa,CAAC;SACtB,CAAA;KACD;SAAM;QACN,SAAS,GAAG,YAAY,CAAC;YACxB,UAAU,EAAE;gBACX,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;oBACxB,MAAM,EAAE,OAAO,CACd,MAAM,CAAC,QAAQ,EAAE,EACjB,MAAM,CAAC,MAAM,EAAE,CACf;iBACD,CAAC;gBACF,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;oBACrB,QAAQ,EAAE,MAAM,OAAO,EAAE;iBACzB,CAAC;aACF;SACD,CAAC,CAAA;KACF;IACD,OAAO,SAAS,CAAA;AACjB,CAAC,CAAA"}
\ No newline at end of file
diff --git a/cli/lib/mscript/Readme.md b/cli/lib/mscript/Readme.md
new file mode 100644
index 0000000..3112f09
--- /dev/null
+++ b/cli/lib/mscript/Readme.md
@@ -0,0 +1,186 @@
+
+
+## lib/mscript
+
+* [lib/mscript](#module_lib/mscript)
+ * [~Mscript](#module_lib/mscript..Mscript)
+ * [.clear()](#module_lib/mscript..Mscript+clear)
+ * [.interpret()](#module_lib/mscript..Mscript+interpret)
+ * [.basic_cmd()](#module_lib/mscript..Mscript+basic_cmd)
+ * [.new_loop()](#module_lib/mscript..Mscript+new_loop)
+ * [.end_loop()](#module_lib/mscript..Mscript+end_loop)
+ * [.move_cam()](#module_lib/mscript..Mscript+move_cam)
+ * [.move_proj()](#module_lib/mscript..Mscript+move_proj)
+ * [.set_state()](#module_lib/mscript..Mscript+set_state)
+ * [.last_loop()](#module_lib/mscript..Mscript+last_loop)
+ * [.parent_loop()](#module_lib/mscript..Mscript+parent_loop)
+ * [.loop_count()](#module_lib/mscript..Mscript+loop_count)
+ * [.fade()](#module_lib/mscript..Mscript+fade)
+ * [.fade_count()](#module_lib/mscript..Mscript+fade_count)
+ * [.fade_start()](#module_lib/mscript..Mscript+fade_start)
+ * [.fade_end()](#module_lib/mscript..Mscript+fade_end)
+ * [.update()](#module_lib/mscript..Mscript+update)
+ * [.str_to_arr()](#module_lib/mscript..Mscript+str_to_arr)
+ * [.light_to_arr()](#module_lib/mscript..Mscript+light_to_arr)
+ * [.light_state()](#module_lib/mscript..Mscript+light_state)
+ * [.fail()](#module_lib/mscript..Mscript+fail)
+ * [~startsWith()](#module_lib/mscript..startsWith)
+
+
+
+### lib/mscript~Mscript
+class Mscript
+
+**Kind**: inner class of [lib/mscript
](#module_lib/mscript)
+
+* [~Mscript](#module_lib/mscript..Mscript)
+ * [.clear()](#module_lib/mscript..Mscript+clear)
+ * [.interpret()](#module_lib/mscript..Mscript+interpret)
+ * [.basic_cmd()](#module_lib/mscript..Mscript+basic_cmd)
+ * [.new_loop()](#module_lib/mscript..Mscript+new_loop)
+ * [.end_loop()](#module_lib/mscript..Mscript+end_loop)
+ * [.move_cam()](#module_lib/mscript..Mscript+move_cam)
+ * [.move_proj()](#module_lib/mscript..Mscript+move_proj)
+ * [.set_state()](#module_lib/mscript..Mscript+set_state)
+ * [.last_loop()](#module_lib/mscript..Mscript+last_loop)
+ * [.parent_loop()](#module_lib/mscript..Mscript+parent_loop)
+ * [.loop_count()](#module_lib/mscript..Mscript+loop_count)
+ * [.fade()](#module_lib/mscript..Mscript+fade)
+ * [.fade_count()](#module_lib/mscript..Mscript+fade_count)
+ * [.fade_start()](#module_lib/mscript..Mscript+fade_start)
+ * [.fade_end()](#module_lib/mscript..Mscript+fade_end)
+ * [.update()](#module_lib/mscript..Mscript+update)
+ * [.str_to_arr()](#module_lib/mscript..Mscript+str_to_arr)
+ * [.light_to_arr()](#module_lib/mscript..Mscript+light_to_arr)
+ * [.light_state()](#module_lib/mscript..Mscript+light_state)
+ * [.fail()](#module_lib/mscript..Mscript+fail)
+
+
+
+#### mscript.clear()
+Clear the state of the script
+
+**Kind**: instance method of [Mscript
](#module_lib/mscript..Mscript)
+
+
+#### mscript.interpret()
+Main function, accepts multi-line string, parses into lines
+and interprets the instructions from the text. Returns an array
+of steps to be fed into the mcopy.
+
+**Kind**: instance method of [Mscript
](#module_lib/mscript..Mscript)
+
+
+#### mscript.basic\_cmd()
+Apply a basic two character command
+
+**Kind**: instance method of [Mscript
](#module_lib/mscript..Mscript)
+
+
+#### mscript.new\_loop()
+Start a new loop
+
+**Kind**: instance method of [Mscript
](#module_lib/mscript..Mscript)
+
+
+#### mscript.end\_loop()
+Close the most recent loop
+
+**Kind**: instance method of [Mscript
](#module_lib/mscript..Mscript)
+
+
+#### mscript.move\_cam()
+Move camera to explicitly-defined frame
+
+**Kind**: instance method of [Mscript
](#module_lib/mscript..Mscript)
+
+
+#### mscript.move\_proj()
+Move projector to explicitly-defined frame
+
+**Kind**: instance method of [Mscript
](#module_lib/mscript..Mscript)
+
+
+#### mscript.set\_state()
+Set the state of either the cam or projector
+
+**Kind**: instance method of [Mscript
](#module_lib/mscript..Mscript)
+
+
+#### mscript.last\_loop()
+Return the last loop
+
+**Kind**: instance method of [Mscript
](#module_lib/mscript..Mscript)
+
+
+#### mscript.parent\_loop()
+Return the second-last loop
+
+**Kind**: instance method of [Mscript
](#module_lib/mscript..Mscript)
+
+
+#### mscript.loop\_count()
+Extract the loop count integer from a LOOP cmd
+
+**Kind**: instance method of [Mscript
](#module_lib/mscript..Mscript)
+
+
+#### mscript.fade()
+Execute a fade of frame length, from color to another color
+
+**Kind**: instance method of [Mscript
](#module_lib/mscript..Mscript)
+
+
+#### mscript.fade\_count()
+Extract the fade length integer from a FADE cmd
+
+**Kind**: instance method of [Mscript
](#module_lib/mscript..Mscript)
+
+
+#### mscript.fade\_start()
+Extract the start color from a string
+
+**Kind**: instance method of [Mscript
](#module_lib/mscript..Mscript)
+
+
+#### mscript.fade\_end()
+Extract the end color from a string
+
+**Kind**: instance method of [Mscript
](#module_lib/mscript..Mscript)
+
+
+#### mscript.update()
+Increase the state of a specific object, such as the camera/projector,
+by the value defined in val
+
+**Kind**: instance method of [Mscript
](#module_lib/mscript..Mscript)
+
+
+#### mscript.str\_to\_arr()
+Split string on command, extract any integers from string
+
+**Kind**: instance method of [Mscript
](#module_lib/mscript..Mscript)
+
+
+#### mscript.light\_to\_arr()
+Split a string on a command to extract data for light array
+
+**Kind**: instance method of [Mscript
](#module_lib/mscript..Mscript)
+
+
+#### mscript.light\_state()
+Split a string to extract an rgb color value
+
+**Kind**: instance method of [Mscript
](#module_lib/mscript..Mscript)
+
+
+#### mscript.fail()
+Throw an error with specific message
+
+**Kind**: instance method of [Mscript
](#module_lib/mscript..Mscript)
+
+
+### lib/mscript~startsWith()
+startswith function from lodash, do not want the entire lib for this
+
+**Kind**: inner method of [lib/mscript
](#module_lib/mscript)
diff --git a/cli/lib/mscript/TODO.md b/cli/lib/mscript/TODO.md
new file mode 100644
index 0000000..b0f824f
--- /dev/null
+++ b/cli/lib/mscript/TODO.md
@@ -0,0 +1,13 @@
+# TODO - mscript
+
+* Add variables and simple evaluation
+* Add "Light" feature
+
+Bash-like variables?
+Similar to LESS/SASS?
+Makes a tokenization easier
+
+@ is better than $
+
+RangeError: Invalid array length
+ at Mscript.str_to_arr (./mcopy/app/lib/mscript/index.js:474:9)
diff --git a/cli/lib/mscript/index.js b/cli/lib/mscript/index.js
new file mode 100644
index 0000000..e2fac5e
--- /dev/null
+++ b/cli/lib/mscript/index.js
@@ -0,0 +1,545 @@
+'use strict';
+
+/** @module lib/mscript */
+
+const BLACK = '0,0,0';
+const WHITE = '255,255,255';
+const CMD = [
+ 'CF',
+ 'PF',
+ 'BF',
+ 'CB',
+ 'PB',
+ 'BB'
+];
+const ALTS = {
+ 'CF' : ['CAMERA FORWARD', 'CAM FORWARD'],
+ 'PF' : ['PROJECTOR FORWARD', 'PROJ FORWARD'],
+ 'BF' : ['BLACK FORWARD', 'BLACK', 'BLANK FORWARD', 'BLANK'],
+ 'CB' : ['CAMERA BACKWARD', 'CAM BACKWARD', 'CAMERA BACK', 'CAM BACK'],
+ 'PB' : ['PROJECTOR FORWARD', 'PROJ FORWARD', 'PROJECTOR BACK', 'PROJ BACK'],
+ 'BB' : ['BLACK BACKWARD', 'BLACK BACK', 'BLANK BACK'],
+ 'L ' : ['LIGHT', 'COLOR', 'LAMP'],
+ 'F ' : ['FADE']
+};
+
+/** helper functions */
+
+/** startswith function from lodash, do not want the entire lib for this */
+function startsWith(string, target, position) {
+ const { length } = string;
+ position = position == null ? 0 : position;
+ if (position < 0) {
+ position = 0;
+ } else if (position > length) {
+ position = length;
+ }
+ target = `${target}`;
+ return string.slice(position, position + target.length) == target;
+}
+
+/** class Mscript */
+class Mscript {
+ constructor () {
+ this.output = {};
+ }
+ /**
+ * Clear the state of the script
+ */
+ clear () {
+ this.lines = [];
+
+ this.cam = 0;
+ this.proj = 0;
+ this.color = '';
+ this.loops = [];
+ this.rec = -1;
+
+ this.two = '';
+ this.arr = [];
+ this.light = [];
+ this.target = 0; //move to target using CAM # or PROJ #
+ this.dist = 0;
+
+ this.variables = {};
+
+ this.output = {};
+ }
+ /**
+ * Main function, accepts multi-line string, parses into lines
+ * and interprets the instructions from the text. Returns an array
+ * of steps to be fed into the mcopy.
+ */
+ interpret (text, callback) {
+ this.clear()
+
+ if (typeof text === 'undefined') {
+ return this.fail('No input');
+ }
+
+ //split string into lines, each containing a command
+ this.lines = text.split('\n');
+
+ this.lines = this.lines.map(line => {
+ line = line.replace(/\t+/g, ''); //strip tabs
+ line = line.trim(); //remove excess whitespace before and after command
+ line = line.toUpperCase();
+ return line;
+ })
+
+ for (let line of this.lines) {
+ this.two = line.substring(0, 2);
+ if (CMD.indexOf(this.two) !== -1) {
+ this.basic_cmd(line);
+ } else if (startsWith(line, '@') || line.indexOf('@') !== -1) {
+ this.variable(line);
+ } else if (startsWith(line, 'LOOP')) {
+ this.new_loop(line);
+ } else if (startsWith(line, 'L ')) {
+ this.light_state(line);
+ } else if (startsWith(line, 'F ')) {
+ this.new_loop(line, true);
+ } else if (startsWith(line, 'END')) {
+ this.end_loop(line);
+ } else if (startsWith(line, 'CAM')) { //directly go to that frame (black?)
+ this.move_cam(line);
+ } else if (startsWith(line, 'PROJ')) { //directly go to that frame
+ this.move_proj(line);
+ } else if (startsWith(line, 'SET')) { //set that state
+ this.set_state(line);
+ } else if (startsWith(line, '#') || startsWith(line, '//')) {
+ //comments
+ //ignore while parsing
+ }
+ }
+
+ this.output.success = true;
+ this.output.arr = this.arr; //all instructions
+ this.output.light = this.light; //all light instructions
+ this.output.cam = this.cam;
+ this.output.proj = this.proj;
+
+ if (typeof callback !== 'undefined') {
+ //should only be invoked by running mscript.tests()
+ callback(this.output);
+ } else {
+ return this.output;
+ }
+ }
+ variable (line) {
+ let parts = line.split('=');
+ let key = parts[0];
+ let value = parts[1];
+ let update = false;
+
+ if (value && value.indexOf('#') !== -1) {
+ value = value.split('#')[0];
+ }
+
+ if (value && value.indexOf('//') !== -1) {
+ value = value.split('//')[0];
+ }
+
+ if (value && value.indexOf('+') !== -1) {
+ if (value)
+ update = true;
+ }
+
+ if (line.indexOf('-') !== -1) {
+
+ update = true;
+ }
+
+ if (line.indexOf(',') === -1) { //if not color string
+ try {
+ value = parseInt(value);
+ } catch (err) {
+ //supress parsing error
+ }
+ }
+ //console.dir(parts)
+ if (!this.variables[key] || update) {
+ this.variables[key] = value;
+ }
+ console.dir(this.variables)
+ }
+ variable_replace(line) {
+
+ }
+ /**
+ * Apply a basic two character command
+ */
+ basic_cmd (line) {
+ if (this.rec !== -1) {
+ //hold generated arr in state loop array
+ this.loops[this.rec].arr
+ .push.apply(this.loops[this.rec].arr,
+ this.str_to_arr(line,
+ this.two));
+ this.loops[this.rec].light
+ .push.apply(this.loops[this.rec].light,
+ this.light_to_arr(line,
+ this.two));
+ } else {
+ this.arr.push.apply(this.arr, this.str_to_arr(line, this.two));
+ this.light.push.apply(this.light, this.light_to_arr(line, this.two))
+ }
+ }
+ /**
+ * Start a new loop
+ */
+ new_loop (line, fade) {
+ this.rec++;
+ this.loops[this.rec] = {
+ arr : [],
+ light : [],
+ cam : 0,
+ proj : 0,
+ cmd : line + ''
+ };
+ if (fade) {
+ this.fade(line);
+ }
+ }
+ /**
+ * Close the most recent loop
+ */
+ end_loop (line) {
+ let light_arr;
+ let start;
+ let end;
+ let len;
+
+ for (let x = 0; x < this.loop_count(this.loops[this.rec].cmd); x++) {
+ light_arr = this.loops[this.rec].light;
+ if (this.loops[this.rec].fade) {
+ start = this.loops[this.rec].start;
+ end = this.loops[this.rec].end;
+ len = this.loops[this.rec].fade_len;
+ light_arr = light_arr.map(l => {
+ return this.fade_rgb(start, end, len, x);
+ })
+ }
+ if (this.rec === 0) {
+ this.arr.push.apply(this.arr, this.loops[this.rec].arr);
+ this.light.push.apply(this.light, light_arr);
+ } else if (this.rec >= 1) {
+ this.loops[this.rec - 1].arr
+ .push.apply(this.loops[this.rec - 1].arr,
+ this.loops[this.rec].arr);
+
+ this.loops[this.rec - 1].light
+ .push.apply(this.loops[this.rec - 1].light,
+ light_arr);
+ }
+ }
+ this.update('END', this.loop_count(this.loops[this.rec].cmd));
+ delete this.loops[this.rec];
+ this.rec--;
+ }
+ /**
+ * Move camera to explicitly-defined frame
+ */
+ move_cam (line) {
+ this.target = parseInt(line.split('CAM ')[1]);
+ if (this.rec !== -1) {
+ if (this.target > this.cam) {
+ this.dist = this.target - this.cam;
+ for (let x = 0; x < this.dist; x++) {
+ this.loops[this.rec].arr.push('BF');
+ this.loops[this.rec].light.push(BLACK);
+ this.update('BF');
+ }
+ } else {
+ this.dist = this.cam - this.target;
+ for (let x = 0; x < this.dist; x++) {
+ this.loops[this.rec].arr.push('BB');
+ this.loops[this.rec].light.push(BLACK);
+ this.update('BB');
+ }
+ }
+ } else {
+ if (target > this.cam) {
+ this.dist = this.target - this.cam;
+ for (let x = 0; x < this.dist; x++) {
+ this.arr.push('BF');
+ this.light.push(BLACK);
+ this.update('BF');
+ }
+ } else {
+ this.dist = this.cam - this.target;
+ for (let x = 0; x < this.dist; x++) {
+ this.arr.push('BB');
+ this.light.push(BLACK);
+ this.update('BB');
+ }
+ }
+ }
+ }
+ /**
+ * Move projector to explicitly-defined frame
+ */
+ move_proj (line) {
+ this.target = parseInt(line.split('PROJ ')[1]);
+ if (this.rec !== -1) {
+ if (this.target > this.proj) {
+ this.dist = this.target - this.proj;
+ for (let x = 0; x < this.dist; x++) {
+ this.loops[this.rec].arr.push('PF');
+ this.loops[this.rec].light.push('');
+ this.update('PF');
+ }
+ } else {
+ this.dist = this.proj - this.target;
+ for (let x = 0; x < this.dist; x++) {
+ this.loops[this.rec].arr.push('PB');
+ this.loops[this.rec].light.push('');
+ this.update('PB');
+ }
+ }
+ } else {
+ if (this.target > this.proj) {
+ this.dist = this.target - this.proj;
+ for (let x = 0; x < this.dist; x++) {
+ this.arr.push('PF');
+ this.light.push('');
+ this.update('PF');
+ }
+ } else {
+ this.dist = this.proj - this.target;
+ for (let x = 0; x < this.dist; x++) {
+ this.arr.push('PB');
+ this.light.push('');
+ this.update('PB');
+ }
+ }
+ }
+ }
+ /**
+ * Set the state of either the cam or projector
+ */
+ set_state (line) {
+ if (startsWith(line, 'SET CAM')) {
+ this.cam = parseInt(line.split('SET CAM')[1]);
+ } else if (startsWith(line, 'SET PROJ')) {
+ this.proj = parseInt(line.split('SET PROJ')[1]);
+ }
+ }
+ /**
+ * Return the last loop
+ */
+ last_loop () {
+ return this.loops[this.loops.length - 1];
+ }
+ /**
+ * Return the second-last loop
+ */
+ parent_loop () {
+ return this.loops[this.loops.length - 2];
+ }
+ /**
+ * Extract the loop count integer from a LOOP cmd
+ */
+ loop_count (str) {
+ return parseInt(str.split(' ')[1]);
+ }
+ /**
+ * Execute a fade of frame length, from color to another color
+ */
+ fade (line) {
+ let len = this.fade_count(line);
+ let start = this.fade_start(line);
+ let end = this.fade_end(line);
+
+ this.loops[this.rec].start = start;
+ this.loops[this.rec].end = end;
+ this.loops[this.rec].fade = true;
+ this.loops[this.rec].fade_count = 0;
+ this.loops[this.rec].fade_len = len;
+ }
+ /**
+ * Extract the fade length integer from a FADE cmd
+ */
+ fade_count (str) {
+ return parseInt(str.split(' ')[1]);
+ }
+ /**
+ * Extract the start color from a string
+ */
+ fade_start (str) {
+ let color = str.split(' ')[2];
+ return this.rgb(color.trim())
+ }
+ /**
+ * Extract the end color from a string
+ */
+ fade_end (str) {
+ let color = str.split(' ')[3];
+ return this.rgb(color.trim())
+ }
+ fade_rgb (start, end, len, x) {
+ let cur = [];
+ let diff;
+ for (let i = 0; i < 3; i++) {
+ if (x === len - 1) {
+ cur[i] = end[i];
+ } else if (start[i] >= end[i]) {
+ diff = start[i] - end[i];
+ cur[i] = start[i] - Math.round((diff / (len - 1)) * x);
+ } else {
+ diff = end[i] - start[i];
+ cur[i] = start[i] + Math.round((diff / (len - 1)) * x);
+ }
+ }
+ return this.rgb_str(cur);
+
+ }
+ rgb (str) {
+ let rgb = str.split(',');
+ return rgb.map( char => {
+ return parseInt(char);
+ })
+ }
+ rgb_str (arr) {
+ return arr.join(',');
+ }
+ /**
+ * Increase the state of a specific object, such as the camera/projector,
+ * by the value defined in val
+ */
+ update (cmd, val = 1) {
+ if (cmd === 'END') {
+ //I don't understand this loop
+ for (let i = 0; i < val; i++) {
+ if (this.rec === 0) {
+ this.cam += this.loops[this.rec].cam;
+ this.proj += this.loops[this.rec].proj;
+ } else if (this.rec >= 1) {
+ this.loops[this.rec - 1].cam += this.loops[this.rec].cam;
+ this.loops[this.rec - 1].proj += this.loops[this.rec].proj;
+ }
+ }
+ } else if (cmd === 'CF') {
+ if (this.rec === -1) {
+ this.cam += val;
+ } else {
+ this.loops[this.rec].cam += val;
+ }
+ } else if (cmd === 'CB') {
+ if (this.rec === -1) {
+ this.cam -= val;
+ } else {
+ this.loops[this.rec].cam--;
+ }
+ } else if (cmd === 'PF') {
+ if (this.rec === -1) {
+ this.proj += val;
+ } else {
+ this.loops[this.rec].proj += val;
+ }
+ } else if (cmd === 'PB') {
+ if (this.rec === -1) {
+ this.proj -= val;
+ } else {
+ this.loops[this.rec].proj--;
+ }
+ } else if (cmd === 'BF') {
+ if (this.rec === -1) {
+ this.cam += val;
+ } else {
+ this.loops[this.rec].cam += val;
+ }
+ } else if (cmd === 'BB') {
+ if (this.rec === -1) {
+ this.cam -= val;
+ } else {
+ this.loops[this.rec].cam -= val;
+ }
+ } else if (cmd === 'L ') {
+
+ }
+ }
+ /**
+ * Split string on command, extract any integers from string
+ */
+ str_to_arr (str, cmd) {
+ const cnt = str.split(cmd);
+ let c = parseInt(cnt[1]);
+ let arr = [];
+ if (cnt[1] === '') {
+ c = 1;
+ } else {
+ c = parseInt(cnt[1]);
+ }
+ arr = new Array(c).fill(cmd);
+ this.update(cmd, c);
+ return arr;
+ }
+ /**
+ * Split a string on a command to extract data for light array
+ */
+ light_to_arr (str, cmd) {
+ const cnt = str.split(cmd);
+ let c = parseInt(cnt[1]);
+ let arr = [];
+ if (cnt[1] === '') {
+ c = 1;
+ } else {
+ c = parseInt(cnt[1]);
+ }
+ for (var i = 0; i < c; i++) {
+ if (cmd === 'CF'
+ || cmd === 'CB') {
+ arr.push(this.color);
+ } else if (cmd === 'BF'
+ || cmd === 'BB') {
+ arr.push(BLACK);
+ } else {
+ arr.push('');
+ }
+ }
+ return arr;
+ }
+ /**
+ * Split a string to extract an rgb color value
+ */
+ light_state (str) {
+ //add parsers for other color spaces
+ const color = str.replace('L ', '').trim();
+ this.color = color;
+ }
+
+ /**
+ * Throw an error with specific message
+ */
+ fail (msg) {
+ throw new Error(msg);
+ }
+}
+
+module.exports = Mscript;
+
+
+/*
+
+CAM # - go to camera frame #
+PROJ # - go to projector frame #
+
+SET CAM # - sets camera count to #
+SET PROJ # - sets projector count to #
+
+LOOP # - begin loop, can nest recursively, # times
+END LOOP - (or END) closes loop
+
+L #RGB - sets light to rgb value
+
+FADE 24 0,0,0 255,255,255
+
+CF - Camera forwards
+PF - Projector forwards
+BF - Black forwards
+CB - Camera backwards
+PB - Projector backwards
+BB - Black backwards
+
+*/
\ No newline at end of file
diff --git a/cli/lib/mscript/index.old.js b/cli/lib/mscript/index.old.js
new file mode 100644
index 0000000..65e8d17
--- /dev/null
+++ b/cli/lib/mscript/index.old.js
@@ -0,0 +1,476 @@
+'use strict';
+
+/** @module lib/mscript */
+
+let fs;
+let input;
+
+/** object mscript */
+const mscript = {};
+
+/**
+ * Check for the presence of specific arguments in process
+ * argv
+ *
+ * @param {string} shrt Short version of argument or flag
+ * @param {string} lng Long version of argument or flag
+ *
+ * @return {boolean} Is flag present
+ */
+mscript.arg = function arg (shrt, lng) {
+ if (process.argv.indexOf(shrt) !== -1 ||
+ process.argv.indexOf(lng) !== -1) {
+ return true;
+ }
+ return false;
+};
+
+/**
+ * Check for the position of specific arguments in process
+ * argv
+ *
+ * @param {string} shrt Short version of argument or flag
+ * @param {string} lng Long version of argument or flag
+ *
+ * @return {boolean} Position of arg or flag, for locating input
+ */
+mscript.arg_pos = function arg_pos (shrt, lng) {
+ var pos = -1;
+ pos = process.argv.indexOf(shrt);
+ if (pos === -1) {
+ pos = process.argv.indexOf(lng);
+ }
+ return pos;
+};
+
+mscript.black = '0,0,0';
+mscript.cmd = [
+ 'CF',
+ 'PF',
+ 'BF',
+ 'CB',
+ 'PB',
+ 'BB'
+];
+mscript.alts = {
+ 'CF' : ['CAMERA FORWARD', 'CAM FORWARD'],
+ 'PF' : ['PROJECTOR FORWARD', 'PROJ FORWARD'],
+ 'BF' : ['BLACK FORWARD', 'BLACK', 'BLANK FORWARD', 'BLANK'],
+ 'CB' : ['CAMERA BACKWARD', 'CAM BACKWARD', 'CAMERA BACK', 'CAM BACK'],
+ 'PB' : ['PROJECTOR FORWARD', 'PROJ FORWARD', 'PROJECTOR BACK', 'PROJ BACK'],
+ 'BB' : ['BLACK BACKWARD', 'BLACK BACK', 'BLANK BACK'],
+ 'L ' : ['LIGHT', 'COLOR', 'LAMP'],
+ 'F ' : ['FADE']
+};
+
+mscript.state = {};
+
+/**
+ * Clear the state object
+ */
+mscript.state_clear = function state_clear () {
+ mscript.state = {
+ cam : 0,
+ proj : 0,
+ color : '',
+ loops : [],
+ rec : -1
+ };
+};
+/**
+ * This is never used and doesn't do anything?
+ */
+mscript.alts_unique = function alts_unique () {
+ var ids = Object.keys(mscript.alts),
+ all = [];
+ for (var i = 0; i < ids.length; i++) {
+ if (all.indexOf(ids[i]) === -1) {
+ all.push(ids[i]);
+ } else {
+ mscript.fail("Can't compile");
+ }
+ }
+};
+/**
+ *
+ */
+mscript.interpret = function interpret (text, callback) {
+ mscript.state_clear();
+ if (typeof text === 'undefined') {
+ mscript.fail('No input');
+ }
+ var lines = text.split('\n'),
+ two = '',
+ arr = [],
+ light = [],
+ target = 0,
+ dist = 0, //?
+ output = {};
+ for (var i = 0; i < lines.length; i++) {
+ lines[i] = lines[i].replace(/\t+/g, ""); //strip tabs
+ lines[i] = lines[i].trim(); //remove excess whitespace before and after command
+ two = lines[i].substring(0, 2);
+ if (mscript.cmd.indexOf(two) !== -1) {
+
+ if (mscript.state.loops.length > 0) {
+ //hold generated arr in state loop array
+ mscript.state.loops[mscript.state.rec].arr
+ .push.apply(mscript.state.loops[mscript.state.rec].arr,
+ mscript.str_to_arr(lines[i],
+ two));
+ mscript.state.loops[mscript.state.rec].light
+ .push.apply(mscript.state.loops[mscript.state.rec].light,
+ mscript.light_to_arr(lines[i],
+ two));
+ } else {
+ arr.push.apply(arr, mscript.str_to_arr(lines[i], two));
+ light.push.apply(light, mscript.light_to_arr(lines[i], two))
+ }
+
+ } else if (lines[i].substring(0, 4) === 'LOOP') {
+ mscript.state.rec++;
+ mscript.state.loops[mscript.state.rec] = {
+ arr : [],
+ light : [],
+ cam : 0,
+ proj : 0,
+ cmd : lines[i] + ''
+ };
+ } else if (lines[i].substring(0, 2) === 'L ') {
+ mscript.light_state(lines[i]);
+ } else if (lines[i].substring(0, 3) === 'END') {
+ for (var x = 0; x < mscript.loop_count(mscript.state.loops[mscript.state.rec].cmd); x++) {
+ if (mscript.state.rec === 0) {
+ arr.push.apply(arr, mscript.state.loops[mscript.state.rec].arr);
+ light.push.apply(light, mscript.state.loops[mscript.state.rec].light);
+ } else if (mscript.state.rec >= 1) {
+ mscript.state.loops[mscript.state.rec - 1].arr
+ .push.apply(mscript.state.loops[mscript.state.rec - 1].arr,
+ mscript.state.loops[mscript.state.rec].arr);
+ mscript.state.loops[mscript.state.rec - 1].light
+ .push.apply(mscript.state.loops[mscript.state.rec - 1].light,
+ mscript.state.loops[mscript.state.rec].light);
+ }
+ }
+ mscript.state_update('END', mscript.loop_count(mscript.state.loops[mscript.state.rec].cmd));
+ delete mscript.state.loops[mscript.state.rec];
+ mscript.state.rec--;
+ } else if (lines[i].substring(0, 3) === 'CAM') { //directly go to that frame (black?)
+ target = parseInt(lines[i].split('CAM ')[1]);
+ if (mscript.state.loops.length > 0) {
+ if (target > mscript.state.cam) {
+ dist = target - mscript.state.cam;
+ for (var x = 0; x < dist; x++) {
+ mscript.state.loops[mscript.state.rec].arr.push('BF');
+ mscript.state.loops[mscript.state.rec].light.push(mscript.black);
+ mscript.state_update('BF');
+ }
+ } else {
+ dist = mscript.state.cam - target;
+ for (var x = 0; x < dist; x++) {
+ mscript.state.loops[mscript.state.rec].arr.push('BB');
+ mscript.state.loops[mscript.state.rec].light.push(mscript.black);
+ mscript.state_update('BB');
+ }
+ }
+ } else {
+ if (target > mscript.state.cam) {
+ dist = target - mscript.state.cam;
+ for (var x = 0; x < dist; x++) {
+ arr.push('BF');
+ light.push(mscript.black);
+ mscript.state_update('BF');
+ }
+ } else {
+ dist = mscript.state.cam - target;
+ for (var x = 0; x < dist; x++) {
+ arr.push('BB');
+ light.push(mscript.black);
+ mscript.state_update('BB');
+ }
+ }
+ }
+ } else if (lines[i].substring(0, 4) === 'PROJ') { //directly go to that frame
+ target = parseInt(lines[i].split('PROJ ')[1]);
+ if (mscript.state.loops.length > 0) {
+ if (target > mscript.state.proj) {
+ dist = target - mscript.state.proj;
+ for (var x = 0; x < dist; x++) {
+ mscript.state.loops[mscript.state.rec].arr.push('PF');
+ mscript.state.loops[mscript.state.rec].light.push('');
+ mscript.state_update('PF');
+ }
+ } else {
+ dist = mscript.state.proj - target;
+ for (var x = 0; x < dist; x++) {
+ mscript.state.loops[mscript.state.rec].arr.push('PB');
+ mscript.state.loops[mscript.state.rec].light.push('');
+ mscript.state_update('PB');
+ }
+ }
+ } else {
+ if (target > mscript.state.proj) {
+ dist = target - mscript.state.proj;
+ for (var x = 0; x < dist; x++) {
+ arr.push('PF');
+ light.push('');
+ mscript.state_update('PF');
+ }
+ } else {
+ dist = mscript.state.proj - target;
+ for (var x = 0; x < dist; x++) {
+ arr.push('PB');
+ light.push('');
+ mscript.state_update('PB');
+ }
+ }
+ }
+ } else if (lines[i].substring(0, 3) === 'SET') { //set that state
+ if (lines[i].substring(0, 7) === 'SET CAM') {
+ mscript.state.cam = parseInt(lines[i].split('SET CAM')[1]);
+ } else if (lines[i].substring(0, 8) === 'SET PROJ') {
+ mscript.state.proj = parseInt(lines[i].split('SET PROJ')[1]);
+ }
+ } else if (lines[i].substring(0, 1) === '#' || lines[i].substring(0, 2) === '//') {
+ //comments
+ //ignore while parsing
+ }
+ }
+ output.success = true;
+ output.arr = arr;
+ output.light = light;
+ output.cam = mscript.state.cam;
+ output.proj = mscript.state.proj;
+ if (typeof callback !== 'undefined') {
+ //should only be invoked by running mscript.tests()
+ callback(output);
+ } else {
+ return mscript.output(output);
+ }
+};
+/**
+ *
+ */
+mscript.last_loop = function last_loop () {
+ return mscript.state.loops[mscript.state.loops.length - 1];
+};
+/**
+ *
+ */
+mscript.parent_loop = function parent_loop () {
+ return mscript.state.loops[mscript.state.loops.length - 2];
+};
+/**
+ *
+ */
+mscript.state_update = function state_update (cmd, val) {
+ if (cmd === 'END') {
+ for (var i = 0; i < val; i++) {
+ if (mscript.state.rec === 0) {
+ mscript.state.cam += mscript.state.loops[mscript.state.rec].cam;
+ mscript.state.proj += mscript.state.loops[mscript.state.rec].proj;
+ } else if (mscript.state.rec >= 1) {
+ mscript.state.loops[mscript.state.rec - 1].cam += mscript.state.loops[mscript.state.rec].cam;
+ mscript.state.loops[mscript.state.rec - 1].proj += mscript.state.loops[mscript.state.rec].proj;
+ }
+ }
+ } else if (cmd === 'CF') {
+ if (mscript.state.loops.length < 1) {
+ mscript.state.cam++;
+ } else {
+ mscript.state.loops[mscript.state.rec].cam++;
+ }
+ } else if (cmd === 'CB') {
+ if (mscript.state.loops.length < 1) {
+ mscript.state.cam--;
+ } else {
+ mscript.state.loops[mscript.state.rec].cam--;
+ }
+ } else if (cmd === 'PF') {
+ if (mscript.state.loops.length < 1) {
+ mscript.state.proj++;
+ } else {
+ mscript.state.loops[mscript.state.rec].proj++;
+ }
+ } else if (cmd === 'PB') {
+ if (mscript.state.loops.length < 1) {
+ mscript.state.proj--;
+ } else {
+ mscript.state.loops[mscript.state.rec].proj--;
+ }
+ } else if (cmd === 'BF') {
+ if (mscript.state.loops.length < 1) {
+ mscript.state.cam++;
+ } else {
+ mscript.state.loops[mscript.state.rec].cam++;
+ }
+ } else if (cmd === 'BB') {
+ if (mscript.state.loops.length < 1) {
+ mscript.state.cam--;
+ } else {
+ mscript.state.loops[mscript.state.rec].cam++;
+ }
+ } else if (cmd === 'L ') {
+
+ }
+};
+/**
+ *
+ */
+mscript.str_to_arr = function str_to_arr (str, cmd) {
+ var cnt = str.split(cmd),
+ c = parseInt(cnt[1]),
+ arr = [];
+ if (cnt[1] === '') {
+ c = 1;
+ } else {
+ c = parseInt(cnt[1]);
+ }
+ for (var i = 0; i < c; i++) {
+ arr.push(cmd);
+ mscript.state_update(cmd);
+ }
+ return arr;
+};
+/**
+ *
+ */
+mscript.light_state = function light_state (str) {
+ //add parsers for other color spaces
+ var color = str.replace('L ', '').trim();
+ mscript.state.color = color;
+};
+/**
+ *
+ */
+mscript.light_to_arr = function light_to_arr (str, cmd) {
+ var cnt = str.split(cmd),
+ c = parseInt(cnt[1]),
+ arr = [];
+ if (cnt[1] === '') {
+ c = 1;
+ } else {
+ c = parseInt(cnt[1]);
+ }
+ for (var i = 0; i < c; i++) {
+ if (cmd === 'CF'
+ || cmd === 'CB') {
+ arr.push(mscript.state.color);
+ } else if (cmd === 'BF'
+ || cmd === 'BB') {
+ arr.push(mscript.black);
+ } else {
+ arr.push('');
+ }
+ }
+ return arr;
+};
+/**
+ *
+ */
+mscript.loop_count = function loop_count (str) {
+ return parseInt(str.split(' ')[1]);
+};
+mscript.fade_count = function fade_count (str) {
+ return parseInt(str.split(' ')[1]);
+}
+/**
+ *
+ */
+mscript.fail = function fail (reason) {
+ console.error(JSON.stringify({success: false, error: true, msg : reason}));
+ if (process) process.exit();
+};
+/**
+ *
+ */
+mscript.output = function output (data) {
+ var json = true; //default
+ if (mscript.arg('-j', '--json')) {
+ json = true;
+ }
+
+ if (mscript.arg('-t', '--text')) {
+ json = false;
+ }
+
+ if (json) {
+ console.log(JSON.stringify(data));
+ } else {
+ var ids = Object.keys(data);
+ for (var i = 0; i < ids.length; i++) {
+ console.log(ids[i] + ': ' + data[ids[i]]);
+ }
+ }
+};
+/**
+ *
+ */
+mscript.init = function init () {
+ if (mscript.arg('-t', '--tests')) {
+ return mscript.tests();
+ }
+
+ if (mscript.arg('-v', '--verbose')) {
+ console.time('mscript');
+ }
+
+ if (mscript.arg('-c', '--cam')) {
+ mscript.state.cam = parseInt(process.argv[mscript.arg_pos('-c', '--cam') + 1]);
+ }
+
+ if (mscript.arg('-p', '--proj')) {
+ mscript.state.proj = parseInt(process.argv[mscript.arg_pos('-p', '--proj') + 1]);
+ }
+
+ if (mscript.arg('-f', '--file')) {
+ input = process.argv[mscript.arg_pos('-f', '--file') + 1];
+ mscript.interpret(fs.readFileSync(input, 'utf8'));
+ } else {
+ mscript.interpret(input);
+ }
+
+ if (mscript.arg('-v', '--verbose')) {
+ console.timeEnd('mscript');
+ }
+};
+
+if (typeof document === 'undefined'
+ && typeof module !== 'undefined'
+ && !module.parent) {
+ //node script
+ fs = require('fs');
+ input = process.argv[2];
+ mscript.init();
+} else if (typeof module !== 'undefined' && module.parent) {
+ //module
+ fs = require('fs');
+ module.exports = mscript;
+} else {
+ //web
+}
+
+
+/*
+
+CAM # - go to camera frame #
+PROJ # - go to projector frame #
+
+SET CAM # - sets camera count to #
+SET PROJ # - sets projector count to #
+
+LOOP # - begin loop, can nest recursively, # times
+END LOOP - (or END) closes loop
+
+L #RGB - sets light to rgb value
+
+FADE
+
+CF - Camera forwards
+PF - Projector forwards
+BF - Black forwards
+CB - Camera backwards
+PB - Projector backwards
+BB - Black backwards
+
+*/
\ No newline at end of file
diff --git a/cli/lib/mscript/package.json b/cli/lib/mscript/package.json
new file mode 100644
index 0000000..5453ae8
--- /dev/null
+++ b/cli/lib/mscript/package.json
@@ -0,0 +1,11 @@
+{
+ "name": "mscript",
+ "version": "1.0.0",
+ "description": "",
+ "main": "index.js",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "author": "",
+ "license": "ISC"
+}
diff --git a/lib/log/index.js b/lib/log/index.js
new file mode 100644
index 0000000..08b6e65
--- /dev/null
+++ b/lib/log/index.js
@@ -0,0 +1,46 @@
+'use strict';
+const { createLogger, format, transports } = require('winston');
+const { combine, timestamp, label, printf } = format;
+const path = require('path');
+const fs = require('fs-extra');
+const os = require('os');
+const logTime = 'MM/DD/YY-HH:mm:ss';
+let transport;
+async function logFile() {
+ let exists;
+ let logPath = path.join(os.homedir(), `/.config/mcopy-cli/`);
+ if (process.platform === 'darwin') {
+ logPath = path.join(os.homedir(), `/Library/Logs/mcopy-cli/`);
+ }
+ else if (process.platform === 'win32') {
+ logPath = path.join(os.homedir(), `/AppData/Roaming/mcopy-cli/`);
+ }
+ exists = await fs.exists(logPath);
+ if (!exists) {
+ await fs.mkdir(logPath);
+ }
+ return path.join(logPath, 'mcopy-cli.log');
+}
+module.exports = async function (arg) {
+ if (arg.quiet) {
+ transport = {
+ info: function () { },
+ warn: function () { },
+ error: function () { }
+ };
+ }
+ else {
+ transport = createLogger({
+ transports: [
+ new (transports.Console)({
+ format: combine(format.colorize(), format.simple())
+ }),
+ new (transports.File)({
+ filename: await logFile()
+ })
+ ]
+ });
+ }
+ return transport;
+};
+//# sourceMappingURL=index.js.map
\ No newline at end of file
diff --git a/lib/log/index.js.map b/lib/log/index.js.map
new file mode 100644
index 0000000..c50dde5
--- /dev/null
+++ b/lib/log/index.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/log/index.ts"],"names":[],"mappings":"AAAA,YAAY,CAAA;AAEZ,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,SAAS,CAAC,CAAA;AAC/D,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,CAAA;AACpD,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;AAC5B,MAAM,EAAE,GAAG,OAAO,CAAC,UAAU,CAAC,CAAA;AAC9B,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;AAExB,MAAM,OAAO,GAAG,mBAAmB,CAAA;AACnC,IAAI,SAAe,CAAA;AAEnB,KAAK,UAAU,OAAO;IACrB,IAAI,MAAgB,CAAA;IACpB,IAAI,OAAO,GAAY,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,qBAAqB,CAAC,CAAA;IACrE,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ,EAAE;QAClC,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,0BAA0B,CAAC,CAAA;KAC7D;SAAM,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE;QACxC,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,6BAA6B,CAAC,CAAA;KAChE;IACD,MAAM,GAAG,MAAM,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;IACjC,IAAI,CAAC,MAAM,EAAE;QACZ,MAAM,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;KACvB;IACD,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,eAAe,CAAC,CAAA;AAC3C,CAAC;AAED,MAAM,CAAC,OAAO,GAAG,KAAK,WAAW,GAAS;IACzC,IAAI,GAAG,CAAC,KAAK,EAAE;QACd,SAAS,GAAG;YACX,IAAI,EAAG,cAAa,CAAC;YACrB,IAAI,EAAG,cAAa,CAAC;YACrB,KAAK,EAAG,cAAa,CAAC;SACtB,CAAA;KACD;SAAM;QACN,SAAS,GAAG,YAAY,CAAC;YACxB,UAAU,EAAE;gBACX,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;oBACxB,MAAM,EAAE,OAAO,CACd,MAAM,CAAC,QAAQ,EAAE,EACjB,MAAM,CAAC,MAAM,EAAE,CACf;iBACD,CAAC;gBACF,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;oBACrB,QAAQ,EAAE,MAAM,OAAO,EAAE;iBACzB,CAAC;aACF;SACD,CAAC,CAAA;KACF;IACD,OAAO,SAAS,CAAA;AACjB,CAAC,CAAA"}
\ No newline at end of file
diff --git a/scripts/build.sh b/scripts/build.sh
index 9e904a4..e10f611 100644
--- a/scripts/build.sh
+++ b/scripts/build.sh
@@ -4,4 +4,5 @@
#electron-build fails when local modules are in parent directory
#copy them into lib directory
-cp -r ./lib/ ./app/lib
\ No newline at end of file
+cp -r ./lib/ ./app/lib
+cp -r ./lib/ ./cli/lib
\ No newline at end of file
diff --git a/src/log/index.ts b/src/log/index.ts
new file mode 100644
index 0000000..04f4a8d
--- /dev/null
+++ b/src/log/index.ts
@@ -0,0 +1,50 @@
+'use strict'
+
+const { createLogger, format, transports } = require('winston')
+const { combine, timestamp, label, printf } = format
+const path = require('path')
+const fs = require('fs-extra')
+const os = require('os')
+
+const logTime = 'MM/DD/YY-HH:mm:ss'
+let transport : any
+
+async function logFile () {
+ let exists : boolean
+ let logPath : string = path.join(os.homedir(), `/.config/mcopy-cli/`)
+ if (process.platform === 'darwin') {
+ logPath = path.join(os.homedir(), `/Library/Logs/mcopy-cli/`)
+ } else if (process.platform === 'win32') {
+ logPath = path.join(os.homedir(), `/AppData/Roaming/mcopy-cli/`)
+ }
+ exists = await fs.exists(logPath)
+ if (!exists) {
+ await fs.mkdir(logPath)
+ }
+ return path.join(logPath, 'mcopy-cli.log')
+}
+
+module.exports = async function (arg : any) {
+ if (arg.quiet) {
+ transport = {
+ info : function () {},
+ warn : function () {},
+ error : function () {}
+ }
+ } else {
+ transport = createLogger({
+ transports: [
+ new (transports.Console)({
+ format: combine(
+ format.colorize(),
+ format.simple()
+ )
+ }),
+ new (transports.File)({
+ filename: await logFile()
+ })
+ ]
+ })
+ }
+ return transport
+}
\ No newline at end of file