<commit_before>'use strict';

pinpointApp.constant('scatterConfig', {
    get: {
        scatterData: '/getScatterData.pinpoint',
        lastScatterData: '/getLastScatterData.pinpoint'
    }
});

pinpointApp.directive('scatter',
    [ 'scatterConfig', '$rootScope', '$timeout', function (scatterConfig, $rootScope, $timeout) {
        return {
            template: '

',
            restrict: 'EA',
            replace: true,
            link: function (scope, element, attrs) {

                var oScatterChart = null;
                var selectdTracesBox = {};

                var showScatter = function (applicationName, from, to, period, filter, w, h) {
                    if (oScatterChart) {
//							oScatterChart.clear();
                    }

                    selectdTracesBox = {};
//						var fullscreenButton = $("#scatterChartContainer I.icon-fullscreen");
//						fullscreenButton.data("applicationName", applicationName);
//						fullscreenButton.data("from", from);
//						fullscreenButton.data("to", to);
//						fullscreenButton.data("period", period);
//						fullscreenButton.data("usePeriod", usePeriod);
//						fullscreenButton.data("filter", filter);

//						var downloadButton = $("#scatterChartContainer A");

//						var imageFileName = applicationName +
//								"_" +
//								new Date(from).toString("yyyyMMdd_HHmm") +
//								"~" +
//								new Date(to).toString("yyyyMMdd_HHmm") +
//								"_response_scatter.png";
//
//						downloadButton.attr("download", imageFileName);
//						downloadButton.unbind("click");
//						downloadButton.bind("click", function() {
//							var sImageUrl = oScatterChart.getChartAsPNG();
//							$(this).attr('href', sImageUrl);
//						});

//						$("#scatterChartContainer SPAN").unbind("click");
//						$("#scatterChartContainer SPAN").bind("click", function() {
//							showRequests(applicationName, from, to, period, usePeriod, filter);
//						});

//						$("#scatterChartContainer").show();

                    var bDrawOnceAll = false,
                        nInterval = 2000,
                        fetchLimit = 2000;

                    var htDataSource = {
                        sUrl: function (nFetchIndex) {
//								if (!usePeriod) {
//									return scatterConfig.get.scatterData;
//								}

//								if (nFetchIndex === 0) {
//									return scatterConfig.get.lastScatterData;
//								} else {
                            return scatterConfig.get.scatterData;
//								}
                        },
                        htParam: function (nFetchIndex, htLastFetchParam, htLastFetchedData) {
                            // calculate parameter
                            var htData;
//								console.log("htParam", nFetchIndex, htLastFetchParam, htLastFetchedData);

//								if (nFetchIndex === 0 && !usePeriod) {
                            if (nFetchIndex === 0) {
                                return {
                                    'application': applicationName,
                                    'from': from,
                                    'to': to,
                                    'limit': fetchLimit,
                                    'filter': filter
                                };
                            }

                            // period만큼 먼저 조회해본다.
                            if (nFetchIndex === 0 /*|| typeof(htLastFetchParam) === 'undefined' || typeof(htLastFetchedData) === 'undefined'*/) {
                                htData = {
                                    'application': applicationName,
                                    'period': period,
                                    'limit': fetchLimit,
                                    'filter': filter
                                };
                            } else {
                                if (bDrawOnceAll || htLastFetchedData.scatter.length == 0) {
                                    htData = {
                                        'application': applicationName,
                                        'from': htLastFetchParam.to + 1,
                                        'to': htLastFetchParam.to + 2000,
                                        'limit': fetchLimit,
                                        'filter': filter
                                    };
                                } else {
                                    htData = {
                                        'application': applicationName,
                                        // array[0] 이 최근 값, array[len]이 오래된 이다.
                                        'from': from,
                                        'to': htLastFetchedData.scatter[htLastFetchedData.scatter.length - 1].x - 1,
                                        'limit': fetchLimit,
                                        'filter': filter
                                    };
                                }
                            }

                            return htData;
                        },
                        nFetch: function (htLastFetchParam, htLastFetchedData) {
                            // -1 : stop, n = 0 : immediately, n > 0 : interval
                            var useInterval = false;

//								console.log("nFetch", htLastFetchedData);

                            if (useInterval && htLastFetchedData.scatter.length === 0) {
//									console.log("2A");
                                bDrawOnceAll = true;
                                return nInterval;
                            }

                            if (htLastFetchedData.scatter.length !== 0) {
                                // array[0] 이 최근 값, array[len]이 오래된 이다.
                                if (htLastFetchedData.scatter[0].x > from) {
                                    // TO THE NEXT
                                    return 0;
                                } else {
                                    // STOP
                                    return -1;
                                }
                            }

                            if (htLastFetchedData.scatter[htLastFetchedData.scatter.length - 1] &&
                                htLastFetchedData.scatter[htLastFetchedData.scatter.length - 1].x < date.getTime()) {
                                if (useInterval) {
                                    bDrawOnceAll = true;
                                    return nInterval;
                                }
                                // TO THE NEXT
                                return 0;
                            }

                            // STOP
                            return -1;
                        },
                        htOption: {
                            dataType: 'jsonp',
                            jsonp: '_callback'
                        }
                    };
                    oScatterChart.drawWithDataSource(htDataSource);
                };
                var makeScatter = function (title, start, end, targetId, period, w, h) {
                    if (!Modernizr.canvas) {
                        alert("Can't draw scatter. Not supported browser.");
                    }

                    var yAxisMAX = 10000;
//                    var date = new Date();

                    var options = {
                        sContainerId: targetId,
                        nWidth: w ? w : 400,
                        nHeight: h ? h : 250,
                        // nXMin: date.getTime() - 86400000, nXMax: date.getTime(),
                        nXMin: start, nXMax: end,
                        nYMin: 0, nYMax: yAxisMAX,
                        nZMin: 0, nZMax: 5,
                        nBubbleSize: 3,
                        sXLabel: '',
                        sYLabel: '(ms)',
                        sTitle: title,
                        htTypeAndColor: {
                            // type name : color
                            'Success': '#2ca02c',
                            // 'Warning' : '#f5d025',
                            'Failed': '#d62728'
                        },
                        fOnSelect: function (htPosition, htXY) {
                            var traces = this.getDataByXY(htXY.nXFrom, htXY.nXTo, htXY.nYFrom, htXY.nYTo);

                            if (traces.length === 0) {
                                return;
                            }

                            if (traces.length === 1) {
//									openTrace(traces[0].traceId, traces[0].x);
                                return;
                            }

                            var token = Math.random() * 10000 + 1;
                            selectdTracesBox[token] = traces;

                            var popupwindow = window.open("/selectedScatter.pinpoint", token);
                        }
                    };

                    $timeout(function () {
                        if (oScatterChart !== null) {
                            oScatterChart.destroy();
                        }
                        oScatterChart = new BigScatterChart(options);
                        showScatter(scope.navbar.applicationName, start, end, period);
                    }, 100);

                };

                scope.$on('navbar.applicationChanged', function (event, navbar) {
                    scope.navbar = navbar;
                    makeScatter(navbar.applicationName, navbar.queryStartTime, navbar.queryEndTime, 'scatterchart', navbar.queryPeriod);
                });
                scope.$on('servermap.passingTransactionResponseToScatterChart', function (event, node) {
                    scope.node = node;
                    makeScatter(node.applicationName || node.text, scope.navbar.queryStartTime, scope.navbar.queryEndTime, 'scatterchart', scope.navbar.queryPeriod);
                });

            }
        };
    } ]);
<commit_msg>[유치수] [NOBTS] 스캐터 차트 점 선택하면 목록 보이지 않는 현상 수정.(임시)<commit_after>'use strict';

pinpointApp.constant('scatterConfig', {
    get: {
        scatterData: '/getScatterData.pinpoint',
        lastScatterData: '/getLastScatterData.pinpoint'
    }
});

// FIXME child window에서 접근할 수 있도록 global변수로 일단 빼둠. 나중에 리팩토링할 것.
var selectdTracesBox = {};

