<commit_before>/**
 * Created with IntelliJ IDEA.
 * User: tparmer
 * Date: 11/27/13
 * Time: 12:21 PM
 * To change this template use File | Settings | File Templates.
 */

var serviceURL = "http://216.74.49.91:8080/tssvc/resourcesS/stories/";
//var serviceURL = "http://localhost:8080/tssvc/resourcesS/stories";
//var serviceURL = "http://localhost:8080/tssvc/getstorylist2.html";

//var employees;
//var stories;

$('#mediaPage').bind('pagebeforecreate', function(event) {
    //alert('bind: pagebeforecreate');
    //getEmployeeList();
});
$('#mediaPage').bind('pagecreate', function(event) {
   // alert('bind: pagecreate');
    //getEmployeeList();
});

$('#mediaPage').bind('pageinit', function(event) {
    //alert('bind: pageinit');
    //getEmployeeList();
});

$('#mediaPage').live('pageinit', function(event) {
    //alert('live: pageinit');
    app.initialize();
   // alert('live: after app.init');
    //getEmployeeList();
});
$('#mediaPage').bind('pagebeforeload', function(event) {
   // alert('bind: pagebeforeload');
    //getEmployeeList();
});

$('#mediaPage').bind('pageload', function(event) {
   // alert('bind: pageload');
    //getEmployeeList();
});

$('#mediaPage').bind('pagebeforeshow', function(event) {
   // alert('bind: pagebeforeshow');
    //getEmployeeList();
});

$('#mediaPage').bind('pageshow', function(event) {
    //alert('bind: pageshow');
    //getEmployeeList();
});
$('#mediaPage').bind('pagebeforechange', function(event) {
    //alert('bind: pagebeforeshow');
    //getEmployeeList();
});

$('#mediaPage').bind('pagechange', function(event) {
   // alert('bind: pageshow');
    //getEmployeeList();
});

var app = {
    // Application Constructor
    initialize: function() {
        this.bindEvents();
    },
    // Bind Event Listeners
    //
    // Bind any events that are required on startup. Common events are:
    // `load`, `deviceready`, `offline`, and `online`.
    bindEvents: function() {
       // alert('before binding events');
// document.addEventListener('deviceready', this.onDeviceReady, false);
// document.getElementById('scan').addEventListener('click', this.scan, false);
// document.getElementById('encode').addEventListener('click', this.encode, false);
// document.getElementById('whitelist').addEventListener('click', this.whitelist, false);
        document.getElementById('camera').addEventListener('click', this.camera, false);
        document.getElementById('video').addEventListener('click', this.captureVideo, false);
        document.getElementById('audio').addEventListener('click', this.captureAudio, false);
        document.getElementById('getphoto').addEventListener('click', this.getphoto, false);
       // alert('after binding events');
    },

// // deviceready Event Handler
// //
// // The scope of `this` is the event. In order to call the `receivedEvent`
// // function, we must explicity call `app.receivedEvent(...);`
// onDeviceReady: function() {
// app.receivedEvent('deviceready');
// console.log('CORDOVA VERSION: ' + window.device.cordova);
// window.addEventListener('batterystatus', app.onBatteryStatus, false);
// },
// // Update DOM on a Received Event
// receivedEvent: function(id) {
// var parentElement = document.getElementById(id);
// var listeningElement = parentElement.querySelector('.listening');
// var receivedElement = parentElement.querySelector('.received');
//
// listeningElement.setAttribute('style', 'display:none;');
// receivedElement.setAttribute('style', 'display:block;');
//
// console.log('Received Event: ' + id);
// },
// onBatteryStatus: function(info) {
// console.log("Level: " + info.level + " isPlugged: " + info.isPlugged);
// },
// scan: function() {
// console.log('scanning');
// var scanner = cordova.require("cordova/plugin/BarcodeScanner");
//
// scanner.scan( function (result) {
//
// alert("We got a barcode\n" +
// "Result: " + result.text + "\n" +
// "Format: " + result.format + "\n" +
// "Cancelled: " + result.cancelled);
//
// console.log("Scanner result: \n" +
// "text: " + result.text + "\n" +
// "format: " + result.format + "\n" +
// "cancelled: " + result.cancelled + "\n");
// document.getElementById("info").innerHTML = result.text;
// console.log(result);
// /*
// if (args.format == "QR_CODE") {
// window.plugins.childBrowser.showWebPage(args.text, { showLocationBar: false });
// }
// */
//
// }, function (error) {
// console.log("Scanning failed: ", error);
// } );
// },
//
// encode: function() {
// var scanner = cordova.require("cordova/plugin/BarcodeScanner");
//
// scanner.encode(scanner.Encode.TEXT_TYPE, "http://www.nhl.com", function(success) {
// alert("encode success: " + success);
// }, function(fail) {
// alert("encoding failed: " + fail);
// }
// );
//
// },
//
// whitelist: function() {
//
// app.xhr("https://tv.eurosport.com/", function(xhr) {
// console.log("eurosport is invalid " + xhr.status);
// console.log("eurosport: " + xhr.responseText.substring(0, 100));
// });
// /*
// app.xhr("http://ajax.googleapis.com/ajax/libs/prototype/1.7.1.0/prototype.js", function(xhr) {
// console.log("googleapis: should succeed: " + xhr.status);
// console.log("googleapis: " + xhr.responseText.substring(0, 100));
// });
//
// app.xhr("http://code.jquery.com/jquery-1.10.2.min.js", function(xhr) {
// console.log("jquery: should fail: " + xhr.status);
// console.log("jquery: " + xhr.responseText.substring(0, 100));
// });
//
// app.xhr("http://phonegap.com", function(xhr) {
// console.log("phonegap: should fail: " + xhr.status);
// console.log("phonegap: " + xhr.responseText.substring(0, 100));
// });
//
// app.xhr("http://googleapis.com", function(xhr) {
// console.log("googleapis.com: should succeed: " + xhr.status);
// console.log("googleapis.com: " + xhr.responseText.substring(0, 100));
// });
//
// app.xhr("http://jquery.com", function(xhr) {
// console.log("jquery.com: should succeed: " + xhr.status);
// console.log("jquery.com: " + xhr.responseText.substring(0, 100));
// });
// */
//
// },

    camera: function() {
        function onSuccessURI(imageURI) {

            var options = new FileUploadOptions();
            options.fileKey="file";
            options.fileName=imageURI.substr(imageURI.lastIndexOf('/')+1);
            options.mimeType="image/jpeg";

            var params = {};
            params.value1 = "test";
            params.value2 = "param";

            options.params = params;

            var ft = new FileTransfer();
            ft.upload(imageURI, encodeURI("http://216.74.49.91:8080/tssvc/resourcesS/upload"), fileok, filefail, options);

        }
        function onSuccess(imageData) {
            //console.log('success');

            // AT: the old code
            //
            document.getElementById('testMsg').value = "in onSuccess";

            //Anna
            //var image = document.getElementById('myImage');
            //image.src = "data:image/jpeg;base64," + imageData;

            var smallImage = document.getElementById('smallImage');

            // Unhide image elements
            //
            smallImage.style.display = 'block';

            // Show the captured photo
            // The inline CSS rules are used to resize the image
            //
            smallImage.src = "data:image/jpeg;base64," + imageData;

            // Get image handle
            //
            var largeImage = document.getElementById('largeImage');

            // Unhide image elements
            //
            largeImage.style.display = 'block';
            largeImage.src = "data:image/jpeg;base64," + imageData;

        }

        function onFail(message) {
            console.log('failed');
        }
        var cameraPopoverOptions = new CameraPopoverOptions(220, 600, 320, 480, Camera.PopoverArrowDirection.ARROW_DOWN) ;
        var cameraHandle = navigator.camera.getPicture(onSuccessURI, onFail, { quality: 10, targetWidth: 100, targetHeight: 100,
            saveToPhotoAlbum: true,
            destinationType: Camera.DestinationType.FILE_URI, popoverOptions:cameraPopoverOptions
        });
        //cameraHandle.setPosition(cameraPopoverOptions);
        function fileok(r) {
            document.getElementById('testMsg').value = "Success. Code = " + r.responseCode + " Resposne = " + r.response + " sent = " + r.byteSent;
            //console.log("Response = " + r.response);
            //console.log("Sent = " + r.bytesSent);
        }

        function filefail(error) {
            document.getElementById('testMsg').value = "Error. Code = " + error.code + " source = " + error.source + " target = " + error.target;
            //alert("An error has occurred: Code = " + error.code);
            //console.log("upload error source " + error.source);
            //console.log("upload error target " + error.target);
        }

    },

    getphoto: function() {

        function onSuccess(imageData) {
            //console.log('success');

            document.getElementById('testMsg').value = "in onSuccess";

            //Anna
            //var image = document.getElementById('myImage');
            //image.src = "data:image/jpeg;base64," + imageData;

            var smallImage = document.getElementById('smallImage');

            // Unhide image elements
            //
            smallImage.style.display = 'block';

            // Show the captured photo
            // The inline CSS rules are used to resize the image
            //
            smallImage.src = "data:image/jpeg;base64," + imageData;

            // Get image handle
            //
            var largeImage = document.getElementById('largeImage');

            // Unhide image elements
            //
            largeImage.style.display = 'block';
            largeImage.src = "data:image/jpeg;base64," + imageData;

        }

        function onFail(message) {
            console.log('failed');
        }

        navigator.camera.getPicture(onSuccess, onFail, { quality: 50, saveToPhotoAlbum: true,
            destinationType: Camera.DestinationType.DATA_URL,sourceType: Camera.PictureSourceType.PHOTOLIBRARY,
            mediaType: Camera.MediaType.ALLMEDIA
        });

    },

    xhr: function(url, cb) {
        var xhr1 = new XMLHttpRequest();
        xhr1.onreadystatechange = function(args) {
            if(xhr1.readyState==4)
                cb(xhr1);
        };
        xhr1.open("GET", url, true);
        xhr1.send();
    },

    captureVideo: function() {
        navigator.device.capture.captureVideo(function(mediaFiles)
            {
                console.log('CALLBACK!');
                console.log(JSON.stringify(mediaFiles));
            }, function(error)
            {
                console.log('Video capture failed');
                alert ('video failed');
            },
            {
                limit: 1,
                duration: 12
            });

    },

 /*   // Record audio
//
     recordAudio: function() {
    var src = "myrecording.wav";
    var mediaRec = new Media(src,
        // success callback
        function() {
            console.log("recordAudio():Audio Success");
            alert('audio success');
        },

        // error callback
        function(err) {
            console.log("recordAudio():Audio Error: "+ err.code);
        }
    );

    // Record audio
    mediaRec.startRecord();

    // Stop recording after 10 seconds
    setTimeout(function() {
        mediaRec.stopRecord();
    }, 10000);
}*/

    captureAudio: function() {

        // Called when capture operation is finished
        //
        function captureSuccess(mediaFiles) {

            alert ('audio success');
            var i, len;
            for (i = 0, len = mediaFiles.length; i < len; i += 1) {
                uploadFile(mediaFiles[i]);
            }

        }

        // Called if something bad happens.
        //
        function captureError(error) {
            var msg = 'An error occurred during capture: ' + error.code;
            navigator.notification.alert(msg, null, 'Uh oh!');
        }

        navigator.device.capture.captureAudio(function(mediaFiles)
            {
                console.log('CALLBACK!');
                console.log(JSON.stringify(mediaFiles));
            }, function(error)
            {
                console.log('Audio capture failed');
            },
            {
                limit: 1,
                duration: 12
            });

        // Upload files to server
//        function uploadFile(mediaFile) {
//            var ft = new FileTransfer(),
//                path = mediaFile.fullPath,
//                name = mediaFile.name;
//
//            ft.upload(path,
//                "http://my.domain.com/upload.php",
//                function(result) {
//                    console.log('Upload success: ' + result.responseCode);
//                    console.log(result.bytesSent + ' bytes sent');
//                },
//                function(error) {
//                    console.log('Error uploading file ' + path + ': ' + error.code);
//                },
//                { fileName: name });
//        }

    }
};

