<commit_before>angular.module('queueController.controller', [])
  .controller('queueController', function($scope, $window, $routeParams) {

    var socket = io();
    $scope.queue = [];
    $scope.playing = null;
    $scope.isPlaying = false;
    $scope.no_results = false;

    // set the header background color
    var color = intToARGB(hashCode($routeParams.key));
    console.log(color);
    $('.banner').css('background', '#' + color);

    // Hash any string into an integer value
    function hashCode(str) {
      var hash = 0;
      for (var i = 0; i < str.length; i++) {
        hash = str.charCodeAt(i) + ((hash << 5) - hash);
      }
      return hash;
    }

    // Convert an int to hexadecimal with a max length
    // of six characters.
    function intToARGB(i) {
      var h = ((i >> 24) & 0xFF).toString(16) +
        ((i >> 16) & 0xFF).toString(16) +
        ((i >> 8) & 0xFF).toString(16) +
        (i & 0xFF).toString(16);
      return h.substring(0, 6);
    }

    // safe apply to check if already in progress
    $scope.safeApply = function(fn) {
      var phase = this.$root.$$phase;
      if (phase == '$apply' || phase == '$digest') {
        if (fn && (typeof(fn) === 'function')) {
          fn();
        }
      } else {
        this.$apply(fn);
      }
    };

    function convertToObjects(list_of_jsons) {
      for (var i = 0; i < list_of_jsons.length; i++) {
        list_of_jsons[i] = JSON.parse(list_of_jsons[i]);
      }
      return list_of_jsons;
    }

    socket.on('connect', function() {
      console.log('connected to server');
    });

    socket.on('search_results', function(data) {
      $scope.safeApply(function() {
        if (data.status == 'failure' || !data) {
          $scope.no_results = true;
        } else {
          $scope.no_results = false;
          $scope.searches = data;
        }
      });
    });

    socket.on($routeParams.key + '-queue', function(data) {
      if (!data || data.status == 'failure') {
        // the video queuing did not work
        return;
      }

      data = convertToObjects(data);
      $scope.safeApply(function() {
        if ($scope.queue.length == 0 && !$scope.isPlaying) {
          $scope.queue = $scope.queue.concat(data);
          loadNextVideo();
        } else {
          $scope.queue = $scope.queue.concat(data);
        }
      });
    });

    $scope.search = function(track, artist) {
      socket.emit('search', {
        artist: artist,
        track: track,
        key: $routeParams.key
      });
    }

    $scope.queueTrack = function(t) {
      socket.emit('queue', {
        track: t,
        key: $routeParams.key
      });
    }

    function loadVideo(video_obj) {
      $scope.playing = video_obj;
      $scope.isPlaying = true;
      player.loadVideoById(video_obj.video_id);

      // this syncs the times with other clients
      // based on the expirey time of the video
      var now = new Date().getTime() / 1000;
      var ex = parseInt(video_obj.extime);
      var diff = ex - now;
      var duration = parseInt(video_obj.duration);
      player.seekTo(duration - diff, true);
    }

    function loadNextVideo() {
      if (player) {
        // queue would be 0 on first load of the page
        if ($scope.queue.length > 0) {
          loadVideo($scope.queue.shift());
        } else {
          $scope.playing = null;
          $scope.isPlaying = false;
        }
      }
    }

    // youtube javascript api v3

    // get height to keep aspect ratio 16:9
    function getHeight(width) {
      return width / (16 / 9);
    }

    var tag = document.createElement('script');
    tag.src = "https://www.youtube.com/iframe_api";
    var firstScriptTag = document.getElementsByTagName('script')[0];
    firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
    var player;

    $window.onYouTubeIframeAPIReady = function() {
      var width = $('.player-wrapper').width();
      var height = getHeight(width);

      player = new YT.Player('player', {
        events: {
          'onReady': onPlayerReady,
          'onStateChange': onPlayerStateChange
        }
      });
    }

    // 4. The API will call this function when the video player is ready.
    $window.onPlayerReady = function(event) {
      socket.emit('get_queue', {
        key: $routeParams.key
      });
    }

    // 5. The API calls this function when the player's state changes.
    //    The function indicates that when playing a video (state=1),
    //    the player should play for six seconds and then stop.
    var done = false;

    $window.onPlayerStateChange = function(event) {
      if (event.data == YT.PlayerState.ENDED) {
        $scope.safeApply(function() {
          loadNextVideo();
        });
      }
    }

    $window.stopVideo = function() {
      player.stopVideo();
    }
  });
<commit_msg>removed dead code<commit_after>angular.module('queueController.controller', [])
  .controller('queueController', function($scope, $window, $routeParams) {

    var socket = io();
    $scope.queue = [];
    $scope.playing = null;
    $scope.isPlaying = false;
    $scope.no_results = false;

    // set the header background color
    var color = intToARGB(hashCode($routeParams.key));
    console.log(color);
    $('.banner').css('background', '#' + color);

    // Hash any string into an integer value
    function hashCode(str) {
      var hash = 0;
      for (var i = 0; i < str.length; i++) {
        hash = str.charCodeAt(i) + ((hash << 5) - hash);
      }
      return hash;
    }

    // Convert an int to hexadecimal with a max length
    // of six characters.
    function intToARGB(i) {
      var h = ((i >> 24) & 0xFF).toString(16) +
        ((i >> 16) & 0xFF).toString(16) +
        ((i >> 8) & 0xFF).toString(16) +
        (i & 0xFF).toString(16);
      return h.substring(0, 6);
    }

    // safe apply to check if already in progress
    $scope.safeApply = function(fn) {
      var phase = this.$root.$$phase;
      if (phase == '$apply' || phase == '$digest') {
        if (fn && (typeof(fn) === 'function')) {
          fn();
        }
      } else {
        this.$apply(fn);
      }
    };

    function convertToObjects(list_of_jsons) {
      for (var i = 0; i < list_of_jsons.length; i++) {
        list_of_jsons[i] = JSON.parse(list_of_jsons[i]);
      }
      return list_of_jsons;
    }

    socket.on('connect', function() {
      console.log('connected to server');
    });

    socket.on('search_results', function(data) {
      $scope.safeApply(function() {
        if (data.status == 'failure' || !data) {
          $scope.no_results = true;
        } else {
          $scope.no_results = false;
          $scope.searches = data;
        }
      });
    });

    socket.on($routeParams.key + '-queue', function(data) {
      if (!data || data.status == 'failure') {
        // the video queuing did not work
        return;
      }

      data = convertToObjects(data);
      $scope.safeApply(function() {
        if ($scope.queue.length == 0 && !$scope.isPlaying) {
          $scope.queue = $scope.queue.concat(data);
          loadNextVideo();
        } else {
          $scope.queue = $scope.queue.concat(data);
        }
      });
    });

    $scope.search = function(track, artist) {
      socket.emit('search', {
        artist: artist,
        track: track,
        key: $routeParams.key
      });
    }

    $scope.queueTrack = function(t) {
      socket.emit('queue', {
        track: t,
        key: $routeParams.key
      });
    }

    function loadVideo(video_obj) {
      $scope.playing = video_obj;
      $scope.isPlaying = true;
      player.loadVideoById(video_obj.video_id);

      // this syncs the times with other clients
      // based on the expirey time of the video
      var now = new Date().getTime() / 1000;
      var ex = parseInt(video_obj.extime);
      var diff = ex - now;
      var duration = parseInt(video_obj.duration);
      player.seekTo(duration - diff, true);
    }

    function loadNextVideo() {
      if (player) {
        // queue would be 0 on first load of the page
        if ($scope.queue.length > 0) {
          loadVideo($scope.queue.shift());
        } else {
          $scope.playing = null;
          $scope.isPlaying = false;
        }
      }
    }

    // youtube javascript api v3

    var tag = document.createElement('script');
    tag.src = "https://www.youtube.com/iframe_api";
    var firstScriptTag = document.getElementsByTagName('script')[0];
    firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
    var player;

    $window.onYouTubeIframeAPIReady = function() {
      player = new YT.Player('player', {
        events: {
          'onReady': onPlayerReady,
          'onStateChange': onPlayerStateChange
        }
      });
    }

    // 4. The API will call this function when the video player is ready.
    $window.onPlayerReady = function(event) {
      socket.emit('get_queue', {
        key: $routeParams.key
      });
    }

    // 5. The API calls this function when the player's state changes.
    //    The function indicates that when playing a video (state=1),
    //    the player should play for six seconds and then stop.
    var done = false;

    $window.onPlayerStateChange = function(event) {
      if (event.data == YT.PlayerState.ENDED) {
        $scope.safeApply(function() {
          loadNextVideo();
        });
      }
    }

    $window.stopVideo = function() {
      player.stopVideo();
    }
  });
<|endoftext|>


