<commit_before>var satAttr = 'Modified Copernicus' +
    ' Sentinel data 2016 by ' +
    'SentinelMap' ;

var osmAttr = ' | © OSM' +
    ' contributors data by ' +
    'Mapzen' ;

var Attr = satAttr + osmAttr ;

// https://mapzen.com/documentation/vector-tiles/layers/#boundaries-properties-optional
// osm_relation: true, which can also be deduced from negative id values.

var tit = 'Earthquake damage:
'
var OSM0 = '
 View on OSM
'
var iD0 = 'Edit with iD'

var scLayer = Tangram.leafletLayer({
    scene: 'scene.yaml',
    attribution: Attr,
    events: {
	hover: function(selection) {
	    if (selection.feature != null & map.getZoom() >= 17) {
		document.getElementById('map').style.cursor = 'pointer'
	    } else {
		document.getElementById('map').style.cursor = ''
	    }
	},
	click: function(selection) {
	    // console.log(selection);
	    if (selection.feature != null & map.getZoom() >= 17) {
		latlng = selection.leaflet_event.latlng;
		// info elements
		bb = String(selection.feature.layers);
		dam = String(bb.split('buildings:', 2)[1]);
		dam = dam.replace(',', '');
		dam = dam.replace('_damage', '');
		// link elements
		fid = selection.feature.properties.id;
		if(fid >= 0) { type= 'way' } else { type='relation' }
		str_id = String( Math.abs(fid) )
		var popup = L.popup({ className: 'custom' })
		    .setLatLng(latlng)
		    .setContent(tit + dam +
				OSM0 + type + '/' + str_id + OSM1 +
				iD0 + type + '=' + str_id + iD1)
		    .openOn(map);
	    } //end of if
	} //end of click
    } //end of events
});

var map = L.map('map' , {
    center: [ 42.629, 13.2872],
    zoom: 15,
    maxZoom: 18,
    minZoom: 5,
    layers: [scLayer],
    zoomControl: false
});

var baseLayers = {
    "Sentinel-2": scLayer,
};

L.control.zoom({position: 'topright'}).addTo(map);

var hash = new L.Hash(map);

var sidebar = L.control.sidebar('sidebar').addTo(map);

// DEBUG
/*
scLayer.scene.subscribe({
    load: function (e) {
        console.log('scene loaded:', e);
    }
});

scLayer.scene.subscribe({
    view_complete: function () {
	console.log('scene view complete');
    }
});
*/
<commit_msg>Add https for targets<commit_after>var satAttr = 'Modified Copernicus' +
    ' Sentinel data 2016 by ' +
    'SentinelMap' ;

var osmAttr = ' | © OSM' +
    ' contributors data by ' +
    'Mapzen' ;

var Attr = satAttr + osmAttr ;

// https://mapzen.com/documentation/vector-tiles/layers/#boundaries-properties-optional
// osm_relation: true, which can also be deduced from negative id values.

var tit = 'Earthquake damage:
'
var OSM0 = '
 View on OSM
'
var iD0 = 'Edit with iD'

var scLayer = Tangram.leafletLayer({
    scene: 'scene.yaml',
    attribution: Attr,
    events: {
	hover: function(selection) {
	    if (selection.feature != null & map.getZoom() >= 17) {
		document.getElementById('map').style.cursor = 'pointer'
	    } else {
		document.getElementById('map').style.cursor = ''
	    }
	},
	click: function(selection) {
	    // console.log(selection);
	    if (selection.feature != null & map.getZoom() >= 17) {
		latlng = selection.leaflet_event.latlng;
		// info elements
		bb = String(selection.feature.layers);
		dam = String(bb.split('buildings:', 2)[1]);
		dam = dam.replace(',', '');
		dam = dam.replace('_damage', '');
		// link elements
		fid = selection.feature.properties.id;
		if(fid >= 0) { type= 'way' } else { type='relation' }
		str_id = String( Math.abs(fid) )
		var popup = L.popup({ className: 'custom' })
		    .setLatLng(latlng)
		    .setContent(tit + dam +
				OSM0 + type + '/' + str_id + OSM1 +
				iD0 + type + '=' + str_id + iD1)
		    .openOn(map);
	    } //end of if
	} //end of click
    } //end of events
});

var map = L.map('map' , {
    center: [ 42.629, 13.2872],
    zoom: 15,
    maxZoom: 18,
    minZoom: 5,
    layers: [scLayer],
    zoomControl: false
});

var baseLayers = {
    "Sentinel-2": scLayer,
};

L.control.zoom({position: 'topright'}).addTo(map);

var hash = new L.Hash(map);

var sidebar = L.control.sidebar('sidebar').addTo(map);

// DEBUG
/*
scLayer.scene.subscribe({
    load: function (e) {
        console.log('scene loaded:', e);
    }
});

scLayer.scene.subscribe({
    view_complete: function () {
	console.log('scene view complete');
    }
});
*/
<|endoftext|>


<commit_before>// Filter functions
// ----------------

const utils = require("./utils");

var artist = function(player, args, callback) {
    // Songs from current artist
    saveFreemodeIndex(player);

    var query = {
        "sql": "SELECT id FROM items WHERE artist = ?",
        "param": player.currentData.artist
    };
    sqlfilter(query, "artist", player, callback);
};

var album = function(player, args, callback) {
    // Songs from current album
    saveFreemodeIndex(player);

    var query = {
        "sql": "SELECT id FROM items WHERE album = ?",
        "param": player.currentData.album
    };
    sqlfilter(query, "album", player, callback);
};

var search = function(player, args, callback) {
    // Search results
    saveFreemodeIndex(player);

    var query = {
        "sql": "SELECT id FROM items WHERE (artist || ' ' || title || ' ' || album) like '%' || ? || '%'",
        "param": args.join(" ")
    };
    sqlfilter(query, "search", player, callback);
};

var similar = function(player, args, callback) {
    // Sort sequence in order of similarity with current song
    saveFreemodeIndex(player);

    var distances = [];
    var anchorPoint = player.coords[player.sequence[player.currentIndex]],
        currentPoint;

    for (var i = 0; i < player.sequence.length; i++) {
        currentPoint = player.coords[player.sequence[i]];
        console.log(i);
        distances.push(Math.abs(anchorPoint.x - currentPoint.x) +
                       Math.abs(anchorPoint.y - currentPoint.y));
    }

    var similarIndices = utils.argsort(distances);
    seq = [];

    for (i = 0; i < similarIndices.length; i++) {
        seq.push(player.sequence[similarIndices[i]]);
    }
    player.sequence = seq;
    player.currentIndex = 0;

    callback(["m", "similar"]);
};

var artistCap = function(player, args, callback) {
    // Put an upper limit on song count by artist
    saveFreemodeIndex(player);

    if (isNaN(args[0])) {
        callback("nf");
    }
    else {
        var cap = parseInt(args[0]);
        if (cap <= 0) {
            callback("nf");
        }
        else {
            var query = {
                "sql": "SELECT id FROM items WHERE artist IN (SELECT artist FROM items GROUP BY artist HAVING count(*) <= ?)",
                "param": cap
            };
            sqlfilter(query, "cap", player, callback);
        }
    }
};

// Common functions

var sqlfilter = function(query, name, player, callback) {
    // General sql filter on beetsDb
    var seq = [];
    player.beetsDb.all(query.sql, query.param, function(err, rows) {
        rows.forEach(function(row) {
            seq.push(row.id);
        });
        if (seq.length == 0) {
            callback("nf");
        }
        else {
            player.seqCount = seq.length;
            seq = utils.shuffle(seq);
            player.sequence = seq;
            player.currentIndex = 0;

            callback(["m", name]);
        }
    });
};

var saveFreemodeIndex = function(player) {
    // Save state for free mode if not already saved
    if (!player.freemodeSave) {
        player.freemodeSave = player.currentIndex;
    }
};

exports.artist = artist;
exports.album = album;
exports.search = search;
exports.similar = similar;
exports.artistCap = artistCap;
<commit_msg>Improved search filter<commit_after>// Filter functions
// ----------------

const utils = require("./utils");

var artist = function(player, args, callback) {
    // Songs from current artist
    saveFreemodeIndex(player);

    var query = {
        "sql": "SELECT id FROM items WHERE artist = ?",
        "param": player.currentData.artist
    };
    sqlfilter(query, "artist", player, callback);
};

var album = function(player, args, callback) {
    // Songs from current album
    saveFreemodeIndex(player);

    var query = {
        "sql": "SELECT id FROM items WHERE album = ?",
        "param": player.currentData.album
    };
    sqlfilter(query, "album", player, callback);
};

var search = function(player, args, callback) {
    // Search results
    saveFreemodeIndex(player);

    // Generate query
    // + is union
    // - is exception
    // others are intersected

    // Clean up continuous repetitions
    var cleaned = args.filter(function(item, index, arr) {
        return (index == 0) || (item != arr[index-1]);
    });

    // Remove first +
    if (cleaned[0] == "+") {
        cleaned.shift();
    }
    // Remove ending operators +/-
    while (["+", "-"].indexOf(cleaned[cleaned.length-1]) > -1) {
        cleaned.pop();
    }
    console.log(cleaned);

    var sql = [],
        param = [],
        inWords = false;
    // Wrap around
    sql.push("SELECT id FROM");
    cleaned.forEach(function(item, index) {
        if (item == "+") {
            if ((!inWords) && (index != 0)) {
                // Override previous operator
                sql.pop();
            }
            // Apply operator
            sql.push(") UNION SELECT id FROM (");
            inWords = false;
        }
        else if (item == "-") {
            if (index == 0) {
                // First -
                sql.push("( SELECT id FROM items");
            }
            else if (!inWords) {
                // Override previous operator
                sql.pop();
            }
            // Apply operator
            sql.push(") EXCEPT SELECT id FROM (");
            inWords = false;
        }
        else {
            if (inWords) {
                sql.push("INTERSECT");
            }
            else if (index == 0 ){
                sql.push("(");
            }
            sql.push("SELECT id FROM items WHERE (artist || ' ' || title || ' ' || album) like '%' || ? || '%'");
            param.push(item);
            inWords = true;
        }
    });
    // Close
    sql.push(")");

    var query = {
        "sql": sql.join(" "),
        "param": param
    };

    console.log(query.sql);
    console.log(query.param);

    sqlfilter(query, "search", player, callback);
};

