<commit_before>const _ = require('lodash');
const {
	readFile,
	delay,
	asyncMapSeries,
	enforceTimeout
} = require('./utilities');
const log = require('./log');

const ymodem = {
	// 128 byte blocks
	SOH: 0x01,
	// 1024 byte blocks
	STX: 0x02,
	EOT: 0x04,
	ACK: 0x06,
	NAK: 0x15,
	CA: 0x18,
	CRC16: 0x43,
	ABORT1: 0x41,
	ABORT2: 0x61
};
const ymodemLookup = _.invert(ymodem);

module.exports = class YModem {
	constructor(serialPort, options){
		this.options = _.defaults(options, {
			packetLength: 128,
			debug: false,
			inListeningMode: true
		});
		this.port = serialPort;

		if (this.options.packetLength === 128){
			this.mark = ymodem.SOH;
		} else if (this.options.packetLength === 1024){
			this.mark = ymodem.STX;
		} else {
			throw new Error('invalid packet length');
		}

		serialPort.once('close', this._close.bind(this));
	}

	send(filenames){
		let self = this;

		if (!_.isArray(filenames)){
			filenames = [filenames];
		}

		return this._open(this.options.inListeningMode)
			.then(() => {
				return asyncMapSeries(filenames, (filename) => {
					console.log('sending file:', filename);
					return readFile(filename)
						.then((buffer) => self._sendFile(buffer));
				});
			})
			.then(() => this._endTransfer())
			.catch((err) => {
				self.errored = true;
				return Promise.reject(err);
			})
			.finally(() => self._close());
	}

	_logData(data){
		if (data.length <= 2){
			for (let i=0; i < data.length; i++){
				let chr = data[i];
				log.verbose(ymodemLookup[chr] || chr);
			}
			return;
		}
		log.verbose(data, data.toString());
	}

	_close(){
		if (this.port.isOpen){
			if (this.errored){
				// ignore error here
				this.port.write([ymodem.ABORT2], () => {});
			}
			this.port.close();
		}
	}

	_open(inListeningMode){
		let self = this;

		if (inListeningMode === undefined){
			inListeningMode = true;
		}

		const promise = new Promise((resolve, reject) => {
			self.port.open((err) => {
				if (err){
					return reject(err);
				}

				// wait for initial response
				let line = '';
				function cmdResponse(){
					let data = self.port.read();
					self._logData(data);
					line += data.toString();
					// if not in listening mode, we get CRC16 back
					// if in listening mode, we get this string
					if (data[0] === ymodem.CRC16 || line.trim() === "Waiting for the binary file to be sent ... (press 'a' to abort)"){
						self.port.removeListener('readable', cmdResponse);
						return resolve();
					}
				}
				self.port.on('readable', cmdResponse);
				self.port.write('f');
			});
		});

		return enforceTimeout(promise, 10000)
			.catch((error) => {
				if (error && error.isTimeout){
					return Promise.reject('Timed out waiting for initial response from device');
				}
				throw error;
			});
	}

	_endTransfer(){
		this.seq = 0;
		this.ending = true;
		return this._sendFileHeader('', 0);
	}

	_sendFile(buffer){
		let self = this;
		this.seq = 0;

		return Promise.resolve()
			.then(() => {
				log.verbose('send file header');
				return self._sendFileHeader('binary', buffer.length);
			})
			.then((fileResponse) => {
				if (fileResponse !== ymodem.ACK){
					return Promise.reject('file header not acknowledged');
				}

				let lastValue;
				async function send(){
					let start = (self.seq - 1) * self.options.packetLength;
					let buf = buffer.slice(start, start + self.options.packetLength);

					lastValue = await self._sendPacket(buf);

					if (isDone()){
						return lastValue;
					}

					await delay(1);
					return send();
				}

				function isDone(){
					return ((self.seq - 1) * self.options.packetLength) >= buffer.length;
				}

				return send();
			})
			.then(() => {
				let buf = Buffer.from([ymodem.EOT]);
				log.verbose('write', self.seq, buf, buf.length);
				return self._sendRawPacket(buf);
			});
	}

	_sendFileHeader(name, length){
		let buf = Buffer.from(name + '\0' + length + ' ');
		return this._sendPacket(buf);
	}

	_sendPacket(packet){
		if (packet.length < this.options.packetLength){
			let filler = Buffer.alloc(this.options.packetLength - packet.length);
			filler.fill(0);
			packet = Buffer.concat([packet, filler], this.options.packetLength);
		}

		let seqchr = this.seq & 0xFF;
		let seqchrNeg = (-this.seq - 1) & 0xFF;
		let header = Buffer.from([this.mark, seqchr, seqchrNeg]);
		let crc16 = Buffer.from([0, 0]);
		packet = Buffer.concat([header, packet, crc16]);
		log.verbose('write', this.seq, header, packet.length);

		return this._sendRawPacket(packet);
	}

	_sendRawPacket(packet){
		const self = this;
		const response = new Promise((resolve, reject) => {
			let resp = Buffer.from([]);
			function writeResponse(){
				let data = self.port.read();

				self._logData(data);
				resp = Buffer.concat([resp, data]);

				switch (resp[0]){
					case ymodem.ACK:
						if (!self.ending && self.seq === 0 && resp.length < 2){
							// on first ACK we expect a CRC16 afterwards
							return;
						}
						self.seq += 1;
						self.port.removeListener('readable', writeResponse);
						resolve(resp[0]);
						break;
					case ymodem.CA:
						if (resp.length < 2){
							// expect two CAs
							return;
						}
						// fallthrough on purpose
					case ymodem.NAK:
						self.port.removeListener('readable', writeResponse);
						reject('Transfer cancelled');
						break;
					default:
						self.port.removeListener('readable', writeResponse);
						reject('unknown message');
						break;
				}
			}
			self.port.on('readable', writeResponse);
		});
		const writeToPort = new Promise((resolve, reject) => {
			self.port.write(packet, (error) => {
				if (error){
					return reject(error);
				}
				return resolve();
			});
		});

		return writeToPort
			.then(() => enforceTimeout(response, 70000));
	}
};

<commit_msg>ensure line-break is received when opening a serial connection to a device<commit_after>const _ = require('lodash');
const {
	readFile,
	delay,
	asyncMapSeries,
	enforceTimeout
} = require('./utilities');
const log = require('./log');

const ymodem = {
	// 128 byte blocks
	SOH: 0x01,
	// 1024 byte blocks
	STX: 0x02,
	EOT: 0x04,
	ACK: 0x06,
	NAK: 0x15,
	CA: 0x18,
	CRC16: 0x43,
	ABORT1: 0x41,
	ABORT2: 0x61
};
const ymodemLookup = _.invert(ymodem);

module.exports = class YModem {
	constructor(serialPort, options){
		this.options = _.defaults(options, {
			packetLength: 128,
			debug: false,
			inListeningMode: true
		});
		this.port = serialPort;

		if (this.options.packetLength === 128){
			this.mark = ymodem.SOH;
		} else if (this.options.packetLength === 1024){
			this.mark = ymodem.STX;
		} else {
			throw new Error('invalid packet length');
		}

		serialPort.once('close', this._close.bind(this));
	}

	send(filenames){
		let self = this;

		if (!_.isArray(filenames)){
			filenames = [filenames];
		}

		return this._open(this.options.inListeningMode)
			.then(() => {
				return asyncMapSeries(filenames, (filename) => {
					console.log('sending file:', filename);
					return readFile(filename)
						.then((buffer) => self._sendFile(buffer));
				});
			})
			.then(() => this._endTransfer())
			.catch((err) => {
				self.errored = true;
				return Promise.reject(err);
			})
			.finally(() => self._close());
	}

	_logData(data){
		if (data.length <= 2){
			for (let i=0; i < data.length; i++){
				let chr = data[i];
				log.verbose(ymodemLookup[chr] || chr);
			}
			return;
		}
		log.verbose(data, data.toString());
	}

	_close(){
		if (this.port.isOpen){
			if (this.errored){
				// ignore error here
				this.port.write([ymodem.ABORT2], () => {});
			}
			this.port.close();
		}
	}

	_open(inListeningMode){
		let self = this;

		if (inListeningMode === undefined){
			inListeningMode = true;
		}

		const promise = new Promise((resolve, reject) => {
			self.port.open((err) => {
				if (err){
					return reject(err);
				}

				// wait for initial response
				const readyMsg = "Waiting for the binary file to be sent ... (press 'a' to abort)";
				const linebreakPtn = /\r?\n/;
				let line = '';
				function cmdResponse(){
					let data = self.port.read();
					self._logData(data);
					line += data.toString();
					const lines = line.split(linebreakPtn);
					// if not in listening mode, we get CRC16 back
					// if in listening mode, we get the ready message
					if (data[0] === ymodem.CRC16 || (lines.length > 1 && lines.some(l => l === readyMsg))){
						self.port.removeListener('readable', cmdResponse);
						return resolve();
					}
				}
				self.port.on('readable', cmdResponse);
				self.port.write('f');
			});
		});

		return enforceTimeout(promise, 10000)
			.catch((error) => {
				if (error && error.isTimeout){
					return Promise.reject('Timed out waiting for initial response from device');
				}
				throw error;
			});
	}

	_endTransfer(){
		this.seq = 0;
		this.ending = true;
		return this._sendFileHeader('', 0);
	}

	_sendFile(buffer){
		let self = this;
		this.seq = 0;

		return Promise.resolve()
			.then(() => {
				log.verbose('send file header');
				return self._sendFileHeader('binary', buffer.length);
			})
			.then((fileResponse) => {
				if (fileResponse !== ymodem.ACK){
					return Promise.reject('file header not acknowledged');
				}

				let lastValue;
				async function send(){
					let start = (self.seq - 1) * self.options.packetLength;
					let buf = buffer.slice(start, start + self.options.packetLength);

					lastValue = await self._sendPacket(buf);

					if (isDone()){
						return lastValue;
					}

					await delay(1);
					return send();
				}

				function isDone(){
					return ((self.seq - 1) * self.options.packetLength) >= buffer.length;
				}

				return send();
			})
			.then(() => {
				let buf = Buffer.from([ymodem.EOT]);
				log.verbose('write', self.seq, buf, buf.length);
				return self._sendRawPacket(buf);
			});
	}

	_sendFileHeader(name, length){
		let buf = Buffer.from(name + '\0' + length + ' ');
		return this._sendPacket(buf);
	}

	_sendPacket(packet){
		if (packet.length < this.options.packetLength){
			let filler = Buffer.alloc(this.options.packetLength - packet.length);
			filler.fill(0);
			packet = Buffer.concat([packet, filler], this.options.packetLength);
		}

		let seqchr = this.seq & 0xFF;
		let seqchrNeg = (-this.seq - 1) & 0xFF;
		let header = Buffer.from([this.mark, seqchr, seqchrNeg]);
		let crc16 = Buffer.from([0, 0]);
		packet = Buffer.concat([header, packet, crc16]);
		log.verbose('write', this.seq, header, packet.length);

		return this._sendRawPacket(packet);
	}

	_sendRawPacket(packet){
		const self = this;
		const response = new Promise((resolve, reject) => {
			let resp = Buffer.from([]);
			function writeResponse(){
				let data = self.port.read();

				self._logData(data);
				resp = Buffer.concat([resp, data]);

				switch (resp[0]){
					case ymodem.ACK:
						if (!self.ending && self.seq === 0 && resp.length < 2){
							// on first ACK we expect a CRC16 afterwards
							return;
						}
						self.seq += 1;
						self.port.removeListener('readable', writeResponse);
						resolve(resp[0]);
						break;
					case ymodem.CA:
						if (resp.length < 2){
							// expect two CAs
							return;
						}
						// fallthrough on purpose
					case ymodem.NAK:
						self.port.removeListener('readable', writeResponse);
						reject('Transfer cancelled');
						break;
					default:
						self.port.removeListener('readable', writeResponse);
						reject('unknown message');
						break;
				}
			}
			self.port.on('readable', writeResponse);
		});
		const writeToPort = new Promise((resolve, reject) => {
			self.port.write(packet, (error) => {
				if (error){
					return reject(error);
				}
				return resolve();
			});
		});

		return writeToPort
			.then(() => enforceTimeout(response, 70000));
	}
};