pinpointApp.directive('scatter',
    [ 'scatterConfig', '$rootScope', '$timeout', function (scatterConfig, $rootScope, $timeout) {
        return {
            template: '

',
            restrict: 'EA',
            replace: true,
            link: function (scope, element, attrs) {

                var oScatterChart = null;

                var showScatter = function (applicationName, from, to, period, filter, w, h) {
                    if (oScatterChart) {
//							oScatterChart.clear();
                    }

                    selectdTracesBox = {};
//						var fullscreenButton = $("#scatterChartContainer I.icon-fullscreen");
//						fullscreenButton.data("applicationName", applicationName);
//						fullscreenButton.data("from", from);
//						fullscreenButton.data("to", to);
//						fullscreenButton.data("period", period);
//						fullscreenButton.data("usePeriod", usePeriod);
//						fullscreenButton.data("filter", filter);

//						var downloadButton = $("#scatterChartContainer A");

//						var imageFileName = applicationName +
//								"_" +
//								new Date(from).toString("yyyyMMdd_HHmm") +
//								"~" +
//								new Date(to).toString("yyyyMMdd_HHmm") +
//								"_response_scatter.png";
//
//						downloadButton.attr("download", imageFileName);
//						downloadButton.unbind("click");
//						downloadButton.bind("click", function() {
//							var sImageUrl = oScatterChart.getChartAsPNG();
//							$(this).attr('href', sImageUrl);
//						});

//						$("#scatterChartContainer SPAN").unbind("click");
//						$("#scatterChartContainer SPAN").bind("click", function() {
//							showRequests(applicationName, from, to, period, usePeriod, filter);
//						});

//						$("#scatterChartContainer").show();

                    var bDrawOnceAll = false,
                        nInterval = 2000,
                        fetchLimit = 2000;

                    var htDataSource = {
                        sUrl: function (nFetchIndex) {
//								if (!usePeriod) {
//									return scatterConfig.get.scatterData;
//								}

//								if (nFetchIndex === 0) {
//									return scatterConfig.get.lastScatterData;
//								} else {
                            return scatterConfig.get.scatterData;
//								}
                        },
                        htParam: function (nFetchIndex, htLastFetchParam, htLastFetchedData) {
                            // calculate parameter
                            var htData;
//								console.log("htParam", nFetchIndex, htLastFetchParam, htLastFetchedData);

//								if (nFetchIndex === 0 && !usePeriod) {
                            if (nFetchIndex === 0) {
                                return {
                                    'application': applicationName,
                                    'from': from,
                                    'to': to,
                                    'limit': fetchLimit,
                                    'filter': filter
                                };
                            }

                            // period만큼 먼저 조회해본다.
                            if (nFetchIndex === 0 /*|| typeof(htLastFetchParam) === 'undefined' || typeof(htLastFetchedData) === 'undefined'*/) {
                                htData = {
                                    'application': applicationName,
                                    'period': period,
                                    'limit': fetchLimit,
                                    'filter': filter
                                };
                            } else {
                                if (bDrawOnceAll || htLastFetchedData.scatter.length == 0) {
                                    htData = {
                                        'application': applicationName,
                                        'from': htLastFetchParam.to + 1,
                                        'to': htLastFetchParam.to + 2000,
                                        'limit': fetchLimit,
                                        'filter': filter
                                    };
                                } else {
                                    htData = {
                                        'application': applicationName,
                                        // array[0] 이 최근 값, array[len]이 오래된 이다.
                                        'from': from,
                                        'to': htLastFetchedData.scatter[htLastFetchedData.scatter.length - 1].x - 1,
                                        'limit': fetchLimit,
                                        'filter': filter
                                    };
                                }
                            }

                            return htData;
                        },
                        nFetch: function (htLastFetchParam, htLastFetchedData) {
                            // -1 : stop, n = 0 : immediately, n > 0 : interval
                            var useInterval = false;

//								console.log("nFetch", htLastFetchedData);

                            if (useInterval && htLastFetchedData.scatter.length === 0) {
//									console.log("2A");
                                bDrawOnceAll = true;
                                return nInterval;
                            }

                            if (htLastFetchedData.scatter.length !== 0) {
                                // array[0] 이 최근 값, array[len]이 오래된 이다.
                                if (htLastFetchedData.scatter[0].x > from) {
                                    // TO THE NEXT
                                    return 0;
                                } else {
                                    // STOP
                                    return -1;
                                }
                            }

                            if (htLastFetchedData.scatter[htLastFetchedData.scatter.length - 1] &&
                                htLastFetchedData.scatter[htLastFetchedData.scatter.length - 1].x < date.getTime()) {
                                if (useInterval) {
                                    bDrawOnceAll = true;
                                    return nInterval;
                                }
                                // TO THE NEXT
                                return 0;
                            }

                            // STOP
                            return -1;
                        },
                        htOption: {
                            dataType: 'jsonp',
                            jsonp: '_callback'
                        }
                    };
                    oScatterChart.drawWithDataSource(htDataSource);
                };
                var makeScatter = function (title, start, end, targetId, period, w, h) {
                    if (!Modernizr.canvas) {
                        alert("Can't draw scatter. Not supported browser.");
                    }

                    var yAxisMAX = 10000;
//                    var date = new Date();

                    var options = {
                        sContainerId: targetId,
                        nWidth: w ? w : 400,
                        nHeight: h ? h : 250,
                        // nXMin: date.getTime() - 86400000, nXMax: date.getTime(),
                        nXMin: start, nXMax: end,
                        nYMin: 0, nYMax: yAxisMAX,
                        nZMin: 0, nZMax: 5,
                        nBubbleSize: 3,
                        sXLabel: '',
                        sYLabel: '(ms)',
                        sTitle: title,
                        htTypeAndColor: {
                            // type name : color
                            'Success': '#2ca02c',
                            // 'Warning' : '#f5d025',
                            'Failed': '#d62728'
                        },
                        fOnSelect: function (htPosition, htXY) {
                            var traces = this.getDataByXY(htXY.nXFrom, htXY.nXTo, htXY.nYFrom, htXY.nYTo);

                            if (traces.length === 0) {
                                return;
                            }

                            if (traces.length === 1) {
//									openTrace(traces[0].traceId, traces[0].x);
                                return;
                            }

                            var token = Math.random() * 10000 + 1;
                            selectdTracesBox[token] = traces;

                            var popupwindow = window.open("/selectedScatter.pinpoint", token);
                        }
                    };

                    $timeout(function () {
                        if (oScatterChart !== null) {
                            oScatterChart.destroy();
                        }
                        oScatterChart = new BigScatterChart(options);
                        showScatter(scope.navbar.applicationName, start, end, period);
                    }, 100);

                };

                scope.$on('navbar.applicationChanged', function (event, navbar) {
                    scope.navbar = navbar;
                    makeScatter(navbar.applicationName, navbar.queryStartTime, navbar.queryEndTime, 'scatterchart', navbar.queryPeriod);
                });
                scope.$on('servermap.passingTransactionResponseToScatterChart', function (event, node) {
                    scope.node = node;
                    makeScatter(node.applicationName || node.text, scope.navbar.queryStartTime, scope.navbar.queryEndTime, 'scatterchart', scope.navbar.queryPeriod);
                });

            }
        };
    } ]);
<|endoftext|>


<commit_before>import { deserialise } from './deserialise'

describe('deserialise', () => {
  it('Should deserialise a resource without included relationships', () => {
    expect(deserialise({
      data: {
        id: '9',
        type: 'roles',
        attributes: {
          name: 'mod'
        }
      }
    })).resolves.toEqual({
      data: {
        id: '9',
        type: 'roles',
        name: 'mod'
      }
    })
  })

  it('Should deserialise a collection without attributes and included relationships', () => {
    expect(deserialise({
      data: [
        {
          id: '1',
          type: 'userRoles'
        },
        {
          id: '2',
          type: 'userRoles'
        }
      ]
    })).resolves.toEqual({
      data: [
        {
          id: '1',
          type: 'userRoles'
        },
        {
          id: '2',
          type: 'userRoles'
        }
      ]
    })
  })

  it('Should deserialise a collection of resources with included relationships', async () => {
    expect.assertions(1)
    await expect(deserialise({
      data: [{
        id: '1',
        type: 'users',
        attributes: {
          name: 'Josh'
        },
        relationships: {
          waifu: {
            data: {
              id: '1',
              type: 'characters'
            }
          }
        }
      }],
      included: [{
        id: '1',
        type: 'characters',
        attributes: {
          name: 'Genkai'
        }
      }]
    })).resolves.toEqual({
      data: [{
        name: 'Josh',
        waifu: {
          name: 'Genkai',
          id: '1',
          type: 'characters'
        },
        id: '1',
        type: 'users'
      }]
    })
  })

  it('Should deserialise a single resource with included relationships', async () => {
    expect.assertions(1)
    await expect(deserialise({
      data: {
        id: '1',
        type: 'users',
        attributes: {
          name: 'Josh'
        },
        relationships: {
          waifu: {
            data: {
              id: '1',
              type: 'characters'
            }
          }
        }
      },
      included: [{
        id: '1',
        type: 'characters',
        attributes: {
          name: 'Genkai'
        }
      }]
    })).resolves.toEqual({
      data: {
        name: 'Josh',
        waifu: {
          name: 'Genkai',
          id: '1',
          type: 'characters'
        },
        id: '1',
        type: 'users'
      }
    })
  })
})
<commit_msg>test: add empty data array spec<commit_after>import { deserialise } from './deserialise'

describe('deserialise', () => {
  it('Should deserialise a resource without included relationships', () => {
    expect(deserialise({
      data: {
        id: '9',
        type: 'roles',
        attributes: {
          name: 'mod'
        }
      }
    })).resolves.toEqual({
      data: {
        id: '9',
        type: 'roles',
        name: 'mod'
      }
    })
  })

  it('Should deserialise a collection without attributes and included relationships', () => {
    expect(deserialise({
      data: [
        {
          id: '1',
          type: 'userRoles'
        },
        {
          id: '2',
          type: 'userRoles'
        }
      ]
    })).resolves.toEqual({
      data: [
        {
          id: '1',
          type: 'userRoles'
        },
        {
          id: '2',
          type: 'userRoles'
        }
      ]
    })
  })

  it('Should deserialise a collection of resources with included relationships', async () => {
    expect.assertions(1)
    await expect(deserialise({
      data: [{
        id: '1',
        type: 'users',
        attributes: {
          name: 'Josh'
        },
        relationships: {
          waifu: {
            data: {
              id: '1',
              type: 'characters'
            }
          }
        }
      }],
      included: [{
        id: '1',
        type: 'characters',
        attributes: {
          name: 'Genkai'
        }
      }]
    })).resolves.toEqual({
      data: [{
        name: 'Josh',
        waifu: {
          name: 'Genkai',
          id: '1',
          type: 'characters'
        },
        id: '1',
        type: 'users'
      }]
    })
  })

  it('Should deserialise a single resource with included relationships', async () => {
    expect.assertions(1)
    await expect(deserialise({
      data: {
        id: '1',
        type: 'users',
        attributes: {
          name: 'Josh'
        },
        relationships: {
          waifu: {
            data: {
              id: '1',
              type: 'characters'
            }
          }
        }
      },
      included: [{
        id: '1',
        type: 'characters',
        attributes: {
          name: 'Genkai'
        }
      }]
    })).resolves.toEqual({
      data: {
        name: 'Josh',
        waifu: {
          name: 'Genkai',
          id: '1',
          type: 'characters'
        },
        id: '1',
        type: 'users'
      }
    })
  })

  it('Should deserialise with empty data arrays', async () => {
    expect.assertions(1)
    await expect(deserialise({
      data: {
        id: '1',
        type: 'users',
        attributes: {
          data: []
        }
      }
    })).resolves.toEqual({
      data: {
        data: [],
        id: '1',
        type: 'users'
      }
    })
  })
})
<|endoftext|>


<commit_before>var fs = require('fs')
var config = require('./config')
var MARKER = '!FABMO!'

var macros = {}

var _createGCodeHeader = function(options) {
	name = options.name || "Untitled Macro"
	description = options.description || ""
	enabled = options.enabled || true
	return "(" + MARKER + "name:" + name + ")\n" +
	       "(" + MARKER + "description:" + description + ")\n" +
	       "(" + MARKER + "enabled:" + enabled + ")\n"
}

var _createOpenSBPHeader = function(options) {
	name = options.name || "Untitled Macro"
	description = options.description || ""
	enabled = options.enabled || true
	return "'" + MARKER + "name:" + name + "\n" +
	       "'" + MARKER + "description:" + description + "\n"
	       "'" + MARKER + "enabled:" + enabled + "\n"

}

var _deleteMacroFile = function(index, callback) {
	var macro_path = config.getDataDir('macros');
	var opensbp = path.join(macro_path, 'macro_' + index + '.sbp')
	var gcode = path.join(macro_path, 'macro_' + index + '.nc')
	fs.unlink(opensbp, function(err) {
		fs.unlink(gcode, function(err) {
			callback(null);
		});
	});
}

var _createMacroFilename = function(id, type) {
	var macro_path = config.getDataDir('macros');
	switch(type) {
		case 'nc':
			return path.join(macro_path, 'macro_' + id + '.nc');
			break;

		case 'sbp':
			return path.join(macro_path, 'macro_' + id + '.sbp');
			break;

		default:
			throw new Error('Invalid macro type: ' + type)
			break;
	}
}