<commit_before>module.exports = function (lncli, config, utils) {
	return {
		restrict: "E",
		replace: true,
		transclude: false,
		scope: { baseValue: "=?baseValue", baseUnit: "=?baseUnit", mainUnit: "=?mainUnit", altUnit: "=?altUnit" },
		templateUrl: "templates/partials/amount.html",
		link: function (scope, elt, attrs) {
			if (!attrs.baseUnit || (attrs.baseUnit === "sat")) {
				var mainUnit = attrs.mainUnit ? attrs.mainUnit : lncli.getConfigValue(config.keys.AMOUNT_MAIN_UNIT);
				if (mainUnit) {
					var mainValue;
					switch (mainUnit) {
						case "btc":
							mainValue = scope.baseValue / 100000000;
							scope.mainValue = utils.toFixedWithoutTrailingZeroes(mainValue, 8);
							scope.mainUnit = "btc";
							break;
						case "mbtc":
							mainValue = scope.baseValue / 100000;
							scope.mainValue = utils.toFixedWithoutTrailingZeroes(mainValue, 5);
							scope.mainUnit = "mbtc";
							break;
						case "bit":
							mainValue = scope.baseValue / 100;
							scope.mainValue = utils.toFixedWithoutTrailingZeroes(mainValue, 2);
							scope.mainUnit = "bit";
							break;
						case "none":
							scope.mainValue = scope.baseValue;
							break;
						case "usd":
						case "eur":
							lncli.getCoinPrice(true, mainUnit).then(function (price) {
								mainValue = price * scope.baseValue / 100000000;
								scope.mainValue = utils.toFixedWithoutTrailingZeroes(mainValue, 4);
								scope.mainUnit = mainUnit;
							}, function (err) {
								console.log("Error:", err);
							});
							break;
						default:
							scope.mainValue = scope.baseValue;
							scope.mainUnit = "sat";
					}
				} else {
					scope.mainValue = scope.baseValue;
					scope.mainUnit = "sat";
				}
				var altUnit = attrs.altUnit ? attrs.altUnit : lncli.getConfigValue(config.keys.AMOUNT_ALT_UNIT);
				if (altUnit) {
					var altValue;
					switch (altUnit) {
						case "btc":
							altValue = scope.baseValue / 100000000;
							scope.altValue = utils.toFixedWithoutTrailingZeroes(altValue, 8);
							scope.altUnit = "btc";
							break;
						case "mbtc":
							altValue = scope.baseValue / 100000;
							scope.altValue = utils.toFixedWithoutTrailingZeroes(altValue, 5);
							scope.altUnit = "mbtc";
							break;
						case "bit":
							altValue = scope.baseValue / 100;
							scope.altValue = utils.toFixedWithoutTrailingZeroes(altValue, 2);
							scope.altUnit = "bit";
							break;
						case "none":
							break;
						case "usd":
						case "eur":
							lncli.getCoinPrice(true, altUnit).then(function (price) {
								altValue = price * scope.baseValue / 100000000;
								scope.altValue = utils.toFixedWithoutTrailingZeroes(altValue, 4);
								scope.altUnit = altUnit;
							}, function (err) {
								console.log("Error:", err);
							});
							break;
						default:
							scope.altValue = scope.baseValue;
							scope.altUnit = "sat";
					}
				}
			}
		},
	};
};
<commit_msg>Fixex #154 channel balances display bug<commit_after>module.exports = function (lncli, config, utils) {
	return {
		restrict: "E",
		replace: true,
		transclude: false,
		scope: { baseValue: "=?baseValue", baseUnit: "=?baseUnit", mainUnit: "=?mainUnit", altUnit: "=?altUnit" },
		templateUrl: "templates/partials/amount.html",
		link: function (scope, elt, attrs) {
			scope.$watch("baseValue", function (baseValue, oldBaseValue) {
				if (!attrs.baseUnit || (attrs.baseUnit === "sat")) {
					var mainUnit = attrs.mainUnit ? attrs.mainUnit : lncli.getConfigValue(config.keys.AMOUNT_MAIN_UNIT);
					if (mainUnit) {
						var mainValue;
						switch (mainUnit) {
							case "btc":
								mainValue = scope.baseValue / 100000000;
								scope.mainValue = utils.toFixedWithoutTrailingZeroes(mainValue, 8);
								scope.mainUnit = "btc";
								break;
							case "mbtc":
								mainValue = scope.baseValue / 100000;
								scope.mainValue = utils.toFixedWithoutTrailingZeroes(mainValue, 5);
								scope.mainUnit = "mbtc";
								break;
							case "bit":
								mainValue = scope.baseValue / 100;
								scope.mainValue = utils.toFixedWithoutTrailingZeroes(mainValue, 2);
								scope.mainUnit = "bit";
								break;
							case "none":
								scope.mainValue = scope.baseValue;
								break;
							case "usd":
							case "eur":
								lncli.getCoinPrice(true, mainUnit).then(function (price) {
									mainValue = price * scope.baseValue / 100000000;
									scope.mainValue = utils.toFixedWithoutTrailingZeroes(mainValue, 4);
									scope.mainUnit = mainUnit;
								}, function (err) {
									console.log("Error:", err);
								});
								break;
							default:
								scope.mainValue = scope.baseValue;
								scope.mainUnit = "sat";
						}
					} else {
						scope.mainValue = scope.baseValue;
						scope.mainUnit = "sat";
					}
					var altUnit = attrs.altUnit ? attrs.altUnit : lncli.getConfigValue(config.keys.AMOUNT_ALT_UNIT);
					if (altUnit) {
						var altValue;
						switch (altUnit) {
							case "btc":
								altValue = scope.baseValue / 100000000;
								scope.altValue = utils.toFixedWithoutTrailingZeroes(altValue, 8);
								scope.altUnit = "btc";
								break;
							case "mbtc":
								altValue = scope.baseValue / 100000;
								scope.altValue = utils.toFixedWithoutTrailingZeroes(altValue, 5);
								scope.altUnit = "mbtc";
								break;
							case "bit":
								altValue = scope.baseValue / 100;
								scope.altValue = utils.toFixedWithoutTrailingZeroes(altValue, 2);
								scope.altUnit = "bit";
								break;
							case "none":
								break;
							case "usd":
							case "eur":
								lncli.getCoinPrice(true, altUnit).then(function (price) {
									altValue = price * scope.baseValue / 100000000;
									scope.altValue = utils.toFixedWithoutTrailingZeroes(altValue, 4);
									scope.altUnit = altUnit;
								}, function (err) {
									console.log("Error:", err);
								});
								break;
							default:
								scope.altValue = scope.baseValue;
								scope.altUnit = "sat";
						}
					}
				}
			});
		},
	};
};
<|endoftext|>


<commit_before>// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.

couchTests.http = function(debug) {
  var db = new CouchDB("test_suite_db", {"X-Couch-Full-Commit":"false"});
  db.deleteDb();

  // bug COUCHDB-100: DELETE on non-existent DB returns 500 instead of 404
  db.deleteDb();

  db.createDb();

  // PUT on existing DB should return 412 instead of 500
  if (debug) debugger;

  var xhr = CouchDB.request("PUT", "/test_suite_db/test", {body: "{}"});

  TEquals("http://127.0.0.1:5984/test_suite_db/test",
    xhr.getResponseHeader("Location"),
    "should include ip address");

  xhr = CouchDB.request("PUT", "/test_suite_db/test2", {
    body: "{}",
    headers: {"X-Forwarded-Host": "mysite.com"}
  });

  TEquals("http://mysite.com/test_suite_db/test2",
    xhr.getResponseHeader("Location"),
    "should include X-Forwarded-Host");

  run_on_modified_server([{
    section:"httpd",
    key:"x_forwarded_host",
    value:"X-Host"}],
    function() {
      xhr = CouchDB.request("PUT", "/test_suite_db/test3", {
        body: "{}",
        headers: {"X-Host": "mysite2.com"}
      });
      TEquals("http://mysite2.com/test_suite_db/test3",
        xhr.getResponseHeader("Location"),
        "should include X-Host");
    });
}
<commit_msg>make http.js hostname-aware, patch by Benoit Chesneau, closes COUCHDB-475<commit_after>// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.

couchTests.http = function(debug) {
  var db = new CouchDB("test_suite_db", {"X-Couch-Full-Commit":"false"});
  db.deleteDb();

  // bug COUCHDB-100: DELETE on non-existent DB returns 500 instead of 404
  db.deleteDb();

  db.createDb();

  // PUT on existing DB should return 412 instead of 500
  if (debug) debugger;

  var xhr = CouchDB.request("PUT", "/test_suite_db/test", {body: "{}"});
  var host = CouchDB.host;

  TEquals("http://" + host + "/test_suite_db/test",
    xhr.getResponseHeader("Location"),
    "should include ip address");

  xhr = CouchDB.request("PUT", "/test_suite_db/test2", {
    body: "{}",
    headers: {"X-Forwarded-Host": "mysite.com"}
  });

  TEquals("http://mysite.com/test_suite_db/test2",
    xhr.getResponseHeader("Location"),
    "should include X-Forwarded-Host");

  run_on_modified_server([{
    section:"httpd",
    key:"x_forwarded_host",
    value:"X-Host"}],
    function() {
      xhr = CouchDB.request("PUT", "/test_suite_db/test3", {
        body: "{}",
        headers: {"X-Host": "mysite2.com"}
      });
      TEquals("http://mysite2.com/test_suite_db/test3",
        xhr.getResponseHeader("Location"),
        "should include X-Host");
    });
}
<|endoftext|>


<commit_before>var TempStore;
var pageNum = 1;

var pdfDoc,
  pageRendering,
  pageNumPending,
  scale,
  canvas,
  ctx;

PDFJS.disableStream = true;
// The workerSrc property shall be specified.
PDFJS.workerSrc = 'scripts/pdf.worker.js';

socket.on('updateDocs', function (data) {

  console.log(data);

  app.service('uploads').get(data.Documents)
    .then(result => {
      const downloadUrl = result.uri;

      console.log('Stored blob with id', result.id);

      showing(downloadUrl, data.Page);
    }).catch(err => {
    console.error(err);
  });

});

socket.on('updatePage', function (data) {

  console.log(data);

  pageNum = data.Page;
  queueRenderPage(pageNum);

});

function getData(data) {

  const docId = data.getAttribute("data-documentId");

  socket.emit('updateDocs', {documentId: docId});

  app.service('uploads').get(docId)
    .then(result => {
      const downloadUrl = result.uri;
      showing(downloadUrl, 1)
    })

}

function renderPage(num) {
  pageRendering = true;
  // Using promise to fetch the page
  pdfDoc.getPage(num).then(function (page) {

    var container = document.getElementById('the-container');

    var viewport = page.getViewport(1);

    if (viewport.width > viewport.height) {
      var scale = (window.innerWidth * 80 / 100) / viewport.width;
    } else if (viewport.width < viewport.height) {
      console.log("ia", (window.innerHeight * 95 / 100) / viewport.height)
      var scale = (window.innerHeight * 95 / 100) / viewport.height;
    } else {
      var scale = 1;
    }

    viewport = page.getViewport(scale);
    canvas.height = viewport.height;
    canvas.width = viewport.width;

    // Render PDF page into canvas context
    var renderContext = {
      canvasContext: ctx,
      viewport: viewport
    };
    var renderTask = page.render(renderContext);

    // Wait for rendering to finish
    renderTask.promise.then(function () {
      pageRendering = false;
      if (pageNumPending !== null) {
        // New page rendering is pending
        renderPage(pageNumPending);
        pageNumPending = null;
      }
    });
  });

  // Update page counters
  document.getElementById('page_num').textContent = pageNum;
}

function queueRenderPage(num) {
  if (pageRendering) {
    pageNumPending = num;
  } else {
    renderPage(num);
  }
}

function onPrevPage() {
  if (pageNum <= 1) {
    return;
  }
  pageNum--;
  queueRenderPage(pageNum);
}
document.getElementById('prev').addEventListener('click', onPrevPage);

/**
 * Displays next page.
 */
function onNextPage() {
  if (pageNum >= pdfDoc.numPages) {
    return;
  }
  pageNum++;
  queueRenderPage(pageNum);
}
document.getElementById('next').addEventListener('click', onNextPage);

$(window).keydown(function (e) {

  var key = e.which;

  if (key == 13 || key == 39) {

    if (app.get('owner') === false) {
      return false
    }

    if (pageNum >= pdfDoc.numPages) {
      return false;
    }
    else {
      socket.emit('updatePage', {page: pageNum + 1});
      onNextPage();
    }

    return false;

  }

  else if (key == 37) { // left arrow

    if (app.get('owner') === false) {
      return false
    }

    if (pageNum <= 1) {
      return false;
    }
    else {
      socket.emit('updatePage', {page: pageNum - 1});
      onPrevPage();
    }

    return false;
  }
});

window.addEventListener('resize', drawStuff, false);

function showing(data, page) {

  if (TempStore != data) {
    reset();
    pageNum = page;
  }

  pdfDoc = null;
  pageRendering = false;
  pageNumPending = null;
  scale = 1.2;
  canvas = document.getElementById('the-canvas');
  ctx = canvas.getContext('2d');

  // If absolute URL from the remote server is provided, configure the CORS
  // header on that server.
  var url = data
  TempStore = data;

  /**
   * Asynchronously downloads PDF.
   */
  PDFJS.getDocument(url).then(function (pdfDoc_) {
    pdfDoc = pdfDoc_;
    document.getElementById('page_count').textContent = pdfDoc.numPages;

    // Initial/first page rendering
    renderPage(pageNum);
  });

}

function drawStuff() {
  if (TempStore) {
    renderPage(pageNum);
  }
}

function reset() {

  var oldcanv = document.getElementById('the-canvas');
  document.getElementById('the-container').removeChild(oldcanv);

  var canv = document.createElement('canvas');
  canv.id = 'the-canvas';
  document.getElementById('the-container').appendChild(canv);

}
<commit_msg>masta<commit_after>var TempStore;
var pageNum = 1;

var pdfDoc,
  pageRendering,
  pageNumPending,
  scale,
  canvas,
  ctx;