<|endoftext|>


<commit_before>var jsdom = require('jsdom');
var req = require('request');
var _ = require('underscore');
var jquery = require('../dongnelibrary_util.js').getJqueryString();
var global = {};

var libraryList = [
  {code: 'MA', name: '경기도립중앙도서관'},
  {code: 'MB', name: '경기도립평택도서관'},
  {code: 'MC', name: '경기도립광주도서관'},
  {code: 'MD', name: '경기도립여주도서관'},
  {code: 'ME', name: '경기도립포천도서관'},
  {code: 'MF', name: '경기도립김포도서관'}
];

function getLibraryNames() {
  return _.pluck(libraryList, 'name');
}

function getLibraryCode(libraryName) {
  var found = _.find(libraryList, function (lib) {
    return lib.name === libraryName;
  });

  if(found) {
    return found.code;
  }
  return '';
}

function exist(str) {
  return !(str.indexOf('대출중') >= 0)
}

function getOffset(str) {
  var offsetPattern = /javascript:detailview\('(\d+)/g,
      matches,
      offsetList = [];

  while (matches = offsetPattern.exec(str)) {
    offsetList.push(matches[1]);
  }

  return offsetList;
}

function appendOffset(booklist, str) {
  var offsetList = getOffset(str);
  return _.map(booklist, function(item, key){
      item.offset = offsetList[key];
      return item;
  });
}

function makeJsdomCallback(libraryName, body, opt, callback) {
  return function (errors, window) {
    var booklist = [],
        maxoffsetPattern = /^(\d+).*/,
        matches,
        $ = window.$,
        maxoffset = $('form:nth-child(1) > table:nth-child(2) > tbody > tr:nth-child(2) > td:nth-child(2)').text().trim();

    maxoffset = parseInt(maxoffset);

    if (maxoffset) {
      opt.maxoffset = maxoffset;
    }

    if (global.debug) {
      console.log('maxoffset: ' + maxoffset);
    }

    var $a = $('body > form:nth-child(1) > form > table > tbody > tr > td > table > tbody > tr');
    var checkPoint = 0;
    var checkPointLimit = 0;

    _.each($a, function (value) {
        var $value = $(value);
        booklist.push({
            libraryName: libraryName,
            title: $value.find('a').text().trim(),
            maxoffset: maxoffset,
            exist: false
        });
    });

    booklist.shift();
    booklist.shift();

    checkPointLimit = booklist.length;

    appendOffset(booklist, body);

    _.each(booklist, function(book, key) {
        var o = _.clone(opt);
        o.offset = book.offset;
        o.maxoffset = book.maxoffset;
        var index = key;

        searchDetail(o, function (exist) {
            booklist[index].exist = exist;
            checkPoint = checkPoint + 1;
            if(checkPoint === checkPointLimit) {
              if(callback) {
                callback({
                    code: 0,
                    totalBookCount: maxoffset,
                    msg: "No Error"
                  }, booklist);
              }
            }
        });
    });

    window.close();
  }
}

function search(opt, callback) {
  var title = 'javascript';
  var libraryName = '경기도립중앙도서관';
  var startPage = 1;

  if(opt.debug) {
    global.debug = true;
  }

  if(opt.title) {
    title = opt.title;
  }

  if(opt.libraryName) {
    libraryName = opt.libraryName;
  }

  if(opt.startPage) {
    startPage = opt.startPage;
  }

  req.post({
      url: 'http://www.gglib.or.kr:8081/kolas3_02/BookSearch/search_result.do',
      timeout: 20000,
      form: {
         jongbook:'',
         value2:'',
         value3:'',
         buhovalue1:'',
         buhovalue2:'',
         buhovalue3:'',
         buhovalue4:'',
         field1:'IAL',
         value1: title,
         sort:'RK DESC',
         msa:'',
         formclass:'',
         textlang:'',
         simplelang:'',
         startyear:'',
         endyear:'',
         limitpage:10,
         local:'',
         startpage: startPage,
         mode:0,
         mgc: getLibraryCode(libraryName)
       }
    }, function (error, res, body) {
      if(global.debug === true) {
        console.log(body);
      }
      if (!error && res.statusCode === 200) {
        jsdom.env({
            html: body,
            src: [jquery],
            done: makeJsdomCallback(libraryName, body, _.clone(opt), callback)
        });
      } else {
        var msg = 'Error';
        if(error) {
          msg = error;
        }

        if(res && res.statusCode) {
          msg = msg + " HTTP return code ("+res.statusCode+")";
        }

        if(callback) {
          callback({
              code: 1,
              msg: msg
            }, []);
        }
      }
    }
  );
}

function searchDetail(opt, callback) {
  var offset = 1;
  var maxoffset = 356;
  var title = 'javascript';
  var libraryName = '경기도립중앙도서관';

  if (global.debug) {
    console.log('opt: ' + JSON.stringify(opt, null, 2));
  }

  if(opt.offset) {
    offset = opt.offset;
  }

  if(opt.maxoffset) {
    maxoffset = opt.maxoffset;
  }

  if(opt.title) {
    title = opt.title;
  }

  if(opt.libraryName) {
    libraryName = opt.libraryName;
  }

  req.post({
      url: 'http://www.gglib.or.kr:8081/kolas3_01/BookSearch/detailview_result.do',
      timeout: 20000,
      form: {
         sort: 'RK DESC',
         beforequery: 'IAL:'+title.toUpperCase()+'* AND MGC:' + getLibraryCode(libraryName),
         msa: 'M',
         offset: offset,
         maxoffset: maxoffset,
         jongbook: '',
         historycount: 0,
         book_code: ''
      }
    }, function (error, res, body) {
      if(global.debug === true) {
        console.log(body);
      }
      if (!error && res.statusCode === 200) {
        jsdom.env({
            html: body,
            src: [jquery],
            done: function (errors, window) {
              var $a = window.$('table:nth-child(2) > tbody > tr:nth-child(4) > td > table > tbody > tr:nth-child(2) > td.view2_01');
              if(callback) {
                //console.log('$a.text(): ' + $a.text());
                if(exist(($a.text() + "").trim())) {
                  callback(true);
                } else {
                  callback(false);
                }
              }

              window.close();
            }
        });
      } else {
        if(callback) {
          callback(false);
        }
      }
    }
  );
}

module.exports = {
  search: search,
  getLibraryNames: getLibraryNames
};
<commit_msg>코드 정렬<commit_after>var jsdom = require('jsdom');
var req = require('request');
var _ = require('underscore');
var jquery = require('../dongnelibrary_util.js').getJqueryString();
var global = {};

var libraryList = [
  {code: 'MA', name: '경기도립중앙도서관'},
  {code: 'MB', name: '경기도립평택도서관'},
  {code: 'MC', name: '경기도립광주도서관'},
  {code: 'MD', name: '경기도립여주도서관'},
  {code: 'ME', name: '경기도립포천도서관'},
  {code: 'MF', name: '경기도립김포도서관'}
];

function getLibraryNames() {
  return _.pluck(libraryList, 'name');
}

function getLibraryCode(libraryName) {
  var found = _.find(libraryList, function (lib) {
    return lib.name === libraryName;
  });

  if(found) {
    return found.code;
  }
  return '';
}

function exist(str) {
  return !(str.indexOf('대출중') >= 0)
}

function getOffset(str) {
  var offsetPattern = /javascript:detailview\('(\d+)/g,
      matches,
      offsetList = [];

  while (matches = offsetPattern.exec(str)) {
    offsetList.push(matches[1]);
  }

  return offsetList;
}

function appendOffset(booklist, str) {
  var offsetList = getOffset(str);
  return _.map(booklist, function(item, key){
      item.offset = offsetList[key];
      return item;
  });
}

function makeJsdomCallback(libraryName, body, opt, callback) {
  return function (errors, window) {
    var booklist = [],
        maxoffsetPattern = /^(\d+).*/,
        matches,
        $ = window.$,
        maxoffset = $('form:nth-child(1) > table:nth-child(2) > tbody > tr:nth-child(2) > td:nth-child(2)').text().trim();

    maxoffset = parseInt(maxoffset);

    if (maxoffset) {
      opt.maxoffset = maxoffset;
    }

    if (global.debug) {
      console.log('maxoffset: ' + maxoffset);
    }

    var $a = $('body > form:nth-child(1) > form > table > tbody > tr > td > table > tbody > tr');
    var checkPoint = 0;
    var checkPointLimit = 0;

    _.each($a, function (value) {
        var $value = $(value);
        booklist.push({
            libraryName: libraryName,
            title: $value.find('a').text().trim(),
            maxoffset: maxoffset,
            exist: false
        });
    });

    booklist.shift();
    booklist.shift();

    checkPointLimit = booklist.length;

    appendOffset(booklist, body);

    _.each(booklist, function(book, key) {
        var o = _.clone(opt);
        o.offset = book.offset;
        o.maxoffset = book.maxoffset;
        var index = key;

        searchDetail(o, function (exist) {
            booklist[index].exist = exist;
            checkPoint = checkPoint + 1;
            if(checkPoint === checkPointLimit) {
              if(callback) {
                callback({
                    code: 0,
                    totalBookCount: maxoffset,
                    msg: "No Error"
                  }, booklist);
              }
            }
        });
    });

    window.close();
  }
}

function search(opt, callback) {
  var title = 'javascript';
  var libraryName = '경기도립중앙도서관';
  var startPage = 1;

  if(opt.debug) {
    global.debug = true;
  }

  if(opt.title) {
    title = opt.title;
  }

  if(opt.libraryName) {
    libraryName = opt.libraryName;
  }

  if(opt.startPage) {
    startPage = opt.startPage;
  }

  req.post({
      url: 'http://www.gglib.or.kr:8081/kolas3_02/BookSearch/search_result.do',
      timeout: 20000,
      form: {
         jongbook: '',
         value2: '',
         value3: '',
         buhovalue1: '',
         buhovalue2: '',
         buhovalue3: '',
         buhovalue4: '',
         field1: 'IAL',
         value1: title,
         sort: 'RK DESC',
         msa: '',
         formclass: '',
         textlang: '',
         simplelang: '',
         startyear: '',
         endyear: '',
         limitpage: 10,
         local: '',
         startpage: startPage,
         mode: 0,
         mgc: getLibraryCode(libraryName)
       }
    }, function (error, res, body) {
      if(global.debug === true) {
        console.log(body);
      }
      if (!error && res.statusCode === 200) {
        jsdom.env({
            html: body,
            src: [jquery],
            done: makeJsdomCallback(libraryName, body, _.clone(opt), callback)
        });
      } else {
        var msg = 'Error';
        if(error) {
          msg = error;
        }

        if(res && res.statusCode) {
          msg = msg + " HTTP return code ("+res.statusCode+")";
        }

        if(callback) {
          callback({
              code: 1,
              msg: msg
            }, []);
        }
      }
    }
  );
}

function searchDetail(opt, callback) {
  var offset = 1;
  var maxoffset = 356;
  var title = 'javascript';
  var libraryName = '경기도립중앙도서관';

  if (global.debug) {
    console.log('opt: ' + JSON.stringify(opt, null, 2));
  }

  if(opt.offset) {
    offset = opt.offset;
  }

  if(opt.maxoffset) {
    maxoffset = opt.maxoffset;
  }

  if(opt.title) {
    title = opt.title;
  }

  if(opt.libraryName) {
    libraryName = opt.libraryName;
  }

  req.post({
      url: 'http://www.gglib.or.kr:8081/kolas3_01/BookSearch/detailview_result.do',
      timeout: 20000,
      form: {
         sort: 'RK DESC',
         beforequery: 'IAL:'+title.toUpperCase()+'* AND MGC:' + getLibraryCode(libraryName),
         msa: 'M',
         offset: offset,
         maxoffset: maxoffset,
         jongbook: '',
         historycount: 0,
         book_code: ''
      }
    }, function (error, res, body) {
      if(global.debug === true) {
        console.log(body);
      }
      if (!error && res.statusCode === 200) {
        jsdom.env({
            html: body,
            src: [jquery],
            done: function (errors, window) {
              var $a = window.$('table:nth-child(2) > tbody > tr:nth-child(4) > td > table > tbody > tr:nth-child(2) > td.view2_01');
              if(callback) {
                //console.log('$a.text(): ' + $a.text());
                if(exist(($a.text() + "").trim())) {
                  callback(true);
                } else {
                  callback(false);
                }
              }

              window.close();
            }
        });
      } else {
        if(callback) {
          callback(false);
        }
      }
    }
  );
}

module.exports = {
  search: search,
  getLibraryNames: getLibraryNames
};
<|endoftext|>


<commit_before>(function ($, window, undefined) {
    'use strict';
    $.fn.extend({
        /**
         * This allows you to set relevant aria live-region states and properties.
         * The primary convenience is that it sets some sensible defaults which you can override.
         * It also allows you to dynamically override one or more of the properties as content is
         * updated.
         * Also, if you've set some of these properties elsewhere before calling this function, your existing
         * property values will remain unless you explicitly overwrite them with this function.
         *
         * Example uses:
         * 1. Create a live region with default options:         $('#foo').liveRegion();
         * 2. Create a live region and give it a label:          $('#foo').liveRegion({label: 'News Ticker'});
         * 3. Change aria-busy state as  new content is loading:  $('#foo').liveRegion({busy: 'true'});
         *
         * Note: for those new to aria:  all aria-* values are strings. So the token values, 'true' and 'false' must
         * be supplied to this function as strings, not booleans.
         *
         * For info on the relevant live region roles and their uses, go to
         * http://www.w3.org/WAI/PF/aria-practices/#liveprops
         *
         * @param opts
         */
        liveRegion: function (opts) {
            var self = $(this),
                current,
                labelledby,
                label,
                role,
                atomic,
                live,
                relevant,
                busy,
                className,
                replace,
                text,
                wait;

            if(typeof opts === 'undefined'){
                opts = {};
            }

            /**
             * function to determine whether something is blank or not
             * @param str
             * @returns {boolean}
             */
            function isEmpty(str) {

                switch (str) {
                    case '':
                    case ' ':
                    case 0:
                    case '0':
                    case null:
                    case false:
                    case undefined:
                        return true;
                    default:
                        return false;
                }
            }

            /**
             *
             * @param obj
             * @returns {*}
             */
            function cleanBlank(obj) {
                var key;

                for (key in obj) {
                    if (obj.hasOwnProperty(key)) {
                        if (false !== isEmpty(obj[key])) {
                            delete obj[key];
                        }
                    }
                }
                return obj;
            }

            // get the values of any existing live-region related properties
            current = {
                labelledby: self.attr('aria-labelledby') || undefined,
                label: self.attr('aria-label') || undefined,
                role: self.attr('role') || undefined,
                atomic: self.attr('aria-atomic') || undefined,
                live: self.attr('aria-live') || undefined,
                relevant: self.attr('aria-relevant') || undefined,
                busy: self.attr('aria-busy') || undefined
            };

            //clean anything that is a blank string because although that's truthy, it is useless to us
            // if we wanted to be really heavy-handed, we could check (some of) these against their
            // valid token values as defined in the ARIA spec.
            current = cleanBlank(current);

            // this section determines what the new values should be.
            // it does so by setting to:
            // 1.  the defined opts value if they exist or,
            // 2.  the currently existing value or,
            // 3.  the default value
            // (in that order)
            labelledby = opts.labelledby || current.labelledby || null;
            label = opts.label || current.label || null;
            role = opts.role || current.role || 'region';
            atomic = opts.atomic || current.atomic || 'false';
            live = opts.live || current.live || 'polite';
            relevant = opts.relevant || current.relevant || 'additions';
            busy = opts.busy || current.busy || 'false';
            className = opts.className || undefined;
            replace = opts.replace || false;
            text = opts.text || undefined,
            wait = opts.wait || 200;

            /**
             * Semi-kludgey: if the role is alert, override any 'live' property value to ensure it is assertive
             */
            if(role === 'alert'){
                live = 'assertive';
            }

            // actually set the values
            self.attr('role', role)
                .attr('aria-atomic', atomic)
                .attr('aria-live', live)
                .attr('aria-busy', busy)
                .attr('aria-relevant', relevant);

            // Note: It is assumed that the consumer is smart enough to know
            // not to use *both* aria-labelledby and aria-label
            // so we don't do any heavy-handed checking here
            if ((labelledby !== undefined) && (labelledby !== null)) {
                self.attr('aria-labelledby', labelledby);
            }

            if ((label !== undefined) && (label !== null)) {
                self.attr('aria-label', label);
            }

            // add CSS class if needed
            if (className !== undefined) {
                self.addClass(className);
            }

            // add or replace text, if needed
            // NOTE the use of setTimeout here to deal with some screen readers not
            // announcing liveRegion content if the content is added at the same time
            // as the other relevant live region attributes
            if (text !== undefined) {
                if (replace === false) {
                    setTimeout(self.append(text), wait);
                }
                else {
                    setTimeout(self.empty().html(text), wait);
                }
            }

            return this;
        }
    });
})(jQuery, window);<commit_msg>fixed karls inability to keep track of the space and time continum<commit_after>;(function ($, window, undefined) {
    'use strict';
    $.fn.extend({
        /**
         * This allows you to set relevant aria live-region states and properties.
         * The primary convenience is that it sets some sensible defaults which you can override.
         * It also allows you to dynamically override one or more of the properties as content is
         * updated.
         * Also, if you've set some of these properties elsewhere before calling this function, your existing
         * property values will remain unless you explicitly overwrite them with this function.
         *
         * Example uses:
         * 1. Create a live region with default options:         $('#foo').liveRegion();
         * 2. Create a live region and give it a label:          $('#foo').liveRegion({label: 'News Ticker'});
         * 3. Change aria-busy state as  new content is loading:  $('#foo').liveRegion({busy: 'true'});
         *
         * Note: for those new to aria:  all aria-* values are strings. So the token values, 'true' and 'false' must
         * be supplied to this function as strings, not booleans.
         *
         * For info on the relevant live region roles and their uses, go to
         * http://www.w3.org/WAI/PF/aria-practices/#liveprops
         *
         * @param opts
         */
        liveRegion: function (opts) {
            var self = $(this),
                current,
                labelledby,
                label,
                role,
                atomic,
                live,
                relevant,
                busy,
                className,
                replace,
                text,
                wait;

            if(typeof opts === 'undefined'){
                opts = {};
            }

            /**
             * function to determine whether something is blank or not
             * @param str
             * @returns {boolean}
             */
            function isEmpty(str) {

                switch (str) {
                    case '':
                    case ' ':
                    case 0:
                    case '0':
                    case null:
                    case false:
                    case undefined:
                        return true;
                    default:
                        return false;
                }
            }

            /**
             *
             * @param obj
             * @returns {*}
             */
            function cleanBlank(obj) {
                var key;

                for (key in obj) {
                    if (obj.hasOwnProperty(key)) {
                        if (false !== isEmpty(obj[key])) {
                            delete obj[key];
                        }
                    }
                }
                return obj;
            }

            // get the values of any existing live-region related properties
            current = {
                labelledby: self.attr('aria-labelledby') || undefined,
                label: self.attr('aria-label') || undefined,
                role: self.attr('role') || undefined,
                atomic: self.attr('aria-atomic') || undefined,
                live: self.attr('aria-live') || undefined,
                relevant: self.attr('aria-relevant') || undefined,
                busy: self.attr('aria-busy') || undefined
            };

            //clean anything that is a blank string because although that's truthy, it is useless to us
            // if we wanted to be really heavy-handed, we could check (some of) these against their
            // valid token values as defined in the ARIA spec.
            current = cleanBlank(current);

            // this section determines what the new values should be.
            // it does so by setting to:
            // 1.  the defined opts value if they exist or,
            // 2.  the currently existing value or,
            // 3.  the default value
            // (in that order)
            labelledby = opts.labelledby || current.labelledby || null;
            label = opts.label || current.label || null;
            role = opts.role || current.role || 'region';
            atomic = opts.atomic || current.atomic || 'false';
            live = opts.live || current.live || 'polite';
            relevant = opts.relevant || current.relevant || 'additions';
            busy = opts.busy || current.busy || 'false';
            className = opts.className || undefined;
            replace = opts.replace || false;
            text = opts.text || undefined;
            wait = opts.wait || 200;

            /**
             * Semi-kludgey: if the role is alert, override any 'live' property value to ensure it is assertive
             */
            if(role === 'alert'){
                live = 'assertive';
            }

            // actually set the values
            self.attr('role', role)
                .attr('aria-atomic', atomic)
                .attr('aria-live', live)
                .attr('aria-busy', busy)
                .attr('aria-relevant', relevant);

            // Note: It is assumed that the consumer is smart enough to know
            // not to use *both* aria-labelledby and aria-label
            // so we don't do any heavy-handed checking here
            if ((labelledby !== undefined) && (labelledby !== null)) {
                self.attr('aria-labelledby', labelledby);
            }

            if ((label !== undefined) && (label !== null)) {
                self.attr('aria-label', label);
            }

            // add CSS class if needed
            if (className !== undefined) {
                self.addClass(className);
            }

            // add or replace text, if needed
            // NOTE the use of setTimeout here to deal with some screen readers not
            // announcing liveRegion content if the content is added at the same time
            // as the other relevant live region attributes
            if (typeof text !== 'undefined') {
                if (replace === false) {
                    setTimeout(function(){
                        self.append(text)
                    }, wait);
                }
                else {
                    setTimeout(function(){
                        self.empty().html(text)
                    }, wait);
                }
            }

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


<commit_before>/**
 * Run Tests
 * Copyright (c) 2011 Reginaldo Silva (reginaldo@ubercomp.com)
 * Created: 30/11/11 23:39
 */
"use strict";

lm32.run_tests = function(wait_time, first_test, last_test) {
    if(! wait_time) {
        wait_time = 500;
    }
    var term_element = 'terminal';
    var tests = [
        'test_add.tst.bin',
        'test_addi.tst.bin',
        'test_and.tst.bin',
        'test_andhi.tst.bin',
        'test_andi.tst.bin',
        'test_b.tst.bin',
        'test_be.tst.bin',
        'test_bg.tst.bin',
        'test_bge.tst.bin',
        'test_bgeu.tst.bin',
        'test_bgu.tst.bin',
        'test_bi.tst.bin',
        'test_bne.tst.bin',
        'test_break.tst.bin',
        'test_bret.tst.bin',
        'test_call.tst.bin',
        'test_calli.tst.bin',
        'test_cmpe.tst.bin',
        'test_cmpei.tst.bin',
        'test_cmpg.tst.bin',
        'test_cmpge.tst.bin',
        'test_cmpgei.tst.bin',
        'test_cmpgeu.tst.bin',
        'test_cmpgeui.tst.bin',
        'test_cmpgi.tst.bin',
        'test_cmpgu.tst.bin',
        'test_cmpgui.tst.bin',
        'test_cmpne.tst.bin',
        'test_cmpnei.tst.bin',
        'test_divu.tst.bin',
        'test_eret.tst.bin',
        'test_lb.tst.bin',
        'test_lbu.tst.bin',
        'test_lh.tst.bin',
        'test_lhu.tst.bin',
        'test_lw.tst.bin',
        'test_modu.tst.bin',
        'test_mul.tst.bin',
        'test_muli.tst.bin',
        'test_nor.tst.bin',
        'test_nori.tst.bin',
        'test_or.tst.bin',
        'test_orhi.tst.bin',
        'test_ori.tst.bin',
        'test_ret.tst.bin',
        'test_sb.tst.bin',
        'test_scall.tst.bin',
        'test_sextb.tst.bin',
        'test_sexth.tst.bin',
        'test_sh.tst.bin',
        'test_sl.tst.bin',
        'test_sli.tst.bin',
        'test_sr.tst.bin',
        'test_sri.tst.bin',
        'test_sru.tst.bin',
        'test_srui.tst.bin',
        'test_sub.tst.bin',
        'test_sw.tst.bin',
        'test_xnor.tst.bin',
        'test_xnori.tst.bin',
        'test_xor.tst.bin',
        'test_xori.tst.bin'
    ];
    if(first_test === undefined) {
        first_test = 0;
    }
    if(last_test === undefined) {
        last_test = tests.length - 1;
    }
    console.log("Running tests " + first_test + " through " + last_test);
    var sys = lm32.start_sys(term_element);
    var i = first_test;
    var f = function() {
        sys.shutdown.value = false;
        sys.run_test(tests[i], i, sys.shutdown);
        i++;
        if(i <= last_test) {
            setTimeout(f, wait_time);
        }
    }
    f();
};

lm32.start_sys = function(terminal_div) {
    var RAM_BASE = 0x08000000;
    var RAM_SIZE = 64*1024*1024;
    var EBA_BASE = RAM_BASE;
    var DEBA_BASE = RAM_BASE;

    var TESTDEV_BASE = 0xffff0000;
    var MAX_STEPS = 1000;
    var BOOT_PC = RAM_BASE;

    var mmu = new lm32.MMU();

    var cpu_params = {
        mmu: mmu,
        bootstrap_pc: BOOT_PC,
        bootstrap_eba: EBA_BASE,
        bootstrap_deba: DEBA_BASE
    };
    var ram = new lm32.RAM(RAM_SIZE, true);

    var term = document.getElementById(terminal_div);
    var terminal = (function() {
        return {
          write: function(str) {
              term.textContent = term.textContent + str;
          }
        };
    })();

    terminal.write("LM32 Test Runner\n");

    var shutdown = { value: false };
    function shutdown_f() {
        terminal.write("Shutdown Requested!\n\n");
        shutdown.value = true;
    }

    var testdev_params = {
        mmu: mmu,
        shutdown: shutdown_f,
        terminal: terminal
    };
    var testdev = new lm32.TestDev(testdev_params);

    mmu.add_memory(RAM_BASE, RAM_SIZE, ram.get_mmio_handlers());
    mmu.add_memory(TESTDEV_BASE, testdev.iomem_size, testdev.get_mmio_handlers());

    function run_test(test_name, idx, shutdown) {
        var cpu = new lm32.Lm32Cpu(cpu_params);
        // testdev.reset();
        var str = "\nRunning Test " + test_name + " (" + idx + ")\n";
        terminal.write(str);
        console.log(str);
        mmu.log = false;
        mmu.load_binary("../test/" + test_name, BOOT_PC);
        mmu.log = true;
        var steps = 0;
        while(shutdown.value == false && steps < MAX_STEPS) {
            cpu.step(1);
            steps++;
        }
        if(shutdown.value == false) {
            terminal.write("Shutdown was never requested. Test FAILED\n");
        }
    }

    var ret = {
      run_test: run_test,
      shutdown: shutdown
    };
    return ret;
};
<commit_msg>Added a fake timer as the cpu needs one.<commit_after>/**
 * Run Tests
 * Copyright (c) 2011 Reginaldo Silva (reginaldo@ubercomp.com)
 * Created: 30/11/11 23:39
 */
"use strict";

lm32.run_tests = function(wait_time, first_test, last_test) {
    if(! wait_time) {
        wait_time = 500;
    }
    var term_element = 'terminal';
    var tests = [
        'test_add.tst.bin',
        'test_addi.tst.bin',
        'test_and.tst.bin',
        'test_andhi.tst.bin',
        'test_andi.tst.bin',
        'test_b.tst.bin',
        'test_be.tst.bin',
        'test_bg.tst.bin',
        'test_bge.tst.bin',
        'test_bgeu.tst.bin',
        'test_bgu.tst.bin',
        'test_bi.tst.bin',
        'test_bne.tst.bin',
        'test_break.tst.bin',
        'test_bret.tst.bin',
        'test_call.tst.bin',
        'test_calli.tst.bin',
        'test_cmpe.tst.bin',
        'test_cmpei.tst.bin',
        'test_cmpg.tst.bin',
        'test_cmpge.tst.bin',
        'test_cmpgei.tst.bin',
        'test_cmpgeu.tst.bin',
        'test_cmpgeui.tst.bin',
        'test_cmpgi.tst.bin',
        'test_cmpgu.tst.bin',
        'test_cmpgui.tst.bin',
        'test_cmpne.tst.bin',
        'test_cmpnei.tst.bin',
        'test_divu.tst.bin',
        'test_eret.tst.bin',
        'test_lb.tst.bin',
        'test_lbu.tst.bin',
        'test_lh.tst.bin',
        'test_lhu.tst.bin',
        'test_lw.tst.bin',
        'test_modu.tst.bin',
        'test_mul.tst.bin',
        'test_muli.tst.bin',
        'test_nor.tst.bin',
        'test_nori.tst.bin',
        'test_or.tst.bin',
        'test_orhi.tst.bin',
        'test_ori.tst.bin',
        'test_ret.tst.bin',
        'test_sb.tst.bin',
        'test_scall.tst.bin',
        'test_sextb.tst.bin',
        'test_sexth.tst.bin',
        'test_sh.tst.bin',
        'test_sl.tst.bin',
        'test_sli.tst.bin',
        'test_sr.tst.bin',
        'test_sri.tst.bin',
        'test_sru.tst.bin',
        'test_srui.tst.bin',
        'test_sub.tst.bin',
        'test_sw.tst.bin',
        'test_xnor.tst.bin',
        'test_xnori.tst.bin',
        'test_xor.tst.bin',
        'test_xori.tst.bin'
    ];
    if(first_test === undefined) {
        first_test = 0;
    }
    if(last_test === undefined) {
        last_test = tests.length - 1;
    }
    console.log("Running tests " + first_test + " through " + last_test);
    var sys = lm32.start_sys(term_element);
    var i = first_test;
    var f = function() {
        sys.shutdown.value = false;
        sys.run_test(tests[i], i, sys.shutdown);
        i++;
        if(i <= last_test) {
            setTimeout(f, wait_time);
        }
    }
    f();
};

lm32.start_sys = function(terminal_div) {
    var RAM_BASE = 0x08000000;
    var RAM_SIZE = 1*1024*1024;
    var EBA_BASE = RAM_BASE;
    var DEBA_BASE = RAM_BASE;

    var TESTDEV_BASE = 0xffff0000;
    var MAX_STEPS = 1000;
    var BOOT_PC = RAM_BASE;

    var mmu = new lm32.MMU();

    var cpu_params = {
        mmu: mmu,
        bootstrap_pc: BOOT_PC,
        bootstrap_eba: EBA_BASE,
        bootstrap_deba: DEBA_BASE
    };
    var ram = new lm32.RAM(RAM_SIZE, true);

    var term = document.getElementById(terminal_div);
    var terminal = (function() {
        return {
          write: function(str) {
              term.textContent = term.textContent + str;
          }
        };
    })();

    terminal.write("LM32 Test Runner\n");

    var shutdown = { value: false };
    function shutdown_f() {
        terminal.write("Shutdown Requested!\n\n");
        shutdown.value = true;
    }

    var testdev_params = {
        mmu: mmu,
        shutdown: shutdown_f,
        terminal: terminal
    };
    var testdev = new lm32.TestDev(testdev_params);
    var DummyTimer = function() {
        this.on_tick = function() {};
    };
    var timer = new DummyTimer();

    mmu.add_memory(RAM_BASE, RAM_SIZE, ram.get_mmio_handlers());
    mmu.add_memory(TESTDEV_BASE, testdev.iomem_size, testdev.get_mmio_handlers());

    function run_test(test_name, idx, shutdown) {
        var cpu = new lm32.Lm32Cpu(cpu_params);
        cpu.set_timers([timer]);
        // testdev.reset();
        var str = "\nRunning Test " + test_name + " (" + idx + ")\n";
        terminal.write(str);
        console.log(str);
        mmu.log = false;
        mmu.load_binary("../test/" + test_name, BOOT_PC);
        mmu.log = true;
        var steps = 0;
        while(shutdown.value == false && steps < MAX_STEPS) {
            cpu.step(1);
            steps++;
        }
        if(shutdown.value == false) {
            terminal.write("Shutdown was never requested. Test FAILED\n");
        }
    }

    var ret = {
      run_test: run_test,
      shutdown: shutdown
    };
    return ret;
};
<|endoftext|>


<commit_before>/**
 * LatticeMico32 timer emulation.
 *
 * Copyright (c) 2011 Reginaldo Silva (reginaldo@ubercomp.com)
 * Created: 11/09/11 00:26
 *
 * With strong inspiration from QEMU's hw/lm32_timer.c
 *
 * Specification available at:
 *   http://www.latticesemi.com/documents/mico32timer.pdf
 */
"use strict";

lm32.Lm32Timer = function(params) {
    var bits = lm32.bits;

    // parameters
    var id = params.id;
    var set_irq  = params.set_irq;  // function(irq_line, irq_value)
    var irq_line = params.irq_line; // my irq number

    // constants
    var R_SR       = 0; // status register
    var R_CR       = 1; // control register
    var R_PERIOD   = 2; // period register
    var R_SNAPSHOT = 3; // snapshot register
    var R_MAX      = 4;

    var SR_TO  = (1 << 0); // time out
    var SR_RUN = (1 << 1); // running

    var CR_ITO   = (1 << 0); // interrupt
    var CR_CONT  = (1 << 1); // continuous?
    var CR_START = (1 << 2); // start?
    var CR_STOP  = (1 << 3); // stop?

    function update_irq() {
        // this works only because ITO is the LSB
        var state = (this.regs[R_SR] & SR_TO) && (this.regs[R_CR] & CR_ITO);
        set_irq(irq_line, state);
        return state;
    }

    function read_32(addr) {
        var r = 0;
        addr = addr >> 2;

        switch (addr) {
            case R_SR:
            case R_CR:
            case R_PERIOD:
            case R_SNAPSHOT:
                r = this.regs[addr];
                break;
            default:
                r = 0;
                console.log("lm32_timer: read access to unknown register 0x" + (addr << 2).toString(16));
                break;
        }
        return r;
    }

    function write_32(addr, value) {
        addr = addr >> 2;
        value = value | 0;
        switch (addr) {
            case R_SR:
                if(value & SR_TO) {
                    this.regs[R_SR] |= SR_TO;
                } else {
                    this.regs[R_SR] &= ~SR_TO;
                }
                break;
            case R_CR:
                this.regs[R_CR] = value;
                if((value & CR_START) != 0) {
                    this.regs[R_SR] |= SR_RUN;
                }
                if((value & CR_STOP) != 0) {
                    this.regs[R_SR] &= ~SR_RUN;
                }
                break;
            case R_PERIOD:
                if(value < 0) {
                   throw ('timer' + id + 'bad period ' + value);
                } else {
                    this.regs[addr] = value;
                    this.regs[R_SNAPSHOT] = value;
                }
                break;
            case R_SNAPSHOT:
                console.log("lm32_timer: write access to read only register 0x" + (addr << 2).toString(16));
                break;
            default:
                console.log("lm32_timer: write access to unknown register 0x" + (addr << 2).toString(16));
                break;
        }
        this.update_irq();
    }

    function on_tick(ticks) {
        if((this.regs[R_SR] & SR_RUN)) {
            this.regs[R_SNAPSHOT] -= ticks;
            if(this.regs[R_SNAPSHOT] <= 0) {
                this.hit(-this.regs[R_SNAPSHOT]);
            }
        }

    }
    this.on_tick = on_tick;

    function hit(remainder) {
        if(remainder > 1000) {
           console.log('timer' + id + ' bad remainder ' + value);
        }

        // timeout
        this.regs[R_SR] = this.regs[R_SR] | SR_TO;

        // when counter is zero, snapshot is updated, regardless of CR_CONT
        this.regs[R_SNAPSHOT] = this.regs[R_PERIOD];

        if((this.regs[R_CR] & CR_CONT) == 0) {
            // not continuous, stop running
            this.regs[R_SR] &= ~SR_RUN;
        }
        this.update_irq();
    }
    this.hit = hit;

    function reset() {
        for(var i = 0; i < R_MAX; i++) {
            this.regs[i] = 0;
        }
    }
    this.reset = reset;

    // publication:
    this.regs = new Array(R_MAX);
    this.reset();
    this.iomem_size = (4 * R_MAX);
    this.update_irq = update_irq;
    this.read_32    = read_32;
    this.write_32   = write_32;
    this.reset      = reset;

};

lm32.Lm32Timer.prototype.get_mmio_handlers = function() {
    var handlers = {
        read_32 : this.read_32.bind(this),
        write_32: this.write_32.bind(this)
    };
    return handlers;
};

<commit_msg>Fixed bug. s/value/remainder/ in function hit<commit_after>/**
 * LatticeMico32 timer emulation.
 *
 * Copyright (c) 2011 Reginaldo Silva (reginaldo@ubercomp.com)
 * Created: 11/09/11 00:26
 *
 * With strong inspiration from QEMU's hw/lm32_timer.c
 *
 * Specification available at:
 *   http://www.latticesemi.com/documents/mico32timer.pdf
 */
"use strict";

lm32.Lm32Timer = function(params) {
    var bits = lm32.bits;

    // parameters
    var id = params.id;
    var set_irq  = params.set_irq;  // function(irq_line, irq_value)
    var irq_line = params.irq_line; // my irq number

    // constants
    var R_SR       = 0; // status register
    var R_CR       = 1; // control register
    var R_PERIOD   = 2; // period register
    var R_SNAPSHOT = 3; // snapshot register
    var R_MAX      = 4;

    var SR_TO  = (1 << 0); // time out
    var SR_RUN = (1 << 1); // running

    var CR_ITO   = (1 << 0); // interrupt
    var CR_CONT  = (1 << 1); // continuous?
    var CR_START = (1 << 2); // start?
    var CR_STOP  = (1 << 3); // stop?

    function update_irq() {
        // this works only because ITO is the LSB
        var state = (this.regs[R_SR] & SR_TO) && (this.regs[R_CR] & CR_ITO);
        set_irq(irq_line, state);
        return state;
    }

    function read_32(addr) {
        var r = 0;
        addr = addr >> 2;

        switch (addr) {
            case R_SR:
            case R_CR:
            case R_PERIOD:
            case R_SNAPSHOT:
                r = this.regs[addr];
                break;
            default:
                r = 0;
                console.log("lm32_timer: read access to unknown register 0x" + (addr << 2).toString(16));
                break;
        }
        return r;
    }

    function write_32(addr, value) {
        addr = addr >> 2;
        value = value | 0;
        switch (addr) {
            case R_SR:
                if(value & SR_TO) {
                    this.regs[R_SR] |= SR_TO;
                } else {
                    this.regs[R_SR] &= ~SR_TO;
                }
                break;
            case R_CR:
                this.regs[R_CR] = value;
                if((value & CR_START) != 0) {
                    this.regs[R_SR] |= SR_RUN;
                }
                if((value & CR_STOP) != 0) {
                    this.regs[R_SR] &= ~SR_RUN;
                }
                break;
            case R_PERIOD:
                if(value < 0) {
                   throw ('timer' + id + 'bad period ' + value);
                } else {
                    this.regs[addr] = value;
                    this.regs[R_SNAPSHOT] = value;
                }
                break;
            case R_SNAPSHOT:
                console.log("lm32_timer: write access to read only register 0x" + (addr << 2).toString(16));
                break;
            default:
                console.log("lm32_timer: write access to unknown register 0x" + (addr << 2).toString(16));
                break;
        }
        this.update_irq();
    }

    function on_tick(ticks) {
        if((this.regs[R_SR] & SR_RUN)) {
            this.regs[R_SNAPSHOT] -= ticks;
            if(this.regs[R_SNAPSHOT] <= 0) {
                this.hit(-this.regs[R_SNAPSHOT]);
            }
        }

    }
    this.on_tick = on_tick;

    function hit(remainder) {
        if(remainder > 1000) {
            console.log('timer' + id + ' bad remainder: ' + remainder);
        }

        // timeout
        this.regs[R_SR] = this.regs[R_SR] | SR_TO;

        // when counter is zero, snapshot is updated, regardless of CR_CONT
        this.regs[R_SNAPSHOT] = this.regs[R_PERIOD];

        if((this.regs[R_CR] & CR_CONT) == 0) {
            // not continuous, stop running
            this.regs[R_SR] &= ~SR_RUN;
        }
        this.update_irq();
    }
    this.hit = hit;

    function reset() {
        for(var i = 0; i < R_MAX; i++) {
            this.regs[i] = 0;
        }
    }
    this.reset = reset;

    // publication:
    this.regs = new Array(R_MAX);
    this.reset();
    this.iomem_size = (4 * R_MAX);
    this.update_irq = update_irq;
    this.read_32    = read_32;
    this.write_32   = write_32;
    this.reset      = reset;

};

lm32.Lm32Timer.prototype.get_mmio_handlers = function() {
    var handlers = {
        read_32 : this.read_32.bind(this),
        write_32: this.write_32.bind(this)
    };
    return handlers;
};

<|endoftext|>


<commit_before>'use strict';

import _ptrMarkup from './_markup.pug';
import _ptrStyles from './_styles.less';

const _defaults = {
  distThreshold: 60,
  distMax: 80,
  distReload: 50,
  bodyOffset: 20,
  mainElement: 'body',
  triggerElement: 'body',
  ptrElement: '.ptr',
  classPrefix: 'ptr--',
  cssProp: 'min-height',
  iconArrow: '⇣',
  iconRefreshing: '…',
  instructionsPullToRefresh: 'Pull down to refresh',
  instructionsReleaseToRefresh: 'Release to refresh',
  instructionsRefreshing: 'Refreshing',
  refreshTimeout: 500,
  getMarkup: _ptrMarkup,
  getStyles: _ptrStyles,
  onInit: () => {},
  onRefresh: () => location.reload(),
  resistanceFunction: t => Math.min(1, t / 2.5),
  shouldPullToRefresh: () => !window.scrollY,
};

const _methods = ['mainElement', 'ptrElement', 'triggerElement'];

const _shared = {
  pullStartY: null,
  pullMoveY: null,
  handlers: [],
  styleEl: null,
  events: null,
  dist: 0,
  state: 'pending',
  timeout: null,
  distResisted: 0,
  supportsPassive: false,
};

try {
  window.addEventListener('test', null, {
    get passive() { // eslint-disable-line getter-return
      _shared.supportsPassive = true;
    },
  });
} catch (e) {
  // do nothing
}

const _ptr = {
  setupDOM(handler) {
    if (!handler.ptrElement) {
      const ptr = document.createElement('div');

      if (handler.mainElement !== document.body) {
        handler.mainElement.parentNode.insertBefore(ptr, handler.mainElement);
      } else {
        document.body.insertBefore(ptr, document.body.firstChild);
      }

      ptr.classList.add(`${handler.classPrefix}ptr`);
      ptr.innerHTML = handler.getMarkup()
        .replace(/__PREFIX__/g, handler.classPrefix);

      handler.ptrElement = ptr;

      if (typeof handler.onInit === 'function') {
        handler.onInit(handler);
      }

      // Add the css styles to the style node, and then
      // insert it into the dom
      if (!_shared.styleEl) {
        _shared.styleEl = document.createElement('style');
        _shared.styleEl.setAttribute('id', 'pull-to-refresh-js-style');

        document.head.appendChild(_shared.styleEl);
      }

      _shared.styleEl.textContent = handler.getStyles()
        .replace(/__PREFIX__/g, handler.classPrefix)
        .replace(/\s+/g, ' ');
    }

    return handler;
  },
  onReset(handler) {
    handler.ptrElement.classList.remove(`${handler.classPrefix}refresh`);
    handler.ptrElement.style[handler.cssProp] = '0px';

    setTimeout(() => {
      // remove previous ptr-element from DOM
      if (handler.ptrElement && handler.ptrElement.parentNode) {
        handler.ptrElement.parentNode.removeChild(handler.ptrElement);
        handler.ptrElement = null;
      }

      // remove used stylesheet from DOM
      if (_shared.styleEl) {
        document.head.removeChild(_shared.styleEl);
      }

      // reset state
      _shared.styleEl = null;
      _shared.state = 'pending';
    }, handler.refreshTimeout);
  },
  update(handler) {
    const iconEl = handler.ptrElement.querySelector(`.${handler.classPrefix}icon`);
    const textEl = handler.ptrElement.querySelector(`.${handler.classPrefix}text`);

    if (iconEl) {
      if (_shared.state === 'refreshing') {
        iconEl.innerHTML = handler.iconRefreshing;
      } else {
        iconEl.innerHTML = handler.iconArrow;
      }
    }

    if (textEl) {
      if (_shared.state === 'releasing') {
        textEl.innerHTML = handler.instructionsReleaseToRefresh;
      }

      if (_shared.state === 'pulling' || _shared.state === 'pending') {
        textEl.innerHTML = handler.instructionsPullToRefresh;
      }

      if (_shared.state === 'refreshing') {
        textEl.innerHTML = handler.instructionsRefreshing;
      }
    }
  },
};

function _setupEvents() {
  let _el;

  function _onTouchStart(e) {
    // here, we must pick a handler first, and then append their html/css on the DOM
    const target = _shared.handlers.filter(h => h.contains(e.target))[0];

    _shared.enable = !!target;

    if (target && _shared.state === 'pending') {
      _el = _ptr.setupDOM(target);

      if (target.shouldPullToRefresh()) {
        _shared.pullStartY = e.touches[0].screenY;
      }

      clearTimeout(_shared.timeout);

      _ptr.update(target);
    }
  }

  function _onTouchMove(e) {
    if (!(_el && _shared.enable)) {
      return;
    }

    if (!_shared.pullStartY) {
      if (_el.shouldPullToRefresh()) {
        _shared.pullStartY = e.touches[0].screenY;
      }
    } else {
      _shared.pullMoveY = e.touches[0].screenY;
    }

    if (_shared.state === 'refreshing') {
      if (_el.shouldPullToRefresh() && _shared.pullStartY < _shared.pullMoveY) {
        e.preventDefault();
      }

      return;
    }

    if (_shared.state === 'pending') {
      _el.ptrElement.classList.add(`${_el.classPrefix}pull`);
      _shared.state = 'pulling';
      _ptr.update(_el);
    }

    if (_shared.pullStartY && _shared.pullMoveY) {
      _shared.dist = _shared.pullMoveY - _shared.pullStartY;
    }

    if (_shared.dist > 0) {
      e.preventDefault();

      _el.ptrElement.style[_el.cssProp] = `${_shared.distResisted}px`;

      _shared.distResisted = _el.resistanceFunction(_shared.dist / _el.distThreshold)
        * Math.min(_el.distMax, _shared.dist);

      if (_shared.state === 'pulling' && _shared.distResisted > _el.distThreshold) {
        _el.ptrElement.classList.add(`${_el.classPrefix}release`);
        _shared.state = 'releasing';
        _ptr.update(_el);
      }

      if (_shared.state === 'releasing' && _shared.distResisted < _el.distThreshold) {
        _el.ptrElement.classList.remove(`${_el.classPrefix}release`);
        _shared.state = 'pulling';
        _ptr.update(_el);
      }
    }
  }

  function _onTouchEnd() {
    if (!(_el && _shared.enable)) {
      return;
    }

    if (_shared.state === 'releasing' && _shared.distResisted > _el.distThreshold) {
      _shared.state = 'refreshing';

      _el.ptrElement.style[_el.cssProp] = `${_el.distReload}px`;
      _el.ptrElement.classList.add(`${_el.classPrefix}refresh`);

      _shared.timeout = setTimeout(() => {
        const retval = _el.onRefresh(() => _ptr.onReset(_el));

        if (retval && typeof retval.then === 'function') {
          retval.then(() => _ptr.onReset(_el));
        }

        if (!retval && !_el.onRefresh.length) {
          _ptr.onReset(_el);
        }
      }, _el.refreshTimeout);
    } else {
      if (_shared.state === 'refreshing') {
        return;
      }

      _el.ptrElement.style[_el.cssProp] = '0px';

      _shared.state = 'pending';
    }

    _ptr.update(_el);

    _el.ptrElement.classList.remove(`${_el.classPrefix}release`);
    _el.ptrElement.classList.remove(`${_el.classPrefix}pull`);

    _shared.pullStartY = _shared.pullMoveY = null;
    _shared.dist = _shared.distResisted = 0;
  }

  function _onScroll() {
    if (_el) {
      _el.mainElement.classList.toggle(`${_el.classPrefix}top`, _el.shouldPullToRefresh());
    }
  }

  const _passiveSettings = _shared.supportsPassive
    ? { passive: _shared.passive || false }
    : undefined;

  window.addEventListener('touchend', _onTouchEnd);
  window.addEventListener('touchstart', _onTouchStart);
  window.addEventListener('touchmove', _onTouchMove, _passiveSettings);
  window.addEventListener('scroll', _onScroll);

  return {
    onTouchEnd: _onTouchEnd,
    onTouchStart: _onTouchStart,
    onTouchMove: _onTouchMove,
    onScroll: _onScroll,

    destroy() {
      // Teardown event listeners
      window.removeEventListener('touchstart', _onTouchStart);
      window.removeEventListener('touchend', _onTouchEnd);
      window.removeEventListener('touchmove', _onTouchMove, _passiveSettings);
      window.removeEventListener('scroll', _onScroll);
    },
  };
}

function _setupHandler(options) {
  const _handler = {};

  // merge options with defaults
  Object.keys(_defaults).forEach(key => {
    _handler[key] = options[key] || _defaults[key];
  });

  // normalize timeout value, even if it is zero
  _handler.refreshTimeout = typeof options.refreshTimeout === 'number'
    ? options.refreshTimeout
    : _defaults.refreshTimeout;

  // normalize elements
  _methods.forEach(method => {
    if (typeof _handler[method] === 'string') {
      _handler[method] = document.querySelector(_handler[method]);
    }
  });

  // attach events lazily
  if (!_shared.events) {
    _shared.events = _setupEvents();
  }

  _handler.contains = target => {
    return _handler.triggerElement.contains(target);
  };

  _handler.destroy = () => {
    // stop pending any pending callbacks
    clearTimeout(_shared.timeout);

    // remove handler from shared state
    _shared.handlers.splice(_handler.offset, 1);
  };

  return _handler;
}

// public API
export default {
  setPassiveMode(isPassive) {
    _shared.passive = isPassive;
  },
  destroyAll() {
    if (_shared.events) {
      _shared.events.destroy();
      _shared.events = null;
    }

    _shared.handlers.forEach(h => {
      h.destroy();
    });
  },
  init(options = {}) {
    const handler = _setupHandler(options);

    // store offset for later unsubscription
    handler.offset = _shared.handlers.push(handler) - 1;

    return handler;
  },

  // export utils for testing
  _: {
    setupHandler: _setupHandler,
    setupEvents: _setupEvents,
    setupDOM: _ptr.setupDOM,
    onReset: _ptr.onReset,
    update: _ptr.update,
  },
};
<commit_msg>Keep stylesheet; double check for ptrElement to avoid errors<commit_after>'use strict';

import _ptrMarkup from './_markup.pug';
import _ptrStyles from './_styles.less';

const _defaults = {
  distThreshold: 60,
  distMax: 80,
  distReload: 50,
  bodyOffset: 20,
  mainElement: 'body',
  triggerElement: 'body',
  ptrElement: '.ptr',
  classPrefix: 'ptr--',
  cssProp: 'min-height',
  iconArrow: '⇣',
  iconRefreshing: '…',
  instructionsPullToRefresh: 'Pull down to refresh',
  instructionsReleaseToRefresh: 'Release to refresh',
  instructionsRefreshing: 'Refreshing',
  refreshTimeout: 500,
  getMarkup: _ptrMarkup,
  getStyles: _ptrStyles,
  onInit: () => {},
  onRefresh: () => location.reload(),
  resistanceFunction: t => Math.min(1, t / 2.5),
  shouldPullToRefresh: () => !window.scrollY,
};

const _methods = ['mainElement', 'ptrElement', 'triggerElement'];

const _shared = {
  pullStartY: null,
  pullMoveY: null,
  handlers: [],
  styleEl: null,
  events: null,
  dist: 0,
  state: 'pending',
  timeout: null,
  distResisted: 0,
  supportsPassive: false,
};

try {
  window.addEventListener('test', null, {
    get passive() { // eslint-disable-line getter-return
      _shared.supportsPassive = true;
    },
  });
} catch (e) {
  // do nothing
}

const _ptr = {
  setupDOM(handler) {
    if (!handler.ptrElement) {
      const ptr = document.createElement('div');

      if (handler.mainElement !== document.body) {
        handler.mainElement.parentNode.insertBefore(ptr, handler.mainElement);
      } else {
        document.body.insertBefore(ptr, document.body.firstChild);
      }

      ptr.classList.add(`${handler.classPrefix}ptr`);
      ptr.innerHTML = handler.getMarkup()
        .replace(/__PREFIX__/g, handler.classPrefix);

      handler.ptrElement = ptr;

      if (typeof handler.onInit === 'function') {
        handler.onInit(handler);
      }

      // Add the css styles to the style node, and then
      // insert it into the dom
      if (!_shared.styleEl) {
        _shared.styleEl = document.createElement('style');
        _shared.styleEl.setAttribute('id', 'pull-to-refresh-js-style');

        document.head.appendChild(_shared.styleEl);
      }

      _shared.styleEl.textContent = handler.getStyles()
        .replace(/__PREFIX__/g, handler.classPrefix)
        .replace(/\s+/g, ' ');
    }

    return handler;
  },
  onReset(handler) {
    handler.ptrElement.classList.remove(`${handler.classPrefix}refresh`);
    handler.ptrElement.style[handler.cssProp] = '0px';

    setTimeout(() => {
      // remove previous ptr-element from DOM
      if (handler.ptrElement && handler.ptrElement.parentNode) {
        handler.ptrElement.parentNode.removeChild(handler.ptrElement);
        handler.ptrElement = null;
      }

      // reset state
      _shared.state = 'pending';
    }, handler.refreshTimeout);
  },
  update(handler) {
    const iconEl = handler.ptrElement.querySelector(`.${handler.classPrefix}icon`);
    const textEl = handler.ptrElement.querySelector(`.${handler.classPrefix}text`);

    if (iconEl) {
      if (_shared.state === 'refreshing') {
        iconEl.innerHTML = handler.iconRefreshing;
      } else {
        iconEl.innerHTML = handler.iconArrow;
      }
    }

    if (textEl) {
      if (_shared.state === 'releasing') {
        textEl.innerHTML = handler.instructionsReleaseToRefresh;
      }

      if (_shared.state === 'pulling' || _shared.state === 'pending') {
        textEl.innerHTML = handler.instructionsPullToRefresh;
      }

      if (_shared.state === 'refreshing') {
        textEl.innerHTML = handler.instructionsRefreshing;
      }
    }
  },
};

function _setupEvents() {
  let _el;

  function _onTouchStart(e) {
    // here, we must pick a handler first, and then append their html/css on the DOM
    const target = _shared.handlers.filter(h => h.contains(e.target))[0];

    _shared.enable = !!target;

    if (target && _shared.state === 'pending') {
      _el = _ptr.setupDOM(target);

      if (target.shouldPullToRefresh()) {
        _shared.pullStartY = e.touches[0].screenY;
      }

      clearTimeout(_shared.timeout);

      _ptr.update(target);
    }
  }

  function _onTouchMove(e) {
    if (!(_el && _el.ptrElement && _shared.enable)) {
      return;
    }

    if (!_shared.pullStartY) {
      if (_el.shouldPullToRefresh()) {
        _shared.pullStartY = e.touches[0].screenY;
      }
    } else {
      _shared.pullMoveY = e.touches[0].screenY;
    }

    if (_shared.state === 'refreshing') {
      if (_el.shouldPullToRefresh() && _shared.pullStartY < _shared.pullMoveY) {
        e.preventDefault();
      }

      return;
    }

    if (_shared.state === 'pending') {
      _el.ptrElement.classList.add(`${_el.classPrefix}pull`);
      _shared.state = 'pulling';
      _ptr.update(_el);
    }

    if (_shared.pullStartY && _shared.pullMoveY) {
      _shared.dist = _shared.pullMoveY - _shared.pullStartY;
    }

    if (_shared.dist > 0) {
      e.preventDefault();

      _el.ptrElement.style[_el.cssProp] = `${_shared.distResisted}px`;

      _shared.distResisted = _el.resistanceFunction(_shared.dist / _el.distThreshold)
        * Math.min(_el.distMax, _shared.dist);

      if (_shared.state === 'pulling' && _shared.distResisted > _el.distThreshold) {
        _el.ptrElement.classList.add(`${_el.classPrefix}release`);
        _shared.state = 'releasing';
        _ptr.update(_el);
      }

      if (_shared.state === 'releasing' && _shared.distResisted < _el.distThreshold) {
        _el.ptrElement.classList.remove(`${_el.classPrefix}release`);
        _shared.state = 'pulling';
        _ptr.update(_el);
      }
    }
  }

  function _onTouchEnd() {
    if (!(_el && _el.ptrElement && _shared.enable)) {
      return;
    }

    if (_shared.state === 'releasing' && _shared.distResisted > _el.distThreshold) {
      _shared.state = 'refreshing';

      _el.ptrElement.style[_el.cssProp] = `${_el.distReload}px`;
      _el.ptrElement.classList.add(`${_el.classPrefix}refresh`);

      _shared.timeout = setTimeout(() => {
        const retval = _el.onRefresh(() => _ptr.onReset(_el));

        if (retval && typeof retval.then === 'function') {
          retval.then(() => _ptr.onReset(_el));
        }

        if (!retval && !_el.onRefresh.length) {
          _ptr.onReset(_el);
        }
      }, _el.refreshTimeout);
    } else {
      if (_shared.state === 'refreshing') {
        return;
      }

      _el.ptrElement.style[_el.cssProp] = '0px';

      _shared.state = 'pending';
    }

    _ptr.update(_el);

    _el.ptrElement.classList.remove(`${_el.classPrefix}release`);
    _el.ptrElement.classList.remove(`${_el.classPrefix}pull`);

    _shared.pullStartY = _shared.pullMoveY = null;
    _shared.dist = _shared.distResisted = 0;
  }

  function _onScroll() {
    if (_el) {
      _el.mainElement.classList.toggle(`${_el.classPrefix}top`, _el.shouldPullToRefresh());
    }
  }

  const _passiveSettings = _shared.supportsPassive
    ? { passive: _shared.passive || false }
    : undefined;

  window.addEventListener('touchend', _onTouchEnd);
  window.addEventListener('touchstart', _onTouchStart);
  window.addEventListener('touchmove', _onTouchMove, _passiveSettings);
  window.addEventListener('scroll', _onScroll);

  return {
    onTouchEnd: _onTouchEnd,
    onTouchStart: _onTouchStart,
    onTouchMove: _onTouchMove,
    onScroll: _onScroll,

    destroy() {
      // Teardown event listeners
      window.removeEventListener('touchstart', _onTouchStart);
      window.removeEventListener('touchend', _onTouchEnd);
      window.removeEventListener('touchmove', _onTouchMove, _passiveSettings);
      window.removeEventListener('scroll', _onScroll);
    },
  };
}

function _setupHandler(options) {
  const _handler = {};

  // merge options with defaults
  Object.keys(_defaults).forEach(key => {
    _handler[key] = options[key] || _defaults[key];
  });

  // normalize timeout value, even if it is zero
  _handler.refreshTimeout = typeof options.refreshTimeout === 'number'
    ? options.refreshTimeout
    : _defaults.refreshTimeout;

  // normalize elements
  _methods.forEach(method => {
    if (typeof _handler[method] === 'string') {
      _handler[method] = document.querySelector(_handler[method]);
    }
  });

  // attach events lazily
  if (!_shared.events) {
    _shared.events = _setupEvents();
  }

  _handler.contains = target => {
    return _handler.triggerElement.contains(target);
  };

  _handler.destroy = () => {
    // stop pending any pending callbacks
    clearTimeout(_shared.timeout);

    // remove handler from shared state
    _shared.handlers.splice(_handler.offset, 1);
  };

  return _handler;
}

// public API
export default {
  setPassiveMode(isPassive) {
    _shared.passive = isPassive;
  },
  destroyAll() {
    if (_shared.events) {
      _shared.events.destroy();
      _shared.events = null;
    }

    _shared.handlers.forEach(h => {
      h.destroy();
    });
  },
  init(options = {}) {
    const handler = _setupHandler(options);

    // store offset for later unsubscription
    handler.offset = _shared.handlers.push(handler) - 1;

    return handler;
  },

  // export utils for testing
  _: {
    setupHandler: _setupHandler,
    setupEvents: _setupEvents,
    setupDOM: _ptr.setupDOM,
    onReset: _ptr.onReset,
    update: _ptr.update,
  },
};
<|endoftext|>


<commit_before>(function () {
    'use strict';

    angular
        .module('${moduleName}')
        .directive('${directiveName}', ${directiveName});

    ${directiveName}.${DS}inject = [${dependencyInjection}];

    /* @ngInject */
    function ${directiveName}(${dependency}) {
        var directive = {
            bindToController: true,
            controller: ${ControllerName},
            controllerAs: '${vm}',
            link: link,
            restrict: 'A',
            scope: {}
        };
        return directive;

        function link(scope, element, attrs) {

        }
    }

    ${ControllerName}.${DS}inject = [${dependencyInjection}];

    /* @ngInject */
    function ${ControllerName}(${dependency}) {

    }

})();

<commit_msg>Remove unnecessary line break and space in IIFE<commit_after>(function() {
    'use strict';

    angular
        .module('${moduleName}')
        .directive('${directiveName}', ${directiveName});

    ${directiveName}.${DS}inject = [${dependencyInjection}];

    /* @ngInject */
    function ${directiveName}(${dependency}) {
        var directive = {
            bindToController: true,
            controller: ${ControllerName},
            controllerAs: '${vm}',
            link: link,
            restrict: 'A',
            scope: {}
        };
        return directive;

        function link(scope, element, attrs) {

        }
    }

    ${ControllerName}.${DS}inject = [${dependencyInjection}];

    /* @ngInject */
    function ${ControllerName}(${dependency}) {

    }

})();<|endoftext|>


<commit_before>/*   Riassence Framework
 *   Copyright 2009 Riassence Inc.
 *   http://riassence.com/
 *
 *   You should have received a copy of the GNU General Public License along
 *   with this software package. If not, contact licensing@riassence.com
 */

HTimeSheetItem = HControl.extend({
  componentName: 'timesheet_item',
  dragMode: 'create',
  prevXY: [0,0],
  prevXYTime: 0,
  startDrag: function(x,y){
    this.origY = y-this.parent.pageY();
    if(this.dragMode === 'normal'){
      var _timeNow = new Date().getTime(),
          _xEquals = (Math.round(this.prevXY[0]/4) === Math.round(x/4)),
          _yEquals = (Math.round(this.prevXY[1]/4) === Math.round(y/4)),
          _noTimeout = ((_timeNow - this.prevXYTime) < 500);
      if( _xEquals && _yEquals && _noTimeout ) {
        if( this.parent['editor'] ){
          var _editor = this.parent.editor;
          _editor.setTimeSheetItem(this);
          _editor.bringToFront();
          _editor.show();
        }
      }
      else {
        var _diffTop = this.rect.top - this.origY,
            _diffBottom = this.rect.bottom - this.origY;
        if(0 >= _diffTop && _diffTop >= -3){
          this.dragMode = 'resize-top';
        }
        else if(0 <= _diffBottom && _diffBottom <= 4){
          this.dragMode = 'resize-bottom';
        }
        else {
          this.dragMode = 'move';
          this.moveDiff = this.origY - this.rect.top;
        }
        this.bringToFront();
      }
    }
    this.prevXY = [x,y];
    this.prevXYTime = _timeNow;
    return true;
  },
  setTimeSheetItemLabel: function(_label){
    this.label = _label;
    this.refreshLabel();
  },
  dragCreate: function(_y){
    var _negative = (_y < this.origY),
        _lineHeight = Math.floor(this.parent.pxPerHour/2),
        _top, _bottom, _diff;
    if(_negative){
      var _floorY = Math.floor(_y/_lineHeight)*_lineHeight,
          _ceilYo = Math.ceil(this.origY/_lineHeight)*_lineHeight;
      if(_floorY<0){_floorY=0;}
      _diff = _floorY-_ceilYo;
      if( _diff <= 0-_lineHeight ){
        _top = _floorY;
        _bottom = _ceilYo;
      }
      else if( _diff === 0 ){
        _top = _floorY-_lineHeight;
        _bottom = _ceilYo;
      }
    }
    else {
      var _ceilY  = Math.ceil(_y/_lineHeight)*_lineHeight,
          _floorYo = Math.floor(this.origY/_lineHeight)*_lineHeight;
      if(_ceilY>(_lineHeight*48)){_ceilY=_lineHeight*48;}
      _diff = _ceilY-_floorYo;
      if( _diff >= _lineHeight ){
        _top = _floorYo;
        _bottom = _ceilY;
      }
      else if( _diff === 0 ){
        _top = _floorYo;
        _bottom = _ceilY+_lineHeight;
      }
    }
    this.rect.setTop(_top);
    this.rect.setBottom(_bottom);
  },
  dragResizeTop: function(_y){
    var _lineHeight = Math.floor(this.parent.pxPerHour/2),
        _top = Math.floor( _y/_lineHeight )*_lineHeight;
    if(_top < 0){ _top = 0; }
    if(_top+_lineHeight > this.rect.bottom){
      _top = this.rect.bottom - _lineHeight;
    }
    this.rect.setTop( _top );
  },
  dragResizeBottom: function(_y){
    var _lineHeight = Math.floor(this.parent.pxPerHour/2),
        _bottom = Math.floor( _y/_lineHeight )*_lineHeight;
    if(_bottom > _lineHeight*48){ _bottom = _lineHeight*48; }
    if(_bottom-_lineHeight < this.rect.top){
      _bottom = this.rect.top + _lineHeight;
    }
    this.rect.setBottom( _bottom );
  },
  dragMove: function(_y){
    var _lineHeight = Math.floor(this.parent.pxPerHour/2),
        _top = Math.floor( (0-this.moveDiff+_y)/_lineHeight )*_lineHeight;
    if(_top<0){_top = 0;}
    if(_top+this.rect.height>_lineHeight*48){
      _top = _lineHeight*48 - this.rect.height;
    }
    this.rect.offsetTo( this.rect.left, _top );
  },
  doDrag: function(x,y){
    var _pageY  = this.parent.pageY(),
        _y = y - _pageY;
    if(this.dragMode === 'create'){
      this.dragCreate(_y);
    }
    else if(this.dragMode === 'resize-top'){
      this.dragResizeTop(_y);
    }
    else if(this.dragMode === 'resize-bottom'){
      this.dragResizeBottom(_y);
    }
    else if(this.dragMode === 'move'){
      this.dragMove(_y);
    }
    this.drawRect();
    return true;
  },
  endDrag: function(x,y){
    var _pxPerHour = Math.floor(this.parent.pxPerHour),
        _value;
    if(this.dragMode === 'create'){
      this.parent.listItemViews.push( this );
      _value = {
        'timeBegin': this.rect.top/_pxPerHour,
        'timeEnd': this.rect.bottom/_pxPerHour,
        'label': this.label
      };
      if(this.parent['editor']){
        this.parent.editor.createItem( _value );
      }
    }
    else {
      _value = COMM.Values.clone( this.value );
      _value['timeBegin'] = this.rect.top/_pxPerHour;
      _value['timeEnd'] = this.rect.bottom/_pxPerHour;
      if(this.parent['editor']){
        this.parent.editor.modifyItem( _value );
      }
    }
    this.setValue( _value );
    this.dragMode = 'normal';
    return true;
  },
  refreshValue: function(){
    var _value = this.value,
        _pxPerHour = this.parent.pxPerHour;
    if((_value instanceof Object) && !(_value instanceof Array)){
      this.setLabel( _value['label'] );
      this.rect.setTop( _value['timeBegin'] * _pxPerHour );
      this.rect.setBottom( _value['timeEnd'] * _pxPerHour );
      this.drawRect();
    }
  }
});

<commit_msg>Documentation update<commit_after>/*   Riassence Framework
 *   Copyright 2009 Riassence Inc.
 *   http://riassence.com/
 *
 *   You should have received a copy of the GNU General Public License along
 *   with this software package. If not, contact licensing@riassence.com
 */

/*** = Description
  ** Item class to be used with HTimeSheet.
  ***/
HTimeSheetItem = HControl.extend({
  componentName: 'timesheet_item',
  dragMode: 'create',
  prevXY: [0,0],
  prevXYTime: 0,

/** = Description
  * Dragging is used to change coordinates.
  *
  * = Parameters
  * +x+:: X coordinate at the start of drag.
  * +y+:: Y coordinate at the start of drag.
  *
  **/
  startDrag: function(x,y){
    this.origY = y-this.parent.pageY();
    if(this.dragMode === 'normal'){
      var _timeNow = new Date().getTime(),
          _xEquals = (Math.round(this.prevXY[0]/4) === Math.round(x/4)),
          _yEquals = (Math.round(this.prevXY[1]/4) === Math.round(y/4)),
          _noTimeout = ((_timeNow - this.prevXYTime) < 500);
      if( _xEquals && _yEquals && _noTimeout ) {
        if( this.parent['editor'] ){
          var _editor = this.parent.editor;
          _editor.setTimeSheetItem(this);
          _editor.bringToFront();
          _editor.show();
        }
      }
      else {
        var _diffTop = this.rect.top - this.origY,
            _diffBottom = this.rect.bottom - this.origY;
        if(0 >= _diffTop && _diffTop >= -3){
          this.dragMode = 'resize-top';
        }
        else if(0 <= _diffBottom && _diffBottom <= 4){
          this.dragMode = 'resize-bottom';
        }
        else {
          this.dragMode = 'move';
          this.moveDiff = this.origY - this.rect.top;
        }
        this.bringToFront();
      }
    }
    this.prevXY = [x,y];
    this.prevXYTime = _timeNow;
    return true;
  },

/** = Description
  * Label setter function.
  *
  * = Parameters
  * +_label+:: New label
  *
  **/
  setTimeSheetItemLabel: function(_label){
    this.label = _label;
    this.refreshLabel();
  },

/** = Description
  * Function used to calculate the right size for a new
  * item created by dragging.
  *
  * = Parameters
  * +_y+:: Y coordinate at the start of drag.
  *
  **/
  dragCreate: function(_y){
    var _negative = (_y < this.origY),
        _lineHeight = Math.floor(this.parent.pxPerHour/2),
        _top, _bottom, _diff;
    if(_negative){
      var _floorY = Math.floor(_y/_lineHeight)*_lineHeight,
          _ceilYo = Math.ceil(this.origY/_lineHeight)*_lineHeight;
      if(_floorY<0){_floorY=0;}
      _diff = _floorY-_ceilYo;
      if( _diff <= 0-_lineHeight ){
        _top = _floorY;
        _bottom = _ceilYo;
      }
      else if( _diff === 0 ){
        _top = _floorY-_lineHeight;
        _bottom = _ceilYo;
      }
    }
    else {
      var _ceilY  = Math.ceil(_y/_lineHeight)*_lineHeight,
          _floorYo = Math.floor(this.origY/_lineHeight)*_lineHeight;
      if(_ceilY>(_lineHeight*48)){_ceilY=_lineHeight*48;}
      _diff = _ceilY-_floorYo;
      if( _diff >= _lineHeight ){
        _top = _floorYo;
        _bottom = _ceilY;
      }
      else if( _diff === 0 ){
        _top = _floorYo;
        _bottom = _ceilY+_lineHeight;
      }
    }
    this.rect.setTop(_top);
    this.rect.setBottom(_bottom);
  },

/** = Description
  * Resize top by dragging auxiliary function.
  *
  * = Parameters
  * +_y+:: Y coordinate at the start of drag.
  **/
  dragResizeTop: function(_y){
    var _lineHeight = Math.floor(this.parent.pxPerHour/2),
        _top = Math.floor( _y/_lineHeight )*_lineHeight;
    if(_top < 0){ _top = 0; }
    if(_top+_lineHeight > this.rect.bottom){
      _top = this.rect.bottom - _lineHeight;
    }
    this.rect.setTop( _top );
  },

/** = Description
  * Resize function for resizing the bottom of item.
  *
  * = Parameters
  * +_y+:: Y coordinate at the start of drag.
  *
  **/
  dragResizeBottom: function(_y){
    var _lineHeight = Math.floor(this.parent.pxPerHour/2),
        _bottom = Math.floor( _y/_lineHeight )*_lineHeight;
    if(_bottom > _lineHeight*48){ _bottom = _lineHeight*48; }
    if(_bottom-_lineHeight < this.rect.top){
      _bottom = this.rect.top + _lineHeight;
    }
    this.rect.setBottom( _bottom );
  },

/** = Description
  * Move function for item by dragging and dropping.
  *
  * = Parameters
  * +_y+:: Y coordinate at the start of drag.
  *
  **/
  dragMove: function(_y){
    var _lineHeight = Math.floor(this.parent.pxPerHour/2),
        _top = Math.floor( (0-this.moveDiff+_y)/_lineHeight )*_lineHeight;
    if(_top<0){_top = 0;}
    if(_top+this.rect.height>_lineHeight*48){
      _top = _lineHeight*48 - this.rect.height;
    }
    this.rect.offsetTo( this.rect.left, _top );
  },

/** = Description
  * Drag function for item. Decides whether the user wants to create a new
  * item, resize top, resize bottom or move an existing item.
  *
  * = Parameters
  * +x+:: X coordinate at the start of drag.
  * +y+:: Y coordinate at the start of drag.
  *
  **/
  doDrag: function(x,y){
    var _pageY  = this.parent.pageY(),
        _y = y - _pageY;
    if(this.dragMode === 'create'){
      this.dragCreate(_y);
    }
    else if(this.dragMode === 'resize-top'){
      this.dragResizeTop(_y);
    }
    else if(this.dragMode === 'resize-bottom'){
      this.dragResizeBottom(_y);
    }
    else if(this.dragMode === 'move'){
      this.dragMove(_y);
    }
    this.drawRect();
    return true;
  },

/** = Description
  * Modifies the existing item's coordinates or creates a new one.
  *
  * = Parameters
  * +x+:: X coordinate at the end of drag.
  * +y+:: Y coordinate at the end of drag.
  *
  **/
  endDrag: function(x,y){
    var _pxPerHour = Math.floor(this.parent.pxPerHour),
        _value;
    if(this.dragMode === 'create'){
      this.parent.listItemViews.push( this );
      _value = {
        'timeBegin': this.rect.top/_pxPerHour,
        'timeEnd': this.rect.bottom/_pxPerHour,
        'label': this.label
      };
      if(this.parent['editor']){
        this.parent.editor.createItem( _value );
      }
    }
    else {
      _value = COMM.Values.clone( this.value );
      _value['timeBegin'] = this.rect.top/_pxPerHour;
      _value['timeEnd'] = this.rect.bottom/_pxPerHour;
      if(this.parent['editor']){
        this.parent.editor.modifyItem( _value );
      }
    }
    this.setValue( _value );
    this.dragMode = 'normal';
    return true;
  },

/** = Description
  * Refreshes the object's label and place on the HTimeSheet.
  *
  **/
  refreshValue: function(){
    var _value = this.value,
        _pxPerHour = this.parent.pxPerHour;
    if((_value instanceof Object) && !(_value instanceof Array)){
      this.setLabel( _value['label'] );
      this.rect.setTop( _value['timeBegin'] * _pxPerHour );
      this.rect.setBottom( _value['timeEnd'] * _pxPerHour );
      this.drawRect();
    }
  }
});

<|endoftext|>


<commit_before>
/**
 * Created by michael on 4/16/15.
 */
var broadcastEventListener = function($){
	'use strict';

	var startIframeBroadcastListener = function() {

		var iframeBroadCastListener = function(event){
			if (event.origin === window.location.origin) {
				if(event.data!=undefined && event.data.type=="eventBroadcast") {
					console.log("got eventBroadcast event:"+JSON.stringify(event.data));
					if (broadcastMapper[event.data.data.event] != undefined) {
						broadcastMapper[event.data.data.event](event.data.data.optionalParams);
					}
					else {
						console.info("broadcastMapper doesn't have " + event.data.data.event + " mapping");
					}
				}
			}
		};

		if (window.addEventListener) {
			window.addEventListener("message", iframeBroadCastListener, false);
		} else {
			window.attachEvent("onmessage", iframeBroadCastListener);
		}
	};

	return {
		startIframeBroadcastListener:startIframeBroadcastListener
	}

}(jQuery);<commit_msg>fix for explorer<commit_after>
/**
 * Created by michael on 4/16/15.
 */
var broadcastEventListener = function($){
	'use strict';

	var startIframeBroadcastListener = function() {

		var iframeBroadCastListener = function(event){
			if (!window.location.origin) {
				window.location.origin = window.location.protocol + "//" + window.location.hostname + (window.location.port ? ':' + window.location.port: '');
			}
			if (event.origin === window.location.origin) {
				if(event.data!=undefined && event.data.type=="eventBroadcast") {
					console.log("got eventBroadcast event:"+JSON.stringify(event.data));
					if (broadcastMapper[event.data.data.event] != undefined) {
						broadcastMapper[event.data.data.event](event.data.data.optionalParams);
					}
					else {
						console.info("broadcastMapper doesn't have " + event.data.data.event + " mapping");
					}
				}
			}
		};

		if (window.addEventListener) {
			window.addEventListener("message", iframeBroadCastListener, false);
		} else {
			window.attachEvent("onmessage", iframeBroadCastListener);
		}
	};

	return {
		startIframeBroadcastListener:startIframeBroadcastListener
	}

}(jQuery);<|endoftext|>


<commit_before>(function( window, document, undefined ) {
  'use strict';

  var shadowColor = '#555',
      shadowBlur  = '0',
      shadowCount = 200;

  var mouse = {
    x: 0,
    y: 0
  };

  var building = document.getElementsByClassName( 'building' )[0],

    buildingWidth  = building.clientWidth,
    buildingHeight = building.clientHeight,

    halfWidth  = 0.5 * buildingWidth,
    halfHeight = 0.5 * buildingHeight;

  function onMouseMove( event ) {
    // Coordinates from center of building.
    mouse.x = event.pageX - building.offsetLeft - halfWidth;
    mouse.y = event.pageY - building.offsetTop  - halfHeight;

    building.style.boxShadow = generateCSS( mouse.x, mouse.y );
  }

  function generateCSS( x, y ) {
    var css = '';

    var length = Math.sqrt( x * x + y * y );

    var dx = -x / length,
        dy = -y / length;

    for ( var i = 0; i < shadowCount; i++ ) {
      css += Math.round( i * dx ) + 'px ' + Math.round( i * dy ) + 'px ' + shadowBlur + ' ' + shadowColor;
      if ( i < shadowCount - 1 ) {
        css += ', ';
      }
    }

    return css;
  }

  onMouseMove({ pageX: 0, pageY: 0 });
  document.addEventListener( 'mousemove', onMouseMove );
}) ( window, document );
<commit_msg>illustrations[top-down-city]: Add key to remove event listeners (power-saving).<commit_after>(function( window, document, undefined ) {
  'use strict';

  var shadowColor = '#555',
      shadowBlur  = '0',
      shadowCount = 200;

  var mouse = {
    x: 0,
    y: 0
  };

  var building = document.getElementsByClassName( 'building' )[0],

    buildingWidth  = building.clientWidth,
    buildingHeight = building.clientHeight,

    halfWidth  = 0.5 * buildingWidth,
    halfHeight = 0.5 * buildingHeight;

  function onMouseMove( event ) {
    // Coordinates from center of building.
    mouse.x = event.pageX - building.offsetLeft - halfWidth;
    mouse.y = event.pageY - building.offsetTop  - halfHeight;

    building.style.boxShadow = generateCSS( mouse.x, mouse.y );
  }

  function generateCSS( x, y ) {
    var css = '';

    var length = Math.sqrt( x * x + y * y );

    var dx = -x / length,
        dy = -y / length;

    for ( var i = 0; i < shadowCount; i++ ) {
      css += Math.round( i * dx ) + 'px ' + Math.round( i * dy ) + 'px ' + shadowBlur + ' ' + shadowColor;
      if ( i < shadowCount - 1 ) {
        css += ', ';
      }
    }

    return css;
  }

  onMouseMove({ pageX: 0, pageY: 0 });
  document.addEventListener( 'mousemove', onMouseMove );

  // Remove all event listeners.
  function onKeyDown( event ) {
    // ESC.
    if ( event.which === 27 ) {
      document.removeEventListener( 'mousemove', onMouseMove );
      document.removeEventListener( 'keydown', onKeyDown );
    }

  }

  document.addEventListener( 'keydown', onKeyDown );
}) ( window, document );
<|endoftext|>


<commit_before>/* eslint-env mocha, browser */
/* global proclaim */

it("should handle zero values for hours, minutes and seconds", function() {

	// 1 Dec 2014 00:00:00
	var date = new Date(1417392000000);
	proclaim.equal(date.toISOString(), "2014-12-01T00:00:00.000Z");
});

it('should handle leap years', function() {

	// 29 Feb 2016 12:01:01
	var date = new Date(1456747261000);
	proclaim.equal(date.toISOString(), "2016-02-29T12:01:01.000Z");
});

it('should handle millisecond accuracy', function() {

	// 1 Dec 2014 00:00:00:123
	var date = new Date(1417392000123);
	proclaim.equal(date.toISOString(), "2014-12-01T00:00:00.123Z");
});
<commit_msg>improve test coverage for Date.prototype.toISOString (#1626)<commit_after>/* eslint-env mocha */
/* globals proclaim */

it('is a function', function () {
	proclaim.isFunction(Date.prototype.toISOString);
});

it('has correct arity', function () {
	proclaim.arity(Date.prototype.toISOString, 0);
});

it('has correct name', function () {
	proclaim.hasName(Date.prototype.toISOString, 'toISOString');
});

it('is not enumerable', function () {
	proclaim.nonEnumerable(Date.prototype, 'toISOString');
});

it("should handle zero values for hours, minutes and seconds", function() {

	// 1 Dec 2014 00:00:00
	var date = new Date(1417392000000);
	proclaim.equal(date.toISOString(), "2014-12-01T00:00:00.000Z");
});

it('should handle leap years', function() {

	// 29 Feb 2016 12:01:01
	var date = new Date(1456747261000);
	proclaim.equal(date.toISOString(), "2016-02-29T12:01:01.000Z");
});

it('should handle millisecond accuracy', function() {

	// 1 Dec 2014 00:00:00:123
	var date = new Date(1417392000123);
	proclaim.equal(date.toISOString(), "2014-12-01T00:00:00.123Z");
});
<|endoftext|>


<commit_before>describe("Weather Application", function() {

  beforeEach(function() {
  });
   /* city and country location through the api */
  it("should successfully retrieve the users current city and country data ", function() {
    displayWeather();
    expect(locationFromIP.ip).toBeDefined();
    expect(locationFromIP.country).toBeDefined();
  });

  /* 5 days weather forecast */

  it("should successfully retrieve the data of 5 days weather forecast of the current location ", function() {
    displayWeather();
    expect(forcastWeatherData.list[0]).toBeDefined();
    expect(forcastWeatherData.list[1]).toBeDefined();
    expect(forcastWeatherData.list[2]).toBeDefined();
    expect(forcastWeatherData.list[3]).toBeDefined();
    expect(forcastWeatherData.list[4]).toBeDefined();
    expect(forcastWeatherData.list[5]).toBeDefined();
  });

  /*should successfully convert the Fahrenheit weather to celsius temperature on clicking the button" {
 */

  it("should successfully convert celsius into fahrenheit on clicking the button", function() {
    displayWeather();
    expect(Math.round(convertToFahrenheit(25))).toBe(77);
  });

  /*should successfully convert the Celsius weather to Fahrenheit temperature on clicking the button" {
 */

  it("should successfully convert fahrenheit into Celsius on clicking the button", function() {
    displayWeather();
     expect(Math.round(convertToFahrenheit(25))).toBe(77);
  });

 /* Renders the weather icons*/

  it("should load the weather icons successfully", function() {
     expect(true).toBeTruthy();
  });

});<commit_msg>Delete ApplicationSpec.js<commit_after><|endoftext|>