var similar = function(player, args, callback) {
    // Sort sequence in order of similarity with current song
    saveFreemodeIndex(player);

    var distances = [];
    var anchorPoint = player.coords[player.sequence[player.currentIndex]],
        currentPoint;

    for (var i = 0; i < player.sequence.length; i++) {
        currentPoint = player.coords[player.sequence[i]];
        console.log(i);
        distances.push(Math.abs(anchorPoint.x - currentPoint.x) +
                       Math.abs(anchorPoint.y - currentPoint.y));
    }

    var similarIndices = utils.argsort(distances);
    seq = [];

    for (i = 0; i < similarIndices.length; i++) {
        seq.push(player.sequence[similarIndices[i]]);
    }
    player.sequence = seq;
    player.currentIndex = 0;

    callback(["m", "similar"]);
};

var artistCap = function(player, args, callback) {
    // Put an upper limit on song count by artist
    saveFreemodeIndex(player);

    if (isNaN(args[0])) {
        callback("nf");
    }
    else {
        var cap = parseInt(args[0]);
        if (cap <= 0) {
            callback("nf");
        }
        else {
            var query = {
                "sql": "SELECT id FROM items WHERE artist IN (SELECT artist FROM items GROUP BY artist HAVING count(*) <= ?)",
                "param": cap
            };
            sqlfilter(query, "cap", player, callback);
        }
    }
};

// Common functions

var sqlfilter = function(query, name, player, callback) {
    // General sql filter on beetsDb
    var seq = [];
    player.beetsDb.all(query.sql, query.param, function(err, rows) {
        if (err) {
            console.log(err);
            callback("nf");
        }
        else {
            rows.forEach(function(row) {
                seq.push(row.id);
            });
            if (seq.length == 0) {
                callback("nf");
            }
            else {
                player.seqCount = seq.length;
                seq = utils.shuffle(seq);
                player.sequence = seq;
                player.currentIndex = 0;

                callback(["m", name]);
            }
        }
    });
};

var saveFreemodeIndex = function(player) {
    // Save state for free mode if not already saved
    if (!player.freemodeSave) {
        player.freemodeSave = player.currentIndex;
    }
};

exports.artist = artist;
exports.album = album;
exports.search = search;
exports.similar = similar;
exports.artistCap = artistCap;
<|endoftext|>


<commit_before>/* Copyright (c) 2013-2016 The TagSpaces Authors.
 * Use of this source code is governed by the MIT license which can be found in the LICENSE.txt file. */

/* globals Nanobar, marked, EXIF, Mousetrap, Viewer  */
"use strict";

$(document).ready(function() {
  function getParameterByName(name) {
    name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
    var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
      results = regex.exec(location.search);
    return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
  }

  var filePath = getParameterByName("cp");

  var imageRotationClass = "";
  var isCordova = parent.isCordova;
  var isWeb = document.URL.indexOf('http') === 0;

  if (isCordova || isWeb) {

  } else {
    filePath = "file://" + filePath;
  }

  var $imgViewer = $("#htmlContent");
  var exifObj;

  var opt = {
    //url: filePath,
    movable: true,
    navbar: false,
    toolbar: false,
    title: false,
    //fullscreen: false,
    inline: 'inline',
    //fading: true,
    hide: function(e) {
      console.log(e.type);
    }
  };
  var viewer = new Viewer(document.getElementById('imageContent'), opt);
  console.debug(viewer);
  $(".viewer-next").css("visibility", "hidden");
  $(".viewer-prev").css("visibility", "hidden");

  $("#imageContent").attr("src", filePath).bind("load", function() {
    $(this).addClass("transparentImageBackground");
    $imgViewer.addClass("imgViewer");
    if (filePath.toLowerCase().indexOf("jpg") === (filePath.length - 3) ||
      filePath.toLowerCase().indexOf("jpeg") === (filePath.length - 4)) {
      EXIF.getData(this, function() {
        var orientation = EXIF.getTag(this, "Orientation");
        correctOrientation(orientation);
        //console.log(EXIF.pretty(this));
        exifObj = {};
        var tags = ['Make', 'Model', 'DateTime', 'Artist', 'Copyright', 'ExposureTime ', 'FNumber', 'ISOSpeedRatings', 'ShutterSpeedValue', 'ApertureValue', 'FocalLength'];
        for (var tag in tags) {
          var prop = tags[tag];
          if (this.exifdata.hasOwnProperty(prop)) {
            exifObj[prop] = this.exifdata[prop];
          }
        }
        jQuery.extend(exifObj, this.iptcdata);
        if (!jQuery.isEmptyObject(exifObj)) {
          $("#exifButton").parent().show();
          printEXIF();
        }
      });
    }
  });

  $("#imageContent").css("visibility", "hidden");
  var offset = 0;

  $("#zoomInButton").on('click', function(e) {
    viewer.zoom(offset + 1);
  });

  $("#zoomOutButton").on('click', function(e) {
    viewer.zoom(offset - 1);
  });

  $("#zoomResetButton").on('click', function(e) {
    viewer.zoomTo(1);
    viewer.scale(1);
    viewer.rotateTo(0);
  });

  $("#rotateLeftButton").on('click', function(e) {
    e.stopPropagation();
    viewer.rotate(-90);
  });

  $("#rotateRightButton").on('click', function(e) {
    e.stopPropagation();
    viewer.rotate(90);
  });

  $("#flipHorizontal").on('click', function(e) {
    e.stopPropagation();
    viewer.scale(-1, 1); // Flip horizontal
  });

  $("#flipVertical").on('click', function(e) {
    e.stopPropagation();
    viewer.scale(1, -1); // Flip vertical
  });

  $("#flipBoth").on('click', function(e) {
    e.stopPropagation();
    viewer.scale(-1); // Flip both horizontal and vertical
  });

  function printEXIF() {
    var $exifRow = $("#exifRow").clone(); // Preparing the template
    var $exifTableBody = $("#exifTableBody");
    $exifTableBody.empty();
    for (var key in exifObj) {
      if (exifObj.hasOwnProperty(key) && exifObj[key].length !== 0) {
        $exifRow.find("th").text(key);
        $exifRow.find("td").text(exifObj[key]);
        $exifTableBody.append($exifRow.clone());
        //$exifTableBody.append("
" + key + "	" + exifObj[key] + "
");
      }
    }
  }

  function correctOrientation(orientation) {
    var $image = $("#imageContent");
    $image.removeClass(imageRotationClass);
    console.log("ORIENTATION: " + orientation);
    switch (orientation) {
      case 8:
        imageRotationClass = "rotate270";
        break;
      case 3:
        imageRotationClass = "rotate180";
        break;
      case 6:
        imageRotationClass = "rotate90";
        break;
      case 1:
        imageRotationClass = "";
        break;
      default:
        imageRotationClass = "";
    }
    $image.addClass(imageRotationClass);
  }

  $("#rotateLeftButton").on("click", function() {
    //console.log("Rotate Left");
    var $image = $("#imageContent");
    $image.removeClass(imageRotationClass);
    switch (imageRotationClass) {
      case "":
        imageRotationClass = "rotate270";
        break;
      case "rotate270":
        imageRotationClass = "rotate180";
        break;
      case "rotate180":
        imageRotationClass = "rotate90";
        break;
      case "rotate90":
        imageRotationClass = "";
        break;
      default:
        imageRotationClass = "";
    }
    $image.addClass(imageRotationClass);
  });

  $("#rotateRightButton").on("click", function() {
    //console.log("Rotate Right");
    var $image = $("#imageContent");
    $image.removeClass(imageRotationClass);
    switch (imageRotationClass) {
      case "":
        imageRotationClass = "rotate90";
        break;
      case "rotate90":
        imageRotationClass = "rotate180";
        break;
      case "rotate180":
        imageRotationClass = "rotate270";
        break;
      case "rotate270":
        imageRotationClass = "";
        break;
      default:
        imageRotationClass = "";
    }
    $image.addClass(imageRotationClass);
  });

  if (isCordova) {
    $("#zoomInButton").hide();
    $("#zoomOutButton").hide();
    $("#printButton").hide();
  }

  // Init internationalization
  $.i18n.init({
    ns: {
      namespaces: ['ns.viewerImage']
    },
    debug: true,
    fallbackLng: 'en_US'
  }, function() {
    $('[data-i18n]').i18n();
  });

  // Nano progressbar
  $(function() {
    var options = {
      bg: '#42BEDB', // (optional) background css property, '#000' by default
      // leave target blank for global nanobar
      target: document.getElementById('nanoBar'), //(optional) Where to put the progress bar, nanobar will be fixed to top of document if target is null
      // id for new nanobar
      id: 'nanoBar' // (optional) id for nanobar div
    };
    var nanobar = new Nanobar(options);
    var pct = 0;
    $(document).ajaxSend(function() {
      pct += 0.1;
      // move bar
      nanobar.go(pct);
      if (pct > 100.0) {
        pct = 0.0;
      }
    }).ajaxComplete(function() {
      // Finish progress bar
      nanobar.go(100);
    });
  });

});
<commit_msg>update<commit_after>/* Copyright (c) 2013-2016 The TagSpaces Authors.
 * Use of this source code is governed by the MIT license which can be found in the LICENSE.txt file. */

/* globals Nanobar, marked, EXIF, Mousetrap, Viewer  */
"use strict";