<commit_msg>add upload for file picker<commit_after>/**
 * Created with IntelliJ IDEA.
 * User: tparmer
 * Date: 11/27/13
 * Time: 12:21 PM
 * To change this template use File | Settings | File Templates.
 */

var serviceURL = "http://216.74.49.91:8080/tssvc/resourcesS/stories/";
//var serviceURL = "http://localhost:8080/tssvc/resourcesS/stories";
//var serviceURL = "http://localhost:8080/tssvc/getstorylist2.html";

//var employees;
//var stories;

$('#mediaPage').bind('pagebeforecreate', function(event) {
    //alert('bind: pagebeforecreate');
    //getEmployeeList();
});
$('#mediaPage').bind('pagecreate', function(event) {
   // alert('bind: pagecreate');
    //getEmployeeList();
});

$('#mediaPage').bind('pageinit', function(event) {
    //alert('bind: pageinit');
    //getEmployeeList();
});

$('#mediaPage').live('pageinit', function(event) {
    //alert('live: pageinit');
    app.initialize();
   // alert('live: after app.init');
    //getEmployeeList();
});
$('#mediaPage').bind('pagebeforeload', function(event) {
   // alert('bind: pagebeforeload');
    //getEmployeeList();
});

$('#mediaPage').bind('pageload', function(event) {
   // alert('bind: pageload');
    //getEmployeeList();
});

$('#mediaPage').bind('pagebeforeshow', function(event) {
   // alert('bind: pagebeforeshow');
    //getEmployeeList();
});

$('#mediaPage').bind('pageshow', function(event) {
    //alert('bind: pageshow');
    //getEmployeeList();
});
$('#mediaPage').bind('pagebeforechange', function(event) {
    //alert('bind: pagebeforeshow');
    //getEmployeeList();
});

$('#mediaPage').bind('pagechange', function(event) {
   // alert('bind: pageshow');
    //getEmployeeList();
});

var app = {
    // Application Constructor
    initialize: function() {
        this.bindEvents();
    },
    // Bind Event Listeners
    //
    // Bind any events that are required on startup. Common events are:
    // `load`, `deviceready`, `offline`, and `online`.
    bindEvents: function() {
       // alert('before binding events');
// document.addEventListener('deviceready', this.onDeviceReady, false);
// document.getElementById('scan').addEventListener('click', this.scan, false);
// document.getElementById('encode').addEventListener('click', this.encode, false);
// document.getElementById('whitelist').addEventListener('click', this.whitelist, false);
        document.getElementById('camera').addEventListener('click', this.camera, false);
        document.getElementById('video').addEventListener('click', this.captureVideo, false);
        document.getElementById('audio').addEventListener('click', this.captureAudio, false);
        document.getElementById('getphoto').addEventListener('click', this.getphoto, false);
       // alert('after binding events');
    },

// // deviceready Event Handler
// //
// // The scope of `this` is the event. In order to call the `receivedEvent`
// // function, we must explicity call `app.receivedEvent(...);`
// onDeviceReady: function() {
// app.receivedEvent('deviceready');
// console.log('CORDOVA VERSION: ' + window.device.cordova);
// window.addEventListener('batterystatus', app.onBatteryStatus, false);
// },
// // Update DOM on a Received Event
// receivedEvent: function(id) {
// var parentElement = document.getElementById(id);
// var listeningElement = parentElement.querySelector('.listening');
// var receivedElement = parentElement.querySelector('.received');
//
// listeningElement.setAttribute('style', 'display:none;');
// receivedElement.setAttribute('style', 'display:block;');
//
// console.log('Received Event: ' + id);
// },
// onBatteryStatus: function(info) {
// console.log("Level: " + info.level + " isPlugged: " + info.isPlugged);
// },
// scan: function() {
// console.log('scanning');
// var scanner = cordova.require("cordova/plugin/BarcodeScanner");
//
// scanner.scan( function (result) {
//
// alert("We got a barcode\n" +
// "Result: " + result.text + "\n" +
// "Format: " + result.format + "\n" +
// "Cancelled: " + result.cancelled);
//
// console.log("Scanner result: \n" +
// "text: " + result.text + "\n" +
// "format: " + result.format + "\n" +
// "cancelled: " + result.cancelled + "\n");
// document.getElementById("info").innerHTML = result.text;
// console.log(result);
// /*
// if (args.format == "QR_CODE") {
// window.plugins.childBrowser.showWebPage(args.text, { showLocationBar: false });
// }
// */
//
// }, function (error) {
// console.log("Scanning failed: ", error);
// } );
// },
//
// encode: function() {
// var scanner = cordova.require("cordova/plugin/BarcodeScanner");
//
// scanner.encode(scanner.Encode.TEXT_TYPE, "http://www.nhl.com", function(success) {
// alert("encode success: " + success);
// }, function(fail) {
// alert("encoding failed: " + fail);
// }
// );
//
// },
//
// whitelist: function() {
//
// app.xhr("https://tv.eurosport.com/", function(xhr) {
// console.log("eurosport is invalid " + xhr.status);
// console.log("eurosport: " + xhr.responseText.substring(0, 100));
// });
// /*
// app.xhr("http://ajax.googleapis.com/ajax/libs/prototype/1.7.1.0/prototype.js", function(xhr) {
// console.log("googleapis: should succeed: " + xhr.status);
// console.log("googleapis: " + xhr.responseText.substring(0, 100));
// });
//
// app.xhr("http://code.jquery.com/jquery-1.10.2.min.js", function(xhr) {
// console.log("jquery: should fail: " + xhr.status);
// console.log("jquery: " + xhr.responseText.substring(0, 100));
// });
//
// app.xhr("http://phonegap.com", function(xhr) {
// console.log("phonegap: should fail: " + xhr.status);
// console.log("phonegap: " + xhr.responseText.substring(0, 100));
// });
//
// app.xhr("http://googleapis.com", function(xhr) {
// console.log("googleapis.com: should succeed: " + xhr.status);
// console.log("googleapis.com: " + xhr.responseText.substring(0, 100));
// });
//
// app.xhr("http://jquery.com", function(xhr) {
// console.log("jquery.com: should succeed: " + xhr.status);
// console.log("jquery.com: " + xhr.responseText.substring(0, 100));
// });
// */
//
// },

    camera: function() {
        function onSuccessURI(imageURI) {

            var options = new FileUploadOptions();
            options.fileKey="file";
            options.fileName=imageURI.substr(imageURI.lastIndexOf('/')+1);
            options.mimeType="image/jpeg";

            var params = {};
            params.value1 = "test";
            params.value2 = "param";

            options.params = params;

            var ft = new FileTransfer();
            ft.upload(imageURI, encodeURI("http://216.74.49.91:8080/tssvc/resourcesS/upload"), fileok, filefail, options);

        }
        function onSuccess(imageData) {
            //console.log('success');

            // AT: the old code
            //
            document.getElementById('testMsg').value = "in onSuccess";

            //Anna
            //var image = document.getElementById('myImage');
            //image.src = "data:image/jpeg;base64," + imageData;

            var smallImage = document.getElementById('smallImage');

            // Unhide image elements
            //
            smallImage.style.display = 'block';

            // Show the captured photo
            // The inline CSS rules are used to resize the image
            //
            smallImage.src = "data:image/jpeg;base64," + imageData;

            // Get image handle
            //
            var largeImage = document.getElementById('largeImage');

            // Unhide image elements
            //
            largeImage.style.display = 'block';
            largeImage.src = "data:image/jpeg;base64," + imageData;

        }

        function onFail(message) {
            console.log('failed');
        }
        var cameraPopoverOptions = new CameraPopoverOptions(220, 600, 320, 480, Camera.PopoverArrowDirection.ARROW_DOWN) ;
        var cameraHandle = navigator.camera.getPicture(onSuccessURI, onFail, { quality: 10, targetWidth: 100, targetHeight: 100,
            saveToPhotoAlbum: true,
            destinationType: Camera.DestinationType.FILE_URI, popoverOptions:cameraPopoverOptions
        });
        //cameraHandle.setPosition(cameraPopoverOptions);
        function fileok(r) {
            document.getElementById('testMsg').value = "Success. Code = " + r.responseCode + " Resposne = " + r.response + " sent = " + r.byteSent;
            //console.log("Response = " + r.response);
            //console.log("Sent = " + r.bytesSent);
        }

        function filefail(error) {
            document.getElementById('testMsg').value = "Error. Code = " + error.code + " source = " + error.source + " target = " + error.target;
            //alert("An error has occurred: Code = " + error.code);
            //console.log("upload error source " + error.source);
            //console.log("upload error target " + error.target);
        }

    },

    getphoto: function() {
        function onSuccessURI(imageURI) {

            var options = new FileUploadOptions();
            options.fileKey="file";
            options.fileName=imageURI.substr(imageURI.lastIndexOf('/')+1);
            options.mimeType="image/jpeg";

            var params = {};
            params.value1 = "test";
            params.value2 = "param";

            options.params = params;

            var ft = new FileTransfer();
            ft.upload(imageURI, encodeURI("http://216.74.49.91:8080/tssvc/resourcesS/upload"), fileok, filefail, options);

        }

        function onSuccess(imageData) {
            //console.log('success');

            document.getElementById('testMsg').value = "in onSuccess";

            //Anna
            //var image = document.getElementById('myImage');
            //image.src = "data:image/jpeg;base64," + imageData;

            var smallImage = document.getElementById('smallImage');

            // Unhide image elements
            //
            smallImage.style.display = 'block';

            // Show the captured photo
            // The inline CSS rules are used to resize the image
            //
            smallImage.src = "data:image/jpeg;base64," + imageData;

            // Get image handle
            //
            var largeImage = document.getElementById('largeImage');

            // Unhide image elements
            //
            largeImage.style.display = 'block';
            largeImage.src = "data:image/jpeg;base64," + imageData;

        }

        function onFail(message) {
            console.log('failed');
        }

        navigator.camera.getPicture(onSuccessURI, onFail, { quality: 10, saveToPhotoAlbum: true,
            targetWidth: 100, targetHeight: 100,
            destinationType: Camera.DestinationType.FILE_URI,sourceType: Camera.PictureSourceType.PHOTOLIBRARY,
            mediaType: Camera.MediaType.ALLMEDIA
        });

    },

    xhr: function(url, cb) {
        var xhr1 = new XMLHttpRequest();
        xhr1.onreadystatechange = function(args) {
            if(xhr1.readyState==4)
                cb(xhr1);
        };
        xhr1.open("GET", url, true);
        xhr1.send();
    },

    captureVideo: function() {
        navigator.device.capture.captureVideo(function(mediaFiles)
            {
                console.log('CALLBACK!');
                console.log(JSON.stringify(mediaFiles));
            }, function(error)
            {
                console.log('Video capture failed');
                alert ('video failed');
            },
            {
                limit: 1,
                duration: 12
            });

    },

 /*   // Record audio
//
     recordAudio: function() {
    var src = "myrecording.wav";
    var mediaRec = new Media(src,
        // success callback
        function() {
            console.log("recordAudio():Audio Success");
            alert('audio success');
        },

        // error callback
        function(err) {
            console.log("recordAudio():Audio Error: "+ err.code);
        }
    );

    // Record audio
    mediaRec.startRecord();

    // Stop recording after 10 seconds
    setTimeout(function() {
        mediaRec.stopRecord();
    }, 10000);
}*/

    captureAudio: function() {

        // Called when capture operation is finished
        //
        function captureSuccess(mediaFiles) {

            alert ('audio success');
            var i, len;
            for (i = 0, len = mediaFiles.length; i < len; i += 1) {
                uploadFile(mediaFiles[i]);
            }

        }

        // Called if something bad happens.
        //
        function captureError(error) {
            var msg = 'An error occurred during capture: ' + error.code;
            navigator.notification.alert(msg, null, 'Uh oh!');
        }

        navigator.device.capture.captureAudio(function(mediaFiles)
            {
                console.log('CALLBACK!');
                console.log(JSON.stringify(mediaFiles));
            }, function(error)
            {
                console.log('Audio capture failed');
            },
            {
                limit: 1,
                duration: 12
            });

        // Upload files to server
//        function uploadFile(mediaFile) {
//            var ft = new FileTransfer(),
//                path = mediaFile.fullPath,
//                name = mediaFile.name;
//
//            ft.upload(path,
//                "http://my.domain.com/upload.php",
//                function(result) {
//                    console.log('Upload success: ' + result.responseCode);
//                    console.log(result.bytesSent + ' bytes sent');
//                },
//                function(error) {
//                    console.log('Error uploading file ' + path + ': ' + error.code);
//                },
//                { fileName: name });
//        }

    }
};