var _createMacroDefaultContent = function(macro) {
	switch(macro.type) {
		case 'nc':
			//return 	'( ' + macro.name + ' )\n( ' + macro.description + ' )\n\n';
			return ''
            break;

		case 'sbp':
			//return 	"' " + macro.name + "\n' " + macro.description + "\n\n";
			return ''
            break;

		default:
			throw new Error('Invalid macro type: ' + type)
			break;
	}
}

var _parseMacroFile = function(filename, callback) {
	var re = /[\(']!FABMO!(\w+):([^\)]*)\)?/
	var obj = {}
	var ok = false;
	fs.readFile(filename, function(err, data) {
		if(err) {
			log.error(err)
		} else {
			lines = data.toString().split('\n');
			i = 0;
			while(i < lines.length) {
				var line = lines[i];
				var groups = line.match(re);
				if(groups) {
					ok = true;
					var key = groups[1];
					var value = groups[2];
					obj[key] = value;
				} else {
					break;
				}
				i+=1;
			}
			if(ok) {
				obj.filename = filename;
				obj.content = lines.slice(i,lines.length).join('\n');
				callback(null, obj);
			} else {
				callback(null, undefined)
			}
		}
	});
}

var update = function(id, macro, callback) {
	var old_macro = get(id);
	if(old_macro) {
		function savemacro(id, callback) {
			old_macro.name = macro.name || old_macro.name;
			old_macro.description = macro.description || old_macro.description;
			old_macro.content = macro.content || old_macro.content;
			old_macro.index = macro.index || old_macro.index;
			old_macro.type = macro.type || old_macro.type;
			old_macro.filename = _createMacroFilename(old_macro.index, old_macro.type);
			save(id, callback);
		}

		if(macro.index) {
			var new_index = parseInt(macro.index);
			if(new_index != old_macro.index) {
				macros[new_index] = old_macro;
				delete macros[old_macro.index];
				_deleteMacroFile(old_macro.index, function(err) {
					savemacro(new_index, callback);
				});
			} else {
				savemacro(id, callback);
			}
		} else {
			savemacro(id, callback);
		}

	} else {
		new_macro = {
			name : macro.name || 'Untitled Macro',
			description : macro.description || 'Macro Description',
			type : macro.type || 'sbp',
			enabled : macro.enabled || true, // TODO fix this
			index : id
		}
		new_macro.filename = _createMacroFilename(id, new_macro.type);
		new_macro.content = macro.content || _createMacroDefaultContent(new_macro);
		macros[id] = new_macro;
		save(id, callback);
	}
}

var save = function(id, callback) {
	macro = get(id);
	if(macro) {
		var macro_path = config.getDataDir('macros');
		var file_path = path.join(macro_path, 'macro_' + macro.index + '.' + macro.type);
		switch(macro.type) {
			case 'nc':
				var header = _createGCodeHeader(macro);
				break;
			case 'sbp':
				var header = _createOpenSBPHeader(macro);
				break;
			default:
				setImmediate(callback, new Error('Invalid macro type: ' + macro.type));
				break;
		}
		fs.writeFile(file_path, header + macro.content, function(err, data) {
			if(err) {
				callback(err);
			} else {
				callback(null, macro);
			}
		});
	} else {
		callback(new Error("No such macro " + id));
	}
}

var load = function(callback) {
	var macro_path = config.getDataDir('macros');
	var re = /macro_([0-9]+)\.(nc|sbp)/
	macros = {};
	fs.readdir(macro_path, function(err, files) {
		if(err) {
			callback(err);
		} else {
			for(i=0; i<files.length; i++) {
				files[i] = path.join(macro_path, files[i]);
			}
			async.map(files, _parseMacroFile, function(err, results) {
				results.forEach(function(info) {
					if(info) {
						groups = info.filename.match(re);
						idx = parseInt(groups[1]);
						ext = groups[2];
						info.index = idx;
						info.type = ext;
						macros[idx] = info;
					}
				});
				callback(null);
			});
		}
	})
}

var list = function() {
	retval = [];
	for(key in macros) {
		retval.push(getInfo(key));
	}
	return retval;
}

var getInfo = function(idx) {
	var macro = get(idx);
	if(macro) {
		return 	{
			'name' : macro.name,
			'description' : macro.description,
			'enabled' : macro.enabled,
			'type' : macro.type,
			'index' : parseInt(macro.index)
		}
	} else {
		return null;
	}
}

var get = function(idx) {
	return macros[idx] || null;
}

var run = function(idx) {
	var machine = require('./machine').machine;

	info = macros[idx];
	if(info) {
			machine.runFile(info.filename);
	} else {
		throw new Error("No such macro.")
	}
}

var del = function(idx, callback) {
	info = macros[idx];
	if(info) {
		_deleteMacroFile(idx, function(err) {
			if(err) {
				callback(err);
			} else {
				delete macros[idx];
				callback(null);
			}
		});
	}
}

exports.load = load;
exports.list = list;
exports.get = get;
exports.del = del;
exports.run = run;
exports.getInfo = getInfo;
exports.update = update;
exports.save = save;
<commit_msg>Fix hangup on bad macro load.<commit_after>var fs = require('fs')
var config = require('./config')
var MARKER = '!FABMO!'

var macros = {}

var _createGCodeHeader = function(options) {
	name = options.name || "Untitled Macro"
	description = options.description || ""
	enabled = options.enabled || true
	return "(" + MARKER + "name:" + name + ")\n" +
	       "(" + MARKER + "description:" + description + ")\n" +
	       "(" + MARKER + "enabled:" + enabled + ")\n"
}

var _createOpenSBPHeader = function(options) {
	name = options.name || "Untitled Macro"
	description = options.description || ""
	enabled = options.enabled || true
	return "'" + MARKER + "name:" + name + "\n" +
	       "'" + MARKER + "description:" + description + "\n"
	       "'" + MARKER + "enabled:" + enabled + "\n"

}

var _deleteMacroFile = function(index, callback) {
	var macro_path = config.getDataDir('macros');
	var opensbp = path.join(macro_path, 'macro_' + index + '.sbp')
	var gcode = path.join(macro_path, 'macro_' + index + '.nc')
	fs.unlink(opensbp, function(err) {
		fs.unlink(gcode, function(err) {
			callback(null);
		});
	});
}

var _createMacroFilename = function(id, type) {
	var macro_path = config.getDataDir('macros');
	switch(type) {
		case 'nc':
			return path.join(macro_path, 'macro_' + id + '.nc');
			break;

		case 'sbp':
			return path.join(macro_path, 'macro_' + id + '.sbp');
			break;

		default:
			throw new Error('Invalid macro type: ' + type)
			break;
	}
}

var _createMacroDefaultContent = function(macro) {
	switch(macro.type) {
		case 'nc':
			//return 	'( ' + macro.name + ' )\n( ' + macro.description + ' )\n\n';
			return ''
            break;

		case 'sbp':
			//return 	"' " + macro.name + "\n' " + macro.description + "\n\n";
			return ''
            break;

		default:
			throw new Error('Invalid macro type: ' + type)
			break;
	}
}

var _parseMacroFile = function(filename, callback) {
	var re = /[\(']!FABMO!(\w+):([^\)]*)\)?/
	var obj = {}
	var ok = false;
	fs.readFile(filename, function(err, data) {
		if(err) {
			log.error(err)
		} else {
			lines = data.toString().split('\n');
			i = 0;
			while(i < lines.length) {
				var line = lines[i];
				var groups = line.match(re);
				if(groups) {
					ok = true;
					var key = groups[1];
					var value = groups[2];
					obj[key] = value;
				} else {
					break;
				}
				i+=1;
			}
			if(ok) {
				obj.filename = filename;
				obj.content = lines.slice(i,lines.length).join('\n');
				callback(null, obj);
			} else {
				callback(null, undefined)
			}
		}
	});
}

var update = function(id, macro, callback) {
	var old_macro = get(id);
	if(old_macro) {
		function savemacro(id, callback) {
			old_macro.name = macro.name || old_macro.name;
			old_macro.description = macro.description || old_macro.description;
			old_macro.content = macro.content || old_macro.content;
			old_macro.index = macro.index || old_macro.index;
			old_macro.type = macro.type || old_macro.type;
			old_macro.filename = _createMacroFilename(old_macro.index, old_macro.type);
			save(id, callback);
		}

		if(macro.index) {
			var new_index = parseInt(macro.index);
			if(new_index != old_macro.index) {
				macros[new_index] = old_macro;
				delete macros[old_macro.index];
				_deleteMacroFile(old_macro.index, function(err) {
					savemacro(new_index, callback);
				});
			} else {
				savemacro(id, callback);
			}
		} else {
			savemacro(id, callback);
		}

	} else {
		new_macro = {
			name : macro.name || 'Untitled Macro',
			description : macro.description || 'Macro Description',
			type : macro.type || 'sbp',
			enabled : macro.enabled || true, // TODO fix this
			index : id
		}
		new_macro.filename = _createMacroFilename(id, new_macro.type);
		new_macro.content = macro.content || _createMacroDefaultContent(new_macro);
		macros[id] = new_macro;
		save(id, callback);
	}
}

var save = function(id, callback) {
	macro = get(id);
	if(macro) {
		var macro_path = config.getDataDir('macros');
		var file_path = path.join(macro_path, 'macro_' + macro.index + '.' + macro.type);
		switch(macro.type) {
			case 'nc':
				var header = _createGCodeHeader(macro);
				break;
			case 'sbp':
				var header = _createOpenSBPHeader(macro);
				break;
			default:
				setImmediate(callback, new Error('Invalid macro type: ' + macro.type));
				break;
		}
		fs.writeFile(file_path, header + macro.content, function(err, data) {
			if(err) {
				callback(err);
			} else {
				callback(null, macro);
			}
		});
	} else {
		callback(new Error("No such macro " + id));
	}
}

var load = function(callback) {
	var macro_path = config.getDataDir('macros');
	var re = /macro_([0-9]+)\.(nc|sbp)/
	macros = {};
	fs.readdir(macro_path, function(err, files) {
		if(err) {
			callback(err);
		} else {
			for(i=0; i<files.length; i++) {
				files[i] = path.join(macro_path, files[i]);
			}
			async.map(files, _parseMacroFile, function(err, results) {
				results.forEach(function(info) {
					if(info) {
						groups = info.filename.match(re);
						if(groups) {
							idx = parseInt(groups[1]);
							ext = groups[2];
							info.index = idx;
							info.type = ext;
							macros[idx] = info;
						}
					}
				});
				callback(null);
			});
		}
	})
}

var list = function() {
	retval = [];
	for(key in macros) {
		retval.push(getInfo(key));
	}
	return retval;
}

var getInfo = function(idx) {
	var macro = get(idx);
	if(macro) {
		return 	{
			'name' : macro.name,
			'description' : macro.description,
			'enabled' : macro.enabled,
			'type' : macro.type,
			'index' : parseInt(macro.index)
		}
	} else {
		return null;
	}
}

var get = function(idx) {
	return macros[idx] || null;
}

var run = function(idx) {
	var machine = require('./machine').machine;

	info = macros[idx];
	if(info) {
			machine.runFile(info.filename);
	} else {
		throw new Error("No such macro.")
	}
}

var del = function(idx, callback) {
	info = macros[idx];
	if(info) {
		_deleteMacroFile(idx, function(err) {
			if(err) {
				callback(err);
			} else {
				delete macros[idx];
				callback(null);
			}
		});
	}
}

exports.load = load;
exports.list = list;
exports.get = get;
exports.del = del;
exports.run = run;
exports.getInfo = getInfo;
exports.update = update;
exports.save = save;
<|endoftext|>


<commit_before>

var http = require('http'),
    formaline = require('../lib/formaline').formaline,
    connect = require('connect'),
    server;

var getHtmlForm = function(req, res,next) {
  if (req.url === '/test/') {
    log( ' -> req url :', req.url );
    res.writeHead(200, {'content-type': 'text/html'});
    res.end('\
             Multiple File Upload:

\
             <form action="/test/upload" enctype="multipart/form-data" method="post">\
             <input type="text" name="demotitle1">
\
             <input type="file" name="multiplefield1" multiple="multiple">
\
             <input type="text" name="demotitle2">
\
             <input type="file" name="multiplefield2" multiple="multiple">
\
             <input type="text" name="demotitle3">
\
             <input type="file" name="multiplefield3" multiple="multiple">
\
             <input type="submit" value="Upload">\
             </form>
\
             Simple Post:

\
             <form action="/test/post" method="post">\
             <input type="text" name="simplefield1">
\
             <input type="text" name="simplefield2">
\
             <input type="text" name="simplefield3">
\
             <input type="submit" value="Submit">\
             </form>
\
             Iframe Multiple File Upload:

\
             <form action="/test/upload" method="post" enctype="multipart/form-data" target="iframe">\
             <input type="file" name="file" multiple  src="" frameborder="1" />\
             <input type="submit" />\
             </form>\
             \
             </form>\
             '
    );
  } else {
    next();
  }
};
var log = console.log,
    dir =  '/tmp/';

var handleFormRequest = function( req, res, next ){
    var receivedFiles = {},
        removedFiles = {},
        receivedFields = {},
        form = null,
        config = {

            //default is true -->
        holdFilesExtensions : true,

            //default is /tmp/ -->
        uploadRootDir: dir,

            //default is false
            //return sha1 digests for files received?  -->
        sha1sum: true,

            // default is false, or integer chunk factor,
            // every n chunk emit event 1+(0*n) 1+(1*n),1+(2*n),1+(3*n),
            // minimum factor value is 2 -->
        emitDataProgress: false,//false,true,3,10,100

            // max bytes allowed, this is the max bytes written to disk before stop to write
            // this is also true for serialzed fields not only for files upload  -->
        uploadThreshold: 1024*1024*1024,//bytes ex.: 1024*1024*1024, 512

            //default false, bypass headers value, continue to write to disk
            //until uploadThreshold bytes are written.
            //if true -> stop receiving data, when headers content length exceeds uploadThreshold
        checkContentLength: false,

            //remove file not completed due to uploadThreshold,
            //if true formaline emit fileremoved event,
            //otherwise return a path array of incomplete files
        removeIncompleteFiles : true,

            //enable various logging levels
            //it is possible to switch on/off one or more levels at the same time
            //debug: 'off' turn off logging
        logging: 'debug:on,1:on,2:on,3:on',

            //listeners
        listeners: {
                'warning': function( msg ){
                    log('\n warning  -->',msg);
                },
                'headersexception': function( isUpload, errmsg, res, next){
                    log('\n headersexception  -->',errmsg);
                    next();
                },
                'exception': function( isUpload, errmsg, res, next){
                    log('\n exception --> ',errmsg);
                    next();
                },
                'pathexception': function( path, errmsg, res, next){//there is a file upload
                    log('\n pathexception -->',path,'msg:',errmsg+'\n');
                    next();
                },
                'field': function( fname, fvalue ){
                    receivedFields[fname] = fvalue;
                    log('\n field--> ',fname,fvalue);
                },
                'filereceived': function( sha1filename, origfilename, filedir, filetype, filesize, filefield, filesha1sum ) {
                    receivedFiles[sha1filename] = { path: filedir, origName: origfilename, type: filetype, size: filesize, field: filefield, sha1sum: filesha1sum  };
                    log('\n filereceived -->  sha1name: '+sha1filename+', original name: '+origfilename+', path: '+filedir+', type: '+filetype+', bytes: '+filesize+', field: '+filefield+'\n');
                },
                'fileremoved': function( sha1filename, origfilename, filedir, filetype, filesize, filefield ) {
                    log('\n fileremoved -->  sha1name: '+sha1filename+', original name: '+origfilename+', path: '+filedir+', type: '+filetype+', bytes received: '+filesize+', field: '+filefield+'\n');
                    removedFiles[sha1filename] = { path: filedir, origName: origfilename, type: filetype, filesize: filesize, field: filefield };
                    //log(' updated list of files removed: ',removedFiles);

                },
                'dataprogress': function( bytesReceived, chunksReceived, ratio ) {
                    log('\n dataprogress --> bytes:', bytesReceived,'chunks:', chunksReceived,' ratio:',  ratio  );
                },
                'end': function( incompleteFiles, stats, res, next) {
                        log( '\n-> Post Done' );
                        res.writeHead( 200, { 'content-type': 'text/plain' } );
                        res.write( '-> request processed! \n');

                        res.write( '\n-> upload dir: ' + form.uploadRootDir + ' \n');
                        res.write( '-> upload threshold : ' + ( form.uploadThreshold ) + ' bytes \n');
                        res.write( '-> checkContentLength: ' + form.checkContentLength + '\n');
                        res.write( '-> holdFilesExtensions: ' + form.holdFilesExtensions + '\n');
                        res.write( '-> sha1sum: ' + form.sha1sum + '\n');
                        res.write( '-> removeIncompleteFiles: ' + form.removeIncompleteFiles + '\n');
                        res.write( '-> emitDataProgress: ' + form.emitDataProgress + '\n');

                        res.write( '\n-> fields received: \n   ****************\n' + JSON.stringify(receivedFields) + '\n');
                        res.write( '\n-> files received: ( { sha1name: {..} }, { .. } )\n   ***************\n ' + JSON.stringify(receivedFiles) + '\n');
                        if( form.removeIncompleteFiles ){
                            res.write( '\n-> files removed: ( { sha1name: {..} }, { .. } )\n   **************\n' + JSON.stringify(removedFiles) + '\n');
                        }else{
                            if( incompleteFiles.length !== 0 ){
                                res.write( '-> incomplete files (not removed) : ' + incompleteFiles + '\n');
                            }
                        }
                        res.write( '\n-> stats -> ' + JSON.stringify(stats) + '\n');
                        receivedFiles = {};
                        removedFiles = {};
                        receivedFields = {};
                        res.end();
                        //next();//test
                }
            }
    };//end config obj

    if ( (req.url === '/test/upload') || (req.url === '/test/post') ){
        log( ' -> req url :', req.url );
        form = new formaline(config);
        form.parse(req,res,next);

    } else {
        log( ' -> req url 404 error :', req.url );
        res.writeHead(404, {'content-type': 'text/plain'});
        res.end('404');
    }

};

server = connect( getHtmlForm , handleFormRequest, function(){console.log('\nHi!, I\'m next() function!');} );

server.listen(3000);

log('\nlistening on http://localhost:3000/');
log(' -> upload directory is:',dir);

<commit_msg>Turned off 3rd level logging on example modified:   examples/simpleUpload.js<commit_after>

var http = require('http'),
    formaline = require('../lib/formaline').formaline,
    connect = require('connect'),
    server;

var getHtmlForm = function(req, res,next) {
  if (req.url === '/test/') {
    log( ' -> req url :', req.url );
    res.writeHead(200, {'content-type': 'text/html'});
    res.end('\
             Multiple File Upload:

\
             <form action="/test/upload" enctype="multipart/form-data" method="post">\
             <input type="text" name="demotitle1">
\
             <input type="file" name="multiplefield1" multiple="multiple">
\
             <input type="text" name="demotitle2">
\
             <input type="file" name="multiplefield2" multiple="multiple">
\
             <input type="text" name="demotitle3">
\
             <input type="file" name="multiplefield3" multiple="multiple">
\
             <input type="submit" value="Upload">\
             </form>
\
             Simple Post:

\
             <form action="/test/post" method="post">\
             <input type="text" name="simplefield1">
\
             <input type="text" name="simplefield2">
\
             <input type="text" name="simplefield3">
\
             <input type="submit" value="Submit">\
             </form>
\
             Iframe Multiple File Upload:

\
             <form action="/test/upload" method="post" enctype="multipart/form-data" target="iframe">\
             <input type="file" name="file" multiple  src="" frameborder="1" />\
             <input type="submit" />\
             </form>\
             \
             </form>\
             '
    );
  } else {
    next();
  }
};
var log = console.log,
    dir =  '/tmp/';

var handleFormRequest = function( req, res, next ){
    var receivedFiles = {},
        removedFiles = {},
        receivedFields = {},
        form = null,
        config = {

            //default is true -->
        holdFilesExtensions : true,

            //default is /tmp/ -->
        uploadRootDir: dir,

            //default is false
            //return sha1 digests for files received?  -->
        sha1sum: true,

            // default is false, or integer chunk factor,
            // every n chunk emit event 1+(0*n) 1+(1*n),1+(2*n),1+(3*n),
            // minimum factor value is 2 -->
        emitDataProgress: false,//false,true,3,10,100

            // max bytes allowed, this is the max bytes written to disk before stop to write
            // this is also true for serialzed fields not only for files upload  -->
        uploadThreshold: 1024*1024*1024,//bytes ex.: 1024*1024*1024, 512

            //default false, bypass headers value, continue to write to disk
            //until uploadThreshold bytes are written.
            //if true -> stop receiving data, when headers content length exceeds uploadThreshold
        checkContentLength: false,

            //remove file not completed due to uploadThreshold,
            //if true formaline emit fileremoved event,
            //otherwise return a path array of incomplete files
        removeIncompleteFiles : true,

            //enable various logging levels
            //it is possible to switch on/off one or more levels at the same time
            //debug: 'off' turn off logging
        logging: 'debug:on,1:on,2:on,3:off',

            //listeners
        listeners: {
                'warning': function( msg ){
                    log('\n warning  -->',msg);
                },
                'headersexception': function( isUpload, errmsg, res, next){
                    log('\n headersexception  -->',errmsg);
                    next();
                },
                'exception': function( isUpload, errmsg, res, next){
                    log('\n exception --> ',errmsg);
                    next();
                },
                'pathexception': function( path, errmsg, res, next){//there is a file upload
                    log('\n pathexception -->',path,'msg:',errmsg+'\n');
                    next();
                },
                'field': function( fname, fvalue ){
                    receivedFields[fname] = fvalue;
                    log('\n field--> ',fname,fvalue);
                },
                'filereceived': function( sha1filename, origfilename, filedir, filetype, filesize, filefield, filesha1sum ) {
                    receivedFiles[sha1filename] = { path: filedir, origName: origfilename, type: filetype, size: filesize, field: filefield, sha1sum: filesha1sum  };
                    log('\n filereceived -->  sha1name: '+sha1filename+', original name: '+origfilename+', path: '+filedir+', type: '+filetype+', bytes: '+filesize+', field: '+filefield+'\n');
                },
                'fileremoved': function( sha1filename, origfilename, filedir, filetype, filesize, filefield ) {
                    log('\n fileremoved -->  sha1name: '+sha1filename+', original name: '+origfilename+', path: '+filedir+', type: '+filetype+', bytes received: '+filesize+', field: '+filefield+'\n');
                    removedFiles[sha1filename] = { path: filedir, origName: origfilename, type: filetype, filesize: filesize, field: filefield };
                    //log(' updated list of files removed: ',removedFiles);

                },
                'dataprogress': function( bytesReceived, chunksReceived, ratio ) {
                    log('\n dataprogress --> bytes:', bytesReceived,'chunks:', chunksReceived,' ratio:',  ratio  );
                },
                'end': function( incompleteFiles, stats, res, next) {
                        log( '\n-> Post Done' );
                        res.writeHead( 200, { 'content-type': 'text/plain' } );
                        res.write( '-> request processed! \n');

                        res.write( '\n-> upload dir: ' + form.uploadRootDir + ' \n');
                        res.write( '-> upload threshold : ' + ( form.uploadThreshold ) + ' bytes \n');
                        res.write( '-> checkContentLength: ' + form.checkContentLength + '\n');
                        res.write( '-> holdFilesExtensions: ' + form.holdFilesExtensions + '\n');
                        res.write( '-> sha1sum: ' + form.sha1sum + '\n');
                        res.write( '-> removeIncompleteFiles: ' + form.removeIncompleteFiles + '\n');
                        res.write( '-> emitDataProgress: ' + form.emitDataProgress + '\n');

                        res.write( '\n-> fields received: \n   ****************\n' + JSON.stringify(receivedFields) + '\n');
                        res.write( '\n-> files received: ( { sha1name: {..} }, { .. } )\n   ***************\n ' + JSON.stringify(receivedFiles) + '\n');
                        if( form.removeIncompleteFiles ){
                            res.write( '\n-> files removed: ( { sha1name: {..} }, { .. } )\n   **************\n' + JSON.stringify(removedFiles) + '\n');
                        }else{
                            if( incompleteFiles.length !== 0 ){
                                res.write( '-> incomplete files (not removed) : ' + incompleteFiles + '\n');
                            }
                        }
                        res.write( '\n-> stats -> ' + JSON.stringify(stats) + '\n');
                        receivedFiles = {};
                        removedFiles = {};
                        receivedFields = {};
                        res.end();
                        //next();//test
                }
            }
    };//end config obj

    if ( (req.url === '/test/upload') || (req.url === '/test/post') ){
        log( ' -> req url :', req.url );
        form = new formaline(config);
        form.parse(req,res,next);

    } else {
        log( ' -> req url 404 error :', req.url );
        res.writeHead(404, {'content-type': 'text/plain'});
        res.end('404');
    }

};

server = connect( getHtmlForm , handleFormRequest, function(){console.log('\nHi!, I\'m next() function!');} );

server.listen(3000);

log('\nlistening on http://localhost:3000/');
log(' -> upload directory is:',dir);

<|endoftext|>


<commit_before>function Vertex() {
	this.position = $V([0, 0, 0, 1]);
	this.normal = $V([0, 0, 0]);
	this.uv = $V([0, 0]);
}
function Face() {
	this.indices = $V([0, 0, 0]);
	this.normal = $V([0, 0, 0]);
}
function Mesh() {
	// internal arrays, less org than external facing arrays
	this._vertices = new Float32Array();
	this._indices = new Uint32Array();
	this._normals = new Float32Array();
	this._uv = new Float32Array();
	// user friendly vertex/index arrays
	this.vertices = [];
	this.faces = [];
	// gl buffers
	this.vertexBuffer = null;
	this.normalBuffer = null;
	this.uvBuffer = null;
	this.indexBuffer = null;
}

Mesh.prototype = {
	_packArrays : function() {
		var tmpVerts = [];
		var tmpNormals = [];
		var tmpUV = [];
		var tmpIndices = [];
		for (var vidx = 0; vidx < this.vertices.length; ++vidx) {
			var v = this.vertices[vidx];
			tmpVerts = tmpVerts.concat(v.position.elements);
			tmpNormals = tmpNormals.concat(v.normal.elements);
			tmpUV = tmpUV.concat(v.uv.elements);
		}
		for (var idx = 0; idx < this.faces.length; ++idx) {
			tmpIndices = tmpIndices.concat(this.faces[idx].indices.elements);
		}
		this._vertices = Float32Array.from(tmpVerts);
		this._normals = Float32Array.from(tmpNormals);
		this._uv = Float32Array.from(tmpUV);
		this._indices = Uint32Array.from(tmpIndices);
		LogError(tmpVerts);
		LogError(tmpIndices);
	},
	initBuffers : function() {
		if (this.vertexBuffer == null) {
			this.vertexBuffer = gl.createBuffer();
		}
		if (this.indexBuffer == null) {
			this.indexBuffer = gl.createBuffer();
		}
		if (this.normalBuffer == null) {
			this.normalBuffer = gl.createBuffer();
		}
		if (this.uvBuffer == null) {
			this.uvBuffer = gl.createBuffer();
		}

		if (this.vertices == null || this._vertices == null) {
			return;
		}
		this._setBufferData();
	},
	_bindBuffers : function() {
		// bind buffers to this mesh's index/vertex buffers
		gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
		// gl.bindBuffer(gl.ARRAY_BUFFER, this.normalBuffer);
		// gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer);
		gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
	},
	updateBuffers : function() {
		// TODO properly updating buffer data in opengl, how do
		this._bindBuffers();
	},
	_setBufferData : function() {
		// set the buffer data, replacing the old memory with new
		// first pack the index/vertex arrays into the typed arrays
		this._packArrays();

		// bind our mesh buffers, only does position and index
		this._bindBuffers();

		// we MUST have vertices, optional indices
		gl.bufferData(gl.ARRAY_BUFFER, this._vertices, gl.STATIC_DRAW);
		if (this._normals != null) {
			gl.bindBuffer(gl.ARRAY_BUFFER, this.normalBuffer);
			gl.bufferData(gl.ARRAY_BUFFER, this._normals, gl.STATIC_DRAW);
		}
		if (this._uv != null) {
			gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer);
			gl.bufferData(gl.ARRAY_BUFFER, this._uv, gl.STATIC_DRAW);
		}

		// INDEX_BUFFER should still be bound to our index buffer, though ARRAY_BUFFER is now bound to the uv or normals potentially
		if (this._indices!= null) {
			gl.bufferData(gl.INDEX_BUFFER, this._indices, gl.STATIC_DRAW);
		}
	},
	_drawMesh : function(material) {
		// material is the material to draw the mesh with
		// TODO ideally you want to batch the draw calls based on the material (shader) being used
		LogError("Drawing Mesh");
		if (this.vertexBuffer == null || this.indexBuffer == null || this.normalBuffer == null || this.uvBuffer == null) {
			return;
		}
		this._packArrays();
		this._setBufferData();
		this._bindBuffers();
		if (material) {
			material.setUniforms();
			material.setAttributes();
			material.useMaterial();
		}
		gl.drawArrays(gl.TRIANGLES, this.vertices.length, gl.UNSIGNED_SHORT, 0);
	}
};

// utilities for making random geometry
function createSingleTriangleMesh(a, b, c, twosided=true) {
	// TODO add texture coordinates, bounding square
	var omesh = new Mesh();

	var va = new Vertex(), vb = new Vertex(), vc = new Vertex();

	va.position = $V(a);
	vb.position = $V(b);
	vc.position = $V(c);

	var faceNorm = vb.position.subtract(va.position).cross(vc.position.subtract(va.position)).normalize();
	va.normal = vb.normal = vc.normal = faceNorm;

	omesh.vertices.push(va);
	omesh.vertices.push(vb);
	omesh.vertices.push(vc);

	var f1 = new Face(), f2 = new Face();
	f1.indices.setElements([0, 1, 2]);
	f1.normal = faceNorm;
	omesh.faces.push(f1);

	if (twosided) {
		// need a second set of verts for a double sided tri with normals pointing the opposite way
		var vd = new Vertex(), ve = new Vertex(), vf = new Vertex();
		vd.normal = ve.normal = vf.normal = faceNorm.multiply(-1);
		vd.position = $V(a);
		vf.position = $V(c);
		ve.position = $V(b);

		omesh.vertices.push(vd);
		omesh.vertices.push(ve);
		omesh.vertices.push(vf);

		var f2 = new Face();
		f2.indices.setElements([3, 4, 5]);
		f2.normal = faceNorm.multiply(-1);
		omesh.faces.push(f2);
	}

	omesh._packArrays();
	omesh.initBuffers;

	LogError("Generated Tri: " + JSON.stringify(omesh));

	return omesh;
}

function createSingleQuadMesh(a, b, c, d, twosided=true) {
	var omesh1 = createSingleTriangleMesh(a, b, c, twosided);
	var omesh2 = createSingleTriangleMesh(c, d, a, twosided);

	// increase the index values to concat properly the two meshes
	for (var idx = 0; idx < omesh2.faces.length; ++idx) {
		omesh2.faces[idx].indices.setElements(omesh2.faces[idx].indices.add($V[omesh1.vertices.length, omesh1.vertices.length, omesh1.vertices.length]));
	}

	LogError("A: " + JSON.stringify(a) + "\nB: " + JSON.stringify(b) + "\nC: " + JSON.stringify(c) + "\nD: " + JSON.stringify(d));

	LogError("Omesh1: " + JSON.stringify(omesh1));
	LogError("Omesh2: " + JSON.stringify(omesh2));

	var omesh = new Mesh();
	omesh.vertices = omesh1.vertices.concat(omesh2.vertices);
	omesh.faces = omesh1.faces.concat(omesh2.faces);

	omesh._packArrays();

	return omesh;
}

function createSquareMesh(dim, normal, twosided=true) {
	// TODO transform so that the normal points in the correct direction
	var omesh = createSingleQuadMesh([dim, dim, 0.0], //
									 [-1.0 * dim, dim, 0.0], //
									 [-1.0 * dim, -1.0 * dim, 0.0], //
									 [dim, -1.0 * dim, 0.0], twosided);
	return omesh;
}

function createRectangleMesh(l, w, normal, twosided=true, ccw=true) {
	var omesh;

	return omesh;
}

function createCircleMesh(center, radius, normal, twosided=true, ccw=true) {
	var omesh;

	return omesh;
}

function createCubeMesh(dim, twosided=true, ccw=true) {
	var omesh;

	return omesh;
}

function createBoxMesh(l, w, h, twosided=true, ccw=true) {
	var omesh;

	return omesh;
}

function createSphereMesh(dim) {
	var omesh;

	return omesh;
}<commit_msg>still bugfixing, optimized the square mesh to have no r repeated vertices (fewer at least, still repeats of positions to include the normals for both directions)<commit_after>function Vertex() {
	this.position = $V([0, 0, 0, 1]);
	this.normal = $V([0, 0, 0]);
	this.uv = $V([0, 0]);
}
function Face() {
	this.indices = $V([0, 0, 0]);
	this.normal = $V([0, 0, 0]);
}
function Mesh() {
	// internal arrays, less org than external facing arrays
	this._vertices = new Float32Array();
	this._indices = new Uint32Array();
	this._normals = new Float32Array();
	this._uv = new Float32Array();
	// user friendly vertex/index arrays
	this.vertices = [];
	this.faces = [];
	// gl buffers
	this.vertexBuffer = null;
	this.normalBuffer = null;
	this.uvBuffer = null;
	this.indexBuffer = null;
}

Mesh.prototype = {
	_packArrays : function() {
		var tmpVerts = [];
		var tmpNormals = [];
		var tmpUV = [];
		var tmpIndices = [];
		for (var vidx = 0; vidx < this.vertices.length; ++vidx) {
			var v = this.vertices[vidx];
			tmpVerts = tmpVerts.concat(v.position.elements);
			tmpNormals = tmpNormals.concat(v.normal.elements);
			tmpUV = tmpUV.concat(v.uv.elements);
		}
		for (var idx = 0; idx < this.faces.length; ++idx) {
			tmpIndices = tmpIndices.concat(this.faces[idx].indices.elements);
		}
		this._vertices = Float32Array.from(tmpVerts);
		this._normals = Float32Array.from(tmpNormals);
		this._uv = Float32Array.from(tmpUV);
		this._indices = Uint32Array.from(tmpIndices);
	},
	initBuffers : function() {
		if (this.vertexBuffer == null) {
			this.vertexBuffer = gl.createBuffer();
		}
		if (this.indexBuffer == null) {
			this.indexBuffer = gl.createBuffer();
		}
		if (this.normalBuffer == null) {
			this.normalBuffer = gl.createBuffer();
		}
		if (this.uvBuffer == null) {
			this.uvBuffer = gl.createBuffer();
		}

		if (this.vertices == null || this._vertices == null) {
			return;
		}
		this._setBufferData();
	},
	_bindBuffers : function() {
		// bind buffers to this mesh's index/vertex buffers
		gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
		// gl.bindBuffer(gl.ARRAY_BUFFER, this.normalBuffer);
		// gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer);
		gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
	},
	updateBuffers : function() {
		// TODO properly updating buffer data in opengl, how do
		this._bindBuffers();
	},
	_setBufferData : function() {
		// set the buffer data, replacing the old memory with new
		// first pack the index/vertex arrays into the typed arrays
		this._packArrays();

		// bind our mesh buffers, only does position and index
		this._bindBuffers();

		// we MUST have vertices, optional indices
		gl.bufferData(gl.ARRAY_BUFFER, this._vertices, gl.STATIC_DRAW);
		if (this._normals != null) {
			gl.bindBuffer(gl.ARRAY_BUFFER, this.normalBuffer);
			gl.bufferData(gl.ARRAY_BUFFER, this._normals, gl.STATIC_DRAW);
		}
		if (this._uv != null) {
			gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer);
			gl.bufferData(gl.ARRAY_BUFFER, this._uv, gl.STATIC_DRAW);
		}

		// INDEX_BUFFER should still be bound to our index buffer, though ARRAY_BUFFER is now bound to the uv or normals potentially
		if (this._indices!= null) {
			gl.bufferData(gl.INDEX_BUFFER, this._indices, gl.STATIC_DRAW);
		}
	},
	_drawMesh : function(material) {
		// material is the material to draw the mesh with
		// TODO ideally you want to batch the draw calls based on the material (shader) being used
		LogError("Drawing Mesh " + JSON.stringify(this) + "; " + this._vertices.toString() + "; " + this._indices.toString());
		if (this.vertexBuffer == null || this.indexBuffer == null || this.normalBuffer == null || this.uvBuffer == null) {
			return;
		}
		this._packArrays();
		this._setBufferData();
		this._bindBuffers();
		if (material) {
			material.setUniforms();
			material.setAttributes();
			material.useMaterial();
		}
		gl.drawArrays(gl.TRIANGLES, this.vertices.length, gl.UNSIGNED_SHORT, 0);
	}
};

// utilities for making random geometry
function createSingleTriangleMesh(a, b, c, twosided=true) {
	// TODO add texture coordinates, bounding square
	var omesh = new Mesh();

	var va = new Vertex(), vb = new Vertex(), vc = new Vertex();

	va.position = $V(a);
	vb.position = $V(b);
	vc.position = $V(c);

	var faceNorm = vb.position.subtract(va.position).cross(vc.position.subtract(va.position)).normalize();
	va.normal = vb.normal = vc.normal = faceNorm;

	omesh.vertices.push(va);
	omesh.vertices.push(vb);
	omesh.vertices.push(vc);

	var f1 = new Face(), f2 = new Face();
	f1.indices.setElements([0, 1, 2]);
	f1.normal = faceNorm;
	omesh.faces.push(f1);

	if (twosided) {
		// need a second set of verts for a double sided tri with normals pointing the opposite way
		var vd = new Vertex(), ve = new Vertex(), vf = new Vertex();
		vd.normal = ve.normal = vf.normal = faceNorm.multiply(-1);
		vd.position = $V(a);
		vf.position = $V(c);
		ve.position = $V(b);

		omesh.vertices.push(vd);
		omesh.vertices.push(ve);
		omesh.vertices.push(vf);

		var f2 = new Face();
		f2.indices.setElements([3, 4, 5]);
		f2.normal = faceNorm.multiply(-1);
		omesh.faces.push(f2);
	}

	omesh._packArrays();
	omesh.initBuffers();

	LogError("Generated Tri: " + JSON.stringify(omesh));

	return omesh;
}

function createSingleQuadMesh(a, b, c, d, twosided=true) {
	// var omesh1 = createSingleTriangleMesh(a, b, c, twosided);
	// var omesh2 = createSingleTriangleMesh(c, d, a, twosided);

	var omesh = createSingleTriangleMesh(a, b, c, twosided);
	var vd = new Vertex();
	vd.position = $V(d);
	vd.normal = omesh.vertices[0].normal;
	omesh.vertices.push(vd);

	var f1 = new Face();
	f1.indices.setElements([0, 2, omesh.vertices.length - 1]);
	omesh.faces.push(f1);

	if (twosided) {
		var vd2 = new Vertex();
		vd2.position = $V(d);
		vd2.normal = omesh.vertices[4].normal;
		omesh.vertices.push(vd2);

		var f2 = new Face();
		f2.indices.setElements([3, 5, omesh.vertices.length - 1]);
		omesh.faces.push(f2);
	}

	// increase the index values to concat properly the two meshes
	// for (var idx = 0; idx < omesh2.faces.length; ++idx) {
		// var tmp = omesh2.faces[idx].indices.add($V([omesh1.vertices.length, omesh1.vertices.length, omesh1.vertices.length]));
		// omesh2.faces[idx].indices.setElements(tmp);
	// }

	LogError("A: " + JSON.stringify(a) + "\nB: " + JSON.stringify(b) + "\nC: " + JSON.stringify(c) + "\nD: " + JSON.stringify(d));

	// LogError("Omesh1: " + JSON.stringify(omesh1));
	// LogError("Omesh2: " + JSON.stringify(omesh2));

	// omesh.vertices = omesh1.vertices.concat(omesh2.vertices);
	// omesh.faces = omesh1.faces.concat(omesh2.faces);
	LogError("Square mesh gen: " + JSON.stringify(omesh));
	omesh._packArrays();
	LogError("Readable verts: " + omesh._vertices.toString());
	LogError("Readable indices: " + omesh._indices.toString());

	return omesh;
}

function createSquareMesh(dim, normal, twosided=true) {
	// TODO transform so that the normal points in the correct direction
	var omesh = createSingleQuadMesh([dim, dim, 0.0], //
									 [-1.0 * dim, dim, 0.0], //
									 [-1.0 * dim, -1.0 * dim, 0.0], //
									 [dim, -1.0 * dim, 0.0], twosided);
	return omesh;
}

function createRectangleMesh(l, w, normal, twosided=true, ccw=true) {
	var omesh;

	return omesh;
}

function createCircleMesh(center, radius, normal, twosided=true, ccw=true) {
	var omesh;

	return omesh;
}

function createCubeMesh(dim, twosided=true, ccw=true) {
	var omesh;

	return omesh;
}

function createBoxMesh(l, w, h, twosided=true, ccw=true) {
	var omesh;

	return omesh;
}

function createSphereMesh(dim) {
	var omesh;

	return omesh;
}<|endoftext|>


<commit_before><commit_msg>parse the booking slot input element's value to get court and timing information<commit_after><|endoftext|>


<commit_before>// Copright (c) 2015-2018, Exa Analytics Development Team
// Distributed under the terms of the Apache License 2.0
/*"""
=================
widgets.js
=================
JavaScript "frontend" complement of exatomic's Container for use within
the Jupyter notebook interface.
*/

"use strict";
var base = require("./base");
var utils = require("./utils");
var three = require("./appthree");
var _ = require('underscore');

var UniverseSceneModel = base.ExatomicSceneModel.extend({

    defaults: function() {
        return _.extend({}, base.ExatomicSceneModel.prototype.defaults, {
            _model_name: "UniverseSceneModel",
            _view_name: "UniverseSceneView"
        });
    }

});

var UniverseSceneView = base.ExatomicSceneView.extend({

    init: function() {
        window.addEventListener("resize", this.resize.bind(this));
        this.app3d = new three.App3D(this);
        this.three_promises = this.app3d.init_promise();
        this.promises = Promise.all([utils.fparse(this, "atom_x"),
            utils.fparse(this, "atom_y"), utils.fparse(this, "atom_z"),
            utils.fparse(this, "atom_s"), utils.mesolv(this, "atom_cr"),
            utils.mesolv(this, "atom_vr"),
            utils.mesolv(this, "atom_c"), utils.mesolv(this, "atom_l"),
            utils.fparse(this, "two_b0"), utils.fparse(this, "two_b1"),
            utils.mesolv(this, "field_i"), utils.mesolv(this, "field_p"),
            utils.mesolv(this, "field_v"), utils.mesolv(this, "tensor_d")]);
        this.three_promises = this.app3d.finalize(this.three_promises)
            .then(this.add_atom.bind(this))
            .then(this.app3d.set_camera_from_scene.bind(this.app3d));
    },

    render: function() {
        return Promise.all([this.three_promises, this.promises]);
    },

    add_atom: function() {
        this.app3d.clear_meshes("atom");
        this.app3d.clear_meshes("two");
        var fdx = this.model.get("frame_idx");
        var syms = this.atom_s[fdx];
        var colrs = utils.mapper(syms, this.atom_c);
        var atom, bond, radii, r = ((this.model.get("bond_r") > 0) ? this.model.get("bond_r") : 0.05);
        if (this.model.get("atom_3d")) {
            switch (this.model.get("fill_idx")) {
                case 0:
                    radii = utils.mapper(syms, this.atom_cr)
                                    .map(function(x) { return x * 0.5; });
                    atom = this.app3d.add_points;
                    bond = this.app3d.add_lines;
                    break;
                case 1:
                    radii = utils.mapper(syms, this.atom_cr)
                                    .map(function(x) { return x * 0.5; });
                    atom = this.app3d.add_spheres;
                    bond = this.app3d.add_cylinders;
                    break;
                case 2:
                    radii = utils.mapper(syms, this.atom_vr);
                    atom = this.app3d.add_spheres;
                    bond = null;
                    break;
                case 3:
                    radii = utils.mapper(syms, this.atom_cr);
                    atom = this.app3d.add_spheres;
                    bond = this.app3d.add_cylinders;
                    break;
                //case 4:
                //    r = 0.6
                //    radii = r+0.05;
                //    atom = this.app3d.add_spheres;
                //    bond = this.app3d.add_cylinders;
                //    break;
            }
        } else {
            radii = utils.mapper(syms, this.atom_cr)
                            .map(function(x) { return x * 0.5; });
            atom = this.app3d.add_points;
            bond = this.app3d.add_lines;
        }
        var labels = utils.mapper(syms, this.atom_l);
        var entry = labels.entries();
        var a = []
        for ( let e of entry ) { a.push(e[1]+e[0].toString()); }
        labels = a;
        this.app3d.meshes["atom"] = atom(
            this.atom_x[fdx], this.atom_y[fdx],
            this.atom_z[fdx], colrs, radii, labels);
        if (this.two_b0.length !== 0) {
            this.app3d.meshes["two"] = (bond != null) ? bond(
                this.two_b0[fdx], this.two_b1[fdx],
                this.atom_x[fdx], this.atom_y[fdx],
                this.atom_z[fdx], colrs, r) : null ;
        };
        this.app3d.add_meshes();
    },

    add_field: function() {
        this.app3d.clear_meshes("field");
        var fldx = this.model.get("field_idx");
        var fdx = this.model.get("frame_idx");
        var fps = this.field_p[fdx][fldx];
        if ((!this.model.get("field_show")) ||
            (fldx === "null") ||
            (typeof fps === "undefined")) { return }
        var idx = this.field_i[fdx][fldx];
        var that = this;
        if (typeof this.field_v[idx] === "string") {
            utils.jsonparse(this.field_v[idx])
                .then(function(values) {
                    that.field_v[idx] = values;
                    that.app3d.meshes["field"] = that.app3d.add_scalar_field(
                        utils.scalar_field(
                            utils.gen_field_arrays(fps),
                            values),
                    that.model.get("field_iso"),
                    that.model.get("field_o"), 2,
                    that.colors());
                    that.app3d.add_meshes("field");
                });
        } else {
            this.app3d.meshes["field"] = this.app3d.add_scalar_field(
                utils.scalar_field(
                    utils.gen_field_arrays(fps),
                    this.field_v[idx]),
                this.model.get("field_iso"),
                this.model.get("field_o"), 2,
                this.colors());
            this.app3d.add_meshes("field");
        };
    },

    add_contour: function() {
        this.app3d.clear_meshes("contour");
        var fldx = this.model.get("field_idx");
        // Specifically test for string null
        var fdx = this.model.get("frame_idx");
        var idx = this.field_i[fdx][fldx];
        var fps = this.field_p[fdx][fldx];
        if ((!this.model.get("cont_show")) ||
            (fldx === "null") ||
            (typeof fps === "undefined")) { return }
        var that = this;
        if (typeof this.field_v[idx] === 'string') {
            utils.jsonparse(this.field_v[idx])
                .then(function(values) {
                    that.field_v[idx] = values;
                    that.app3d.meshes["contour"] = that.app3d.add_contour(
                        utils.scalar_field(
                            utils.gen_field_arrays(fps),
                            values),
                        that.model.get("cont_num"),
                        that.model.get("cont_lim"),
                        that.model.get("cont_axis"),
                        that.model.get("cont_val"),
                        that.colors());
                    that.app3d.add_meshes("contour");
                });
        } else {
            this.app3d.meshes["contour"] = this.app3d.add_contour(
                utils.scalar_field(
                    utils.gen_field_arrays(fps),
                    this.field_v[idx]),
                this.model.get("cont_num"),
                this.model.get("cont_lim"),
                this.model.get("cont_axis"),
                this.model.get("cont_val"),
                this.colors());
            that.app3d.add_meshes("contour");
        };
    },

    add_axis: function() {
        // Additionally adds the unit cell
        this.app3d.clear_meshes("generic");
        if (this.model.get("axis")) {
            this.app3d.meshes["generic"] = this.app3d.add_unit_axis(
                this.model.get("atom_3d"));
        };
        this.app3d.add_meshes("generic");
    },

    get_tensor: function(fdx, tdx) {
        var t = this.tensor_d[fdx][tdx];
        return [[t["xx"], t["xy"], t["xz"]],
                [t["yx"], t["yy"], t["yz"]],
                [t["zx"], t["zy"], t["zz"]]];
    },

    color_tensor: function() {
        var tdx = this.model.get("tidx");
        var fdx = this.model.get("frame_idx");
        var color;
        for ( var property in this.tensor_d[fdx] ) {
            if ( this.tensor_d[fdx].hasOwnProperty( property ) ) {
                if ( parseInt(property) === tdx ) { color = 0xafafaf; }
                else { color = 0x000000; }
                if ( this.model.get("tens") ) {
                    this.app3d.meshes["tensor"+property][0].children[0].material.color.setHex(color);
                }
            }
        }
    },

    add_tensor: function() {
        var scaling = this.model.get("scale");
        var fdx = this.model.get("frame_idx");
        for ( var property in this.tensor_d[fdx] ) {
            if ( this.tensor_d[fdx].hasOwnProperty( property ) ) {
                this.app3d.clear_meshes("tensor"+property);
                var adx = this.tensor_d[fdx][property]["atom"];
                if ( this.model.get("tens") ) {
                    this.app3d.meshes["tensor"+property] =
                                this.app3d.add_tensor_surface(
                                    this.get_tensor(fdx, property),
                                    this.colors(),
                                    this.atom_x[fdx][adx],
                                    this.atom_y[fdx][adx],
                                    this.atom_z[fdx][adx],
                                    scaling,
                                    this.tensor_d[fdx][property]["label"]+" tensor "+property.toString());
                }
                this.app3d.add_meshes("tensor"+property);
            }
        }
        if (this.model.get("tens")) {this.color_tensor();}
    },

    events: {
        'click': '_handle_click'
    },

    _handle_click: function(event) {
        // Handles click event to write data to a Python traitlet value
        event.preventDefault();
        if (this.app3d.selected.length > 0) {
            var idx = this.app3d.selected.map(function(obj) {return obj.name;});
            var type = this.app3d.selected.map(function(obj) {return obj.geometry.type;});
            this.model.set('selected', {'idx': idx, 'type': type}); //Types must match exactly
            this.touch();
        }
    },

    init_listeners: function() {
        base.ExatomicSceneView.prototype.init_listeners.call(this);
        this.listenTo(this.model, "change:frame_idx", this.add_atom);
        this.listenTo(this.model, "change:atom_3d", this.add_atom);
        this.listenTo(this.model, "change:field_idx", this.add_field);
        this.listenTo(this.model, "change:field_show", this.add_field);
        this.listenTo(this.model, "change:field_idx", this.add_contour);
        this.listenTo(this.model, "change:cont_show", this.add_contour);
        this.listenTo(this.model, "change:cont_axis", this.add_contour);
        this.listenTo(this.model, "change:cont_num", this.add_contour);
        this.listenTo(this.model, "change:cont_lim", this.add_contour);
        this.listenTo(this.model, "change:cont_val", this.add_contour);
        this.listenTo(this.model, "change:atom_3d", this.add_axis);
        this.listenTo(this.model, "change:axis", this.add_axis);
        this.listenTo(this.model, "change:tens", this.add_tensor);
        this.listenTo(this.model, "change:scale", this.add_tensor);
        this.listenTo(this.model, "change:tidx", this.color_tensor);
        this.listenTo(this.model, "change:fill_idx", this.add_atom);
        this.listenTo(this.model, "change:bond_r", this.add_atom);
    }

});

module.exports = {
    UniverseSceneModel: UniverseSceneModel,
    UniverseSceneView: UniverseSceneView
}

<commit_msg>Removing High Performance option from the fill widget.<commit_after>// Copright (c) 2015-2018, Exa Analytics Development Team
// Distributed under the terms of the Apache License 2.0
/*"""
=================
widgets.js
=================
JavaScript "frontend" complement of exatomic's Container for use within
the Jupyter notebook interface.
*/

"use strict";
var base = require("./base");
var utils = require("./utils");
var three = require("./appthree");
var _ = require('underscore');

var UniverseSceneModel = base.ExatomicSceneModel.extend({

    defaults: function() {
        return _.extend({}, base.ExatomicSceneModel.prototype.defaults, {
            _model_name: "UniverseSceneModel",
            _view_name: "UniverseSceneView"
        });
    }

});

var UniverseSceneView = base.ExatomicSceneView.extend({

    init: function() {
        window.addEventListener("resize", this.resize.bind(this));
        this.app3d = new three.App3D(this);
        this.three_promises = this.app3d.init_promise();
        this.promises = Promise.all([utils.fparse(this, "atom_x"),
            utils.fparse(this, "atom_y"), utils.fparse(this, "atom_z"),
            utils.fparse(this, "atom_s"), utils.mesolv(this, "atom_cr"),
            utils.mesolv(this, "atom_vr"),
            utils.mesolv(this, "atom_c"), utils.mesolv(this, "atom_l"),
            utils.fparse(this, "two_b0"), utils.fparse(this, "two_b1"),
            utils.mesolv(this, "field_i"), utils.mesolv(this, "field_p"),
            utils.mesolv(this, "field_v"), utils.mesolv(this, "tensor_d")]);
        this.three_promises = this.app3d.finalize(this.three_promises)
            .then(this.add_atom.bind(this))
            .then(this.app3d.set_camera_from_scene.bind(this.app3d));
    },

    render: function() {
        return Promise.all([this.three_promises, this.promises]);
    },

    add_atom: function() {
        this.app3d.clear_meshes("atom");
        this.app3d.clear_meshes("two");
        var fdx = this.model.get("frame_idx");
        var syms = this.atom_s[fdx];
        var colrs = utils.mapper(syms, this.atom_c);
        var atom, bond, radii, r = ((this.model.get("bond_r") > 0) ? this.model.get("bond_r") : 0.05);
        if (this.model.get("atom_3d")) {
            switch (this.model.get("fill_idx")) {
                case 0:
                    radii = utils.mapper(syms, this.atom_cr)
                                    .map(function(x) { return x * 0.5; });
                    atom = this.app3d.add_spheres;
                    bond = this.app3d.add_cylinders;
                    break;
                case 1:
                    radii = utils.mapper(syms, this.atom_vr);
                    atom = this.app3d.add_spheres;
                    bond = null;
                    break;
                case 2:
                    radii = utils.mapper(syms, this.atom_cr);
                    atom = this.app3d.add_spheres;
                    bond = this.app3d.add_cylinders;
                    break;
                //case 3:
                //    radii = utils.mapper(syms, this.atom_cr)
                //                    .map(function(x) { return x * 0.5; });
                //    atom = this.app3d.add_points;
                //    bond = this.app3d.add_lines;
                //    break;
                //case 4:
                //    r = 0.6
                //    radii = r+0.05;
                //    atom = this.app3d.add_spheres;
                //    bond = this.app3d.add_cylinders;
                //    break;
            }
        } else {
            radii = utils.mapper(syms, this.atom_cr)
                            .map(function(x) { return x * 0.5; });
            atom = this.app3d.add_points;
            bond = this.app3d.add_lines;
        }
        var labels = utils.mapper(syms, this.atom_l);
        var entry = labels.entries();
        var a = []
        for ( let e of entry ) { a.push(e[1]+e[0].toString()); }
        labels = a;
        this.app3d.meshes["atom"] = atom(
            this.atom_x[fdx], this.atom_y[fdx],
            this.atom_z[fdx], colrs, radii, labels);
        if (this.two_b0.length !== 0) {
            this.app3d.meshes["two"] = (bond != null) ? bond(
                this.two_b0[fdx], this.two_b1[fdx],
                this.atom_x[fdx], this.atom_y[fdx],
                this.atom_z[fdx], colrs, r) : null ;
        };
        this.app3d.add_meshes();
    },

    add_field: function() {
        this.app3d.clear_meshes("field");
        var fldx = this.model.get("field_idx");
        var fdx = this.model.get("frame_idx");
        var fps = this.field_p[fdx][fldx];
        if ((!this.model.get("field_show")) ||
            (fldx === "null") ||
            (typeof fps === "undefined")) { return }
        var idx = this.field_i[fdx][fldx];
        var that = this;
        if (typeof this.field_v[idx] === "string") {
            utils.jsonparse(this.field_v[idx])
                .then(function(values) {
                    that.field_v[idx] = values;
                    that.app3d.meshes["field"] = that.app3d.add_scalar_field(
                        utils.scalar_field(
                            utils.gen_field_arrays(fps),
                            values),
                    that.model.get("field_iso"),
                    that.model.get("field_o"), 2,
                    that.colors());
                    that.app3d.add_meshes("field");
                });
        } else {
            this.app3d.meshes["field"] = this.app3d.add_scalar_field(
                utils.scalar_field(
                    utils.gen_field_arrays(fps),
                    this.field_v[idx]),
                this.model.get("field_iso"),
                this.model.get("field_o"), 2,
                this.colors());
            this.app3d.add_meshes("field");
        };
    },

    add_contour: function() {
        this.app3d.clear_meshes("contour");
        var fldx = this.model.get("field_idx");
        // Specifically test for string null
        var fdx = this.model.get("frame_idx");
        var idx = this.field_i[fdx][fldx];
        var fps = this.field_p[fdx][fldx];
        if ((!this.model.get("cont_show")) ||
            (fldx === "null") ||
            (typeof fps === "undefined")) { return }
        var that = this;
        if (typeof this.field_v[idx] === 'string') {
            utils.jsonparse(this.field_v[idx])
                .then(function(values) {
                    that.field_v[idx] = values;
                    that.app3d.meshes["contour"] = that.app3d.add_contour(
                        utils.scalar_field(
                            utils.gen_field_arrays(fps),
                            values),
                        that.model.get("cont_num"),
                        that.model.get("cont_lim"),
                        that.model.get("cont_axis"),
                        that.model.get("cont_val"),
                        that.colors());
                    that.app3d.add_meshes("contour");
                });
        } else {
            this.app3d.meshes["contour"] = this.app3d.add_contour(
                utils.scalar_field(
                    utils.gen_field_arrays(fps),
                    this.field_v[idx]),
                this.model.get("cont_num"),
                this.model.get("cont_lim"),
                this.model.get("cont_axis"),
                this.model.get("cont_val"),
                this.colors());
            that.app3d.add_meshes("contour");
        };
    },

    add_axis: function() {
        // Additionally adds the unit cell
        this.app3d.clear_meshes("generic");
        if (this.model.get("axis")) {
            this.app3d.meshes["generic"] = this.app3d.add_unit_axis(
                this.model.get("atom_3d"));
        };
        this.app3d.add_meshes("generic");
    },

    get_tensor: function(fdx, tdx) {
        var t = this.tensor_d[fdx][tdx];
        return [[t["xx"], t["xy"], t["xz"]],
                [t["yx"], t["yy"], t["yz"]],
                [t["zx"], t["zy"], t["zz"]]];
    },

    color_tensor: function() {
        var tdx = this.model.get("tidx");
        var fdx = this.model.get("frame_idx");
        var color;
        for ( var property in this.tensor_d[fdx] ) {
            if ( this.tensor_d[fdx].hasOwnProperty( property ) ) {
                if ( parseInt(property) === tdx ) { color = 0xafafaf; }
                else { color = 0x000000; }
                if ( this.model.get("tens") ) {
                    this.app3d.meshes["tensor"+property][0].children[0].material.color.setHex(color);
                }
            }
        }
    },

    add_tensor: function() {
        var scaling = this.model.get("scale");
        var fdx = this.model.get("frame_idx");
        for ( var property in this.tensor_d[fdx] ) {
            if ( this.tensor_d[fdx].hasOwnProperty( property ) ) {
                this.app3d.clear_meshes("tensor"+property);
                var adx = this.tensor_d[fdx][property]["atom"];
                if ( this.model.get("tens") ) {
                    this.app3d.meshes["tensor"+property] =
                                this.app3d.add_tensor_surface(
                                    this.get_tensor(fdx, property),
                                    this.colors(),
                                    this.atom_x[fdx][adx],
                                    this.atom_y[fdx][adx],
                                    this.atom_z[fdx][adx],
                                    scaling,
                                    this.tensor_d[fdx][property]["label"]+" tensor "+property.toString());
                }
                this.app3d.add_meshes("tensor"+property);
            }
        }
        if (this.model.get("tens")) {this.color_tensor();}
    },

    events: {
        'click': '_handle_click'
    },

    _handle_click: function(event) {
        // Handles click event to write data to a Python traitlet value
        event.preventDefault();
        if (this.app3d.selected.length > 0) {
            var idx = this.app3d.selected.map(function(obj) {return obj.name;});
            var type = this.app3d.selected.map(function(obj) {return obj.geometry.type;});
            this.model.set('selected', {'idx': idx, 'type': type}); //Types must match exactly
            this.touch();
        }
    },

    init_listeners: function() {
        base.ExatomicSceneView.prototype.init_listeners.call(this);
        this.listenTo(this.model, "change:frame_idx", this.add_atom);
        this.listenTo(this.model, "change:atom_3d", this.add_atom);
        this.listenTo(this.model, "change:field_idx", this.add_field);
        this.listenTo(this.model, "change:field_show", this.add_field);
        this.listenTo(this.model, "change:field_idx", this.add_contour);
        this.listenTo(this.model, "change:cont_show", this.add_contour);
        this.listenTo(this.model, "change:cont_axis", this.add_contour);
        this.listenTo(this.model, "change:cont_num", this.add_contour);
        this.listenTo(this.model, "change:cont_lim", this.add_contour);
        this.listenTo(this.model, "change:cont_val", this.add_contour);
        this.listenTo(this.model, "change:atom_3d", this.add_axis);
        this.listenTo(this.model, "change:axis", this.add_axis);
        this.listenTo(this.model, "change:tens", this.add_tensor);
        this.listenTo(this.model, "change:scale", this.add_tensor);
        this.listenTo(this.model, "change:tidx", this.color_tensor);
        this.listenTo(this.model, "change:fill_idx", this.add_atom);
        this.listenTo(this.model, "change:bond_r", this.add_atom);
    }

});

module.exports = {
    UniverseSceneModel: UniverseSceneModel,
    UniverseSceneView: UniverseSceneView
}

<|endoftext|>