$(document).ready(function() {
  function getParameterByName(name) {
    name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
    var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
      results = regex.exec(location.search);
    return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
  }

  var filePath = getParameterByName("cp");

  var imageRotationClass = "";
  var isCordova = parent.isCordova;
  var isWeb = document.URL.indexOf('http') === 0;

  if (isCordova || isWeb) {

  } else {
    filePath = "file://" + filePath;
  }

  var $imgViewer = $("#htmlContent");
  var exifObj;

  var opt = {
    //url: filePath,
    movable: true,
    navbar: false,
    toolbar: false,
    title: false,
    //fullscreen: false,
    inline: 'inline',
    //fading: true,
    hide: function(e) {
      console.log(e.type);
    }
  };
  var viewer = new Viewer(document.getElementById('imageContent'), opt);
  console.debug(viewer);
  $(".viewer-next").css("visibility", "hidden");
  $(".viewer-prev").css("visibility", "hidden");

  $("#imageContent").attr("src", filePath).bind("load", function() {
    $(this).addClass("transparentImageBackground");
    $imgViewer.addClass("imgViewer");
    if (filePath.toLowerCase().indexOf("jpg") === (filePath.length - 3) ||
      filePath.toLowerCase().indexOf("jpeg") === (filePath.length - 4)) {
      EXIF.getData(this, function() {
        var orientation = EXIF.getTag(this, "Orientation");
        correctOrientation(orientation);
        //console.log(EXIF.pretty(this));
        exifObj = {};
        var tags = ['Make', 'Model', 'DateTime', 'Artist', 'Copyright', 'ExposureTime ', 'FNumber', 'ISOSpeedRatings', 'ShutterSpeedValue', 'ApertureValue', 'FocalLength'];
        for (var tag in tags) {
          var prop = tags[tag];
          if (this.exifdata.hasOwnProperty(prop)) {
            exifObj[prop] = this.exifdata[prop];
          }
        }
        jQuery.extend(exifObj, this.iptcdata);
        if (!jQuery.isEmptyObject(exifObj)) {
          $("#exifButton").parent().show();
          printEXIF();
        }
      });
    }
  });

  $("#imageContent").css("visibility", "hidden");
  var offset = 0;

  $("#zoomInButton").on('click', function(e) {
    viewer.zoom(offset + 1);
  });

  $("#zoomOutButton").on('click', function(e) {
    viewer.zoom(offset - 1);
  });

  $("#zoomResetButton").on('click', function(e) {
    viewer.rotateTo(0);
    viewer.zoomTo(1);
    //viewer.scale(1);
  });

  $("#rotateLeftButton").on('click', function(e) {
    e.stopPropagation();
    viewer.rotate(-90);
  });

  $("#rotateRightButton").on('click', function(e) {
    e.stopPropagation();
    viewer.rotate(90);
  });

  $("#flipHorizontal").on('click', function(e) {
    e.stopPropagation();
    viewer.scale(-1, 1); // Flip horizontal
  });

  $("#flipVertical").on('click', function(e) {
    e.stopPropagation();
    viewer.scale(1, -1); // Flip vertical
  });

  $("#flipBoth").on('click', function(e) {
    e.stopPropagation();
    viewer.scale(-1); // Flip both horizontal and vertical
  });

  function printEXIF() {
    var $exifRow = $("#exifRow").clone(); // Preparing the template
    var $exifTableBody = $("#exifTableBody");
    $exifTableBody.empty();
    for (var key in exifObj) {
      if (exifObj.hasOwnProperty(key) && exifObj[key].length !== 0) {
        $exifRow.find("th").text(key);
        $exifRow.find("td").text(exifObj[key]);
        $exifTableBody.append($exifRow.clone());
        //$exifTableBody.append("
" + key + "	" + exifObj[key] + "
");
      }
    }
  }

  function correctOrientation(orientation) {
    var $image = $("#imageContent");
    $image.removeClass(imageRotationClass);
    console.log("ORIENTATION: " + orientation);
    switch (orientation) {
      case 8:
        imageRotationClass = "rotate270";
        break;
      case 3:
        imageRotationClass = "rotate180";
        break;
      case 6:
        imageRotationClass = "rotate90";
        break;
      case 1:
        imageRotationClass = "";
        break;
      default:
        imageRotationClass = "";
    }
    $image.addClass(imageRotationClass);
  }

  if (isCordova) {
    $("#zoomInButton").hide();
    $("#zoomOutButton").hide();
    $("#printButton").hide();
  }

  // Init internationalization
  $.i18n.init({
    ns: {
      namespaces: ['ns.viewerImage']
    },
    debug: true,
    fallbackLng: 'en_US'
  }, function() {
    $('[data-i18n]').i18n();
  });

  // Nano progressbar
  $(function() {
    var options = {
      bg: '#42BEDB', // (optional) background css property, '#000' by default
      // leave target blank for global nanobar
      target: document.getElementById('nanoBar'), //(optional) Where to put the progress bar, nanobar will be fixed to top of document if target is null
      // id for new nanobar
      id: 'nanoBar' // (optional) id for nanobar div
    };
    var nanobar = new Nanobar(options);
    var pct = 0;
    $(document).ajaxSend(function() {
      pct += 0.1;
      // move bar
      nanobar.go(pct);
      if (pct > 100.0) {
        pct = 0.0;
      }
    }).ajaxComplete(function() {
      // Finish progress bar
      nanobar.go(100);
    });
  });

});
<|endoftext|>


<commit_before>/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

"use strict";

var config = require('./config.js');

var anyDB = require('any-db');
var mysqlConnection = anyDB.createPool(config.MYSQL_DATABASE_URL, {min: 2, max: 20});

var utils = require('./utils.js');

var express = require('express');

var app = express();
app.enable('trust proxy');
app.use(express.logger());
app.use(express.bodyParser());
app.use(express.compress());

app.use('/bootstrap', express.static(__dirname + '/bootstrap'));
app.use('/img', express.static(__dirname + '/img'));

var swig = require('swig');
app.engine('html', swig.renderFile);
app.engine('twig', swig.renderFile);
app.engine('swig', swig.renderFile);
app.set('view engine', 'twig'); // historical reasons
app.set('views', __dirname + '/templates');

var phpgate = require('./cgi.js').phpgate;

/*** routing routines ***/

app.get('/node/', function(request, response) {
	response.send('Node.js is up and running.');
});

app.get('/node-about/', function(request, response) {
	// warning: for testing purposes only
	var options = {};
	options.now = new Date();
	options.instance = 'about';
	options.loggedIn = false;
	response.render('about', options);
});

app.get('/', phpgate);
app.get('/about/', phpgate);
app.get('/register/', phpgate);
app.post('/register/', phpgate);
app.get('/login/', phpgate);
app.post('/login/', phpgate);
app.get('/profile/', phpgate);
app.get('/profile/id/:id/', phpgate);
app.get('/profile/user/:user/', phpgate);
app.get('/action/logout', phpgate);
app.get('/game/', phpgate);
app.get('/action/go/:to', phpgate);
app.get('/action/attack', phpgate);
app.get('/action/escape', phpgate);

app.get('/ajax/isNickBusy/:nick', function(request, response) {
	utils.user.userExists(mysqlConnection, request.param('nick'), function(error, result){
		if (!!error) { response.send(500); return; }
		response.json({ 'nick': request.param('nick'), 'isNickBusy': result });
	});
});

app.get('/stats/', phpgate);
app.get('/world/', phpgate);
app.get('/development/', phpgate);

/*
app.get('/', function(request, response) {
	response.redirect('/about/');
});

app.get('/about/', function(request, response) {
	var t = Date.now();
	var options = {};
	options.instance = 'about';
	options.loggedIn = false;
	response.render('about.twig', options);
	console.log(request.path+' - done in '+(Date.now()-t)+' ms');
});
*/

/***** main *****/
var port = process.env.PORT || 5000;
app.listen(port, function() {
	console.log("Listening on " + port);
	if (port==5000) console.log("Try http://localhost:" + port + "/");
});
<commit_msg>Add JS session refreshing middleware.<commit_after>/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

"use strict";

var config = require('./config.js');

var anyDB = require('any-db');
var mysqlConnection = anyDB.createPool(config.MYSQL_DATABASE_URL, {min: 2, max: 20});

var utils = require('./utils.js');

var async = require('async');

var express = require('express');

var app = express();
app.enable('trust proxy');
app.use(express.logger());
app.use(express.cookieParser());
app.use(express.bodyParser());
app.use(express.compress());

app.use('/bootstrap', express.static(__dirname + '/bootstrap'));
app.use('/img', express.static(__dirname + '/img'));

var swig = require('swig');
app.engine('html', swig.renderFile);
app.engine('twig', swig.renderFile);
app.engine('swig', swig.renderFile);
app.set('view engine', 'twig'); // historical reasons
app.set('views', __dirname + '/templates');

var phpgate = require('./cgi.js').phpgate;

app.use(function(request, response, next){
	if (!!request.cookies.sessid)
	{
		var sessid = request.cookies.sessid;
		async.waterfall([
				function(callback){
					utils.user.sessionActive(mysqlConnection, sessid, callback);
				},
				function(active, callback) {
					if (active)
					{
						console.log('REFRESHING ' + sessid);
						utils.user.refreshSession(mysqlConnection, sessid, config.sessionExpireTime, callback);
					}
					else
					{
						callback();
					}
				}
			],
			function(error, result)
			{
				next();
			}
		);
	}
});

/*** routing routines ***/

app.get('/node/', function(request, response) {
	response.send('Node.js is up and running.');
});

app.get('/node-about/', function(request, response) {
	// warning: for testing purposes only
	var options = {};
	options.now = new Date();
	options.instance = 'about';
	options.loggedIn = false;
	response.render('about', options);
});

app.get('/', phpgate);
app.get('/about/', phpgate);
app.get('/register/', phpgate);
app.post('/register/', phpgate);
app.get('/login/', phpgate);
app.post('/login/', phpgate);
app.get('/profile/', phpgate);
app.get('/profile/id/:id/', phpgate);
app.get('/profile/user/:user/', phpgate);
app.get('/action/logout', phpgate);
app.get('/game/', phpgate);
app.get('/action/go/:to', phpgate);
app.get('/action/attack', phpgate);
app.get('/action/escape', phpgate);

app.get('/ajax/isNickBusy/:nick', function(request, response) {
	utils.user.userExists(mysqlConnection, request.param('nick'), function(error, result){
		if (!!error) { response.send(500); return; }
		response.json({ 'nick': request.param('nick'), 'isNickBusy': result });
	});
});

app.get('/stats/', phpgate);
app.get('/world/', phpgate);
app.get('/development/', phpgate);