PDFJS.disableStream = true;
// The workerSrc property shall be specified.
PDFJS.workerSrc = 'scripts/pdf.worker.js';

socket.on('updateDocs', function (data) {

  console.log(data);

  app.service('uploads').get(data.Documents)
    .then(result => {
      const downloadUrl = result.uri;

      console.log('Stored blob with id', result.id);

      showing(downloadUrl, data.Page);
    }).catch(err => {
    console.error(err);
  });

});

socket.on('updatePage', function (data) {

  console.log(data);

  pageNum = data.Page;
  queueRenderPage(pageNum);

});

function getData(data) {

  const docId = data.getAttribute("data-documentId");

  socket.emit('updateDocs', {documentId: docId});

  app.service('uploads').get(docId)
    .then(result => {
      const downloadUrl = result.uri;
      showing(downloadUrl, 1)
    }).catch(err => {
    console.error(err);
  });

}

function renderPage(num) {
  pageRendering = true;
  // Using promise to fetch the page
  pdfDoc.getPage(num).then(function (page) {

    var container = document.getElementById('the-container');

    var viewport = page.getViewport(1);

    if (viewport.width > viewport.height) {
      var scale = (window.innerWidth * 80 / 100) / viewport.width;
    } else if (viewport.width < viewport.height) {
      console.log("ia", (window.innerHeight * 95 / 100) / viewport.height)
      var scale = (window.innerHeight * 95 / 100) / viewport.height;
    } else {
      var scale = 1;
    }

    viewport = page.getViewport(scale);
    canvas.height = viewport.height;
    canvas.width = viewport.width;

    // Render PDF page into canvas context
    var renderContext = {
      canvasContext: ctx,
      viewport: viewport
    };
    var renderTask = page.render(renderContext);

    // Wait for rendering to finish
    renderTask.promise.then(function () {
      pageRendering = false;
      if (pageNumPending !== null) {
        // New page rendering is pending
        renderPage(pageNumPending);
        pageNumPending = null;
      }
    });
  });

  // Update page counters
  document.getElementById('page_num').textContent = pageNum;
}

function queueRenderPage(num) {
  if (pageRendering) {
    pageNumPending = num;
  } else {
    renderPage(num);
  }
}

function onPrevPage() {
  if (pageNum <= 1) {
    return;
  }
  pageNum--;
  queueRenderPage(pageNum);
}
document.getElementById('prev').addEventListener('click', onPrevPage);

/**
 * Displays next page.
 */
function onNextPage() {
  if (pageNum >= pdfDoc.numPages) {
    return;
  }
  pageNum++;
  queueRenderPage(pageNum);
}
document.getElementById('next').addEventListener('click', onNextPage);

$(window).keydown(function (e) {

  var key = e.which;

  if (key == 13 || key == 39) {

    if (app.get('owner') === false) {
      return false
    }

    if (pageNum >= pdfDoc.numPages) {
      return false;
    }
    else {
      socket.emit('updatePage', {page: pageNum + 1});
      onNextPage();
    }

    return false;

  }

  else if (key == 37) { // left arrow

    if (app.get('owner') === false) {
      return false
    }

    if (pageNum <= 1) {
      return false;
    }
    else {
      socket.emit('updatePage', {page: pageNum - 1});
      onPrevPage();
    }

    return false;
  }
});

window.addEventListener('resize', drawStuff, false);

function showing(data, page) {

  if (TempStore != data) {
    reset();
    pageNum = page;
  }

  pdfDoc = null;
  pageRendering = false;
  pageNumPending = null;
  scale = 1.2;
  canvas = document.getElementById('the-canvas');
  ctx = canvas.getContext('2d');

  // If absolute URL from the remote server is provided, configure the CORS
  // header on that server.
  var url = data
  TempStore = data;

  /**
   * Asynchronously downloads PDF.
   */
  PDFJS.getDocument(url).then(function (pdfDoc_) {
    pdfDoc = pdfDoc_;
    document.getElementById('page_count').textContent = pdfDoc.numPages;

    // Initial/first page rendering
    renderPage(pageNum);
  });

}

function drawStuff() {
  if (TempStore) {
    renderPage(pageNum);
  }
}

function reset() {

  var oldcanv = document.getElementById('the-canvas');
  document.getElementById('the-container').removeChild(oldcanv);

  var canv = document.createElement('canvas');
  canv.id = 'the-canvas';
  document.getElementById('the-container').appendChild(canv);

}
<|endoftext|>


<commit_before>#!/usr/bin/env node
var _ = require('lodash');
var cheerio = require('cheerio');
var moment = require('moment');
var debug = require('debug')('parser:promotedTitle');
var parse = require('./lib/parse');
var utils = require('../lib/utils');
var entities = require('entities');
var nconf = require('nconf');

var postcount = 0;
var errorcount = 0;

nconf.set("PARSER_PROMOTEDTITLE_VERSION", "201612.03");

function getPromotedTitle(snippet) {

	var title;
	var title_type;
	var found = false;

	var e_threshold;
	var e_ptr;

	postcount ++;

    var $ = cheerio.load(snippet.html);

	var e_threshold = $('div.userContent');

	// original missed p title ObjectId("5838f145c8c8b82a4efe1fe4")
	e_ptr = $(e_threshold).find("p").first();
	if (e_ptr.text() !== "") {
		title = e_ptr.text();
		found = true;
	} else {
		e_ptr = $(e_threshold).next().find(".clearfix").first();
		e_ptr.children("div").each(function() {
			if (!$(this).find("button")[0]) {
				if ($(this).children().first().text() === entities.decodeHTML($(this).children().first().html()) && $(this).children().first().text() !== "") {
					title = $(this).children().first().text();
					found = true;
				}
			}
		});
	}

	if (!found) {
		errorcount++;
        debug("Err %d post %d [%s] Title NOT FOUND", errorcount, postcount, snippet.id);
        return { "promotedTitle": false };
	} else {
		debug("Err %d post %d [%s] Title: %s", errorcount, postcount, snippet.id, title);
	    return {
            "promotedTitle": true,
            "title": title,
            "titleId": utils.hash({'title': title})
        };
	}
};

return parse.please({
    'name': 'promotedTitle', /* this name is the same in parsers-key */
    'requirements': {'type': 'promoted'},
    'implementation': getPromotedTitle,
    'since': "2016-09-13",
    'until': moment().toISOString(),
});

<commit_msg>updated promotedTitle<commit_after>#!/usr/bin/env node
var _ = require('lodash');
var cheerio = require('cheerio');
var moment = require('moment');
var debug = require('debug')('parser:promotedTitle');
var parse = require('./lib/parse');
var utils = require('../lib/utils');
var entities = require('entities');
var nconf = require('nconf');

var postcount = 0;
var errorcount = 0;

nconf.set("PARSER_PROMOTEDTITLE_VERSION", "201612.03");

function getPromotedTitle(snippet) {

	var title;
    var name;
	var title_type;
	var found = false;
	var e_threshold;
	var e_ptr;

	postcount ++;

    var $ = cheerio.load(snippet.html);

	var e_threshold = $('div.userContent');

	e_ptr = $(e_threshold).find("p").first();
	if (e_ptr.text() !== "") {
		title = e_ptr.text();
		found = true;
	} else {
		e_ptr = $(e_threshold).next().find(".clearfix").first();
		e_ptr.children("div").each(function() {
			if (!$(this).find("button")[0]) {
				if ($(this).children().first().text() === entities.decodeHTML($(this).children().first().html()) && $(this).children().first().text() !== "") {
					title = $(this).children().first().text();
					found = true;
				}
			}
		});
	}

    try {
        var name = $('a[data-hovercard^="/ajax/hovercard/page"]').text();
    } catch(error) {
        name = null;
    }

	if (!found) {
		errorcount++;
        debug("Err %d post %d [%s] Title NOT FOUND", errorcount, postcount, snippet.id);
        return { "promotedTitle": false };
	} else {
		debug("+[%s] %s ≬ %s (err %d/%d)", snippet.id, name, title, errorcount, postcount);
	    return {
            "promotedTitle": true,
            "title": title,
            "promotedName": name,
            "titleId": utils.hash({'title': title})
        };
	}
};

return parse.please({
    'name': 'promotedTitle', /* this name is the same in parsers-key */
    'requirements': {'type': 'promoted'},
    'implementation': getPromotedTitle,
    'since': "2016-09-13",
    'until': moment().toISOString(),
});

<|endoftext|>