<|endoftext|>


<commit_before>// KSP Aerobraking Calculator
$(document).ready(function() {
(function() {

	this.mkPlanet = function(Rmin, Ratm, SOI, mu, H0, P0) {
		return {
			Rmin: Rmin,	// Radius of planet (distance to surface from center)
			Ratm: Ratm+Rmin,	// Simplifies calculations later
			SOI: SOI,	// Radius of sphere of influence of planet
			mu: mu,	// Grav. parameter
			H0: H0,	// Scale height of atmosphere (P falls off by 1/e for each H0)
			P0: P0	// Pressure at zero altitude.
		};
	};

	this.Planets = {
		Eve: mkPlanet(700000,107974.64,85109365,8.1717302e12,7000,5),
		Kerbin: mkPlanet(600000,69077.553,84159286,3.5316e12,5000,1),
		Duna: mkPlanet(320000,36618.218,47921949,301363210000,3000,0.2),
		Jool: mkPlanet(6000000,165235.61,2455985200,2.82528e14,10000,15),
		Laythe: mkPlanet(500000,55262.042,3723645.8,1.962e12,4000,0.8)
	};

	var sign = function(x) { return x > 0 ? 1 : x < 0 ? -1 : 0; }

	// Simple (and UGLY) vector math implementation
	this.vmult = function( k, v ) {
		var ret = new Array();
		for (var i = 0; i < v.length; ++i) {ret[i] = v[i]*k;}
		return ret;
	};
	this.vsum = function() {
		var ret = new Array();
		for (var i = 0; i < arguments[0].length; ++i) {
			ret[i] = 0;
			for (var j = 0; j < arguments.length; ++j) {
				ret[i] += arguments[j][i];
			}
		}
		return ret;
	};
	this.vdiff = function( a, b ) {
		var ret = new Array();
		for (var i = 0; i < a.length; ++i) {ret[i] = a[i] - b[i];}
		return ret;
	};
	this.vnorm = function( v ) {
		var norm = 0;
		for (var i = 0; i < v.length; ++i) {norm += v[i]*v[i];}
		return Math.sqrt(norm);
	};
	this.vdot = function( a, b ) {
		var ret = 0;
		for (var i = 0; i < a.length; ++i) ret += a[i]*b[i];
		return ret;
	};
	this.vcross2d = function( a, b ) {	// Cross [a0 a1 0] with [b0 b1 0]
		return a[0]*b[1] - a[1]*b[0];
	};
	this.vec2 = function( x, y ) {
		return [x, y];
	};

	// Method of bisection for root finding
	this.fzero = function( f, Ain, Bin, Tol, Nmax ) {
		Tol = typeof Tol !== 'undefined' ? Tol : 1e-2;	// This is tiny relative to the values involved!
		Nmax = typeof Nmax !== 'undefined' ? Nmax : 1000;
		var N = 1;
		var a = Ain;
		var b = Bin;
		var c;
		var fc;
		var fa = f(a);
		while (N < Nmax) {
			c = (a+b)/2;
			fc = f(c);	// Don't want to re-evaluate this -- it's expensive!
			if (fc == 0|| (b-a)/2<Tol) return c;
			N = N + 1;
			if (sign(fc) == sign(fa)) {
				a = c;
				fa = fc;
			} else {
				b = c;
			}
		}
		console.log('Bisection failed!');
	};

	// Physics integrator
	// Velocity-Verlet with Velocity-dependent forces
	// Terminates once atmosphere is breached OR if impact occurs.
	this.integrate_path = function( F, m, r0, v0, dt, Planet ) {
		var t = 0;
		var r = r0;
		var v = v0;

		var a = function(rin, vin) { return vmult(1/m, F(rin, vin)); };

		firstrun = true;

		var rold;
		var vold;
		var vest;
		var a_t;

		while (firstrun || (vnorm(r) <= Planet.Ratm && vnorm(r) >= Planet.Rmin)) {
			rold = r;
			vold = v;
			a_t = a(rold, vold);
			r = vsum(rold, vmult(dt, vold), vmult(0.5*dt*dt, a_t));
			vest = vsum(vold, vmult(0.5*dt, vsum(a_t,a(r,vsum(vold,vmult(dt,a_t))))));
			v = vsum(vold, vmult(0.5*dt,vsum(a_t,a(r,vest))));
			t = t + dt;
			firstrun = false;
		}

		return {rf:r, vf:v, tf:t};
	};

	//console.log(integrate_path(my_F, 1, [0, 10], [0, 0], 0.0001, {Rmin:0, Ratm:10000}));

	// Get orbit parameters in the plane of orbit
	var get_orbit_params = function( r, v, Planet ) {
		// sp. orbital energy
		var ep = vdot(v,v)/2 - Planet.mu/vnorm(r);
		// sp. angular momentum
		var hmag = vcross2d(r,v);

		// eccentricity
		var ec = Math.sqrt(1+2*ep*hmag*hmag/Planet.mu/Planet.mu);

		// semi-major axis
		var a = -Planet.mu/(2*ep);

		// Periapse distance
		var rpe = -a*(ec-1);

		// Apoapse distance
		var rap = (1+ec)*a;

		return {ep: ep, ec: ec, a: a, hmag: hmag, rpe: rpe, rap: rap};
	};

	// Net force in atmosphere
	var in_atmo_force = function(d, m, A, Planet) {
		Kp = 1.2230948554874*0.008;
		return function(r,v) {return vsum(vmult(-0.5*Kp*Planet.P0*Math.exp((Planet.Rmin-vnorm(r))/Planet.H0)*vnorm(v)*d*m*A, v), vmult(-m*Planet.mu/Math.pow(vnorm(r),3), r));};
	};

	var calc1 = function(dist, vx, vy, d, Planet) {
		var r0 = [dist, 0];
		var v0 = [vx, vy];
		var dt = 1;
		var m = 1;
		var A = 1;

		var rap_out = 0;

		var p1 = get_orbit_params( r0, v0, Planet );

		// Short-circuit tests
		if (p1.rpe < Planet.Rmin) {
			// Initial suborbital
			rap_out = Planet.Rmin;	// Technically right!
			return rap_out;
		}
		else if (p1.ep >= 0 && p1.rpe > Planet.Ratm) {
			// Initial hyperbolic (or parabolic) escape
			rap_out = Planet.SOI+1;	// Still technically right . . .
			return rap_out;
		}
		else if (p1.ep < 0 && p1.rpe > Planet.Ratm) {
			if (p1.rap < Planet.SOI) {
				// Initial stable, no atmosphere entry
				rap_out = p1.rap;
				return rap_out;
			} else {
				// Initial ep<0 SOI escape
				rap_out = Planet.SOI+1;
				return rap_out;
			}
		}
		// If we've made it this far, we're hitting the atmosphere without guarantee of impact!
		//console.log(Planet);
		// Angle from periapsis at which we contact the atmosphere.
		var theta_contact = Math.acos((1/p1.ec)*(p1.a*(1-p1.ec*p1.ec)/Planet.Ratm-1));
		// Magnitude of velocity when contacting atmosphere
		var vcontact_mag = Math.sqrt(2*(p1.ep+Planet.mu/Planet.Ratm));

		// Use conservation of angular momentum to find angle between velocity and radial position
		var theta_1 = Math.asin(p1.hmag/(Planet.Ratm*vcontact_mag));

		var rcontact = vmult(Planet.Ratm, [Math.cos(theta_contact), Math.sin(theta_contact)]);

		// The sines and cosines here have been chosen to give the velocity as [vr, vtheta]
		var vcontact = vmult(vcontact_mag, [-Math.cos(theta_1+theta_contact), -Math.sin(theta_1+theta_contact)]);

		var F = in_atmo_force( d, m, A, Planet );

		// Integrate path in atmosphere.
		var rvt = integrate_path(F, m, rcontact, vcontact, dt, Planet);
		//console.log(rvt.rf);
		//console.log('Aero-encounter!');
		if (vnorm(rvt.rf) >= Planet.Rmin) {// If not, we've impacted!
			var p2 = get_orbit_params(rvt.rf, rvt.vf, Planet);
			if (p2.ep < 0) {
				rap_out = (1+p2.ec)*p2.a;	// Tentative apoapse distance
				if (rap_out > Planet.SOI) { // Post aerobrake SOI escape!
					rap_out = Planet.SOI+1;
					return rap_out;
				}
				//console.log('Capture!');
			} else {
				rap_out = Planet.SOI+1;	// Parabolic or hyperbolic escape
				//console.log('Escape!');
				return rap_out;
			}
		} else {
			// Impact!
			//console.log('Impact!');
			rap_out = Planet.Rmin;
			return rap_out;
		}
		return rap_out;
	};
	//console.log(calc1(1200000,-800,1540,0.2,Planets.Kerbin));

	// Perform calculations for a given r (scalar), v (scalar), rpe (scalar)
	var calc_pe = function( r, v, rpe, d, Planet ) {
		var vy = (rpe/r)*Math.sqrt(v*v+2*Planet.mu*(1/rpe-1/r));
		var vx = Math.sqrt(v*v-vy*vy);
		var ap = calc1(r, vx, vy, d, Planet);
		return ap;
	};

	var parseUnitFloat = function(v) {
		var v = v.toLowerCase();
		var value = parseFloat(v);
		if (v.indexOf("mm") !== -1) {
			return value * 1000000
		} else if (v.indexOf("km") !== -1) {
			return value * 1000;
		} else {
			return value;
		}
	};

	// Main function
	// r is scalar (distance from centre of planet)
	// v is scalar (magnitude of orbital velocity)
	// rpe is scalar (periapse distance)
	// We search for a constant-velocity solution to this problem.
	var solve = function( r, v, rpe, targ, d, Planet ) {
		var vy = (rpe/r)*Math.sqrt(v*v+2*Planet.mu*(1/rpe-1/r));
		var vx = Math.sqrt(v*v-vy*vy);

		var c_ap = function(pe) {return calc_pe(r,v,pe,d,Planet)-targ};

		var new_pe = fzero(c_ap,Planet.Rmin, Planet.Ratm);

		var vy1 = (new_pe/r)*Math.sqrt(v*v+2*Planet.mu*(1/new_pe-1/r));
		var vx1 = Math.sqrt(v*v-vy1*vy1);

		var dv = vnorm(vdiff([vx1, vy1], [vx, vy]));
		var dvtheta = Math.atan2(vy1-vy,vx1-vx);

		if (isNaN(dv) || isNaN(dvtheta) || isNaN(vnorm([vx1, vy1]))) {
			$('#inputAlt').parent().parent().addClass('error');
			$('#inputVel').parent().parent().addClass('error');
			$('#inputPE').parent().parent().addClass('error');
			$('#inputAP').parent().parent().addClass('error');

			$('#outputPE').val('No Solution!');
			$('#outputDV').val('No Solution!');
			$('#outputAng').val('No Solution!');
			$('#outputVel2').val('No Solution!');

			return;
		}

		$('#outputPE').val((new_pe-Planet.Rmin).toFixed(2));
		$('#outputDV').val(dv.toFixed(2));
		$('#outputAng').val((dvtheta*180/Math.PI).toFixed(2));
		$('#outputVel2').val((vnorm([vx1, vy1])).toFixed(2));
	};
	//solve(5600000 ,364.9,660000 , 1600000 , 0.2, Planets.Kerbin);
	var that = this;

	$('#go').click(function() {

		$('#inputAlt').parent().parent().removeClass('error');
		$('#inputVel').parent().parent().removeClass('error');
		$('#inputPE').parent().parent().removeClass('error');
		$('#inputAP').parent().parent().removeClass('error');

		var Planet = that.Planets[$('#inputBody').val()];
		var r = parseUnitFloat($('#inputAlt').val(), 10)+Planet.Rmin;
		var v = parseFloat($('#inputVel').val(), 10);
		var pe = parseUnitFloat($('#inputPE').val(), 10)+Planet.Rmin;

		var d = parseFloat($('#inputD').val(), 10);

		var target = parseUnitFloat($('#inputAP').val(), 10)+Planet.Rmin;

		solve(r,v,pe,target,d,Planet);
		//solve(5600000 ,364.9,660000 , 1600000 , 0.2, Planets.Kerbin);
	});
	return this;
})();
});
<commit_msg>Add semicolon, comments.<commit_after>// KSP Aerobraking Calculator
$(document).ready(function() {
(function() {

	this.mkPlanet = function(Rmin, Ratm, SOI, mu, H0, P0) {
		return {
			Rmin: Rmin,	// Radius of planet (distance to surface from center)
			Ratm: Ratm+Rmin,	// Simplifies calculations later
			SOI: SOI,	// Radius of sphere of influence of planet
			mu: mu,	// Grav. parameter
			H0: H0,	// Scale height of atmosphere (P falls off by 1/e for each H0)
			P0: P0	// Pressure at zero altitude.
		};
	};

	this.Planets = {
		Eve: mkPlanet(700000,107974.64,85109365,8.1717302e12,7000,5),
		Kerbin: mkPlanet(600000,69077.553,84159286,3.5316e12,5000,1),
		Duna: mkPlanet(320000,36618.218,47921949,301363210000,3000,0.2),
		Jool: mkPlanet(6000000,165235.61,2455985200,2.82528e14,10000,15),
		Laythe: mkPlanet(500000,55262.042,3723645.8,1.962e12,4000,0.8)
	};

	var sign = function(x) { return x > 0 ? 1 : x < 0 ? -1 : 0; }

	// Simple (and UGLY) vector math implementation
	this.vmult = function( k, v ) {
		var ret = new Array();
		for (var i = 0; i < v.length; ++i) {ret[i] = v[i]*k;}
		return ret;
	};
	this.vsum = function() {
		var ret = new Array();
		for (var i = 0; i < arguments[0].length; ++i) {
			ret[i] = 0;
			for (var j = 0; j < arguments.length; ++j) {
				ret[i] += arguments[j][i];
			}
		}
		return ret;
	};
	this.vdiff = function( a, b ) {
		var ret = new Array();
		for (var i = 0; i < a.length; ++i) {ret[i] = a[i] - b[i];}
		return ret;
	};
	this.vnorm = function( v ) {
		var norm = 0;
		for (var i = 0; i < v.length; ++i) {norm += v[i]*v[i];}
		return Math.sqrt(norm);
	};
	this.vdot = function( a, b ) {
		var ret = 0;
		for (var i = 0; i < a.length; ++i) ret += a[i]*b[i];
		return ret;
	};
	this.vcross2d = function( a, b ) {	// Cross [a0 a1 0] with [b0 b1 0]
		return a[0]*b[1] - a[1]*b[0];
	};
	this.vec2 = function( x, y ) {
		return [x, y];
	};

	// Method of bisection for root finding
	this.fzero = function( f, Ain, Bin, Tol, Nmax ) {
		Tol = typeof Tol !== 'undefined' ? Tol : 1e-2;	// This is tiny relative to the values involved!
		Nmax = typeof Nmax !== 'undefined' ? Nmax : 1000;
		var N = 1;
		var a = Ain;
		var b = Bin;
		var c;
		var fc;
		var fa = f(a);
		while (N < Nmax) {
			c = (a+b)/2;
			fc = f(c);	// Don't want to re-evaluate this -- it's expensive!
			if (fc == 0|| (b-a)/2<Tol) return c;
			N = N + 1;
			if (sign(fc) == sign(fa)) {
				a = c;
				fa = fc;
			} else {
				b = c;
			}
		}
		console.log('Bisection failed!');
	};

	// Physics integrator
	// Velocity-Verlet with Velocity-dependent forces
	// Terminates once atmosphere is breached OR if impact occurs.
	this.integrate_path = function( F, m, r0, v0, dt, Planet ) {
		var t = 0;
		var r = r0;
		var v = v0;

		var a = function(rin, vin) { return vmult(1/m, F(rin, vin)); };

		firstrun = true;

		var rold;
		var vold;
		var vest;
		var a_t;

		while (firstrun || (vnorm(r) <= Planet.Ratm && vnorm(r) >= Planet.Rmin)) {
			rold = r;
			vold = v;
			a_t = a(rold, vold);
			r = vsum(rold, vmult(dt, vold), vmult(0.5*dt*dt, a_t));
			vest = vsum(vold, vmult(0.5*dt, vsum(a_t,a(r,vsum(vold,vmult(dt,a_t))))));
			v = vsum(vold, vmult(0.5*dt,vsum(a_t,a(r,vest))));
			t = t + dt;
			firstrun = false;
		}

		return {rf:r, vf:v, tf:t};
	};

	//console.log(integrate_path(my_F, 1, [0, 10], [0, 0], 0.0001, {Rmin:0, Ratm:10000}));

	// Get orbit parameters in the plane of orbit
	var get_orbit_params = function( r, v, Planet ) {
		// sp. orbital energy
		var ep = vdot(v,v)/2 - Planet.mu/vnorm(r);
		// sp. angular momentum
		var hmag = vcross2d(r,v);

		// eccentricity
		var ec = Math.sqrt(1+2*ep*hmag*hmag/Planet.mu/Planet.mu);

		// semi-major axis
		var a = -Planet.mu/(2*ep);

		// Periapse distance
		var rpe = -a*(ec-1);

		// Apoapse distance
		var rap = (1+ec)*a;

		return {ep: ep, ec: ec, a: a, hmag: hmag, rpe: rpe, rap: rap};
	};

	// Net force in atmosphere
	var in_atmo_force = function(d, m, A, Planet) {
		Kp = 1.2230948554874*0.008;
		return function(r,v) {return vsum(vmult(-0.5*Kp*Planet.P0*Math.exp((Planet.Rmin-vnorm(r))/Planet.H0)*vnorm(v)*d*m*A, v), vmult(-m*Planet.mu/Math.pow(vnorm(r),3), r));};
	};

	var calc1 = function(dist, vx, vy, d, Planet) {
		var r0 = [dist, 0];
		var v0 = [vx, vy];
		var dt = 1;
		var m = 1;
		var A = 1;

		var rap_out = 0;

		var p1 = get_orbit_params( r0, v0, Planet );

		// Short-circuit tests
		if (p1.rpe < Planet.Rmin) {
			// Initial suborbital
			rap_out = Planet.Rmin;	// Technically right!
			return rap_out;
		}
		else if (p1.ep >= 0 && p1.rpe > Planet.Ratm) {
			// Initial hyperbolic (or parabolic) escape
			rap_out = Planet.SOI+1;	// Still technically right . . .
			return rap_out;
		}
		else if (p1.ep < 0 && p1.rpe > Planet.Ratm) {
			if (p1.rap < Planet.SOI) {
				// Initial stable, no atmosphere entry
				rap_out = p1.rap;
				return rap_out;
			} else {
				// Initial ep<0 SOI escape
				rap_out = Planet.SOI+1;
				return rap_out;
			}
		}
		// If we've made it this far, we're hitting the atmosphere without guarantee of impact!
		//console.log(Planet);
		// Angle from periapsis at which we contact the atmosphere.
		var theta_contact = Math.acos((1/p1.ec)*(p1.a*(1-p1.ec*p1.ec)/Planet.Ratm-1));
		// Magnitude of velocity when contacting atmosphere
		var vcontact_mag = Math.sqrt(2*(p1.ep+Planet.mu/Planet.Ratm));

		// Use conservation of angular momentum to find angle between velocity and radial position
		var theta_1 = Math.asin(p1.hmag/(Planet.Ratm*vcontact_mag));

		var rcontact = vmult(Planet.Ratm, [Math.cos(theta_contact), Math.sin(theta_contact)]);

		// The sines and cosines here have been chosen to give the velocity as [vr, vtheta]
		var vcontact = vmult(vcontact_mag, [-Math.cos(theta_1+theta_contact), -Math.sin(theta_1+theta_contact)]);

		var F = in_atmo_force( d, m, A, Planet );

		// Integrate path in atmosphere.
		var rvt = integrate_path(F, m, rcontact, vcontact, dt, Planet);
		//console.log(rvt.rf);
		//console.log('Aero-encounter!');
		if (vnorm(rvt.rf) >= Planet.Rmin) {// If not, we've impacted!
			var p2 = get_orbit_params(rvt.rf, rvt.vf, Planet);
			if (p2.ep < 0) {
				rap_out = (1+p2.ec)*p2.a;	// Tentative apoapse distance
				if (rap_out > Planet.SOI) { // Post aerobrake SOI escape!
					rap_out = Planet.SOI+1;
					return rap_out;
				}
				//console.log('Capture!');
			} else {
				rap_out = Planet.SOI+1;	// Parabolic or hyperbolic escape
				//console.log('Escape!');
				return rap_out;
			}
		} else {
			// Impact!
			//console.log('Impact!');
			rap_out = Planet.Rmin;
			return rap_out;
		}
		return rap_out;
	};
	//console.log(calc1(1200000,-800,1540,0.2,Planets.Kerbin));

	// Perform calculations for a given r (scalar), v (scalar), rpe (scalar)
	var calc_pe = function( r, v, rpe, d, Planet ) {
		var vy = (rpe/r)*Math.sqrt(v*v+2*Planet.mu*(1/rpe-1/r));
		var vx = Math.sqrt(v*v-vy*vy);
		var ap = calc1(r, vx, vy, d, Planet);
		return ap;
	};

	// Allow (optional) use of units.
	var parseUnitFloat = function(v) {
		var v = v.toLowerCase();
		var value = parseFloat(v);
		if (v.indexOf("mm") !== -1) {
			return value * 1000000;
		} else if (v.indexOf("km") !== -1) {
			return value * 1000;
		} else {
			return value;
		}
	};

	// Main function
	// r is scalar (distance from centre of planet)
	// v is scalar (magnitude of orbital velocity)
	// rpe is scalar (periapse distance)
	// We search for a constant-velocity solution to this problem.
	var solve = function( r, v, rpe, targ, d, Planet ) {
		var vy = (rpe/r)*Math.sqrt(v*v+2*Planet.mu*(1/rpe-1/r));
		var vx = Math.sqrt(v*v-vy*vy);

		var c_ap = function(pe) {return calc_pe(r,v,pe,d,Planet)-targ};

		var new_pe = fzero(c_ap,Planet.Rmin, Planet.Ratm);

		var vy1 = (new_pe/r)*Math.sqrt(v*v+2*Planet.mu*(1/new_pe-1/r));
		var vx1 = Math.sqrt(v*v-vy1*vy1);

		var dv = vnorm(vdiff([vx1, vy1], [vx, vy]));
		var dvtheta = Math.atan2(vy1-vy,vx1-vx);

		if (isNaN(dv) || isNaN(dvtheta) || isNaN(vnorm([vx1, vy1]))) {
			$('#inputAlt').parent().parent().addClass('error');
			$('#inputVel').parent().parent().addClass('error');
			$('#inputPE').parent().parent().addClass('error');
			$('#inputAP').parent().parent().addClass('error');

			$('#outputPE').val('No Solution!');
			$('#outputDV').val('No Solution!');
			$('#outputAng').val('No Solution!');
			$('#outputVel2').val('No Solution!');

			return;
		}

		$('#outputPE').val((new_pe-Planet.Rmin).toFixed(2));
		$('#outputDV').val(dv.toFixed(2));
		$('#outputAng').val((dvtheta*180/Math.PI).toFixed(2));
		$('#outputVel2').val((vnorm([vx1, vy1])).toFixed(2));
	};
	//solve(5600000 ,364.9,660000 , 1600000 , 0.2, Planets.Kerbin);
	var that = this;

	$('#go').click(function() {

		$('#inputAlt').parent().parent().removeClass('error');
		$('#inputVel').parent().parent().removeClass('error');
		$('#inputPE').parent().parent().removeClass('error');
		$('#inputAP').parent().parent().removeClass('error');

		var Planet = that.Planets[$('#inputBody').val()];
		var r = parseUnitFloat($('#inputAlt').val(), 10)+Planet.Rmin;
		var v = parseFloat($('#inputVel').val(), 10);
		var pe = parseUnitFloat($('#inputPE').val(), 10)+Planet.Rmin;

		var d = parseFloat($('#inputD').val(), 10);

		var target = parseUnitFloat($('#inputAP').val(), 10)+Planet.Rmin;

		solve(r,v,pe,target,d,Planet);
		//solve(5600000 ,364.9,660000 , 1600000 , 0.2, Planets.Kerbin);
	});
	return this;
})();
});
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2013-2016 Memba Sarl. All rights reserved.
 * Sources at https://github.com/Memba
 */