/*
app.get('/', function(request, response) {
	response.redirect('/about/');
});

app.get('/about/', function(request, response) {
	var t = Date.now();
	var options = {};
	options.instance = 'about';
	options.loggedIn = false;
	response.render('about.twig', options);
	console.log(request.path+' - done in '+(Date.now()-t)+' ms');
});
*/

/***** main *****/
var port = process.env.PORT || 5000;
app.listen(port, function() {
	console.log("Listening on " + port);
	if (port==5000) console.log("Try http://localhost:" + port + "/");
});
<|endoftext|>


<commit_before>'use strict'
var async = require('async')
var EventManager = require('ethereum-remix').lib.EventManager
var remix = require('ethereum-remix')
var codeUtil = remix.util.code
var Web3VMProvider = remix.web3.web3VMProvider

/**
  * poll web3 each 2s if web3
  * listen on transaction executed event if VM
  * attention: blocks returned by the event `newBlock` have slightly different json properties whether web3 or the VM is used
  * trigger 'newBlock'
  *
  */
class TxListener {
  constructor (opt) {
    this.event = new EventManager()
    this._appAPI = opt.appAPI
    this._web3VMProvider = new Web3VMProvider() // TODO this should maybe be put in app.js
    this._web3VMProvider.setVM(opt.appAPI.vm())
    this._resolvedTransactions = {}
    this._resolvedContracts = {}
    this.init()
    opt.appEvent.executionContext.register('contextChanged', (context) => {
      if (this.loopId) {
        this.startListening(context)
      }
    })
    opt.appEvent.udapp.register('transactionExecuted', (to, data, lookupOnly, txResult) => {
      if (this.loopId && this._appAPI.isVM()) {
        this._web3VMProvider.getTransaction(txResult.transactionHash, (error, tx) => {
          if (error) return console.log(error)
          this._newBlock({
            type: 'VM',
            number: -1,
            transactions: [tx]
          })
        })
      }
    })
  }

  /**
    * reset recorded transactions
    */
  init () {
    this.blocks = []
    this.lastBlock = null
  }

  /**
    * start listening for incoming transactions
    *
    * @param {String} type - type/name of the provider to add
    * @param {Object} obj  - provider
    */
  startListening () {
    this.stopListening()
    this.init()
    if (this._appAPI.context() === 'vm') {
      this.loopId = 'vm-listener'
    } else {
      this.loopId = setInterval(() => {
        this._appAPI.web3().eth.getBlockNumber((error, blockNumber) => {
          if (error) return console.log(error)
          if (!this.lastBlock || blockNumber > this.lastBlock) {
            this.lastBlock = blockNumber
            this._appAPI.web3().eth.getBlock(this.lastBlock, true, (error, result) => {
              if (!error) {
                this._newBlock(Object.assign({type: 'web3'}, result))
              }
            })
          }
        })
      }, 2)
    }
  }

  currentWeb3 () { // TODO this should maybe be put in app.js
    return this._appAPI.isVM() ? this._web3VMProvider : this._appAPI.web3()
  }

  /**
    * stop listening for incoming transactions. do not reset the recorded pool.
    *
    * @param {String} type - type/name of the provider to add
    * @param {Object} obj  - provider
    */
  stopListening () {
    if (this.loopId) {
      clearInterval(this.loopId)
    }
    this.loopId = null
  }

  /**
    * try to resolve the contract name from the given @arg address
    *
    * @param {String} address - contract address to resolve
    * @return {String} - contract name
    */
  resolvedContract (address) {
    return this._resolvedContracts[address]
  }

  /**
    * try to resolve the transaction from the given @arg txHash
    *
    * @param {String} txHash - contract address to resolve
    * @return {String} - contract name
    */
  resolvedTransaction (txHash) {
    return this._resolvedTransactions[txHash]
  }

  _newBlock (block) {
    this.blocks.push(block)
    this._resolve(block, () => {
      this.event.trigger('newBlock', [block])
    })
  }

  _resolve (block, callback) {
    async.each(block.transactions, (tx, cb) => {
      this._resolveTx(tx, cb)
    }, () => {
      callback()
    })
  }

  _resolveTx (tx, cb) {
    var contracts = this._appAPI.contracts()
    if (!contracts) return cb()
    var contractName
    if (!tx.to) {
      // contract creation / resolve using the creation bytes code
      // if web3: we have to call getTransactionReceipt to get the created address
      // if VM: created address already included
      var code = tx.input
      contractName = this._tryResolveContract(code, contracts, 'bytecode')
      if (contractName) {
        this._resolveCreationAddress(tx, (error, address) => {
          if (error) return cb(error)
          this._resolvedContracts[address] = contractName
          this._resolveFunction(contractName, contracts, tx, true)
          if (this._resolvedTransactions[tx.hash]) {
            this._resolvedTransactions[tx.hash].contractAddress = address
          }
          return cb()
        })
        return
      }
      return cb()
    } else {
      // first check known contract, resolve against the `runtimeBytecode` if not known
      contractName = this._resolvedContracts[tx.to]
      if (!contractName) {
        this.currentWeb3().eth.getCode(tx.to, (error, code) => {
          if (error) return cb(error)
          if (code) {
            var contractName = this._tryResolveContract(code, contracts, 'runtimeBytecode')
            if (contractName) {
              this._resolvedContracts[tx.to] = contractName
              this._resolveFunction(contractName, contracts, tx, false)
              return cb()
            }
            return cb()
          }
          return cb()
        })
        return
      }
      if (contractName) {
        this._resolveFunction(contractName, contracts, tx, false)
        return cb()
      }
      return cb()
    }
  }

  _resolveCreationAddress (tx, cb) {
    this.currentWeb3().eth.getTransactionReceipt(tx.hash, (error, receipt) => {
      if (!error) {
        cb(null, receipt.contractAddress)
      } else {
        cb(error)
      }
    })
  }

  _resolveFunction (contractName, compiledContracts, tx, isCtor) {
    if (!isCtor) {
      for (var fn in compiledContracts[contractName].functionHashes) {
        if (compiledContracts[contractName].functionHashes[fn] === tx.input.replace('0x', '').substring(0, 8)) {
          this._resolvedTransactions[tx.hash] = {
            to: tx.to,
            fn: fn,
            params: null
          }
        }
      // fallback function
      this._resolvedTransactions[tx.hash] = {
        to: tx.to,
        fn: '(fallback)',
        params: null
      }
    } else {
      this._resolvedTransactions[tx.hash] = {
        to: null,
        fn: '(constructor)',
        params: null
      }
    }
  }

  _tryResolveContract (codeToResolve, compiledContracts, type) {
    for (var k in compiledContracts) {
      if (codeUtil.compareByteCode(codeToResolve, '0x' + compiledContracts[k][type])) {
        return k
      }
    }
    return null
  }
}

module.exports = TxListener
<commit_msg>decodeParam in tx listener<commit_after>'use strict'
var async = require('async')
var ethJSABI = require('ethereumjs-abi')
var ethJSUtil = require('ethereumjs-util')
var EventManager = require('ethereum-remix').lib.EventManager
var remix = require('ethereum-remix')
var codeUtil = remix.util.code
var Web3VMProvider = remix.web3.web3VMProvider

/**
  * poll web3 each 2s if web3
  * listen on transaction executed event if VM
  * attention: blocks returned by the event `newBlock` have slightly different json properties whether web3 or the VM is used
  * trigger 'newBlock'
  *
  */
class TxListener {
  constructor (opt) {
    this.event = new EventManager()
    this._appAPI = opt.appAPI
    this._web3VMProvider = new Web3VMProvider() // TODO this should maybe be put in app.js
    this._web3VMProvider.setVM(opt.appAPI.vm())
    this._resolvedTransactions = {}
    this._resolvedContracts = {}
    this.init()
    opt.appEvent.executionContext.register('contextChanged', (context) => {
      if (this.loopId) {
        this.startListening(context)
      }
    })
    opt.appEvent.udapp.register('transactionExecuted', (to, data, lookupOnly, txResult) => {
      if (this.loopId && this._appAPI.isVM()) {
        this._web3VMProvider.getTransaction(txResult.transactionHash, (error, tx) => {
          if (error) return console.log(error)
          this._newBlock({
            type: 'VM',
            number: -1,
            transactions: [tx]
          })
        })
      }
    })
  }

  /**
    * reset recorded transactions
    */
  init () {
    this.blocks = []
    this.lastBlock = null
  }

  /**
    * start listening for incoming transactions
    *
    * @param {String} type - type/name of the provider to add
    * @param {Object} obj  - provider
    */
  startListening () {
    this.stopListening()
    this.init()
    if (this._appAPI.context() === 'vm') {
      this.loopId = 'vm-listener'
    } else {
      this.loopId = setInterval(() => {
        this._appAPI.web3().eth.getBlockNumber((error, blockNumber) => {
          if (error) return console.log(error)
          if (!this.lastBlock || blockNumber > this.lastBlock) {
            this.lastBlock = blockNumber
            this._appAPI.web3().eth.getBlock(this.lastBlock, true, (error, result) => {
              if (!error) {
                this._newBlock(Object.assign({type: 'web3'}, result))
              }
            })
          }
        })
      }, 2)
    }
  }

  currentWeb3 () { // TODO this should maybe be put in app.js
    return this._appAPI.isVM() ? this._web3VMProvider : this._appAPI.web3()
  }

  /**
    * stop listening for incoming transactions. do not reset the recorded pool.
    *
    * @param {String} type - type/name of the provider to add
    * @param {Object} obj  - provider
    */
  stopListening () {
    if (this.loopId) {
      clearInterval(this.loopId)
    }
    this.loopId = null
  }

  /**
    * try to resolve the contract name from the given @arg address
    *
    * @param {String} address - contract address to resolve
    * @return {String} - contract name
    */
  resolvedContract (address) {
    return this._resolvedContracts[address]
  }

  /**
    * try to resolve the transaction from the given @arg txHash
    *
    * @param {String} txHash - contract address to resolve
    * @return {String} - contract name
    */
  resolvedTransaction (txHash) {
    return this._resolvedTransactions[txHash]
  }