<commit_before>define(['utils', 'config', 'jquery', 'underscore'],
function(utils, config, $, _) {
  'use strict';

  /*
   * utils.ensure_jquery
   */
  describe('utils.ensure_jquery', function() {
    it('should always return a jQuery object', function() {
      expect(utils.ensure_jquery()).toBeAjQueryObject();
      expect(utils.ensure_jquery([])).toBeAjQueryObject();
      expect(utils.ensure_jquery($('<div>')[0])).toBeAjQueryObject();
    });

    it('should wrap HTMLElement(s)', function() {
      var div_1 = $('<div>')[0];
      var div_2 = $('<div>')[0];
      var div_3 = $('<div>')[0];

      expect(utils.ensure_jquery(div_1).length).toEqual(1);
      expect(utils.ensure_jquery([div_1]).length).toEqual(1);
      expect(utils.ensure_jquery([div_1, div_2]).length).toEqual(2);
      expect(utils.ensure_jquery([div_1, div_2, div_3]).length).toEqual(3);
    });

    it('should return an empty set for non HTMLElement/Arrays', function() {
      expect(utils.ensure_jquery().length).toEqual(0);
      expect(utils.ensure_jquery(123).length).toEqual(0);
      expect(utils.ensure_jquery('div').length).toEqual(0);
    });
  });

  /*
   * utils.ensure_array
   */
  describe('utils.ensure_array', function() {
    it('should always return an array', function() {
      expect(utils.ensure_array()).toEqual([]);
      expect(utils.ensure_array(null)).toEqual([]);
      expect(utils.ensure_array([])).toEqual([]);
      expect(utils.ensure_array([1,2,3])).toEqual([1,2,3]);
      expect(utils.ensure_array(123)).toEqual([123]);
      expect(utils.ensure_array({})).toBeAnArray();
      expect(utils.ensure_array({ 'foo': [] })).toBeAnArray();
      expect(utils.ensure_array(function(){})).toBeAnArray();
    });
  });

  /*
   * utils.ensure_string
   */
  describe('utils.ensure_string', function() {
    var input;

    it('should always return a string', function() {
      expect(utils.ensure_string()).toEqual('');
      expect(utils.ensure_string(null)).toEqual('');
      expect(utils.ensure_string(-1)).toEqual('-1');
      expect(utils.ensure_string('foo')).toEqual('foo');

      input = [1,2,3];
      expect(utils.ensure_string(input)).toEqual(Array.prototype.toString.call(input));

      input = { foo: 'bar' };
      expect(utils.ensure_string(input)).toEqual(Object.prototype.toString.call(input));

      input = function foo() {};
      expect(utils.ensure_string(input)).toEqual(Function.prototype.toString.call(input));
    });
  });

  /*
   * utils.module
   */
  describe('utils.module', function() {
    it('should initially return an empty object', function() {
      var module = utils.module('foo', null, false);
      expect(module.priv).toBeDefined();
      expect(_.size(module)).toEqual(1); // just priv
    });

    it('should allow extending a base object', function() {
      var module = utils.module('foo', { 'bar': 123 }, false);
      expect(module.bar).toEqual(123);
    });

    it('should allow attaching to the global window', function() {
      var module = utils.module('foo_test', null, false);
      expect(window.foo_test).toBeUndefined();

      module = utils.module('foo_test', null, true);
      expect(window.foo_test).toBeDefined();
      expect(module).toEqual(window.foo_test);
      delete window.foo_test;
    });
  });

  /*
   * utils.no_quotes
   */
  describe('utils.no_quotes', function() {
    it('should always return a string', function() {
      expect(utils.no_quotes()).toEqual('');
      expect(utils.no_quotes('')).toEqual('');
      expect(utils.no_quotes(null)).toEqual('');
    });

    it('should remove all double quotes', function() {
      expect(utils.no_quotes('"""')).toEqual('');
      expect(utils.no_quotes('foo"bar')).toEqual('foobar');
      expect(utils.no_quotes('foo\"bar')).toEqual('foobar');
      expect(utils.no_quotes('"foo" says "bar"')).toEqual('foo says bar');
    });
  });

  /*
   * utils.extension
   */
  describe('utils.extension', function() {
    it('should return the correct extension', function() {
      expect(utils.extension()).toEqual('');
      expect(utils.extension('')).toEqual('');
      expect(utils.extension('foo.js')).toEqual('js');
      expect(utils.extension('" foo.bar.css "')).toEqual('css');
    });
  });

  /*
   * utils.script_element_string
   */
  describe('utils.script_element_string', function() {
    it('should return a <script> element string for a URI', function() {
      var script = utils.script_element_string('foo.js');
      expect(script).toEqual('<script type="application/javascript" src="foo.js"></script>');
    });

    it('should allow for a custom mime-type', function() {
      var script = utils.script_element_string('bar.js', 'foo/bar');
      expect(script).toEqual('<script type="foo/bar" src="bar.js"></script>');
    });
  });

  /*
   * utils.style_element_string
   */
  describe('utils.style_element_string', function() {
    it('should return a <style> element string for a URI', function() {
      var style = utils.style_element_string('foo.css');
      expect(style).toEqual('<link rel="stylesheet" type="text/css" href="foo.css">');
    });

    it('should allow for a custom mime-type', function() {
      var style = utils.style_element_string('bar.css', 'foo/bar');
      expect(style).toEqual('<link rel="stylesheet" type="foo/bar" href="bar.css">');
    });
  });

  /*
   * utils.resource_tag
   */
  describe('utils.resource_tag', function() {
    it('should return "script" for JavaScript files', function() {
      expect(utils.resource_tag('foo.js')).toEqual('script');
    });

    it('should return "link" for CSS files', function() {
      expect(utils.resource_tag('bar.css')).toEqual('link');
    });

    it('should return null for unknown file types', function() {
      expect(utils.resource_tag()).toEqual(null);
      expect(utils.resource_tag('')).toEqual(null);
      expect(utils.resource_tag('foo.bar')).toEqual(null);
      expect(utils.resource_tag('bar.tld')).toEqual(null);
    });
  });

  /*
   * utils.promise_now
   */
  describe('utils.promise_now', function() {
    var value;

    it('should return a promise to resolve to a value', function() {
      runs(function() {
        utils.promise_now('foobar').done(function(val) { value = val; });
      });

      waitsFor(function() {
        return value === 'foobar';
      }, 'promise to resolve to an expected value', 1000);
    });
  });

  /*
   * utils.clamp
   */
  describe('utils.clamp', function() {

    it('should return value, if no min or max provided', function() {
      expect(utils.clamp(-3)).toEqual(-3);
      expect(utils.clamp(0)).toEqual(0);
      expect(utils.clamp(5)).toEqual(5);
    });

    it('should clamp value over min, if max is not provided', function() {
      expect(utils.clamp(0, 0)).toEqual(0);
      expect(utils.clamp(100, 200)).toEqual(200);
      expect(utils.clamp(100, 50)).toEqual(100);
      expect(utils.clamp(-100, -200)).toEqual(-100);
      expect(utils.clamp(-100, -50)).toEqual(-50);
    });

    it('should clamp value under max, if min is not provided', function() {
      expect(utils.clamp(0, null, 0)).toEqual(0);
      expect(utils.clamp(100, null, 200)).toEqual(100);
      expect(utils.clamp(100, null, 50)).toEqual(50);
      expect(utils.clamp(-100, null, -200)).toEqual(-200);
      expect(utils.clamp(-100, null, -50)).toEqual(-100);
    });

    it('should clamp value between min and max, if both provided', function() {
      expect(utils.clamp(0, 0, 0)).toEqual(0);
      expect(utils.clamp(100, -20, 200)).toEqual(100);
      expect(utils.clamp(60, 40, 50)).toEqual(50);
      expect(utils.clamp(20, 60, 90)).toEqual(60);
    });
  });

});
<commit_msg>minor: move variable declaration<commit_after>define(['utils', 'config', 'jquery', 'underscore'],
function(utils, config, $, _) {
  'use strict';

  /*
   * utils.ensure_jquery
   */
  describe('utils.ensure_jquery', function() {
    it('should always return a jQuery object', function() {
      expect(utils.ensure_jquery()).toBeAjQueryObject();
      expect(utils.ensure_jquery([])).toBeAjQueryObject();
      expect(utils.ensure_jquery($('<div>')[0])).toBeAjQueryObject();
    });

    it('should wrap HTMLElement(s)', function() {
      var div_1 = $('<div>')[0];
      var div_2 = $('<div>')[0];
      var div_3 = $('<div>')[0];

      expect(utils.ensure_jquery(div_1).length).toEqual(1);
      expect(utils.ensure_jquery([div_1]).length).toEqual(1);
      expect(utils.ensure_jquery([div_1, div_2]).length).toEqual(2);
      expect(utils.ensure_jquery([div_1, div_2, div_3]).length).toEqual(3);
    });

    it('should return an empty set for non HTMLElement/Arrays', function() {
      expect(utils.ensure_jquery().length).toEqual(0);
      expect(utils.ensure_jquery(123).length).toEqual(0);
      expect(utils.ensure_jquery('div').length).toEqual(0);
    });
  });

  /*
   * utils.ensure_array
   */
  describe('utils.ensure_array', function() {
    it('should always return an array', function() {
      expect(utils.ensure_array()).toEqual([]);
      expect(utils.ensure_array(null)).toEqual([]);
      expect(utils.ensure_array([])).toEqual([]);
      expect(utils.ensure_array([1,2,3])).toEqual([1,2,3]);
      expect(utils.ensure_array(123)).toEqual([123]);
      expect(utils.ensure_array({})).toBeAnArray();
      expect(utils.ensure_array({ 'foo': [] })).toBeAnArray();
      expect(utils.ensure_array(function(){})).toBeAnArray();
    });
  });

  /*
   * utils.ensure_string
   */
  describe('utils.ensure_string', function() {
    var input;

    it('should always return a string', function() {
      expect(utils.ensure_string()).toEqual('');
      expect(utils.ensure_string(null)).toEqual('');
      expect(utils.ensure_string(-1)).toEqual('-1');
      expect(utils.ensure_string('foo')).toEqual('foo');

      input = [1,2,3];
      expect(utils.ensure_string(input)).toEqual(Array.prototype.toString.call(input));

      input = { foo: 'bar' };
      expect(utils.ensure_string(input)).toEqual(Object.prototype.toString.call(input));

      input = function foo() {};
      expect(utils.ensure_string(input)).toEqual(Function.prototype.toString.call(input));
    });
  });

  /*
   * utils.module
   */
  describe('utils.module', function() {
    it('should initially return an empty object', function() {
      var module = utils.module('foo', null, false);
      expect(module.priv).toBeDefined();
      expect(_.size(module)).toEqual(1); // just priv
    });

    it('should allow extending a base object', function() {
      var module = utils.module('foo', { 'bar': 123 }, false);
      expect(module.bar).toEqual(123);
    });

    it('should allow attaching to the global window', function() {
      var module = utils.module('foo_test', null, false);
      expect(window.foo_test).toBeUndefined();

      module = utils.module('foo_test', null, true);
      expect(window.foo_test).toBeDefined();
      expect(module).toEqual(window.foo_test);
      delete window.foo_test;
    });
  });

  /*
   * utils.no_quotes
   */
  describe('utils.no_quotes', function() {
    it('should always return a string', function() {
      expect(utils.no_quotes()).toEqual('');
      expect(utils.no_quotes('')).toEqual('');
      expect(utils.no_quotes(null)).toEqual('');
    });

    it('should remove all double quotes', function() {
      expect(utils.no_quotes('"""')).toEqual('');
      expect(utils.no_quotes('foo"bar')).toEqual('foobar');
      expect(utils.no_quotes('foo\"bar')).toEqual('foobar');
      expect(utils.no_quotes('"foo" says "bar"')).toEqual('foo says bar');
    });
  });

  /*
   * utils.extension
   */
  describe('utils.extension', function() {
    it('should return the correct extension', function() {
      expect(utils.extension()).toEqual('');
      expect(utils.extension('')).toEqual('');
      expect(utils.extension('foo.js')).toEqual('js');
      expect(utils.extension('" foo.bar.css "')).toEqual('css');
    });
  });

  /*
   * utils.script_element_string
   */
  describe('utils.script_element_string', function() {
    it('should return a <script> element string for a URI', function() {
      var script = utils.script_element_string('foo.js');
      expect(script).toEqual('<script type="application/javascript" src="foo.js"></script>');
    });

    it('should allow for a custom mime-type', function() {
      var script = utils.script_element_string('bar.js', 'foo/bar');
      expect(script).toEqual('<script type="foo/bar" src="bar.js"></script>');
    });
  });

  /*
   * utils.style_element_string
   */
  describe('utils.style_element_string', function() {
    it('should return a <style> element string for a URI', function() {
      var style = utils.style_element_string('foo.css');
      expect(style).toEqual('<link rel="stylesheet" type="text/css" href="foo.css">');
    });

    it('should allow for a custom mime-type', function() {
      var style = utils.style_element_string('bar.css', 'foo/bar');
      expect(style).toEqual('<link rel="stylesheet" type="foo/bar" href="bar.css">');
    });
  });

  /*
   * utils.resource_tag
   */
  describe('utils.resource_tag', function() {
    it('should return "script" for JavaScript files', function() {
      expect(utils.resource_tag('foo.js')).toEqual('script');
    });

    it('should return "link" for CSS files', function() {
      expect(utils.resource_tag('bar.css')).toEqual('link');
    });

    it('should return null for unknown file types', function() {
      expect(utils.resource_tag()).toEqual(null);
      expect(utils.resource_tag('')).toEqual(null);
      expect(utils.resource_tag('foo.bar')).toEqual(null);
      expect(utils.resource_tag('bar.tld')).toEqual(null);
    });
  });

  /*
   * utils.promise_now
   */
  describe('utils.promise_now', function() {
    it('should return a promise to resolve to a value', function() {
      var value;

      runs(function() {
        utils.promise_now('foobar').done(function(val) { value = val; });
      });

      waitsFor(function() {
        return value === 'foobar';
      }, 'promise to resolve to an expected value', 1000);
    });
  });

  /*
   * utils.clamp
   */
  describe('utils.clamp', function() {
    it('should return value, if no min or max provided', function() {
      expect(utils.clamp(-3)).toEqual(-3);
      expect(utils.clamp(0)).toEqual(0);
      expect(utils.clamp(5)).toEqual(5);
    });

    it('should clamp value over min, if max is not provided', function() {
      expect(utils.clamp(0, 0)).toEqual(0);
      expect(utils.clamp(100, 200)).toEqual(200);
      expect(utils.clamp(100, 50)).toEqual(100);
      expect(utils.clamp(-100, -200)).toEqual(-100);
      expect(utils.clamp(-100, -50)).toEqual(-50);
    });

    it('should clamp value under max, if min is not provided', function() {
      expect(utils.clamp(0, null, 0)).toEqual(0);
      expect(utils.clamp(100, null, 200)).toEqual(100);
      expect(utils.clamp(100, null, 50)).toEqual(50);
      expect(utils.clamp(-100, null, -200)).toEqual(-200);
      expect(utils.clamp(-100, null, -50)).toEqual(-100);
    });

    it('should clamp value between min and max, if both provided', function() {
      expect(utils.clamp(0, 0, 0)).toEqual(0);
      expect(utils.clamp(100, -20, 200)).toEqual(100);
      expect(utils.clamp(60, 40, 50)).toEqual(50);
      expect(utils.clamp(20, 60, 90)).toEqual(60);
    });
  });

});
<|endoftext|>