/* jshint browser: true */
/* globals require: false, __NODE_ENV__: false */

if (typeof(require) === 'function') {
    // require('./window.assert');
    // require('./window.logger');
    // require('./app.logger.js');
    require('./app.config.jsx?env=' + __NODE_ENV__);
    require('./app.support.js');
}

/**
 * The application has <meta name="apple-mobile-web-app-capable" content="yes">
 * so to run the app ull screen when pinned to IOS home screen
 * The following prevents links from opening in a new safari window
 * Source: https://gist.github.com/irae/1042167
 */
(function(document,navigator,standalone) {
    // prevents links from apps from opening in mobile safari
    // this javascript must be the first script in your <head>
    if ((standalone in navigator) && navigator[standalone]) {
        var curnode, location=document.location, stop=/^(a|html)$/i;
        document.addEventListener('click', function(e) {
            curnode=e.target;
            while (!(stop).test(curnode.nodeName)) {
                curnode=curnode.parentNode;
            }
            // Conditions to do this only on links to your own app
            // if you want all links, use if('href' in curnode) instead.
            if(
                'href' in curnode && // is a link
                (chref=curnode.href).replace(location.href,'').indexOf('#') && // is not an anchor
                (	!(/^[a-z\+\.\-]+:/i).test(chref) ||                       // either does not have a proper scheme (relative links)
                chref.indexOf(location.protocol+'//'+location.host)===0 ) // or is in the same protocol and domain
            ) {
                e.preventDefault();
                location.href = curnode.href;
            }
        },false);
    }
})(document,window.navigator,'standalone');