  _newBlock (block) {
    this.blocks.push(block)
    this._resolve(block, () => {
      this.event.trigger('newBlock', [block])
    })
  }

  _resolve (block, callback) {
    async.each(block.transactions, (tx, cb) => {
      this._resolveTx(tx, cb)
    }, () => {
      callback()
    })
  }

  _resolveTx (tx, cb) {
    var contracts = this._appAPI.contracts()
    if (!contracts) return cb()
    var contractName
    if (!tx.to) {
      // contract creation / resolve using the creation bytes code
      // if web3: we have to call getTransactionReceipt to get the created address
      // if VM: created address already included
      var code = tx.input
      contractName = this._tryResolveContract(code, contracts, 'bytecode')
      if (contractName) {
        this._resolveCreationAddress(tx, (error, address) => {
          if (error) return cb(error)
          this._resolvedContracts[address] = contractName
          this._resolveFunction(contractName, contracts, tx, true)
          if (this._resolvedTransactions[tx.hash]) {
            this._resolvedTransactions[tx.hash].contractAddress = address
          }
          return cb()
        })
        return
      }
      return cb()
    } else {
      // first check known contract, resolve against the `runtimeBytecode` if not known
      contractName = this._resolvedContracts[tx.to]
      if (!contractName) {
        this.currentWeb3().eth.getCode(tx.to, (error, code) => {
          if (error) return cb(error)
          if (code) {
            var contractName = this._tryResolveContract(code, contracts, 'runtimeBytecode')
            if (contractName) {
              this._resolvedContracts[tx.to] = contractName
              this._resolveFunction(contractName, contracts, tx, false)
              return cb()
            }
            return cb()
          }
          return cb()
        })
        return
      }
      if (contractName) {
        this._resolveFunction(contractName, contracts, tx, false)
        return cb()
      }
      return cb()
    }
  }

  _resolveCreationAddress (tx, cb) {
    this.currentWeb3().eth.getTransactionReceipt(tx.hash, (error, receipt) => {
      if (!error) {
        cb(null, receipt.contractAddress)
      } else {
        cb(error)
      }
    })
  }

  _resolveFunction (contractName, compiledContracts, tx, isCtor) {
    var abi = JSON.parse(compiledContracts[contractName].interface)
    var inputData = tx.input.replace('0x', '')
    if (!isCtor) {
      for (var fn in compiledContracts[contractName].functionHashes) {
        if (compiledContracts[contractName].functionHashes[fn] === inputData.substring(0, 8)) {
          this._resolvedTransactions[tx.hash] = {
            to: tx.to,
            fn: fn,
            params: this._decodeInputParams(inputData.substring(8), getFunction(abi, fn))
          }
          return
        }
      }
      // fallback function
      this._resolvedTransactions[tx.hash] = {
        to: tx.to,
        fn: '(fallback)',
        params: null
      }
    } else {
      var bytecode = compiledContracts[contractName].bytecode
      var params = null
      if (bytecode && bytecode.length) {
        params = this._decodeInputParams(inputData.substring(bytecode.length), getConstructorInterface(abi))
      }
      this._resolvedTransactions[tx.hash] = {
        to: null,
        fn: '(constructor)',
        params: params
      }
    }
  }

  _tryResolveContract (codeToResolve, compiledContracts, type) {
    for (var k in compiledContracts) {
      if (codeUtil.compareByteCode(codeToResolve, '0x' + compiledContracts[k][type])) {
        return k
      }
    }
    return null
  }