<commit_before>/** kate-script
 * name: Ruby
 * license: LGPL
 * author: Robin Pedersen <robin.pedersen@runbox.com>
 * version: 1
 * kate-version: 3.0
 * type: indentation
 *
 * This file is part of the Kate Project.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License version 2 as published by the Free Software Foundation.
 *
 * This library 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

//BEGIN USER CONFIGURATION
//END USER CONFIGURATION

// specifies the characters which should trigger indent, beside the default '\n'
var triggerCharacters = "cdefhilnrsuw}]";

// Indent after lines that match this regexp
var rxIndent = /^\s*(def|if|unless|for|while|until|class|module|else|elsif|case|when|begin|rescue|ensure|catch)\b/;

// Unindent lines that match this regexp
var rxUnindent = /^\s*((end|when|else|elsif|rescue|ensure)\b|[\]\}])(.*)$/;

function assert(cond)
{
  if (!cond)
    throw "assertion failure";
}

function isComment(attr)
{
  return (attr == 30 || attr == 31);
}

function isString(attr)
{
  return (attr == 13 || attr == 14);
}

function isCommentAttr(line, column)
{
  var attr = document.attribute(line, column);
  return isComment(attr);
}

// Return the closest non-empty line, ignoring comments
// (result <= line). Return -1 if the document
function findPrevNonCommentLine(line)
{
  line = document.prevNonEmptyLine(line);
  while (line >= 0 && isCommentAttr(line, document.firstColumn(line))) {
    line = document.prevNonEmptyLine(line - 1);
  }
  return line;
}

function isLineContinuing(line)
{
  return /\\$/.test(document.line(line));
}

// Return true if the given column is at least equal to the column that
// contains the last non-whitespace character at the given line, or if
// the rest of the line is a comment.
function isLastCodeColumn(line, column)
{
  if (column >= document.lastColumn(line))
    return true;
  else if (isCommentAttr(line, document.nextNonSpaceColumn(line, column+1)))
    return true;
  else
    return false;
}

// Look for a pattern at the end of the statement.
//
// Returns true if the pattern is found, in a position
// that is not inside a string or a comment, and the position +
// the length of the matching part is either the end of the
// statement, or a comment.
//
// The regexp must be global, and the search is continued until
// a match is found, or the end of the string is reached.
function testAtEnd(stmt, rx)
{
  assert(rx.global);

  var cnt = stmt.content();
  var res;
  while (res = rx.exec(cnt)) {
    var start = res.index;
    var end = rx.lastIndex;
    if (stmt.isCode(start)) {
      if (end == cnt.length)
        return true;
      if (isComment(stmt.attribute(end)))
        return true;
    }
  }
  return false;
}

function isStmtContinuing(line)
{
  // Is there an open parentesis?
  var anch = lastAnchor(line+1, 0);
  if (anch.line >= 0)
    return true;

  var stmt = new Statement(line, line);
  var rx = /((\+|\-|\*|\/|\=|&&|\|\||\band\b|\bor\b|,)\s*)/g;

  return testAtEnd(stmt, rx);
}

// Return the first line that is not preceeded by a "continuing" line.
// Return currLine if currLine <= 0
function findStmtStart(currLine)
{
  var p, l = currLine;
  do {
    if (l <= 0) return l;
    p = l;
    l = findPrevNonCommentLine(l - 1);
  } while ((l == p-1 && isLineContinuing(l)) || isStmtContinuing(l));
  return p;
}

// Statement class
function Statement(start, end)
{
  this.start = start;
  this.end = end;

  // Convert to string for debugging
  this.toString = function() {
    return "{" + this.start + "," + this.end + "}";
  }

  // Return document.attribute at the given offset in a statement
  this.attribute = function(offset) {
    var line = this.start;
    while (line < this.end && document.lineLength(line) < offset) {
      offset -= document.lineLength(line++) + 1;
    }
    return document.attribute(line, offset);
  }

  // Return document.isCode at the given offset in a statement
  this.isCode = function(offset) {
    var line = this.start;
    while (line < this.end && document.lineLength(line) < offset) {
      offset -= document.lineLength(line++) + 1;
    }
    return document.isCode(line, offset);
  }

  this.indent = function() {
    return document.firstVirtualColumn(this.start)
  }

  // Return the content of the statement from the document
  this.content = function() {
    var cnt = "";
    for (var l = this.start; l <= this.end; l++) {
      cnt += document.line(l).replace(/\\$/, " ");
      if (l < this.end)
        cnt += " ";
    }
    return cnt;
  }
}

// Returns a tuple that contains the first and last line of the
// previous statement before line.
function findPrevStmt(line)
{
  var stmtEnd = findPrevNonCommentLine(line);
  var stmtStart = findStmtStart(stmtEnd);

  return new Statement(stmtStart, stmtEnd);
}

function isBlockStart(stmt)
{
  var cnt = stmt.content();
  var len = cnt.length;

  if (rxIndent.test(cnt))
    return true;

  var rx = /((\bdo\b|\{)(\s*\|.*\|)?\s*)/g;

  return testAtEnd(stmt, rx);
}

function isBlockEnd(stmt)
{
  var cnt = stmt.content();

  return rxUnindent.test(cnt);
}

function findBlockStart(line)
{
  var nested = 0;
  var stmt = new Statement(line, line);
  while (true) {
    if (stmt.start < 0) return stmt;

    stmt = findPrevStmt(stmt.start - 1);
    if (isBlockEnd(stmt)) {
      nested++;
    }
    if (isBlockStart(stmt)) {
      if (nested == 0)
        return stmt;
      else
        nested--;
    }
  }
}

// check if the trigger characters are in the right context,
// otherwise running the indenter might be annoying to the user
function isValidTrigger(line, ch)
{
  if (ch == "" || ch == "\n")
    return true; // Explicit align or new line

  var res = rxUnindent.exec(document.line(line));
  if (res) {
    if (res[3] == "")
      return true; // Exact match
  }
  return false;
}

// Helper function to compare two KTextEditor::Cursor objects.
// Returns 0 if equal, 1 if ca > cb, -1 if ca < cb
function compare(ca, cb)
{
  if (ca.line != cb.line) {
    return (ca.line > cb.line) ? 1 : -1;
  } else if (ca.column != cb.column) {
    return (ca.column > cb.column) ? 1 : -1;
  } else {
    return 0;
  }
}

// Find the last open bracket before the current line.
// Result is a KTextEditor::Cursor object, with an extra attribute, 'ch'
// containing the type of bracket.
function lastAnchor(line, column)
{
  var anch = document.anchor(line, column, '(');
  anch.ch = '(';
  var tmp1 = document.anchor(line, column, '{');
  tmp1.ch = '{';
  var tmp2 = document.anchor(line, column, '[');
  tmp2.ch = '[';

  if (compare(tmp1, anch) == 1)
    anch = tmp1;
  if (compare(tmp2, anch) == 1)
    anch = tmp2;

  return anch;
}

// indent gets three arguments: line, indentwidth in spaces,
// typed character indent
function indent(line, indentWidth, ch)
{
  if (!isValidTrigger(line, ch))
    return -2;

  var prevStmt = findPrevStmt(line - 1);
  if (prevStmt.end < 0)
    return -2; // Can't indent the first line

  var prevStmtCnt = prevStmt.content();
  var prevStmtInd = prevStmt.indent();

  // Are we inside a parameter list, array or hash?
  var anch = lastAnchor(line, 0);
  if (anch.line >= 0) {
    var shouldIndent = (anch.line == prevStmt.end) || testAtEnd(prevStmt, /,\s*/g);
    if (!isLastCodeColumn(anch.line, anch.column) || lastAnchor(anch.line, anch.column).line >= 0) {
      // TODO This is alignment, should force using spaces instead of tabs:
      if (shouldIndent) {
        anch.column += 1;
        var nextCol = document.nextNonSpaceColumn(anch.line, anch.column);
        if (nextCol > 0 && !isCommentAttr(anch.line, nextCol))
          anch.column = nextCol;
      }
      return document.toVirtualColumn(anch.line, anch.column);
    } else {
      return document.firstVirtualColumn(anch.line) + (shouldIndent ? indentWidth : 0);
    }
  }

  // Handle indenting of multiline statements.
  if ((prevStmt.end == line-1 && isLineContinuing(prevStmt.end)) || isStmtContinuing(prevStmt.end)) {
    if (prevStmt.start == prevStmt.end) {
      if (ch == '' && document.firstVirtualColumn(line) > document.firstVirtualColumn(prevStmt.end)) {
        return -2; // Don't force a specific indent level when aligning manually
      }
      return prevStmtInd + indentWidth * 2;
    } else {
      return document.firstVirtualColumn(prevStmt.end);
    }
  }

  if (rxUnindent.test(document.line(line))) {
    var startStmt = findBlockStart(line);
    if (startStmt.start >= 0)
      return startStmt.indent();
    else
      return -2;
  }

  if (isBlockStart(prevStmt)) {
    return prevStmtInd + indentWidth;
  } else if (prevStmtCnt.search(/[\[\{]\s*$/) != -1) {
    return prevStmtInd + indentWidth;
  }

  // Keep current
  return prevStmtInd;
}

// kate: indent-width 2; indent-spaces on;
<commit_msg>Hack to disable indenting inside here documents. Need better support for detecting context at start of line.<commit_after>/** kate-script
 * name: Ruby
 * license: LGPL
 * author: Robin Pedersen <robin.pedersen@runbox.com>
 * version: 1
 * kate-version: 3.0
 * type: indentation
 *
 * This file is part of the Kate Project.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License version 2 as published by the Free Software Foundation.
 *
 * This library 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

//BEGIN USER CONFIGURATION
//END USER CONFIGURATION

// specifies the characters which should trigger indent, beside the default '\n'
var triggerCharacters = "cdefhilnrsuw}]";

// Indent after lines that match this regexp
var rxIndent = /^\s*(def|if|unless|for|while|until|class|module|else|elsif|case|when|begin|rescue|ensure|catch)\b/;

// Unindent lines that match this regexp
var rxUnindent = /^\s*((end|when|else|elsif|rescue|ensure)\b|[\]\}])(.*)$/;

function assert(cond)
{
  if (!cond)
    throw "assertion failure";
}

function isComment(attr)
{
  return (attr == 30 || attr == 31);
}

function isString(attr)
{
  return (attr == 13 || attr == 14);
}

function isCommentAttr(line, column)
{
  var attr = document.attribute(line, column);
  return isComment(attr);
}

// Return the closest non-empty line, ignoring comments
// (result <= line). Return -1 if the document
function findPrevNonCommentLine(line)
{
  line = document.prevNonEmptyLine(line);
  while (line >= 0 && isCommentAttr(line, document.firstColumn(line))) {
    line = document.prevNonEmptyLine(line - 1);
  }
  return line;
}

function isLineContinuing(line)
{
  return /\\$/.test(document.line(line));
}

// Return true if the given column is at least equal to the column that
// contains the last non-whitespace character at the given line, or if
// the rest of the line is a comment.
function isLastCodeColumn(line, column)
{
  if (column >= document.lastColumn(line))
    return true;
  else if (isCommentAttr(line, document.nextNonSpaceColumn(line, column+1)))
    return true;
  else
    return false;
}

// Look for a pattern at the end of the statement.
//
// Returns true if the pattern is found, in a position
// that is not inside a string or a comment, and the position +
// the length of the matching part is either the end of the
// statement, or a comment.
//
// The regexp must be global, and the search is continued until
// a match is found, or the end of the string is reached.
function testAtEnd(stmt, rx)
{
  assert(rx.global);

  var cnt = stmt.content();
  var res;
  while (res = rx.exec(cnt)) {
    var start = res.index;
    var end = rx.lastIndex;
    if (stmt.isCode(start)) {
      if (end == cnt.length)
        return true;
      if (isComment(stmt.attribute(end)))
        return true;
    }
  }
  return false;
}

function isStmtContinuing(line)
{
  // Is there an open parentesis?
  var anch = lastAnchor(line+1, 0);
  if (anch.line >= 0)
    return true;

  var stmt = new Statement(line, line);
  var rx = /((\+|\-|\*|\/|\=|&&|\|\||\band\b|\bor\b|,)\s*)/g;

  return testAtEnd(stmt, rx);
}

// Return the first line that is not preceeded by a "continuing" line.
// Return currLine if currLine <= 0
function findStmtStart(currLine)
{
  var p, l = currLine;
  do {
    if (l <= 0) return l;
    p = l;
    l = findPrevNonCommentLine(l - 1);
  } while ((l == p-1 && isLineContinuing(l)) || isStmtContinuing(l));
  return p;
}

// Statement class
function Statement(start, end)
{
  this.start = start;
  this.end = end;

  // Convert to string for debugging
  this.toString = function() {
    return "{" + this.start + "," + this.end + "}";
  }

  // Return document.attribute at the given offset in a statement
  this.attribute = function(offset) {
    var line = this.start;
    while (line < this.end && document.lineLength(line) < offset) {
      offset -= document.lineLength(line++) + 1;
    }
    return document.attribute(line, offset);
  }

  // Return document.isCode at the given offset in a statement
  this.isCode = function(offset) {
    var line = this.start;
    while (line < this.end && document.lineLength(line) < offset) {
      offset -= document.lineLength(line++) + 1;
    }
    return document.isCode(line, offset);
  }

  this.indent = function() {
    return document.firstVirtualColumn(this.start)
  }

  // Return the content of the statement from the document
  this.content = function() {
    var cnt = "";
    for (var l = this.start; l <= this.end; l++) {
      cnt += document.line(l).replace(/\\$/, " ");
      if (l < this.end)
        cnt += " ";
    }
    return cnt;
  }
}

// Returns a tuple that contains the first and last line of the
// previous statement before line.
function findPrevStmt(line)
{
  var stmtEnd = findPrevNonCommentLine(line);
  var stmtStart = findStmtStart(stmtEnd);

  return new Statement(stmtStart, stmtEnd);
}

function isBlockStart(stmt)
{
  var cnt = stmt.content();
  var len = cnt.length;

  if (rxIndent.test(cnt))
    return true;

  var rx = /((\bdo\b|\{)(\s*\|.*\|)?\s*)/g;

  return testAtEnd(stmt, rx);
}

function isBlockEnd(stmt)
{
  var cnt = stmt.content();

  return rxUnindent.test(cnt);
}

function findBlockStart(line)
{
  var nested = 0;
  var stmt = new Statement(line, line);
  while (true) {
    if (stmt.start < 0) return stmt;

    stmt = findPrevStmt(stmt.start - 1);
    if (isBlockEnd(stmt)) {
      nested++;
    }
    if (isBlockStart(stmt)) {
      if (nested == 0)
        return stmt;
      else
        nested--;
    }
  }
}

// check if the trigger characters are in the right context,
// otherwise running the indenter might be annoying to the user
function isValidTrigger(line, ch)
{
  if (ch == "" || ch == "\n")
    return true; // Explicit align or new line

  var res = rxUnindent.exec(document.line(line));
  if (res) {
    if (res[3] == "")
      return true; // Exact match
  }
  return false;
}

// Helper function to compare two KTextEditor::Cursor objects.
// Returns 0 if equal, 1 if ca > cb, -1 if ca < cb
function compare(ca, cb)
{
  if (ca.line != cb.line) {
    return (ca.line > cb.line) ? 1 : -1;
  } else if (ca.column != cb.column) {
    return (ca.column > cb.column) ? 1 : -1;
  } else {
    return 0;
  }
}

// Find the last open bracket before the current line.
// Result is a KTextEditor::Cursor object, with an extra attribute, 'ch'
// containing the type of bracket.
function lastAnchor(line, column)
{
  var anch = document.anchor(line, column, '(');
  anch.ch = '(';
  var tmp1 = document.anchor(line, column, '{');
  tmp1.ch = '{';
  var tmp2 = document.anchor(line, column, '[');
  tmp2.ch = '[';

  if (compare(tmp1, anch) == 1)
    anch = tmp1;
  if (compare(tmp2, anch) == 1)
    anch = tmp2;

  return anch;
}

// indent gets three arguments: line, indentwidth in spaces,
// typed character indent
function indent(line, indentWidth, ch)
{
  if (!isValidTrigger(line, ch))
    return -2;

  var prevStmt = findPrevStmt(line - 1);
  if (prevStmt.end < 0)
    return -2; // Can't indent the first line

  // HACK Must have a way to detect if we are inside a non-code context
  if (document.attribute(line-1, document.lineLength(line-1)-1) == 34) {
    return -1; // HERE-DOCUMENT
  }

  var prevStmtCnt = prevStmt.content();
  var prevStmtInd = prevStmt.indent();

  // Are we inside a parameter list, array or hash?
  var anch = lastAnchor(line, 0);
  if (anch.line >= 0) {
    var shouldIndent = (anch.line == prevStmt.end) || testAtEnd(prevStmt, /,\s*/g);
    if (!isLastCodeColumn(anch.line, anch.column) || lastAnchor(anch.line, anch.column).line >= 0) {
      // TODO This is alignment, should force using spaces instead of tabs:
      if (shouldIndent) {
        anch.column += 1;
        var nextCol = document.nextNonSpaceColumn(anch.line, anch.column);
        if (nextCol > 0 && !isCommentAttr(anch.line, nextCol))
          anch.column = nextCol;
      }
      return document.toVirtualColumn(anch.line, anch.column);
    } else {
      return document.firstVirtualColumn(anch.line) + (shouldIndent ? indentWidth : 0);
    }
  }

  // Handle indenting of multiline statements.
  if ((prevStmt.end == line-1 && isLineContinuing(prevStmt.end)) || isStmtContinuing(prevStmt.end)) {
    if (prevStmt.start == prevStmt.end) {
      if (ch == '' && document.firstVirtualColumn(line) > document.firstVirtualColumn(prevStmt.end)) {
        return -2; // Don't force a specific indent level when aligning manually
      }
      return prevStmtInd + indentWidth * 2;
    } else {
      return document.firstVirtualColumn(prevStmt.end);
    }
  }

  if (rxUnindent.test(document.line(line))) {
    var startStmt = findBlockStart(line);
    if (startStmt.start >= 0)
      return startStmt.indent();
    else
      return -2;
  }

  if (isBlockStart(prevStmt)) {
    return prevStmtInd + indentWidth;
  } else if (prevStmtCnt.search(/[\[\{]\s*$/) != -1) {
    return prevStmtInd + indentWidth;
  }

  // Keep current
  return prevStmtInd;
}

// kate: indent-width 2; indent-spaces on;
<|endoftext|>


<commit_before>(function ($) {
    $.fn.sketchpad = function (options) {
        // Canvas info
        var canvas = this;
        var ctx = $(this)[0].getContext('2d');

        // Default aspect ratio
        var aspectRatio = 1;

        // For storing strokes
        var strokes = [];

        // Whether or not currently drawing
        var sketching = false;

        // Default Context
        var lineColor = 'black';
        var lineSize = 20;
        var lineCap = 'round';
        var lineJoin = 'round';
        var lineMiterLimit = 10;

        // Array for storing strokes that were undone
        var undo = [];

        // Resize canvas with window
        canvas.parent().resize(function (e) {
            var width = canvas.parent().width();
            var height = width / aspectRatio;

            setSize(width, height);
            redraw();
        });

        // Return the mouse/touch location
        function getCursor(element, event) {
            var cur = {x: 0, y: 0};
            if (event.type.indexOf('touch') !== -1) {
                cur.x = event.originalEvent.touches[0].pageX;
                cur.y = event.originalEvent.touches[0].pageY;
            } else {
                cur.x = event.pageX;
                cur.y = event.pageY;
            }
            return {
                x: (cur.x - $(element).offset().left) / $(element).width(),
                y: (cur.y - $(element).offset().top) / $(element).height()
            }
        }

        // Set the canvas size
        function setSize(w, h) {
            lineSize *= (w / canvas.width());
            canvas.width(w);
            canvas.height(h);

            canvas[0].setAttribute('width', w);
            canvas[0].setAttribute('height', h);
        }

        // On mouse down, create new stroke, push start location
        var startEvent = 'mousedown touchstart ';
        canvas.on(startEvent, function (e) {
            if (e.type == 'touchstart') {
                e.preventDefault();
            } else {
                e.originalEvent.preventDefault();
            }

            sketching = true;
            undo = []; // Clear undo strokes

            strokes.push({
                stroke: [],
                color: lineColor,
                size: lineSize / $(this).width(),
                cap: lineCap,
                join: lineJoin,
                miterLimit: lineMiterLimit
            });

            var cursor = getCursor(this, e);

            strokes[strokes.length - 1].stroke.push({
                x: cursor.x,
                y: cursor.y
            });

            redraw();
        });

        // On mouse move, record movements
        var moveEvent = 'mousemove touchmove ';
        canvas.on(moveEvent, function (e) {
            var cursor = getCursor(this, e);

            if (sketching) {
                strokes[strokes.length - 1].stroke.push({
                    x: cursor.x,
                    y: cursor.y
                });
                redraw();
            }
        });

        // On mouse up, end stroke
        var endEvent = 'mouseup mouseleave touchend ';
        canvas.on(endEvent, function (e) {
            sketching = false;
        });

        function redraw() {
            var width = $(canvas).width();
            var height = $(canvas).height();

            ctx.clearRect(0, 0, width, height); // Clear Canvas

            for (var i = 0; i < strokes.length; i++) {
                var stroke = strokes[i].stroke;

                ctx.beginPath();
                for (var j = 0; j < stroke.length - 1; j++) {
                    ctx.moveTo(stroke[j].x * width, stroke[j].y * height);
                    ctx.lineTo(stroke[j + 1].x * width, stroke[j + 1].y * height);
                }
                ctx.closePath();

                ctx.strokeStyle = strokes[i].color;
                ctx.lineWidth = strokes[i].size * width;
                ctx.lineJoin = strokes[i].join;
                ctx.lineCap = strokes[i].cap;
                ctx.miterLimit = strokes[i].miterLimit;

                ctx.stroke()
            }
        }

        function init() {
            if (options.data) {
                aspectRatio = typeof options.data.aspectRatio !== 'undefined' ? options.data.aspectRatio : aspectRatio;
                strokes = typeof options.data.strokes !== 'undefined' ? options.data.strokes : [];
            } else {
                aspectRatio = typeof options.aspectRatio !== 'undefined' ? options.aspectRatio : aspectRatio;
            }

            var canvasColor = typeof options.canvasColor !== 'undefined' ? options.canvasColor : '#fff';
            canvas.css('background-color', canvasColor);

            var locked = typeof options.locked !== 'undefined' ? options.locked : false;
            if (locked) {
                canvas.unbind(startEvent + moveEvent + endEvent);
            } else {
                canvas.css('cursor', 'crosshair');
            }

            // Set canvas size
            var width = canvas.parent().width();
            var height = width / aspectRatio;

            setSize(width, height);
            redraw();
        }

        init();

        this.json = function () {
            return JSON.stringify({
                aspectRatio: aspectRatio,
                strokes: strokes
            });
        };

        this.jsonLoad = function (json) {
            var array = JSON.parse(json);
            aspectRatio = array.aspectRatio;
            strokes = array.strokes;
            redraw()
        };

        this.getImage = function () {
            return '';
        };

        this.getLineColor = function () {
            return lineColor;
        };

        this.setLineColor = function (color) {
            lineColor = color;
        };

        this.getLineSize = function () {
            return lineSize;
        };

        this.setLineSize = function (size) {
            lineSize = size;
        };

        this.undo = function () {
            if (strokes.length > 0) {
                undo.push(strokes.pop());
                redraw();
            }
        };

        this.redo = function () {
            if (undo.length > 0) {
                strokes.push(undo.pop());
                redraw();
            }
        };

        this.clear = function () {
            strokes = [];
            redraw();
        };

        return this;
    };
}(jQuery));
<commit_msg>Implemented `setReadOnly` method.<commit_after>(function ($) {
    $.fn.sketchpad = function (options) {
        // Canvas info
        var canvas = this;
        canvas.readOnly = false;
        var ctx = $(this)[0].getContext('2d');

        // Default aspect ratio
        var aspectRatio = 1;

        // For storing strokes
        var strokes = [];

        // Whether or not currently drawing
        var sketching = false;

        // Default Context
        var lineColor = 'black';
        var lineSize = 20;
        var lineCap = 'round';
        var lineJoin = 'round';
        var lineMiterLimit = 10;

        // Array for storing strokes that were undone
        var undo = [];

        // Resize canvas with window
        canvas.parent().resize(function (e) {
            var width = canvas.parent().width();
            var height = width / aspectRatio;

            setSize(width, height);
            redraw();
        });

        // Return the mouse/touch location
        function getCursor(element, event) {
            var cur = {x: 0, y: 0};
            if (event.type.indexOf('touch') !== -1) {
                cur.x = event.originalEvent.touches[0].pageX;
                cur.y = event.originalEvent.touches[0].pageY;
            } else {
                cur.x = event.pageX;
                cur.y = event.pageY;
            }
            return {
                x: (cur.x - $(element).offset().left) / $(element).width(),
                y: (cur.y - $(element).offset().top) / $(element).height()
            }
        }

        // Set the canvas size
        function setSize(w, h) {
            lineSize *= (w / canvas.width());
            canvas.width(w);
            canvas.height(h);

            canvas[0].setAttribute('width', w);
            canvas[0].setAttribute('height', h);
        }

        // On mouse down, create new stroke, push start location
        var startEvent = 'mousedown touchstart ';
        canvas.on(startEvent, function (e) {
            if (canvas.readOnly) {
                return false;
            }

            if (e.type == 'touchstart') {
                e.preventDefault();
            } else {
                e.originalEvent.preventDefault();
            }

            sketching = true;
            undo = []; // Clear undo strokes

            strokes.push({
                stroke: [],
                color: lineColor,
                size: lineSize / $(this).width(),
                cap: lineCap,
                join: lineJoin,
                miterLimit: lineMiterLimit
            });

            var cursor = getCursor(this, e);

            strokes[strokes.length - 1].stroke.push({
                x: cursor.x,
                y: cursor.y
            });

            redraw();
        });

        // On mouse move, record movements
        var moveEvent = 'mousemove touchmove ';
        canvas.on(moveEvent, function (e) {
            if (canvas.readOnly) {
                return false;
            }

            var cursor = getCursor(this, e);

            if (sketching) {
                strokes[strokes.length - 1].stroke.push({
                    x: cursor.x,
                    y: cursor.y
                });
                redraw();
            }
        });

        // On mouse up, end stroke
        var endEvent = 'mouseup mouseleave touchend ';
        canvas.on(endEvent, function (e) {
            sketching = false;
        });

        function redraw() {
            var width = $(canvas).width();
            var height = $(canvas).height();

            ctx.clearRect(0, 0, width, height); // Clear Canvas

            for (var i = 0; i < strokes.length; i++) {
                var stroke = strokes[i].stroke;

                ctx.beginPath();
                for (var j = 0; j < stroke.length - 1; j++) {
                    ctx.moveTo(stroke[j].x * width, stroke[j].y * height);
                    ctx.lineTo(stroke[j + 1].x * width, stroke[j + 1].y * height);
                }
                ctx.closePath();

                ctx.strokeStyle = strokes[i].color;
                ctx.lineWidth = strokes[i].size * width;
                ctx.lineJoin = strokes[i].join;
                ctx.lineCap = strokes[i].cap;
                ctx.miterLimit = strokes[i].miterLimit;

                ctx.stroke()
            }
        }

        function init() {
            if (options.data) {
                aspectRatio = typeof options.data.aspectRatio !== 'undefined' ? options.data.aspectRatio : aspectRatio;
                strokes = typeof options.data.strokes !== 'undefined' ? options.data.strokes : [];
            } else {
                aspectRatio = typeof options.aspectRatio !== 'undefined' ? options.aspectRatio : aspectRatio;
            }

            var canvasColor = typeof options.canvasColor !== 'undefined' ? options.canvasColor : '#fff';
            canvas.css('background-color', canvasColor);

            var locked = typeof options.locked !== 'undefined' ? options.locked : false;
            if (locked) {
                canvas.unbind(startEvent + moveEvent + endEvent);
            } else {
                canvas.css('cursor', 'crosshair');
            }

            // Set canvas size
            var width = canvas.parent().width();
            var height = width / aspectRatio;

            setSize(width, height);
            redraw();
        }

        init();

        this.json = function () {
            return JSON.stringify({
                aspectRatio: aspectRatio,
                strokes: strokes
            });
        };

        this.jsonLoad = function (json) {
            var array = JSON.parse(json);
            aspectRatio = array.aspectRatio;
            strokes = array.strokes;
            redraw()
        };

        this.getImage = function () {
            return '';
        };

        this.getLineColor = function () {
            return lineColor;
        };

        this.setLineColor = function (color) {
            lineColor = color;
        };

        this.getLineSize = function () {
            return lineSize;
        };

        this.setLineSize = function (size) {
            lineSize = size;
        };

        this.undo = function () {
            if (strokes.length > 0) {
                undo.push(strokes.pop());
                redraw();
            }
        };

        this.redo = function () {
            if (undo.length > 0) {
                strokes.push(undo.pop());
                redraw();
            }
        };

        this.clear = function () {
            strokes = [];
            redraw();
        };

        this.setReadOnly = function(state) {
            this.readOnly = state;
            if (state) {
                canvas.css('cursor', 'default');
            }
            else {
                canvas.css('cursor', 'crosshair');
            }
        };

        return this;
    };
}(jQuery));
<|endoftext|>


<commit_before>// Copyright 2016, University of Colorado Boulder

/* eslint-env node */

const http = require( 'http' );
const spawn = require( 'child_process' ).spawn; // eslint-disable-line
const path = require( 'path' );
const url = require( 'url' );
const fs = require( 'fs' );

var port = 45362;

// Allow CORS
var jsonHeaders = {
  'Content-Type': 'application/json',
  'Access-Control-Allow-Origin': '*'
};

// root of your GitHub working copy, relative to the name of the directory that the currently-executing script resides in
var rootDir = path.normalize( __dirname + '/../../' ); // eslint-disable-line

// callback(), errCallback( code )
function execute( cmd, args, cwd, callback, errCallback ) {
  'use strict';

  const process = spawn( cmd, args, {
    cwd: cwd
  } );
  console.log( 'running ' + cmd + ' ' + args.join( ' ' ) + ' from ' + cwd );

  process.on( 'error', function( error ) {
    console.log( 'uncaught error:', error );
  } );
  process.stderr.on( 'data', function( data ) {
    console.log( 'stderr: ' + data );
  } );
  process.stdout.on( 'data', function( data ) {
    console.log( 'stdout: ' + data );
  } );
  process.on( 'close', function( code ) {
    console.log( 'finished executing', cmd, args, cwd, code );

    // Failure
    if ( code !== 0 ) {
      errCallback( code );
    }
    // Success
    else {
      callback();
    }
  } );
}

// callback(), errCallback( code )
function pull( repo, callback, errCallback ) {
  'use strict';

  execute( 'git', [ 'pull' ], rootDir + repo, callback, errCallback );
}

// callback(), errCallback( code )
function npmUpdate( repo, callback, errCallback ) {
  'use strict';

  execute( 'npm', [ 'update' ], rootDir + repo, callback, errCallback );
}

// callback(), errCallback( code )
function grunt( repo, callback, errCallback ) {
  'use strict';

  execute( 'grunt', [ '--no-color', '--minify.uglify=false' ], rootDir + repo, callback, errCallback );
}

function isSameAsRemoteMaster( repo, sameCallback, differentCallback ) {
  'use strict';

  execute( 'bash', [ '../phetmarks/phettest/same-as-remote-master.sh' ], rootDir + repo, sameCallback, differentCallback );
}

function getActiveRepos() {
  'use strict';

  return fs.readFileSync( rootDir + 'perennial/data/active-repos', 'utf8' )
    .split( '\n' )
    .filter( function( name ) { return name.length > 0; } );
}

function getActiveSims() {
  'use strict';

  return fs.readFileSync( rootDir + 'perennial/data/active-sims', 'utf8' )
    .split( '\n' )
    .filter( function( name ) { return name.length > 0; } );
}

function successFunction( req, res, name ) {
  'use strict';

  return function() {
    res.writeHead( 200, jsonHeaders );
    res.end( JSON.stringify( {
      output: name,
      success: true
    } ) );
  };
}

function errorFunction( req, res, name ) {
  'use strict';

  return function( code ) {
    res.writeHead( 500, jsonHeaders );
    res.end( JSON.stringify( {
      output: name + ' exit code ' + code,
      success: false
    } ) );
  };
}

function taskBuild( req, res, query ) {
  'use strict';

  const simName = query.sim;

  if ( !validateSimName( simName ) ) {
    res.writeHead( 403, jsonHeaders );
    res.end( JSON.stringify( {
      output: 'Invalid sim name',
      success: false
    } ) );
    return;
  }

  npmUpdate( 'chipper', function() {
    npmUpdate( simName, function() {
      grunt( simName,
        successFunction( req, res, 'build ' + simName ),
        errorFunction( req, res, 'grunt ' + simName ) );
    }, errorFunction( req, res, 'npm update ' + simName ) );
  }, errorFunction( req, res, 'npm update chipper' ) );
}

function taskSimList( req, res, query ) {
  'use strict';

  const activeSims = getActiveSims();

  res.writeHead( 200, jsonHeaders );
  res.end( JSON.stringify( {
    output: activeSims,
    success: true
  } ) );
}

function taskRepoList( req, res, query ) {
  'use strict';

  const activeSims = getActiveRepos();

  res.writeHead( 200, jsonHeaders );
  res.end( JSON.stringify( {
    output: activeSims,
    success: true
  } ) );
}

function taskPerennialRefresh( req, res, query ) {
  'use strict';

  pull( 'perennial', function() {
    npmUpdate( 'perennial', function() {
      execute( rootDir + 'perennial/bin/clone-missing-repos.sh', [], rootDir,
        successFunction( req, res, 'perennial refresh' ),
        errorFunction( req, res, 'perennial clone missing repos' ) );
    }, errorFunction( req, res, 'perennial npm update' ) );
  }, errorFunction( req, res, 'pull perennial' ) );
}

function taskPull( req, res, query ) {
  'use strict';

  const simName = query.sim;

  if ( !validateSimName( simName ) ) {
    res.writeHead( 403, jsonHeaders );
    res.end( JSON.stringify( {
      output: 'Invalid sim name',
      success: false
    } ) );
    return;
  }

  pull( simName, successFunction( req, res, 'pull ' + simName ), errorFunction( req, res, 'pull ' + simName ) );
}

function taskPullAll( req, res, query ) {
  'use strict';

  execute( rootDir + 'perennial/bin/pull-all.sh', [ '-p' ], rootDir,
    successFunction( req, res, 'pulled' ),
    errorFunction( req, res, 'pull failed' ) );
}

function taskSameAsRemoteMaster( req, res, query ) {
  'use strict';

  const simName = query.repo;

  if ( !validateSimName( simName ) ) {
    res.writeHead( 403, jsonHeaders );
    res.end( JSON.stringify( {
      output: 'Invalid repo name',
      success: false
    } ) );
    return;
  }

  isSameAsRemoteMaster( simName, successFunction( req, res, 'same' ), successFunction( req, res, 'different' ) );
}

function validateSimName( simName ) {
  'use strict';

  // validate that it is lower-case with hyphens
  for ( let i = 0; i < simName.length; i++ ) {
    const charCode = simName.charCodeAt( i );
    if ( charCode !== '-'.charCodeAt( 0 ) && ( charCode < 'a'.charCodeAt( 0 ) || charCode > 'z'.charCodeAt( 0 ) ) ) {
      return false;
    }
  }
  return true;
}

http.createServer( function( req, res ) {
  'use strict';

  // req.url
  // req.method
  // req.headers

  const bits = url.parse( req.url, true );
  const path = bits.pathname;
  const query = bits.query;

  if ( path === '/build' ) {
    taskBuild( req, res, query );
  }
  else if ( path === '/sim-list' ) {
    taskSimList( req, res, query );
  }
  else if ( path === '/repo-list' ) {
    taskRepoList( req, res, query );
  }
  else if ( path === '/perennial-refresh' ) {
    taskPerennialRefresh( req, res, query );
  }
  else if ( path === '/pull-all' ) {
    taskPullAll( req, res, query );
  }
  else if ( path === '/pull' ) {
    taskPull( req, res, query );
  }
  else if ( path === '/same-as-remote-master' ) {
    taskSameAsRemoteMaster( req, res, query );
  }
  else {
    res.writeHead( 403, jsonHeaders );
    res.end( JSON.stringify( {
      output: 'Unknown task',
      success: false
    } ) );
  }

  // var simName = req.url.slice( 1 );

} ).listen( port );

console.log( 'running on port ' + port + ' with root directory ' + rootDir );
<commit_msg>add todo, https://github.com/phetsims/special-ops/issues/170<commit_after>// Copyright 2016, University of Colorado Boulder

/* eslint-env node */

const http = require( 'http' );
const spawn = require( 'child_process' ).spawn; // eslint-disable-line
const path = require( 'path' );
const url = require( 'url' );
const fs = require( 'fs' );

var port = 45362;

// Allow CORS
var jsonHeaders = {
  'Content-Type': 'application/json',
  'Access-Control-Allow-Origin': '*'
};

// root of your GitHub working copy, relative to the name of the directory that the currently-executing script resides in
var rootDir = path.normalize( __dirname + '/../../' ); // eslint-disable-line

// callback(), errCallback( code )
function execute( cmd, args, cwd, callback, errCallback ) {
  'use strict';

  const process = spawn( cmd, args, {
    cwd: cwd
  } );
  console.log( 'running ' + cmd + ' ' + args.join( ' ' ) + ' from ' + cwd );

  process.on( 'error', function( error ) {
    console.log( 'uncaught error:', error );
  } );
  process.stderr.on( 'data', function( data ) {
    console.log( 'stderr: ' + data );
  } );
  process.stdout.on( 'data', function( data ) {
    console.log( 'stdout: ' + data );
  } );
  process.on( 'close', function( code ) {
    console.log( 'finished executing', cmd, args, cwd, code );

    // Failure
    if ( code !== 0 ) {
      errCallback( code );
    }
    // Success
    else {
      callback();
    }
  } );
}

// callback(), errCallback( code )
function pull( repo, callback, errCallback ) {
  'use strict';

  execute( 'git', [ 'pull' ], rootDir + repo, callback, errCallback );
}

// callback(), errCallback( code )
function npmUpdate( repo, callback, errCallback ) {
  'use strict';

  execute( 'npm', [ 'update' ], rootDir + repo, callback, errCallback );
}

// callback(), errCallback( code )
function grunt( repo, callback, errCallback ) {
  'use strict';

  execute( 'grunt', [ '--no-color', '--minify.uglify=false' ], rootDir + repo, callback, errCallback );
}

function isSameAsRemoteMaster( repo, sameCallback, differentCallback ) {
  'use strict';

  execute( 'bash', [ '../phetmarks/phettest/same-as-remote-master.sh' ], rootDir + repo, sameCallback, differentCallback );
}

function getActiveRepos() {
  'use strict';

  return fs.readFileSync( rootDir + 'perennial/data/active-repos', 'utf8' )
    .split( '\n' )
    .filter( function( name ) { return name.length > 0; } );
}

function getActiveSims() {
  'use strict';

  return fs.readFileSync( rootDir + 'perennial/data/active-sims', 'utf8' )
    .split( '\n' )
    .filter( function( name ) { return name.length > 0; } );
}

function successFunction( req, res, name ) {
  'use strict';

  return function() {
    res.writeHead( 200, jsonHeaders );
    res.end( JSON.stringify( {
      output: name,
      success: true
    } ) );
  };
}

function errorFunction( req, res, name ) {
  'use strict';

  return function( code ) {
    res.writeHead( 500, jsonHeaders );
    res.end( JSON.stringify( {
      output: name + ' exit code ' + code,
      success: false
    } ) );
  };
}

function taskBuild( req, res, query ) {
  'use strict';

  const simName = query.sim;

  if ( !validateSimName( simName ) ) {
    res.writeHead( 403, jsonHeaders );
    res.end( JSON.stringify( {
      output: 'Invalid sim name',
      success: false
    } ) );
    return;
  }

  npmUpdate( 'chipper', function() {
    npmUpdate( simName, function() {
      grunt( simName,
        successFunction( req, res, 'build ' + simName ),
        errorFunction( req, res, 'grunt ' + simName ) );
    }, errorFunction( req, res, 'npm update ' + simName ) );
  }, errorFunction( req, res, 'npm update chipper' ) );
}

function taskSimList( req, res, query ) {
  'use strict';

  const activeSims = getActiveSims();

  res.writeHead( 200, jsonHeaders );
  res.end( JSON.stringify( {
    output: activeSims,
    success: true
  } ) );
}

function taskRepoList( req, res, query ) {
  'use strict';

  const activeSims = getActiveRepos();

  res.writeHead( 200, jsonHeaders );
  res.end( JSON.stringify( {
    output: activeSims,
    success: true
  } ) );
}

function taskPerennialRefresh( req, res, query ) {
  'use strict';

  pull( 'perennial', function() {
    npmUpdate( 'perennial', function() {
      execute( rootDir + 'perennial/bin/clone-missing-repos.sh', [], rootDir,
        successFunction( req, res, 'perennial refresh' ),
        errorFunction( req, res, 'perennial clone missing repos' ) );
    }, errorFunction( req, res, 'perennial npm update' ) );
  }, errorFunction( req, res, 'pull perennial' ) );
}

function taskPull( req, res, query ) {
  'use strict';

  const simName = query.sim;

  if ( !validateSimName( simName ) ) {
    res.writeHead( 403, jsonHeaders );
    res.end( JSON.stringify( {
      output: 'Invalid sim name',
      success: false
    } ) );
    return;
  }

  pull( simName, successFunction( req, res, 'pull ' + simName ), errorFunction( req, res, 'pull ' + simName ) );
}

function taskPullAll( req, res, query ) {
  'use strict';

  execute( rootDir + 'perennial/bin/pull-all.sh', [ '-p' ], rootDir,
    successFunction( req, res, 'pulled' ),
    errorFunction( req, res, 'pull failed' ) );
}

function taskSameAsRemoteMaster( req, res, query ) {
  'use strict';

  const simName = query.repo;

  if ( !validateSimName( simName ) ) {
    res.writeHead( 403, jsonHeaders );
    res.end( JSON.stringify( {
      output: 'Invalid repo name',
      success: false
    } ) );
    return;
  }

  isSameAsRemoteMaster( simName, successFunction( req, res, 'same' ), successFunction( req, res, 'different' ) );
}

function validateSimName( simName ) {
  'use strict';

  // validate that it is lower-case with hyphens
  for ( let i = 0; i < simName.length; i++ ) {
    const charCode = simName.charCodeAt( i );

    // TODO: use a perennial data list as a white list, https://github.com/phetsims/special-ops/issues/170
    if ( charCode !== '-'.charCodeAt( 0 ) && ( charCode < 'a'.charCodeAt( 0 ) || charCode > 'z'.charCodeAt( 0 ) ) ) {
      return false;
    }
  }
  return true;
}

http.createServer( function( req, res ) {
  'use strict';

  // req.url
  // req.method
  // req.headers

  const bits = url.parse( req.url, true );
  const path = bits.pathname;
  const query = bits.query;

  if ( path === '/build' ) {
    taskBuild( req, res, query );
  }
  else if ( path === '/sim-list' ) {
    taskSimList( req, res, query );
  }
  else if ( path === '/repo-list' ) {
    taskRepoList( req, res, query );
  }
  else if ( path === '/perennial-refresh' ) {
    taskPerennialRefresh( req, res, query );
  }
  else if ( path === '/pull-all' ) {
    taskPullAll( req, res, query );
  }
  else if ( path === '/pull' ) {
    taskPull( req, res, query );
  }
  else if ( path === '/same-as-remote-master' ) {
    taskSameAsRemoteMaster( req, res, query );
  }
  else {
    res.writeHead( 403, jsonHeaders );
    res.end( JSON.stringify( {
      output: 'Unknown task',
      success: false
    } ) );
  }

  // var simName = req.url.slice( 1 );

} ).listen( port );

console.log( 'running on port ' + port + ' with root directory ' + rootDir );
<|endoftext|>