// TODO Consider javascript disabled
// TODO use app.support to display a message for older browsers
<commit_msg>Make application apple-mobile-web-app-capable<commit_after>/**
 * Copyright (c) 2013-2016 Memba Sarl. All rights reserved.
 * Sources at https://github.com/Memba
 */

/* jshint browser: true */
/* globals require: false, __NODE_ENV__: false */

if (typeof(require) === 'function') {
    // require('./window.assert');
    // require('./window.logger');
    // require('./app.logger.js');
    require('./app.config.jsx?env=' + __NODE_ENV__);
    require('./app.support.js');
}

/**
 * The application has <meta name="apple-mobile-web-app-capable" content="yes">
 * so to run the app ull screen when pinned to IOS home screen
 * The following prevents links from opening in a new safari window
 * Source: https://gist.github.com/irae/1042167
 */
(function (document,navigator,standalone) {

    'use strict';

    // prevents links from apps from opening in mobile safari
    // this javascript must be the first script in your <head>
    if ((standalone in navigator) && navigator[standalone]) {
        var curnode;
        var chref;
        var location = document.location;
        var stop = /^(a|html)$/i;
        document.addEventListener('click', function (e) {
            curnode = e.target;
            while (!(stop).test(curnode.nodeName)) {
                curnode = curnode.parentNode;
            }
            // Conditions to do this only on links to your own app
            // if you want all links, use if('href' in curnode) instead.
            if (
                'href' in curnode && // is a link
                (chref = curnode.href).replace(location.href, '').indexOf('#') && // is not an anchor
                (!(/^[a-z\+\.\-]+:/i).test(chref) ||                       // either does not have a proper scheme (relative links)
                chref.indexOf(location.protocol + '//' + location.host) === 0) // or is in the same protocol and domain
            ) {
                e.preventDefault();
                location.href = curnode.href;
            }
        }, false);
    }
})(document, window.navigator, 'standalone');

// TODO Consider javascript disabled
// TODO use app.support to display a message for older browsers
<|endoftext|>


<commit_before>/*
	the namespace object
*/
var autosave_js = autosave_js || {
	options : {
		defaultSaveTime : 10000
	},
	t : 0,
	Items : [],
	localStorageName : "ats-js"
};
/*
	a simple "enum" type
*/
autosave_js.ItemType = {
	Input : 'input',
	Textarea : 'textarea'
}

/*
* the entities used
*/
autosave_js.Item = function(guid,id,name,value,type,url){
	this.Guid = guid;
	this.Id = id;
	this.Name = name;
	this.Value = value;
	this.Type = type;
	this.Key = url+'|'+id+'|'+name;
}
autosave_js.Site = function(url){
	this.Url = url;
	this.Items = [];
}
/*
	guid/uid generator
	code found at http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript
*/
autosave_js.GenerateId = function(){
	var S4 = function (){
        return Math.floor(
                Math.random() * 0x10000 /* 65536 */
            ).toString(16);
    };
    return (
            S4() + S4() + "-" +
            S4() + "-" +
            S4() + "-" +
            S4() + "-" +
            S4() + S4() + S4()
        );
}

/*
	scan the markup and load the items
*/
autosave_js.loadItems = function(){

	var selection = $('input[type="text"],textarea');
	$.each(selection,function(index,element){
		var self = $(element);
		var nodeName = self.prop('nodeName').toLowerCase();
		var guid = autosave_js.GenerateId();
		var newItem = new autosave_js.Item(guid,self.prop('id'),self.prop('name'),self.val(),nodeName,document.location.href);

		//add the items array
		autosave_js.Items.push(newItem);

		//decorate the html tags
		self.attr('autosave-guid',guid);
	});
}

autosave_js.save = function(){
	if(autosave_js.Items !== null){
		var cache = autosave_js.Items;
		var str = '[';
		for(var i=0;i<cache.length;i++)
		{
			var newVal = $('[autosave-guid="'+cache[i].Guid+'"]').val();
			cache[i].Value = newVal;

			if(i===0)
			{
				str += '{"k":"'+cache[i].Key+'","v":"'+cache[i].Value+'"}';
			}
			else
			{
				str += ',{"k":"'+cache[i].Key+'","v":"'+cache[i].Value+'"}'
			}
			str += ']';
		}

		localStorage.setItem(autosave_js.localStorageName,str);
	}

	// console.log('..saved...');
	// autosave_js.debug();
}

autosave_js.debug = function(){
	var cache = autosave_js.Items;
	for(var i=0;i<cache.length;i++)
	{
		var str = cache[i].Guid+'='+cache[i].Value;
		console.log(str);
	}
}

/*
	check for requirements
*/
autosave_js.checkDependencies = function(){
		if(!localStorage)
		{
			throw new Exception('An error ocured : autosave.js needs a browser that supports localStorage.');
		};

		if(!window.jQuery)
		{
			throw new Exception('An error ocured : autosave.js needs jQuery enabled.');
		}
}

/*
	main function
*/
autosave_js.StartAutoSave = function(){
	try
	{
		autosave_js.checkDependencies();
		autosave_js.loadItems();
		autosave_js.t = setInterval('autosave_js.save()',autosave_js.options.defaultSaveTime);
	}
	catch(e)
	{
		console.log(e);
	}
}

/*
	fireStarter!
*/
$(function(){
	autosave_js.StartAutoSave();
});
<commit_msg>added load from localStorage function<commit_after>/*
	the namespace object
*/
var autosave_js = autosave_js || {
	options : {
		defaultSaveTime : 10000
	},
	t : 0,
	Items : [],
	localStorageName : "ats-js"
};
/*
	a simple "enum" type
*/
autosave_js.ItemType = {
	Input : 'input',
	Textarea : 'textarea'
}

/*
* the entities used
*/
autosave_js.Item = function(guid,id,name,value,type,url){
	this.Guid = guid;
	this.Id = id;
	this.Name = name;
	this.Value = value;
	this.Type = type;
	this.Key = url+'|'+id+'|'+name;
}
autosave_js.Site = function(url){
	this.Url = url;
	this.Items = [];
}
/*
	guid/uid generator
	code found at http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript
*/
autosave_js.GenerateId = function(){
	var S4 = function (){
        return Math.floor(
                Math.random() * 0x10000 /* 65536 */
            ).toString(16);
    };
    return (
            S4() + S4() + "-" +
            S4() + "-" +
            S4() + "-" +
            S4() + "-" +
            S4() + S4() + S4()
        );
}

/*
	scan the markup and load the items
*/
autosave_js.loadItems = function(){

	var selection = $('input[type="text"],textarea');
	$.each(selection,function(index,element){
		var self = $(element);
		var nodeName = self.prop('nodeName').toLowerCase();
		var guid = autosave_js.GenerateId();
		var newItem = new autosave_js.Item(guid,self.prop('id'),self.prop('name'),self.val(),nodeName,document.location.href);

		//add the items array
		autosave_js.Items.push(newItem);

		//decorate the html tags
		self.attr('autosave-guid',guid);
	});
}
/*
	function that loads saved valus from localDb to form.
*/
autosave_js.fillFormFromDB = function(){
	var dbValue = localStorage.getItem(autosave_js.localStorageName);
	if(dbValue !== null)
	{
		var dbList = jQuery.parseJSON(dbValue);
		if(dbList != null)
		{
			for(var i=0;i<dbList.length;i++)
			{
				var itemProps = dbList[i].k.split('|');
				if(document.location.href == itemProps[0])
				{
					if( itemProps[1] !== '')
					{
						$('#'+itemProps[1]).val(dbList[i].v);
					}
					else
					{
						$('[name="'+itemProps[2]+'"]').val(dbList[i].v);
					}
				}
			}
		}
	}
}
/*
	function that saves key-value pairs to localStorage
*/
autosave_js.save = function(){
	if(autosave_js.Items !== null){
		var cache = autosave_js.Items;
		var str = '[';
		for(var i=0;i<cache.length;i++)
		{
			var newVal = $('[autosave-guid="'+cache[i].Guid+'"]').val();
			cache[i].Value = newVal;

			if(i===0)
			{
				str += '{"k":"'+cache[i].Key+'","v":"'+cache[i].Value+'"}';
			}
			else
			{
				str += ',{"k":"'+cache[i].Key+'","v":"'+cache[i].Value+'"}'
			}
		}
		str += ']';
		localStorage.setItem(autosave_js.localStorageName,str);
	}

	// console.log('..saved...');
	// autosave_js.debug();
}