  _decodeInputParams (data, abi) {
    data = ethJSUtil.toBuffer('0x' + data)
    var inputTypes = []
    for (var i = 0; i < abi.inputs.length; i++) {
      inputTypes.push(abi.inputs[i].type)
    }
    return ethJSABI.rawDecode(inputTypes, data)
  }
}

// those function will be duplicate after the merged of the compile and run tabs split
function getConstructorInterface (abi) {
  var funABI = { 'name': '', 'inputs': [], 'type': 'constructor', 'outputs': [] }
  for (var i = 0; i < abi.length; i++) {
    if (abi[i].type === 'constructor') {
      funABI.inputs = abi[i].inputs || []
      break
    }
  }

  return funABI
}

function getFunction (abi, fnName) {
  fnName = fnName.split('(')[0]
  for (var i = 0; i < abi.length; i++) {
    if (abi[i].name === fnName) {
      return abi[i]
    }
  }
  return null
}

module.exports = TxListener
<|endoftext|>


<commit_before>/* Module dependencies */
var URI = require('URIjs');
var ipaddr = require('ipaddr.js');
var _ = require('lodash');
var _s = require('underscore.string');
var tld = require('tldjs');

function cleanLocation(location) {
    // Replace tabulations and line breaks by spaces
    location = location.replace(/(\r\n|\n|\r|\t)/gm, ' ');
    // Trim spaces and dashes
    location = _s.trim(location, '- ');
    return location;
}

function OnlineResource(onlineResource) {
    this.name = onlineResource.name;
    this.sourceLocation = onlineResource.link;
    this.sourceProtocol = onlineResource.protocol;
    this.description = onlineResource.description;

    this.location = this.parseLocation();
    this.query = this.parseAndNormalizeQuery();
}

OnlineResource.prototype.parseLocation = function () {
    if (!this.sourceLocation) throw new Error('location must be defined');
    var cleanedLocation = cleanLocation(this.sourceLocation);

    var uri = new URI(cleanedLocation);

    if (!uri.is('url')) throw new Error('Location must be an url');
    if (uri.is('relative')) throw new Error('Location must be absolute');
    if (uri.protocol() !== 'http' && uri.protocol() !== 'https') throw new Error('Location protocol must be http ou https');
    if (!uri.is('ip') && !uri.is('name')) throw new Error('Location must contain an IP address or a hostname');

    if (uri.is('ip')) {
        var addr = ipaddr.parse(uri.hostname());
        var range = addr.range();
        var rangesToExclude = [
            'unspecified',
            'broadcast',
            'multicast',
            'linkLocal',
            'loopback',
            'private',
            'reserved'
        ];
        if (range && _.includes(rangesToExclude, range)) throw new Error('IP address must be public');
    }

    if (uri.is('name')) {
        var hostname = uri.hostname();
        if (!tld.tldExists(hostname)) throw new Error('Hostname must be a valid TLD');
        if (_s.endsWith(hostname, 'ader.gouv.fr')) throw new Error('Hostname must be publicly accessible');
    }

    return uri;
};

OnlineResource.prototype.parseAndNormalizeQuery = function () {
    var query = {};

    // Ensure query string param names are lower-cased
    _.forEach(this.location.search(true), function (val, key) {
        query[key.toLowerCase()] = val;
    });

    return query;
};

OnlineResource.prototype.isWfsFeatureType = function () {
    var sourceProtocolContainsWfs = (this.sourceProtocol || '').toLowerCase().indexOf('wfs') >= 0;
    var sourceLocationIsWfsQuery = (this.query.service || '').toLowerCase() === 'wfs';

    var detectWfsProtocol = sourceProtocolContainsWfs || sourceLocationIsWfsQuery;

    if (!detectWfsProtocol) return false;

    var typeNameInQuery = this.query.typename || this.query.typenames || this.query.layers;
    var typeNameFromName = sourceProtocolContainsWfs && this.name;

    this.typeNameFound = typeNameInQuery || typeNameFromName;

    return !!this.typeNameFound;
};

OnlineResource.prototype.getFeatureTypeName = function () {
    return this.typeNameFound;
};

OnlineResource.prototype.getNormalizedWfsServiceLocation = function () {
    var location = this.location.clone();
    location.search(_.pick(this.query, 'map')); // Pick only map param from query string (MapServer)
    location.fragment('').normalize();
    return location.valueOf();
};

OnlineResource.prototype.isWmsLayer = function () {
    var sourceProtocolContainsWms = (this.sourceProtocol || '').toLowerCase().indexOf('wms') >= 0;
    var sourceLocationIsWmsQuery = (this.query.service || '').toLowerCase() === 'wms';

    var detectWmsProtocol = sourceProtocolContainsWms || sourceLocationIsWmsQuery;

    return detectWmsProtocol;
};

OnlineResource.prototype.isWellKnownService = function () {
    return _.includes(['wfs', 'wms'], this.query.service);
};

exports.OnlineResource = OnlineResource;
<commit_msg>Monkey-patch atom.geo-ide.application.i2<commit_after>/* Module dependencies */
var URI = require('URIjs');
var ipaddr = require('ipaddr.js');
var _ = require('lodash');
var _s = require('underscore.string');
var tld = require('tldjs');

function cleanLocation(location) {
    // Replace tabulations and line breaks by spaces
    location = location.replace(/(\r\n|\n|\r|\t)/gm, ' ');
    // Trim spaces and dashes
    location = _s.trim(location, '- ');
    return location;
}

function OnlineResource(onlineResource) {
    this.name = onlineResource.name;
    this.sourceLocation = onlineResource.link;
    this.sourceProtocol = onlineResource.protocol;
    this.description = onlineResource.description;

    this.location = this.parseLocation();
    this.query = this.parseAndNormalizeQuery();
}

OnlineResource.prototype.parseLocation = function () {
    if (!this.sourceLocation) throw new Error('location must be defined');
    var cleanedLocation = cleanLocation(this.sourceLocation);

    var uri = new URI(cleanedLocation);

    if (!uri.is('url')) throw new Error('Location must be an url');
    if (uri.is('relative')) throw new Error('Location must be absolute');
    if (uri.protocol() !== 'http' && uri.protocol() !== 'https') throw new Error('Location protocol must be http ou https');
    if (!uri.is('ip') && !uri.is('name')) throw new Error('Location must contain an IP address or a hostname');

    if (uri.is('ip')) {
        var addr = ipaddr.parse(uri.hostname());
        var range = addr.range();
        var rangesToExclude = [
            'unspecified',
            'broadcast',
            'multicast',
            'linkLocal',
            'loopback',
            'private',
            'reserved'
        ];
        if (range && _.includes(rangesToExclude, range)) throw new Error('IP address must be public');
    }

    if (uri.is('name')) {

        // TODO: Add a warning for that
        if (uri.hostname() === 'atom.geo-ide.application.i2') {
            uri.hostname('atom.geo-ide.developpement-durable.gouv.fr');
        }

        if (!tld.tldExists(uri.hostname())) throw new Error('Hostname must be a valid TLD');
        if (_s.endsWith(uri.hostname(), 'ader.gouv.fr')) throw new Error('Hostname must be publicly accessible');
    }

    return uri;
};

OnlineResource.prototype.parseAndNormalizeQuery = function () {
    var query = {};

    // Ensure query string param names are lower-cased
    _.forEach(this.location.search(true), function (val, key) {
        query[key.toLowerCase()] = val;
    });

    return query;
};

OnlineResource.prototype.isWfsFeatureType = function () {
    var sourceProtocolContainsWfs = (this.sourceProtocol || '').toLowerCase().indexOf('wfs') >= 0;
    var sourceLocationIsWfsQuery = (this.query.service || '').toLowerCase() === 'wfs';

    var detectWfsProtocol = sourceProtocolContainsWfs || sourceLocationIsWfsQuery;

    if (!detectWfsProtocol) return false;

    var typeNameInQuery = this.query.typename || this.query.typenames || this.query.layers;
    var typeNameFromName = sourceProtocolContainsWfs && this.name;

    this.typeNameFound = typeNameInQuery || typeNameFromName;

    return !!this.typeNameFound;
};

OnlineResource.prototype.getFeatureTypeName = function () {
    return this.typeNameFound;
};

OnlineResource.prototype.getNormalizedWfsServiceLocation = function () {
    var location = this.location.clone();
    location.search(_.pick(this.query, 'map')); // Pick only map param from query string (MapServer)
    location.fragment('').normalize();
    return location.valueOf();
};

OnlineResource.prototype.isWmsLayer = function () {
    var sourceProtocolContainsWms = (this.sourceProtocol || '').toLowerCase().indexOf('wms') >= 0;
    var sourceLocationIsWmsQuery = (this.query.service || '').toLowerCase() === 'wms';

    var detectWmsProtocol = sourceProtocolContainsWms || sourceLocationIsWmsQuery;

    return detectWmsProtocol;
};

OnlineResource.prototype.isWellKnownService = function () {
    return _.includes(['wfs', 'wms'], this.query.service);
};

exports.OnlineResource = OnlineResource;
<|endoftext|>


<commit_before>define(function () {
    "use strict";

    /**
     * @author Eberhard Graether / http://egraether.com/
     */

    var TrackballControls = function ( object, domElement ) {

        var _this = this;
        var STATE = { NONE: -1, ROTATE: 0, ZOOM: 1, PAN: 2, TOUCH_ROTATE: 3, TOUCH_ZOOM: 4, TOUCH_PAN: 5 };

        this.object = object;
        this.domElement = ( domElement !== undefined ) ? domElement : document;

        // API

        this.enabled = true;

        this.screen = { left: 0, top: 0, width: 0, height: 0 };

        this.rotateSpeed = 1.0;
        this.zoomSpeed = 1.2;
        this.panSpeed = 0.3;

        this.noRotate = false;
        this.noZoom = false;
        this.noPan = false;
        this.noRoll = false;

        this.staticMoving = false;
        this.dynamicDampingFactor = 0.2;

        this.minDistance = 0;
        this.maxDistance = Infinity;

        this.keys = [ 65 /*A*/, 83 /*S*/, 68 /*D*/ ];

        // internals

        this.target = new THREE.Vector3();

        var lastPosition = new THREE.Vector3();

        var _state = STATE.NONE,
        _prevState = STATE.NONE,

        _eye = new THREE.Vector3(),

        _rotateStart = new THREE.Vector3(),
        _rotateEnd = new THREE.Vector3(),

        _zoomStart = new THREE.Vector2(),
        _zoomEnd = new THREE.Vector2(),

        _touchZoomDistanceStart = 0,
        _touchZoomDistanceEnd = 0,

        _panStart = new THREE.Vector2(),
        _panEnd = new THREE.Vector2();

        // for reset

        this.target0 = this.target.clone();
        this.position0 = this.object.position.clone();
        this.up0 = this.object.up.clone();

        // events

        var changeEvent = { type: 'change' };
        var startEvent = { type: 'start'};
        var endEvent = { type: 'end'};

        // methods

        this.handleResize = function () {

            if ( this.domElement === document ) {

                this.screen.left = 0;
                this.screen.top = 0;
                this.screen.width = window.innerWidth;
                this.screen.height = window.innerHeight;

            } else {

                this.screen = this.domElement.getBoundingClientRect();

            }

        };

        this.handleEvent = function ( event ) {

            if ( typeof this[ event.type ] == 'function' ) {

                this[ event.type ]( event );

            }

        };

        this.getMouseOnScreen = function ( clientX, clientY ) {

            return new THREE.Vector2(
                ( clientX - _this.screen.left ) / _this.screen.width,
                ( clientY - _this.screen.top ) / _this.screen.height
            );

        };

        this.getMouseProjectionOnBall = function ( clientX, clientY ) {

            var mouseOnBall = new THREE.Vector3(
                ( clientX - _this.screen.width * 0.5 - _this.screen.left ) / (_this.screen.width*.5),
                ( _this.screen.height * 0.5 + _this.screen.top - clientY ) / (_this.screen.height*.5),
                0.0
            );

            var length = mouseOnBall.length();

            if ( _this.noRoll ) {

                if ( length < Math.SQRT1_2 ) {

                    mouseOnBall.z = Math.sqrt( 1.0 - length*length );

                } else {

                    mouseOnBall.z = .5 / length;

                }

            } else if ( length > 1.0 ) {

                mouseOnBall.normalize();

            } else {

                mouseOnBall.z = Math.sqrt( 1.0 - length * length );

            }

            _eye.copy( _this.object.position ).sub( _this.target );

            var projection = _this.object.up.clone().setLength( mouseOnBall.y );
            projection.add( _this.object.up.clone().cross( _eye ).setLength( mouseOnBall.x ) );
            projection.add( _eye.setLength( mouseOnBall.z ) );

            return projection;

        };

        this.rotateCamera = function () {

            var angle = Math.acos( _rotateStart.dot( _rotateEnd ) / _rotateStart.length() / _rotateEnd.length() );

            if ( angle ) {

                var axis = ( new THREE.Vector3() ).crossVectors( _rotateStart, _rotateEnd ).normalize(),
                    quaternion = new THREE.Quaternion();

                angle *= _this.rotateSpeed;

                quaternion.setFromAxisAngle( axis, -angle );

                _eye.applyQuaternion( quaternion );
                _this.object.up.applyQuaternion( quaternion );

                _rotateEnd.applyQuaternion( quaternion );

                if ( _this.staticMoving ) {

                    _rotateStart.copy( _rotateEnd );

                } else {

                    quaternion.setFromAxisAngle( axis, angle * ( _this.dynamicDampingFactor - 1.0 ) );
                    _rotateStart.applyQuaternion( quaternion );

                }

            }

        };

        this.zoomCamera = function () {

            if ( _state === STATE.TOUCH_ZOOM ) {

                var factor = _touchZoomDistanceStart / _touchZoomDistanceEnd;
                _touchZoomDistanceStart = _touchZoomDistanceEnd;
                _eye.multiplyScalar( factor );

            } else {

                var factor = 1.0 + ( _zoomEnd.y - _zoomStart.y ) * _this.zoomSpeed;

                if ( factor !== 1.0 && factor > 0.0 ) {

                    _eye.multiplyScalar( factor );

                    if ( _this.staticMoving ) {

                        _zoomStart.copy( _zoomEnd );

                    } else {

                        _zoomStart.y += ( _zoomEnd.y - _zoomStart.y ) * this.dynamicDampingFactor;

                    }

                }

            }

        };

        this.panCamera = function () {

            var mouseChange = _panEnd.clone().sub( _panStart );

            if ( mouseChange.lengthSq() ) {

                mouseChange.multiplyScalar( _eye.length() * _this.panSpeed );

                var pan = _eye.clone().cross( _this.object.up ).setLength( mouseChange.x );
                pan.add( _this.object.up.clone().setLength( mouseChange.y ) );

                _this.object.position.add( pan );
                _this.target.add( pan );

                if ( _this.staticMoving ) {

                    _panStart = _panEnd;

                } else {

                    _panStart.add( mouseChange.subVectors( _panEnd, _panStart ).multiplyScalar( _this.dynamicDampingFactor ) );

                }

            }

        };

        this.checkDistances = function () {

            if ( !_this.noZoom || !_this.noPan ) {

                if ( _eye.lengthSq() > _this.maxDistance * _this.maxDistance ) {

                    _this.object.position.addVectors( _this.target, _eye.setLength( _this.maxDistance ) );

                }

                if ( _eye.lengthSq() < _this.minDistance * _this.minDistance ) {

                    _this.object.position.addVectors( _this.target, _eye.setLength( _this.minDistance ) );

                }

            }

        };

        this.update = function () {

            _eye.subVectors( _this.object.position, _this.target );

            if ( !_this.noRotate ) {

                _this.rotateCamera();

            }

            if ( !_this.noZoom ) {

                _this.zoomCamera();

            }

            if ( !_this.noPan ) {

                _this.panCamera();

            }

            _this.object.position.addVectors( _this.target, _eye );

            _this.checkDistances();

            _this.object.lookAt( _this.target );

            if ( lastPosition.distanceToSquared( _this.object.position ) > 0 ) {

                _this.dispatchEvent( changeEvent );

                lastPosition.copy( _this.object.position );

            }

        };

        this.reset = function () {

            _state = STATE.NONE;
            _prevState = STATE.NONE;

            _this.target.copy( _this.target0 );
            _this.object.position.copy( _this.position0 );
            _this.object.up.copy( _this.up0 );

            _eye.subVectors( _this.object.position, _this.target );

            _this.object.lookAt( _this.target );

            _this.dispatchEvent( changeEvent );

            lastPosition.copy( _this.object.position );

        };

        // listeners

        function keydown( event ) {

            if ( _this.enabled === false ) return;

            window.removeEventListener( 'keydown', keydown );

            _prevState = _state;

            if ( _state !== STATE.NONE ) {

                return;

            } else if ( event.keyCode === _this.keys[ STATE.ROTATE ] && !_this.noRotate ) {

                _state = STATE.ROTATE;

            } else if ( event.keyCode === _this.keys[ STATE.ZOOM ] && !_this.noZoom ) {

                _state = STATE.ZOOM;

            } else if ( event.keyCode === _this.keys[ STATE.PAN ] && !_this.noPan ) {

                _state = STATE.PAN;

            }

        }

        function keyup( event ) {

            if ( _this.enabled === false ) return;

            _state = _prevState;

            window.addEventListener( 'keydown', keydown, false );

        }

        function mousedown( event ) {

            if ( _this.enabled === false ) return;

            event.preventDefault();
            event.stopPropagation();

            if ( _state === STATE.NONE ) {

                _state = event.button;

            }

            if ( _state === STATE.ROTATE && !_this.noRotate ) {

                _rotateStart = _this.getMouseProjectionOnBall( event.clientX, event.clientY );
                _rotateEnd.copy(_rotateStart)

            } else if ( _state === STATE.ZOOM && !_this.noZoom ) {

                _zoomStart = _this.getMouseOnScreen( event.clientX, event.clientY );
                _zoomEnd.copy(_zoomStart);

            } else if ( _state === STATE.PAN && !_this.noPan ) {

                _panStart = _this.getMouseOnScreen( event.clientX, event.clientY );
                _panEnd.copy(_panStart)

            }

            document.addEventListener( 'mousemove', mousemove, false );
            document.addEventListener( 'mouseup', mouseup, false );
            _this.dispatchEvent( startEvent );

        }

        function mousemove( event ) {

            if ( _this.enabled === false ) return;

            event.preventDefault();
            event.stopPropagation();

            if ( _state === STATE.ROTATE && !_this.noRotate ) {

                _rotateEnd = _this.getMouseProjectionOnBall( event.clientX, event.clientY );

            } else if ( _state === STATE.ZOOM && !_this.noZoom ) {

                _zoomEnd = _this.getMouseOnScreen( event.clientX, event.clientY );

            } else if ( _state === STATE.PAN && !_this.noPan ) {

                _panEnd = _this.getMouseOnScreen( event.clientX, event.clientY );

            }

        }

        function mouseup( event ) {

            if ( _this.enabled === false ) return;

            event.preventDefault();
            event.stopPropagation();

            _state = STATE.NONE;

            document.removeEventListener( 'mousemove', mousemove );
            document.removeEventListener( 'mouseup', mouseup );
            _this.dispatchEvent( endEvent );

        }

        function mousewheel( event ) {

            if ( _this.enabled === false ) return;

            event.preventDefault();
            event.stopPropagation();

            var delta = 0;

            if ( event.wheelDelta ) { // WebKit / Opera / Explorer 9

                delta = event.wheelDelta / 40;

            } else if ( event.detail ) { // Firefox

                delta = - event.detail / 3;

            }

            _zoomStart.y += delta * 0.01;
            _this.dispatchEvent( startEvent );
            _this.dispatchEvent( endEvent );

        }

        function touchstart( event ) {

            if ( _this.enabled === false ) return;

            switch ( event.touches.length ) {

                case 1:
                    _state = STATE.TOUCH_ROTATE;
                    _rotateStart = _rotateEnd = _this.getMouseProjectionOnBall( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
                    break;

                case 2:
                    _state = STATE.TOUCH_ZOOM;
                    var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
                    var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
                    _touchZoomDistanceEnd = _touchZoomDistanceStart = Math.sqrt( dx * dx + dy * dy );
                    break;

                case 3:
                    _state = STATE.TOUCH_PAN;
                    _panStart = _panEnd = _this.getMouseOnScreen( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
                    break;

                default:
                    _state = STATE.NONE;

            }
            _this.dispatchEvent( startEvent );

        }

        function touchmove( event ) {

            if ( _this.enabled === false ) return;

            event.preventDefault();
            event.stopPropagation();

            switch ( event.touches.length ) {

                case 1:
                    _rotateEnd = _this.getMouseProjectionOnBall( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
                    break;

                case 2:
                    var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
                    var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
                    _touchZoomDistanceEnd = Math.sqrt( dx * dx + dy * dy )
                    break;

                case 3:
                    _panEnd = _this.getMouseOnScreen( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
                    break;

                default:
                    _state = STATE.NONE;

            }

        }

        function touchend( event ) {

            if ( _this.enabled === false ) return;

            switch ( event.touches.length ) {

                case 1:
                    _rotateStart = _rotateEnd = _this.getMouseProjectionOnBall( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
                    break;

                case 2:
                    _touchZoomDistanceStart = _touchZoomDistanceEnd = 0;
                    break;

                case 3:
                    _panStart = _panEnd = _this.getMouseOnScreen( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
                    break;

            }

            _state = STATE.NONE;
            _this.dispatchEvent( endEvent );

        }

        this.domElement.addEventListener( 'contextmenu', function ( event ) { event.preventDefault(); }, false );

        this.domElement.addEventListener( 'mousedown', mousedown, false );

        this.domElement.addEventListener( 'mousewheel', mousewheel, false );
        this.domElement.addEventListener( 'DOMMouseScroll', mousewheel, false ); // firefox

        this.domElement.addEventListener( 'touchstart', touchstart, false );
        this.domElement.addEventListener( 'touchend', touchend, false );
        this.domElement.addEventListener( 'touchmove', touchmove, false );

        window.addEventListener( 'keydown', keydown, false );
        window.addEventListener( 'keyup', keyup, false );

        this.handleResize();

    };

    TrackballControls.prototype = Object.create( THREE.EventDispatcher.prototype );

    return TrackballControls;
});
<commit_msg>Update to the latest TrackballControls<commit_after>define(function () {
    "use strict";

    /**
     * @author Eberhard Graether / http://egraether.com/
     * @author Mark Lundin 	/ http://mark-lundin.com
     */

    var TrackballControls = function ( object, domElement ) {

        var _this = this;
        var STATE = { NONE: -1, ROTATE: 0, ZOOM: 1, PAN: 2, TOUCH_ROTATE: 3, TOUCH_ZOOM: 4, TOUCH_PAN: 5 };

        this.object = object;
        this.domElement = ( domElement !== undefined ) ? domElement : document;

        // API

        this.enabled = true;

        this.screen = { left: 0, top: 0, width: 0, height: 0 };

        this.rotateSpeed = 1.0;
        this.zoomSpeed = 1.2;
        this.panSpeed = 0.3;

        this.noRotate = false;
        this.noZoom = false;
        this.noPan = false;
        this.noRoll = false;

        this.staticMoving = false;
        this.dynamicDampingFactor = 0.2;

        this.minDistance = 0;
        this.maxDistance = Infinity;

        this.keys = [ 65 /*A*/, 83 /*S*/, 68 /*D*/ ];

        // internals

        this.target = new THREE.Vector3();

        var lastPosition = new THREE.Vector3();

        var _state = STATE.NONE,
        _prevState = STATE.NONE,

        _eye = new THREE.Vector3(),

        _rotateStart = new THREE.Vector3(),
        _rotateEnd = new THREE.Vector3(),

        _zoomStart = new THREE.Vector2(),
        _zoomEnd = new THREE.Vector2(),

        _touchZoomDistanceStart = 0,
        _touchZoomDistanceEnd = 0,

        _panStart = new THREE.Vector2(),
        _panEnd = new THREE.Vector2();

        // for reset

        this.target0 = this.target.clone();
        this.position0 = this.object.position.clone();
        this.up0 = this.object.up.clone();

        // events

        var changeEvent = { type: 'change' };
        var startEvent = { type: 'start'};
        var endEvent = { type: 'end'};

        // methods

        this.handleResize = function () {

            if ( this.domElement === document ) {

                this.screen.left = 0;
                this.screen.top = 0;
                this.screen.width = window.innerWidth;
                this.screen.height = window.innerHeight;

            } else {

                this.screen = this.domElement.getBoundingClientRect();
                // adjustments come from similar code in the jquery offset() function
                var d = this.domElement.ownerDocument.documentElement
                this.screen.left += window.pageXOffset - d.clientLeft
                this.screen.top += window.pageYOffset - d.clientTop

            }

        };

        this.handleEvent = function ( event ) {

            if ( typeof this[ event.type ] == 'function' ) {

                this[ event.type ]( event );

            }

        };

        this.getMouseOnScreen = function ( pageX, pageY, vector ) {

            return vector.set(
                ( pageX - _this.screen.left ) / _this.screen.width,
                ( pageY - _this.screen.top ) / _this.screen.height
            );

        };

        this.getMouseProjectionOnBall = (function(){

            var objectUp = new THREE.Vector3(),
                mouseOnBall = new THREE.Vector3();

            return function ( pageX, pageY, projection ) {

                mouseOnBall.set(
                    ( pageX - _this.screen.width * 0.5 - _this.screen.left ) / (_this.screen.width*.5),
                    ( _this.screen.height * 0.5 + _this.screen.top - pageY ) / (_this.screen.height*.5),
                    0.0
                );

                var length = mouseOnBall.length();

                if ( _this.noRoll ) {

                    if ( length < Math.SQRT1_2 ) {

                        mouseOnBall.z = Math.sqrt( 1.0 - length*length );

                    } else {

                        mouseOnBall.z = .5 / length;

                    }

                } else if ( length > 1.0 ) {

                    mouseOnBall.normalize();

                } else {

                    mouseOnBall.z = Math.sqrt( 1.0 - length * length );

                }

                _eye.copy( _this.object.position ).sub( _this.target );

                projection.copy( _this.object.up ).setLength( mouseOnBall.y )
                projection.add( objectUp.copy( _this.object.up ).cross( _eye ).setLength( mouseOnBall.x ) );
                projection.add( _eye.setLength( mouseOnBall.z ) );

                return projection;
            }

        }());

        this.rotateCamera = (function(){

            var axis = new THREE.Vector3(),
                quaternion = new THREE.Quaternion();

            return function () {

                var angle = Math.acos( _rotateStart.dot( _rotateEnd ) / _rotateStart.length() / _rotateEnd.length() );

                if ( angle ) {

                    axis.crossVectors( _rotateStart, _rotateEnd ).normalize();

                    angle *= _this.rotateSpeed;

                    quaternion.setFromAxisAngle( axis, -angle );

                    _eye.applyQuaternion( quaternion );
                    _this.object.up.applyQuaternion( quaternion );

                    _rotateEnd.applyQuaternion( quaternion );

                    if ( _this.staticMoving ) {

                        _rotateStart.copy( _rotateEnd );

                    } else {

                        quaternion.setFromAxisAngle( axis, angle * ( _this.dynamicDampingFactor - 1.0 ) );
                        _rotateStart.applyQuaternion( quaternion );

                    }

                }
            }

        }());

        this.zoomCamera = function () {

            if ( _state === STATE.TOUCH_ZOOM ) {

                var factor = _touchZoomDistanceStart / _touchZoomDistanceEnd;
                _touchZoomDistanceStart = _touchZoomDistanceEnd;
                _eye.multiplyScalar( factor );

            } else {

                var factor = 1.0 + ( _zoomEnd.y - _zoomStart.y ) * _this.zoomSpeed;

                if ( factor !== 1.0 && factor > 0.0 ) {

                    _eye.multiplyScalar( factor );

                    if ( _this.staticMoving ) {

                        _zoomStart.copy( _zoomEnd );

                    } else {

                        _zoomStart.y += ( _zoomEnd.y - _zoomStart.y ) * this.dynamicDampingFactor;

                    }

                }

            }

        };

        this.panCamera = (function(){

            var mouseChange = new THREE.Vector2(),
                objectUp = new THREE.Vector3(),
                pan = new THREE.Vector3();

            return function () {

                mouseChange.copy( _panEnd ).sub( _panStart );

                if ( mouseChange.lengthSq() ) {

                    mouseChange.multiplyScalar( _eye.length() * _this.panSpeed );

                    pan.copy( _eye ).cross( _this.object.up ).setLength( mouseChange.x );
                    pan.add( objectUp.copy( _this.object.up ).setLength( mouseChange.y ) );

                    _this.object.position.add( pan );
                    _this.target.add( pan );

                    if ( _this.staticMoving ) {

                        _panStart.copy( _panEnd );

                    } else {

                        _panStart.add( mouseChange.subVectors( _panEnd, _panStart ).multiplyScalar( _this.dynamicDampingFactor ) );

                    }

                }
            }

        }());

        this.checkDistances = function () {

            if ( !_this.noZoom || !_this.noPan ) {

                if ( _eye.lengthSq() > _this.maxDistance * _this.maxDistance ) {

                    _this.object.position.addVectors( _this.target, _eye.setLength( _this.maxDistance ) );

                }

                if ( _eye.lengthSq() < _this.minDistance * _this.minDistance ) {

                    _this.object.position.addVectors( _this.target, _eye.setLength( _this.minDistance ) );

                }

            }

        };

        this.update = function () {

            _eye.subVectors( _this.object.position, _this.target );

            if ( !_this.noRotate ) {

                _this.rotateCamera();

            }

            if ( !_this.noZoom ) {

                _this.zoomCamera();

            }

            if ( !_this.noPan ) {

                _this.panCamera();

            }

            _this.object.position.addVectors( _this.target, _eye );

            _this.checkDistances();

            _this.object.lookAt( _this.target );

            if ( lastPosition.distanceToSquared( _this.object.position ) > 0 ) {

                _this.dispatchEvent( changeEvent );

                lastPosition.copy( _this.object.position );

            }

        };

        this.reset = function () {

            _state = STATE.NONE;
            _prevState = STATE.NONE;

            _this.target.copy( _this.target0 );
            _this.object.position.copy( _this.position0 );
            _this.object.up.copy( _this.up0 );

            _eye.subVectors( _this.object.position, _this.target );

            _this.object.lookAt( _this.target );

            _this.dispatchEvent( changeEvent );

            lastPosition.copy( _this.object.position );

        };

        // listeners

        function keydown( event ) {

            if ( _this.enabled === false ) return;

            window.removeEventListener( 'keydown', keydown );

            _prevState = _state;

            if ( _state !== STATE.NONE ) {

                return;

            } else if ( event.keyCode === _this.keys[ STATE.ROTATE ] && !_this.noRotate ) {

                _state = STATE.ROTATE;

            } else if ( event.keyCode === _this.keys[ STATE.ZOOM ] && !_this.noZoom ) {

                _state = STATE.ZOOM;

            } else if ( event.keyCode === _this.keys[ STATE.PAN ] && !_this.noPan ) {

                _state = STATE.PAN;

            }

        }

        function keyup( event ) {

            if ( _this.enabled === false ) return;

            _state = _prevState;

            window.addEventListener( 'keydown', keydown, false );

        }

        function mousedown( event ) {

            if ( _this.enabled === false ) return;

            event.preventDefault();
            event.stopPropagation();

            if ( _state === STATE.NONE ) {

                _state = event.button;

            }

            if ( _state === STATE.ROTATE && !_this.noRotate ) {

                _this.getMouseProjectionOnBall( event.pageX, event.pageY, _rotateStart );
                _rotateEnd.copy(_rotateStart)

            } else if ( _state === STATE.ZOOM && !_this.noZoom ) {

                _this.getMouseOnScreen( event.pageX, event.pageY, _zoomStart );
                _zoomEnd.copy(_zoomStart);

            } else if ( _state === STATE.PAN && !_this.noPan ) {

                _this.getMouseOnScreen( event.pageX, event.pageY, _panStart );
                _panEnd.copy(_panStart)

            }

            document.addEventListener( 'mousemove', mousemove, false );
            document.addEventListener( 'mouseup', mouseup, false );
            _this.dispatchEvent( startEvent );

        }

        function mousemove( event ) {

            if ( _this.enabled === false ) return;

            event.preventDefault();
            event.stopPropagation();

            if ( _state === STATE.ROTATE && !_this.noRotate ) {

                _this.getMouseProjectionOnBall( event.pageX, event.pageY, _rotateEnd );

            } else if ( _state === STATE.ZOOM && !_this.noZoom ) {

                _this.getMouseOnScreen( event.pageX, event.pageY, _zoomEnd );

            } else if ( _state === STATE.PAN && !_this.noPan ) {

                _this.getMouseOnScreen( event.pageX, event.pageY, _panEnd );

            }

        }

        function mouseup( event ) {

            if ( _this.enabled === false ) return;

            event.preventDefault();
            event.stopPropagation();

            _state = STATE.NONE;

            document.removeEventListener( 'mousemove', mousemove );
            document.removeEventListener( 'mouseup', mouseup );
            _this.dispatchEvent( endEvent );

        }

        function mousewheel( event ) {

            if ( _this.enabled === false ) return;

            event.preventDefault();
            event.stopPropagation();

            var delta = 0;

            if ( event.wheelDelta ) { // WebKit / Opera / Explorer 9

                delta = event.wheelDelta / 40;

            } else if ( event.detail ) { // Firefox

                delta = - event.detail / 3;

            }

            _zoomStart.y += delta * 0.01;
            _this.dispatchEvent( startEvent );
            _this.dispatchEvent( endEvent );

        }

        function touchstart( event ) {

            if ( _this.enabled === false ) return;

            switch ( event.touches.length ) {

                case 1:
                    _state = STATE.TOUCH_ROTATE;
                    _rotateEnd.copy( _this.getMouseProjectionOnBall( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY, _rotateStart ));
                    break;

                case 2:
                    _state = STATE.TOUCH_ZOOM;
                    var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
                    var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
                    _touchZoomDistanceEnd = _touchZoomDistanceStart = Math.sqrt( dx * dx + dy * dy );
                    break;

                case 3:
                    _state = STATE.TOUCH_PAN;
                    _panEnd.copy( _this.getMouseOnScreen( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY, _panStart ));
                    break;

                default:
                    _state = STATE.NONE;

            }
            _this.dispatchEvent( startEvent );

        }

        function touchmove( event ) {

            if ( _this.enabled === false ) return;

            event.preventDefault();
            event.stopPropagation();

            switch ( event.touches.length ) {

                case 1:
                    _this.getMouseProjectionOnBall( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY, _rotateEnd );
                    break;

                case 2:
                    var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
                    var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
                    _touchZoomDistanceEnd = Math.sqrt( dx * dx + dy * dy )
                    break;

                case 3:
                    _this.getMouseOnScreen( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY, _panEnd );
                    break;

                default:
                    _state = STATE.NONE;

            }

        }

        function touchend( event ) {

            if ( _this.enabled === false ) return;

            switch ( event.touches.length ) {

                case 1:
                    _rotateStart.copy( _this.getMouseProjectionOnBall( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY, _rotateEnd ));
                    break;

                case 2:
                    _touchZoomDistanceStart = _touchZoomDistanceEnd = 0;
                    break;

                case 3:
                    _panStart.copy( _this.getMouseOnScreen( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY, _panEnd ));
                    break;

            }

            _state = STATE.NONE;
            _this.dispatchEvent( endEvent );

        }

        this.domElement.addEventListener( 'contextmenu', function ( event ) { event.preventDefault(); }, false );

        this.domElement.addEventListener( 'mousedown', mousedown, false );

        this.domElement.addEventListener( 'mousewheel', mousewheel, false );
        this.domElement.addEventListener( 'DOMMouseScroll', mousewheel, false ); // firefox

        this.domElement.addEventListener( 'touchstart', touchstart, false );
        this.domElement.addEventListener( 'touchend', touchend, false );
        this.domElement.addEventListener( 'touchmove', touchmove, false );

        window.addEventListener( 'keydown', keydown, false );
        window.addEventListener( 'keyup', keyup, false );

        this.handleResize();

    };

    TrackballControls.prototype = Object.create( THREE.EventDispatcher.prototype );

    return TrackballControls;
});
<|endoftext|>