/*
	check for requirements
*/
autosave_js.checkDependencies = function(){
	if(!localStorage)
	{
		throw new Exception('An error ocured : autosave.js needs a browser that supports localStorage.');
	};

	if(!window.jQuery)
	{
		throw new Exception('An error ocured : autosave.js needs jQuery enabled.');
	}
}

/*
	main function
*/
autosave_js.StartAutoSave = function(){
	try
	{
		autosave_js.checkDependencies();
		autosave_js.fillFormFromDB();
		autosave_js.loadItems();
		autosave_js.t = setInterval('autosave_js.save()',autosave_js.options.defaultSaveTime);
	}
	catch(e)
	{
		console.log(e);
	}
}

/*
	fireStarter!
*/
$(function(){
	autosave_js.StartAutoSave();
});
<|endoftext|>


<commit_before>function getUrl(url){
	var webrequest = new XMLHttpRequest();
	webrequest.open('GET', url, false);
	webrequest.send(null);
	return webrequest.responseText;
}
function getMobileOS() {
  var userAgent = navigator.userAgent || navigator.vendor || window.opera;

  if( userAgent.match( /iPad/i ) || userAgent.match( /iPhone/i ) || userAgent.match( /iPod/i ) || ("standalone" in window.navigator) &&!window.navigator.standalone )
  {
	return 'iOS';

  }
  else if( userAgent.match( /Android/i ) )
  {

	return 'Android';
  }
  else
  {
	return 'unknown';
  }
}
function getOS(){
	if(getMobileOS()=="unknown"){
		 if(navigator.userAgent.indexOf("Chrome") != -1 )
		{
			return 'Chrome-'+navigator.platform.replace(/\s+/g, '');
		}
		else if(navigator.userAgent.indexOf("Opera") != -1 )
		{
		 return 'Opera-'+navigator.platform.replace(/\s+/g, '');
		}
		else if(navigator.userAgent.toLowerCase().indexOf("opr") != -1 )
		{
		 return 'Opera-'+navigator.platform.replace(/\s+/g, '');
		}
		else if(navigator.userAgent.toLowerCase().indexOf("trident") != -1 )
		{
		 return 'IE-'+navigator.platform.replace(/\s+/g, '');
		}
		else if(navigator.userAgent.indexOf("Firefox") != -1 )
		{
			 return 'Firefox-'+navigator.platform.replace(/\s+/g, '');
		}
		else if((navigator.userAgent.indexOf("MSIE") != -1 ) || (!!document.documentMode == true )) //IF IE > 10
		{
		  return 'IE-'+navigator.platform.replace(/\s+/g, '');
		}
		else
		{
		   return 'unknown-on-'+navigator.platform.replace(/\s+/g, '');
		}
	}
	else{
		return getMobileOS()
	}
}
function baseDir(){
	var wholeURL=location.protocol+"//"+window.location.hostname+document.location.pathname.replace("index.php","");
	var pg = window.location.pathname.substring(window.location.pathname.lastIndexOf('/')+1 );
	return wholeURL.replace(pg,'');
}
function bookCheckISBN(){
	isbn=document.getElementById("ISBN").value;
	if(isbn=="rcn"){
		document.getElementById("ISBN").value=getUrl(baseDir()+"api.php?mode=rcn");
		return 0;
	}
	var titolo=getUrl(baseDir()+"api.php?mode=titolo&isbn="+isbn);
	if(titolo=="Nessun dato"){
		document.getElementById('titolo').focus();
	}
	else{
		document.getElementById('titolo').value=titolo;
		var autore=getUrl(baseDir()+"api.php?mode=autore&isbn="+isbn);
		document.getElementById('autore').value=autore;
		document.getElementById('posizione').focus();
	}
	//##########################################
	//CONTROLLO RCN quando si salva
}
function generateUUID() {
	var d = new Date().getTime();
	var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
		var r = (d + Math.random()*16)%16 | 0;
		d = Math.floor(d/16);
		return (c=='x' ? r : (r&0x3|0x8)).toString(16);
	});
	return uuid;
}
function setCookie(cname, cvalue, exdays) {
	var d = new Date();
	d.setTime(d.getTime() + (exdays*24*60*60*1000));
	var expires = "expires="+d.toUTCString();
	if (exdays==-1){
		document.cookie = cname + "=" + cvalue;+"; expires=Fri, 31 Dec 2038 23:59:59 GMT;"
	}
	else{
		document.cookie = cname + "=" + cvalue + "; " + expires;
	}
}

function getCookie(cname) {
	var name = cname + "=";
	var ca = document.cookie.split(';');
	for(var i=0; i<ca.length; i++) {
		var c = ca[i];
		while (c.charAt(0)==' ') c = c.substring(1);
		if (c.indexOf(name) == 0) return c.substring(name.length, c.length).replace("=","");
	}
	return "";
}

function checkCookie(name) {
	var user = getCookie(name);
	if (user != "") {
		return true;
	}
	else {
		return false;
	}
}
function asyncImg(url,id){
	if(document.getElementById(id).src.indexOf("vuoto.png") !== -1){
		document.getElementById(id).src=url;
	}
}
function loadBlock(a,b){
	for(var i=parseInt(a);i<=parseInt(b);i++){
		var url=decodeURIComponent(document.getElementById("url"+i.toString()).innerHTML).replace(/&/g,"&");
		asyncImg(url,i.toString());
	}
}<commit_msg>Sistemato JS<commit_after>function getUrl(url){
	var webrequest = new XMLHttpRequest();
	webrequest.open('GET', url, false);
	webrequest.send(null);
	return webrequest.responseText;
}
function getMobileOS() {
  var userAgent = navigator.userAgent || navigator.vendor || window.opera;

  if( userAgent.match( /iPad/i ) || userAgent.match( /iPhone/i ) || userAgent.match( /iPod/i ) || ("standalone" in window.navigator) &&!window.navigator.standalone )
  {
	return 'iOS';

  }
  else if( userAgent.match( /Android/i ) )
  {

	return 'Android';
  }
  else
  {
	return 'unknown';
  }
}
function getOS(){
	if(getMobileOS()=="unknown"){
		 if(navigator.userAgent.indexOf("Chrome") != -1 )
		{
			return 'Chrome-'+navigator.platform.replace(/\s+/g, '');
		}
		else if(navigator.userAgent.indexOf("Opera") != -1 )
		{
		 return 'Opera-'+navigator.platform.replace(/\s+/g, '');
		}
		else if(navigator.userAgent.toLowerCase().indexOf("opr") != -1 )
		{
		 return 'Opera-'+navigator.platform.replace(/\s+/g, '');
		}
		else if(navigator.userAgent.toLowerCase().indexOf("trident") != -1 )
		{
		 return 'IE-'+navigator.platform.replace(/\s+/g, '');
		}
		else if(navigator.userAgent.indexOf("Firefox") != -1 )
		{
			 return 'Firefox-'+navigator.platform.replace(/\s+/g, '');
		}
		else if((navigator.userAgent.indexOf("MSIE") != -1 ) || (!!document.documentMode == true )) //IF IE > 10
		{
		  return 'IE-'+navigator.platform.replace(/\s+/g, '');
		}
		else
		{
		   return 'unknown-on-'+navigator.platform.replace(/\s+/g, '');
		}
	}
	else{
		return getMobileOS()
	}
}
function baseDir(){
	var wholeURL=location.protocol+"//"+window.location.hostname+document.location.pathname.replace("index.php","");
	var pg = window.location.pathname.substring(window.location.pathname.lastIndexOf('/')+1 );
	return wholeURL.replace(pg,'');
}
function bookCheckISBN(){
	var isbn=document.getElementById("ISBN").value;
	if(isbn=="rcn"){
		document.getElementById("ISBN").value=getUrl(baseDir()+"api.php?mode=rcn");
		document.getElementById('titolo').focus();
		isbn=document.getElementById("ISBN").value;
	}
	var titolo=getUrl(baseDir()+"api.php?mode=titolo&isbn="+isbn);
	if(titolo=="Nessun dato"){
		document.getElementById('titolo').focus();
	}
	else{
		document.getElementById('titolo').value=titolo;
		var autore=getUrl(baseDir()+"api.php?mode=autore&isbn="+isbn);
		document.getElementById('autore').value=autore;
		document.getElementById('posizione').focus();
	}
	//##########################################
	//CONTROLLO RCN quando si salva
}
function generateUUID() {
	var d = new Date().getTime();
	var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
		var r = (d + Math.random()*16)%16 | 0;
		d = Math.floor(d/16);
		return (c=='x' ? r : (r&0x3|0x8)).toString(16);
	});
	return uuid;
}
function setCookie(cname, cvalue, exdays) {
	var d = new Date();
	d.setTime(d.getTime() + (exdays*24*60*60*1000));
	var expires = "expires="+d.toUTCString();
	if (exdays==-1){
		document.cookie = cname + "=" + cvalue;+"; expires=Fri, 31 Dec 2038 23:59:59 GMT;"
	}
	else{
		document.cookie = cname + "=" + cvalue + "; " + expires;
	}
}

function getCookie(cname) {
	var name = cname + "=";
	var ca = document.cookie.split(';');
	for(var i=0; i<ca.length; i++) {
		var c = ca[i];
		while (c.charAt(0)==' ') c = c.substring(1);
		if (c.indexOf(name) == 0) return c.substring(name.length, c.length).replace("=","");
	}
	return "";
}

function checkCookie(name) {
	var user = getCookie(name);
	if (user != "") {
		return true;
	}
	else {
		return false;
	}
}
function asyncImg(url,id){
	if(document.getElementById(id).src.indexOf("vuoto.png") !== -1){
		document.getElementById(id).src=url;
	}
}
function loadBlock(a,b){
	for(var i=parseInt(a);i<=parseInt(b);i++){
		var url=decodeURIComponent(document.getElementById("url"+i.toString()).innerHTML).replace(/&/g,"&");
		asyncImg(url,i.toString());
	}
}<|endoftext|>


<commit_before>'use strict';

//  ---------------------------------------------------------------------------

const Exchange = require ('./base/Exchange');
const { ExchangeError, OrderNotFound } = require ('./base/errors');

//  ---------------------------------------------------------------------------

module.exports = class bitflyer extends Exchange {
    describe () {
        return this.deepExtend (super.describe (), {
            'id': 'bitflyer',
            'name': 'bitFlyer',
            'countries': 'JP',
            'version': 'v1',
            'rateLimit': 1000, // their nonce-timestamp is in seconds...
            'has': {
                'CORS': false,
                'withdraw': true,
                'fetchMyTrades': true,
                'fetchOrders': true,
                'fetchOrder': true,
                'fetchOpenOrders': 'emulated',
                'fetchClosedOrders': 'emulated',
            },
            'urls': {
                'logo': 'https://user-images.githubusercontent.com/1294454/28051642-56154182-660e-11e7-9b0d-6042d1e6edd8.jpg',
                'api': 'https://api.bitflyer.jp',
                'www': 'https://bitflyer.jp',
                'doc': 'https://bitflyer.jp/API',
            },
            'api': {
                'public': {
                    'get': [
                        'getmarkets/usa', // new (wip)
                        'getmarkets/eu',  // new (wip)
                        'getmarkets',     // or 'markets'
                        'getboard',       // ...
                        'getticker',
                        'getexecutions',
                        'gethealth',
                        'getboardstate',
                        'getchats',
                    ],
                },
                'private': {
                    'get': [
                        'getpermissions',
                        'getbalance',
                        'getcollateral',
                        'getcollateralaccounts',
                        'getaddresses',
                        'getcoinins',
                        'getcoinouts',
                        'getbankaccounts',
                        'getdeposits',
                        'getwithdrawals',
                        'getchildorders',
                        'getparentorders',
                        'getparentorder',
                        'getexecutions',
                        'getpositions',
                        'gettradingcommission',
                    ],
                    'post': [
                        'sendcoin',
                        'withdraw',
                        'sendchildorder',
                        'cancelchildorder',
                        'sendparentorder',
                        'cancelparentorder',
                        'cancelallchildorders',
                    ],
                },
            },
            'fees': {
                'trading': {
                    'maker': 0.25 / 100,
                    'taker': 0.25 / 100,
                },
            },
        });
    }

    async fetchMarkets () {
        let jp_markets = await this.publicGetGetmarkets ();
        let us_markets = await this.publicGetGetmarketsUsa ();
        let eu_markets = await this.publicGetGetmarketsEu ();
        let markets = this.arrayConcat (jp_markets, us_markets);
        markets = this.arrayConcat (markets, eu_markets);
        let result = [];
        for (let p = 0; p < markets.length; p++) {
            let market = markets[p];
            let id = market['product_code'];
            let currencies = id.split ('_');
            let base = undefined;
            let quote = undefined;
            let symbol = id;
            let numCurrencies = currencies.length;
            if (numCurrencies === 1) {
                base = symbol.slice (0, 3);
                quote = symbol.slice (3, 6);
            } else if (numCurrencies === 2) {
                base = currencies[0];
                quote = currencies[1];
                symbol = base + '/' + quote;
            } else {
                base = currencies[1];
                quote = currencies[2];
            }
            result.push ({
                'id': id,
                'symbol': symbol,
                'base': base,
                'quote': quote,
                'info': market,
            });
        }
        return result;
    }

    async fetchBalance (params = {}) {
        await this.loadMarkets ();
        let response = await this.privateGetGetbalance ();
        let balances = {};
        for (let b = 0; b < response.length; b++) {
            let account = response[b];
            let currency = account['currency_code'];
            balances[currency] = account;
        }
        let result = { 'info': response };
        let currencies = Object.keys (this.currencies);
        for (let i = 0; i < currencies.length; i++) {
            let currency = currencies[i];
            let account = this.account ();
            if (currency in balances) {
                account['total'] = balances[currency]['amount'];
                account['free'] = balances[currency]['available'];
                account['used'] = account['total'] - account['free'];
            }
            result[currency] = account;
        }
        return this.parseBalance (result);
    }

    async fetchOrderBook (symbol, limit = undefined, params = {}) {
        await this.loadMarkets ();
        let orderbook = await this.publicGetGetboard (this.extend ({
            'product_code': this.marketId (symbol),
        }, params));
        return this.parseOrderBook (orderbook, undefined, 'bids', 'asks', 'price', 'size');
    }

    async fetchTicker (symbol, params = {}) {
        await this.loadMarkets ();
        let ticker = await this.publicGetGetticker (this.extend ({
            'product_code': this.marketId (symbol),
        }, params));
        let timestamp = this.parse8601 (ticker['timestamp']);
        let last = this.safeFloat (ticker, 'ltp');
        return {
            'symbol': symbol,
            'timestamp': timestamp,
            'datetime': this.iso8601 (timestamp),
            'high': undefined,
            'low': undefined,
            'bid': this.safeFloat (ticker, 'best_bid'),
            'bidVolume': undefined,
            'ask': this.safeFloat (ticker, 'best_ask'),
            'askVolume': undefined,
            'vwap': undefined,
            'open': undefined,
            'close': last,
            'last': last,
            'previousClose': undefined,
            'change': undefined,
            'percentage': undefined,
            'average': undefined,
            'baseVolume': this.safeFloat (ticker, 'volume_by_product'),
            'quoteVolume': undefined,
            'info': ticker,
        };
    }

    parseTrade (trade, market = undefined) {
        let side = undefined;
        let order = undefined;
        if ('side' in trade)
            if (trade['side']) {
                side = trade['side'].toLowerCase ();
                let id = side + '_child_order_acceptance_id';
                if (id in trade)
                    order = trade[id];
            }
        if (typeof order === 'undefined')
            order = this.safeString (trade, 'child_order_acceptance_id');
        let timestamp = this.parse8601 (trade['exec_date']);
        return {
            'id': trade['id'].toString (),
            'info': trade,
            'timestamp': timestamp,
            'datetime': this.iso8601 (timestamp),
            'symbol': market['symbol'],
            'order': order,
            'type': undefined,
            'side': side,
            'price': trade['price'],
            'amount': trade['size'],
        };
    }

    async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets ();
        let market = this.market (symbol);
        let response = await this.publicGetGetexecutions (this.extend ({
            'product_code': market['id'],
        }, params));
        return this.parseTrades (response, market, since, limit);
    }

    async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
        await this.loadMarkets ();
        let order = {
            'product_code': this.marketId (symbol),
            'child_order_type': type.toUpperCase (),
            'side': side.toUpperCase (),
            'price': price,
            'size': amount,
        };
        let result = await this.privatePostSendchildorder (this.extend (order, params));
        // { "status": - 200, "error_message": "Insufficient funds", "data": null }
        return {
            'info': result,
            'id': result['child_order_acceptance_id'],
        };
    }

    async cancelOrder (id, symbol = undefined, params = {}) {
        if (typeof symbol === 'undefined')
            throw new ExchangeError (this.id + ' cancelOrder() requires a symbol argument');
        await this.loadMarkets ();
        return await this.privatePostCancelchildorder (this.extend ({
            'product_code': this.marketId (symbol),
            'child_order_acceptance_id': id,
        }, params));
    }

    parseOrderStatus (status) {
        let statuses = {
            'ACTIVE': 'open',
            'COMPLETED': 'closed',
            'CANCELED': 'canceled',
            'EXPIRED': 'canceled',
            'REJECTED': 'canceled',
        };
        if (status in statuses)
            return statuses[status];
        return status.toLowerCase ();
    }

    parseOrder (order, market = undefined) {
        let timestamp = this.parse8601 (order['child_order_date']);
        let amount = this.safeFloat (order, 'size');
        let remaining = this.safeFloat (order, 'outstanding_size');
        let filled = this.safeFloat (order, 'executed_size');
        let price = this.safeFloat (order, 'price');
        let cost = price * filled;
        let status = this.parseOrderStatus (order['child_order_state']);
        let type = order['child_order_type'].toLowerCase ();
        let side = order['side'].toLowerCase ();
        let symbol = undefined;
        if (typeof market === 'undefined') {
            let marketId = this.safeString (order, 'product_code');
            if (typeof marketId !== 'undefined') {
                if (marketId in this.markets_by_id)
                    market = this.markets_by_id[marketId];
            }
        }
        if (typeof market !== 'undefined')
            symbol = market['symbol'];
        let fee = undefined;
        let feeCost = this.safeFloat (order, 'total_commission');
        if (typeof feeCost !== 'undefined') {
            fee = {
                'cost': feeCost,
                'currency': undefined,
                'rate': undefined,
            };
        }
        return {
            'id': order['child_order_acceptance_id'],
            'info': order,
            'timestamp': timestamp,
            'datetime': this.iso8601 (timestamp),
            'lastTradeTimestamp': undefined,
            'status': status,
            'symbol': symbol,
            'type': type,
            'side': side,
            'price': price,
            'cost': cost,
            'amount': amount,
            'filled': filled,
            'remaining': remaining,
            'fee': fee,
        };
    }

    async fetchOrders (symbol = undefined, since = undefined, limit = 100, params = {}) {
        if (typeof symbol === 'undefined')
            throw new ExchangeError (this.id + ' fetchOrders() requires a symbol argument');
        await this.loadMarkets ();
        let market = this.market (symbol);
        let request = {
            'product_code': market['id'],
            'count': limit,
        };
        let response = await this.privateGetGetchildorders (this.extend (request, params));
        let orders = this.parseOrders (response, market, since, limit);
        if (symbol)
            orders = this.filterBy (orders, 'symbol', symbol);
        return orders;
    }

    async fetchOpenOrders (symbol = undefined, since = undefined, limit = 100, params = {}) {
        params['child_order_state'] = 'ACTIVE';
        return this.fetchOrders (symbol, since, limit, params);
    }

    async fetchClosedOrders (symbol = undefined, since = undefined, limit = 100, params = {}) {
        params['child_order_state'] = 'COMPLETED';
        return this.fetchOrders (symbol, since, limit, params);
    }

    async fetchOrder (id, symbol = undefined, params = {}) {
        if (typeof symbol === 'undefined')
            throw new ExchangeError (this.id + ' fetchOrder() requires a symbol argument');
        let orders = await this.fetchOrders (symbol);
        let ordersById = this.indexBy (orders, 'id');
        if (id in ordersById)
            return ordersById[id];
        throw new OrderNotFound (this.id + ' No order found with id ' + id);
    }

    async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
        if (typeof symbol === 'undefined')
            throw new ExchangeError (this.id + ' fetchMyTrades requires a symbol argument');
        await this.loadMarkets ();
        let market = this.market (symbol);
        let request = {
            'product_code': market['id'],
        };
        if (limit)
            request['count'] = limit;
        let response = await this.privateGetGetexecutions (this.extend (request, params));
        return this.parseTrades (response, market, since, limit);
    }

    async withdraw (code, amount, address, tag = undefined, params = {}) {
        this.checkAddress (address);
        await this.loadMarkets ();
        if (code !== 'JPY' && code !== 'USD' && code !== 'EUR')
            throw new ExchangeError (this.id + ' allows withdrawing JPY, USD, EUR only, ' + code + ' is not supported');
        let currency = this.currency (code);
        let response = await this.privatePostWithdraw (this.extend ({
            'currency_code': currency['id'],
            'amount': amount,
            // 'bank_account_id': 1234,
        }, params));
        return {
            'info': response,
            'id': response['message_id'],
        };
    }

    sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
        let request = '/' + this.version + '/';
        if (api === 'private')
            request += 'me/';
        request += path;
        if (method === 'GET') {
            if (Object.keys (params).length)
                request += '?' + this.urlencode (params);
        }
        let url = this.urls['api'] + request;
        if (api === 'private') {
            this.checkRequiredCredentials ();
            let nonce = this.nonce ().toString ();
            let auth = [ nonce, method, request ].join ('');
            if (Object.keys (params).length) {
                if (method !== 'GET') {
                    body = this.json (params);
                    auth += body;
                }
            }
            headers = {
                'ACCESS-KEY': this.apiKey,
                'ACCESS-TIMESTAMP': nonce,
                'ACCESS-SIGN': this.hmac (this.encode (auth), this.encode (this.secret)),
                'Content-Type': 'application/json',
            };
        }
        return { 'url': url, 'method': method, 'body': body, 'headers': headers };
    }
};
<commit_msg>added type, spot, future to bitflyer markets fix #2892<commit_after>'use strict';

//  ---------------------------------------------------------------------------

const Exchange = require ('./base/Exchange');
const { ExchangeError, OrderNotFound } = require ('./base/errors');

//  ---------------------------------------------------------------------------

module.exports = class bitflyer extends Exchange {
    describe () {
        return this.deepExtend (super.describe (), {
            'id': 'bitflyer',
            'name': 'bitFlyer',
            'countries': 'JP',
            'version': 'v1',
            'rateLimit': 1000, // their nonce-timestamp is in seconds...
            'has': {
                'CORS': false,
                'withdraw': true,
                'fetchMyTrades': true,
                'fetchOrders': true,
                'fetchOrder': true,
                'fetchOpenOrders': 'emulated',
                'fetchClosedOrders': 'emulated',
            },
            'urls': {
                'logo': 'https://user-images.githubusercontent.com/1294454/28051642-56154182-660e-11e7-9b0d-6042d1e6edd8.jpg',
                'api': 'https://api.bitflyer.jp',
                'www': 'https://bitflyer.jp',
                'doc': 'https://bitflyer.jp/API',
            },
            'api': {
                'public': {
                    'get': [
                        'getmarkets/usa', // new (wip)
                        'getmarkets/eu',  // new (wip)
                        'getmarkets',     // or 'markets'
                        'getboard',       // ...
                        'getticker',
                        'getexecutions',
                        'gethealth',
                        'getboardstate',
                        'getchats',
                    ],
                },
                'private': {
                    'get': [
                        'getpermissions',
                        'getbalance',
                        'getcollateral',
                        'getcollateralaccounts',
                        'getaddresses',
                        'getcoinins',
                        'getcoinouts',
                        'getbankaccounts',
                        'getdeposits',
                        'getwithdrawals',
                        'getchildorders',
                        'getparentorders',
                        'getparentorder',
                        'getexecutions',
                        'getpositions',
                        'gettradingcommission',
                    ],
                    'post': [
                        'sendcoin',
                        'withdraw',
                        'sendchildorder',
                        'cancelchildorder',
                        'sendparentorder',
                        'cancelparentorder',
                        'cancelallchildorders',
                    ],
                },
            },
            'fees': {
                'trading': {
                    'maker': 0.25 / 100,
                    'taker': 0.25 / 100,
                },
            },
        });
    }

    async fetchMarkets () {
        let jp_markets = await this.publicGetGetmarkets ();
        let us_markets = await this.publicGetGetmarketsUsa ();
        let eu_markets = await this.publicGetGetmarketsEu ();
        let markets = this.arrayConcat (jp_markets, us_markets);
        markets = this.arrayConcat (markets, eu_markets);
        let result = [];
        for (let p = 0; p < markets.length; p++) {
            let market = markets[p];
            let id = market['product_code'];
            let spot = true;
            let future = false;
            let type = 'spot';
            if ('alias' in market) {
                type = 'future';
                future = true;
                spot = false;
            }
            let currencies = id.split ('_');
            let base = undefined;
            let quote = undefined;
            let symbol = id;
            let numCurrencies = currencies.length;
            if (numCurrencies === 1) {
                base = symbol.slice (0, 3);
                quote = symbol.slice (3, 6);
            } else if (numCurrencies === 2) {
                base = currencies[0];
                quote = currencies[1];
                symbol = base + '/' + quote;
            } else {
                base = currencies[1];
                quote = currencies[2];
            }
            result.push ({
                'id': id,
                'symbol': symbol,
                'base': base,
                'quote': quote,
                'type': type,
                'spot': spot,
                'future': future,
                'info': market,
            });
        }
        return result;
    }

    async fetchBalance (params = {}) {
        await this.loadMarkets ();
        let response = await this.privateGetGetbalance ();
        let balances = {};
        for (let b = 0; b < response.length; b++) {
            let account = response[b];
            let currency = account['currency_code'];
            balances[currency] = account;
        }
        let result = { 'info': response };
        let currencies = Object.keys (this.currencies);
        for (let i = 0; i < currencies.length; i++) {
            let currency = currencies[i];
            let account = this.account ();
            if (currency in balances) {
                account['total'] = balances[currency]['amount'];
                account['free'] = balances[currency]['available'];
                account['used'] = account['total'] - account['free'];
            }
            result[currency] = account;
        }
        return this.parseBalance (result);
    }

    async fetchOrderBook (symbol, limit = undefined, params = {}) {
        await this.loadMarkets ();
        let orderbook = await this.publicGetGetboard (this.extend ({
            'product_code': this.marketId (symbol),
        }, params));
        return this.parseOrderBook (orderbook, undefined, 'bids', 'asks', 'price', 'size');
    }

    async fetchTicker (symbol, params = {}) {
        await this.loadMarkets ();
        let ticker = await this.publicGetGetticker (this.extend ({
            'product_code': this.marketId (symbol),
        }, params));
        let timestamp = this.parse8601 (ticker['timestamp']);
        let last = this.safeFloat (ticker, 'ltp');
        return {
            'symbol': symbol,
            'timestamp': timestamp,
            'datetime': this.iso8601 (timestamp),
            'high': undefined,
            'low': undefined,
            'bid': this.safeFloat (ticker, 'best_bid'),
            'bidVolume': undefined,
            'ask': this.safeFloat (ticker, 'best_ask'),
            'askVolume': undefined,
            'vwap': undefined,
            'open': undefined,
            'close': last,
            'last': last,
            'previousClose': undefined,
            'change': undefined,
            'percentage': undefined,
            'average': undefined,
            'baseVolume': this.safeFloat (ticker, 'volume_by_product'),
            'quoteVolume': undefined,
            'info': ticker,
        };
    }

    parseTrade (trade, market = undefined) {
        let side = undefined;
        let order = undefined;
        if ('side' in trade)
            if (trade['side']) {
                side = trade['side'].toLowerCase ();
                let id = side + '_child_order_acceptance_id';
                if (id in trade)
                    order = trade[id];
            }
        if (typeof order === 'undefined')
            order = this.safeString (trade, 'child_order_acceptance_id');
        let timestamp = this.parse8601 (trade['exec_date']);
        return {
            'id': trade['id'].toString (),
            'info': trade,
            'timestamp': timestamp,
            'datetime': this.iso8601 (timestamp),
            'symbol': market['symbol'],
            'order': order,
            'type': undefined,
            'side': side,
            'price': trade['price'],
            'amount': trade['size'],
        };
    }

    async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets ();
        let market = this.market (symbol);
        let response = await this.publicGetGetexecutions (this.extend ({
            'product_code': market['id'],
        }, params));
        return this.parseTrades (response, market, since, limit);
    }

    async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
        await this.loadMarkets ();
        let order = {
            'product_code': this.marketId (symbol),
            'child_order_type': type.toUpperCase (),
            'side': side.toUpperCase (),
            'price': price,
            'size': amount,
        };
        let result = await this.privatePostSendchildorder (this.extend (order, params));
        // { "status": - 200, "error_message": "Insufficient funds", "data": null }
        return {
            'info': result,
            'id': result['child_order_acceptance_id'],
        };
    }

    async cancelOrder (id, symbol = undefined, params = {}) {
        if (typeof symbol === 'undefined')
            throw new ExchangeError (this.id + ' cancelOrder() requires a symbol argument');
        await this.loadMarkets ();
        return await this.privatePostCancelchildorder (this.extend ({
            'product_code': this.marketId (symbol),
            'child_order_acceptance_id': id,
        }, params));
    }

    parseOrderStatus (status) {
        let statuses = {
            'ACTIVE': 'open',
            'COMPLETED': 'closed',
            'CANCELED': 'canceled',
            'EXPIRED': 'canceled',
            'REJECTED': 'canceled',
        };
        if (status in statuses)
            return statuses[status];
        return status.toLowerCase ();
    }

    parseOrder (order, market = undefined) {
        let timestamp = this.parse8601 (order['child_order_date']);
        let amount = this.safeFloat (order, 'size');
        let remaining = this.safeFloat (order, 'outstanding_size');
        let filled = this.safeFloat (order, 'executed_size');
        let price = this.safeFloat (order, 'price');
        let cost = price * filled;
        let status = this.parseOrderStatus (order['child_order_state']);
        let type = order['child_order_type'].toLowerCase ();
        let side = order['side'].toLowerCase ();
        let symbol = undefined;
        if (typeof market === 'undefined') {
            let marketId = this.safeString (order, 'product_code');
            if (typeof marketId !== 'undefined') {
                if (marketId in this.markets_by_id)
                    market = this.markets_by_id[marketId];
            }
        }
        if (typeof market !== 'undefined')
            symbol = market['symbol'];
        let fee = undefined;
        let feeCost = this.safeFloat (order, 'total_commission');
        if (typeof feeCost !== 'undefined') {
            fee = {
                'cost': feeCost,
                'currency': undefined,
                'rate': undefined,
            };
        }
        return {
            'id': order['child_order_acceptance_id'],
            'info': order,
            'timestamp': timestamp,
            'datetime': this.iso8601 (timestamp),
            'lastTradeTimestamp': undefined,
            'status': status,
            'symbol': symbol,
            'type': type,
            'side': side,
            'price': price,
            'cost': cost,
            'amount': amount,
            'filled': filled,
            'remaining': remaining,
            'fee': fee,
        };
    }

    async fetchOrders (symbol = undefined, since = undefined, limit = 100, params = {}) {
        if (typeof symbol === 'undefined')
            throw new ExchangeError (this.id + ' fetchOrders() requires a symbol argument');
        await this.loadMarkets ();
        let market = this.market (symbol);
        let request = {
            'product_code': market['id'],
            'count': limit,
        };
        let response = await this.privateGetGetchildorders (this.extend (request, params));
        let orders = this.parseOrders (response, market, since, limit);
        if (symbol)
            orders = this.filterBy (orders, 'symbol', symbol);
        return orders;
    }

    async fetchOpenOrders (symbol = undefined, since = undefined, limit = 100, params = {}) {
        params['child_order_state'] = 'ACTIVE';
        return this.fetchOrders (symbol, since, limit, params);
    }

    async fetchClosedOrders (symbol = undefined, since = undefined, limit = 100, params = {}) {
        params['child_order_state'] = 'COMPLETED';
        return this.fetchOrders (symbol, since, limit, params);
    }

    async fetchOrder (id, symbol = undefined, params = {}) {
        if (typeof symbol === 'undefined')
            throw new ExchangeError (this.id + ' fetchOrder() requires a symbol argument');
        let orders = await this.fetchOrders (symbol);
        let ordersById = this.indexBy (orders, 'id');
        if (id in ordersById)
            return ordersById[id];
        throw new OrderNotFound (this.id + ' No order found with id ' + id);
    }

    async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
        if (typeof symbol === 'undefined')
            throw new ExchangeError (this.id + ' fetchMyTrades requires a symbol argument');
        await this.loadMarkets ();
        let market = this.market (symbol);
        let request = {
            'product_code': market['id'],
        };
        if (limit)
            request['count'] = limit;
        let response = await this.privateGetGetexecutions (this.extend (request, params));
        return this.parseTrades (response, market, since, limit);
    }

    async withdraw (code, amount, address, tag = undefined, params = {}) {
        this.checkAddress (address);
        await this.loadMarkets ();
        if (code !== 'JPY' && code !== 'USD' && code !== 'EUR')
            throw new ExchangeError (this.id + ' allows withdrawing JPY, USD, EUR only, ' + code + ' is not supported');
        let currency = this.currency (code);
        let response = await this.privatePostWithdraw (this.extend ({
            'currency_code': currency['id'],
            'amount': amount,
            // 'bank_account_id': 1234,
        }, params));
        return {
            'info': response,
            'id': response['message_id'],
        };
    }

    sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
        let request = '/' + this.version + '/';
        if (api === 'private')
            request += 'me/';
        request += path;
        if (method === 'GET') {
            if (Object.keys (params).length)
                request += '?' + this.urlencode (params);
        }
        let url = this.urls['api'] + request;
        if (api === 'private') {
            this.checkRequiredCredentials ();
            let nonce = this.nonce ().toString ();
            let auth = [ nonce, method, request ].join ('');
            if (Object.keys (params).length) {
                if (method !== 'GET') {
                    body = this.json (params);
                    auth += body;
                }
            }
            headers = {
                'ACCESS-KEY': this.apiKey,
                'ACCESS-TIMESTAMP': nonce,
                'ACCESS-SIGN': this.hmac (this.encode (auth), this.encode (this.secret)),
                'Content-Type': 'application/json',
            };
        }
        return { 'url': url, 'method': method, 'body': body, 'headers': headers };
    }
};
<|endoftext|>