<commit_before>export default {
  el: {
    colorpicker: {
      confirm: '확인',
      clear: '초기화'
    },
    datepicker: {
      now: '지금',
      today: '오늘',
      cancel: '취소',
      clear: '초기화',
      confirm: '확인',
      selectDate: '날짜 선택',
      selectTime: '시간 선택',
      startDate: '시작 날짜',
      startTime: '시작 시간',
      endDate: '종료 날짜',
      endTime: '종료 시간',
      year: '년',
      month1: '1월',
      month2: '2월',
      month3: '3월',
      month4: '4월',
      month5: '5월',
      month6: '6월',
      month7: '7월',
      month8: '8월',
      month9: '9월',
      month10: '10월',
      month11: '11월',
      month12: '12월',
      // week: 'week',
      weeks: {
        sun: '일',
        mon: '월',
        tue: '화',
        wed: '수',
        thu: '목',
        fri: '금',
        sat: '토'
      },
      months: {
        jan: '1월',
        feb: '2월',
        mar: '3월',
        apr: '4월',
        may: '5월',
        jun: '6월',
        jul: '7월',
        aug: '8월',
        sep: '9월',
        oct: '10월',
        nov: '11월',
        dec: '12월'
      }
    },
    select: {
      loading: '불러오는 중',
      noMatch: '맞는 데이터가 없습니다',
      noData: '데이터 없음',
      placeholder: '선택'
    },
    cascader: {
      noMatch: '맞는 데이터가 없습니다',
      loading: '불러오는 중',
      placeholder: '선택'
    },
    pagination: {
      goto: '이동',
      pagesize: '/page',
      total: '총 {total}',
      pageClassifier: ''
    },
    messagebox: {
      title: '메시지',
      confirm: '확인',
      cancel: '취소',
      error: '올바르지 않은 입력'
    },
    upload: {
      delete: '삭제',
      preview: '미리보기',
      continue: '계속하기'
    },
    table: {
      emptyText: '데이터 없음',
      confirmFilter: '확인',
      resetFilter: '초기화',
      clearFilter: '전체',
      sumText: 'Sum' // to be translated
    },
    tree: {
      emptyText: '데이터 없음'
    },
    transfer: {
      noMatch: '맞는 데이터가 없습니다',
      noData: '데이터 없음',
      titles: ['List 1', 'List 2'], // to be translated
      filterPlaceholder: 'Enter keyword', // to be translated
      noCheckedFormat: '{total} items', // to be translated
      hasCheckedFormat: '{checked}/{total} checked' // to be translated
    }
  }
};
<commit_msg>Update ko.js<commit_after>export default {
  el: {
    colorpicker: {
      confirm: '확인',
      clear: '초기화'
    },
    datepicker: {
      now: '지금',
      today: '오늘',
      cancel: '취소',
      clear: '초기화',
      confirm: '확인',
      selectDate: '날짜 선택',
      selectTime: '시간 선택',
      startDate: '시작 날짜',
      startTime: '시작 시간',
      endDate: '종료 날짜',
      endTime: '종료 시간',
      year: '년',
      month1: '1월',
      month2: '2월',
      month3: '3월',
      month4: '4월',
      month5: '5월',
      month6: '6월',
      month7: '7월',
      month8: '8월',
      month9: '9월',
      month10: '10월',
      month11: '11월',
      month12: '12월',
      // week: 'week',
      weeks: {
        sun: '일',
        mon: '월',
        tue: '화',
        wed: '수',
        thu: '목',
        fri: '금',
        sat: '토'
      },
      months: {
        jan: '1월',
        feb: '2월',
        mar: '3월',
        apr: '4월',
        may: '5월',
        jun: '6월',
        jul: '7월',
        aug: '8월',
        sep: '9월',
        oct: '10월',
        nov: '11월',
        dec: '12월'
      }
    },
    select: {
      loading: '불러오는 중',
      noMatch: '맞는 데이터가 없습니다',
      noData: '데이터 없음',
      placeholder: '선택'
    },
    cascader: {
      noMatch: '맞는 데이터가 없습니다',
      loading: '불러오는 중',
      placeholder: '선택'
    },
    pagination: {
      goto: '이동',
      pagesize: '/page',
      total: '총 {total}',
      pageClassifier: ''
    },
    messagebox: {
      title: '메시지',
      confirm: '확인',
      cancel: '취소',
      error: '올바르지 않은 입력'
    },
    upload: {
      delete: '삭제',
      preview: '미리보기',
      continue: '계속하기'
    },
    table: {
      emptyText: '데이터 없음',
      confirmFilter: '확인',
      resetFilter: '초기화',
      clearFilter: '전체',
      sumText: '합'
    },
    tree: {
      emptyText: '데이터 없음'
    },
    transfer: {
      noMatch: '맞는 데이터가 없습니다',
      noData: '데이터 없음',
      titles: ['리스트 1', '리스트 2'],
      filterPlaceholder: ' 입력하세요',
      noCheckedFormat: '{total} 항목',
      hasCheckedFormat: '{checked}/{total} 선택됨'
    }
  }
};
<|endoftext|>


<commit_before>'use strict'

const Https = require('https')
const ParseString = require('xml2js').praseString

function run (msg, text) {
	msg.say('Lets play a word association game, tell me a word first.')
		.route('deviantart_response')
}

function DeviantArtResponse (msg) {
	// Make ajax request to deviant art random url
	var text = (msg.body.event && msg.body.event.text) || ''
	var url = 'https://api.flickr.com/services/feeds/photos_public.gne?jsoncallback=?'
	console.log(url)
	Https.get(url, function(res) {
		res.setEncoding('utf8');
		let raw_data = '';
		res.on('data', (chunk) => { raw_data += chunk; });
		console.log('Here is raw data')
		// console.log(raw_data)
		res.on('end', () => {
			try {
				// console.log(raw_data)
				ParseString(raw_data, function (err, result) {
					console.log('Parsed raw_data')
					console.log(result)
				})
				// var parser = new DOMParser();
				// var xml_doc = parser.paserFromString(raw_data, 'text/xml')

				// console.log(xml_doc)

				// const parsed_data = JSON.parse(raw_data);
				// var page_id = Object.keys(parsed_data.query.pages)[0]
				// var title = parsed_data.query.pages[page_id].title
				// var extract = parsed_data.query.pages[page_id].extract
				// msg.say({
				// 	text: 'Tell me what you think of this random Wikipedia article:',
				// 		'attachments': [
				// 		{
				// 			"fallback": '',
				// 			"color": '',
				// 			"pretext": '',
				// 			"title": title,
				// 			"title_link": 'https://en.wikipedia.org/wiki?curid=' + page_id,
				// 			"text": extract.replace(/<(?:.|\n)*?>/gm, ''),
				// 		}]
				// 	})
				// 	.route('wikipedia_response')
			} catch (e) {
				console.error(e.message);
			}
		});
	}).on('error', function(e) {
		console.log('Got error: ' + e.message)
	})
	// Creature-bot returns the wikipedia page url in message
}

module.exports = {
	run: run,
	DeviantArtResponse:  DeviantArtResponse
}
<commit_msg>Enhances Parsestring function.<commit_after>'use strict'

const Https = require('https')
const ParseString = require('xml2js').parseString

function run (msg, text) {
	msg.say('Lets play a word association game, tell me a word first.')
		.route('deviantart_response')
}

function DeviantArtResponse (msg) {
	// Make ajax request to deviant art random url
	var text = (msg.body.event && msg.body.event.text) || ''
	var url = 'https://api.flickr.com/services/feeds/photos_public.gne?jsoncallback=?'
	console.log(url)
	Https.get(url, function(res) {
		res.setEncoding('utf8');
		let raw_data = '';
		res.on('data', (chunk) => { raw_data += chunk; });
		console.log('Here is raw data')
		// console.log(raw_data)
		res.on('end', () => {
			try {
				// console.log(raw_data)
				ParseString(raw_data, function (err, result) {
					console.log('Parsed raw_data')
					console.log(result)
				})
				// var parser = new DOMParser();
				// var xml_doc = parser.paserFromString(raw_data, 'text/xml')

				// console.log(xml_doc)

				// const parsed_data = JSON.parse(raw_data);
				// var page_id = Object.keys(parsed_data.query.pages)[0]
				// var title = parsed_data.query.pages[page_id].title
				// var extract = parsed_data.query.pages[page_id].extract
				// msg.say({
				// 	text: 'Tell me what you think of this random Wikipedia article:',
				// 		'attachments': [
				// 		{
				// 			"fallback": '',
				// 			"color": '',
				// 			"pretext": '',
				// 			"title": title,
				// 			"title_link": 'https://en.wikipedia.org/wiki?curid=' + page_id,
				// 			"text": extract.replace(/<(?:.|\n)*?>/gm, ''),
				// 		}]
				// 	})
				// 	.route('wikipedia_response')
			} catch (e) {
				console.error(e.message);
			}
		});
	}).on('error', function(e) {
		console.log('Got error: ' + e.message)
	})
	// Creature-bot returns the wikipedia page url in message
}

module.exports = {
	run: run,
	DeviantArtResponse:  DeviantArtResponse
}
<|endoftext|>


<commit_before>"use strict";

const ImageData    = require("./ImageData");
const ImageResizer = require("./ImageResizer");
const ImageReducer = require("./ImageReducer");
const S3           = require("./S3");

class ImageProcessor {

    /**
     * Image processor
     * management resize/reduce image list by configration,
     * and pipe AWS Lambda's event/context
     *
     * @constructor
     * @param Object s3Object
     */
    constructor(s3Object) {
        this.s3Object = s3Object;
    }

    /**
     * Run the process
     *
     * @public
     * @param Config config
     */
    run(config) {
        if ( ! config.get("bucket") ) {
            config.set("bucket", this.s3Object.bucket.name);
        }

        return S3.getObject(
            this.s3Object.bucket.name,
            unescape(this.s3Object.object.key.replace(/\+/g, ' '))
        )
        .then((imageData) => this.processImage(imageData, config))
        .then(S3.putObjects);
    }

    /**
     * Processing image
     *
     * @public
     * @param ImageData imageData
     * @param Config config
     * @return Promise
     */
    processImage(imageData, config) {
        const jpegOptimizer = config.get("jpegOptimizer", "mozjpeg");
        const promiseList   = config.get("resizes", []).filter((option) => {
            return option.size &&
                imageData.fileName.indexOf(option.directory) !== 0 // don't process images in the output folder
        }).map((option) => {
            if ( ! option.bucket ) {
                option.bucket = config.get("bucket");
            }
            if ( ! option.acl ){
                option.acl = config.get("acl");
            }
            option.jpegOptimizer = option.jpegOptimizer || jpegOptimizer;
            return this.execResizeImage(option, imageData);
        });

        if ( config.exists("reduce") ) {
            const reduce = config.get("reduce");

            if ( ! reduce.bucket ) {
                reduce.bucket = config.get("bucket");
            }
            reduce.jpegOptimizer = reduce.jpegOptimizer || jpegOptimizer;
            promiseList.unshift(this.execReduceImage(reduce, imageData));
        }

        if ( config.exists("backup") ) {
            const backup = config.get("backup");

            if ( ! backup.bucket ) {
                backup.bucket = config.get("bucket");
            }
            promiseList.unshift(this.execBackupImage(backup, imageData));
        }

        return Promise.all(promiseList);
    }

    /**
     * Execute resize image
     *
     * @public
     * @param Object option
     * @param imageData imageData
     * @return Promise
     */
    execResizeImage(option, imageData) {
        const resizer = new ImageResizer(option);

        return resizer.exec(imageData)
        .then((resizedImage) => {
            const reducer = new ImageReducer(option);

            return reducer.exec(resizedImage);
        });
    }

    /**
     * Execute reduce image
     *
     * @public
     * @param Object option
     * @param ImageData imageData
     * @return Promise
     */
    execReduceImage(option, imageData) {
        const reducer = new ImageReducer(option);

        return reducer.exec(imageData);
    }

    execBackupImage(option, image) {
        let dir;

        if ( option.directory ) {
            if ( option.directory.match(/^\.\//) ) {
                dir = image.dirName + "/" + option.directory.replace(/^\.\//, '') + "/";
            } else {
                dir = option.directory + "/" + image.dirName + "/";
            }
        } else {
            dir = image.dirName + "/";
        }

        dir = dir.replace(/[\/]+/g, "/");

        return new Promise((resolve, reject) => {
            resolve(
                new ImageData(
                    dir + image.baseName,
                    option.bucket || image.bucketName,
                    image.data,
                    image.headers,
                    image.acl
                )
            );
        });
    }
}

module.exports = ImageProcessor;
<commit_msg>support unicode filename (unescape -> decodeURIComponent)<commit_after>"use strict";

const ImageData    = require("./ImageData");
const ImageResizer = require("./ImageResizer");
const ImageReducer = require("./ImageReducer");
const S3           = require("./S3");

class ImageProcessor {

    /**
     * Image processor
     * management resize/reduce image list by configration,
     * and pipe AWS Lambda's event/context
     *
     * @constructor
     * @param Object s3Object
     */
    constructor(s3Object) {
        this.s3Object = s3Object;
    }

    /**
     * Run the process
     *
     * @public
     * @param Config config
     */
    run(config) {
        if ( ! config.get("bucket") ) {
            config.set("bucket", this.s3Object.bucket.name);
        }

        return S3.getObject(
            this.s3Object.bucket.name,
            decodeURIComponent(this.s3Object.object.key.replace(/\+/g, ' '))
        )
        .then((imageData) => this.processImage(imageData, config))
        .then(S3.putObjects);
    }

    /**
     * Processing image
     *
     * @public
     * @param ImageData imageData
     * @param Config config
     * @return Promise
     */
    processImage(imageData, config) {
        const jpegOptimizer = config.get("jpegOptimizer", "mozjpeg");
        const promiseList   = config.get("resizes", []).filter((option) => {
            return option.size &&
                imageData.fileName.indexOf(option.directory) !== 0 // don't process images in the output folder
        }).map((option) => {
            if ( ! option.bucket ) {
                option.bucket = config.get("bucket");
            }
            if ( ! option.acl ){
                option.acl = config.get("acl");
            }
            option.jpegOptimizer = option.jpegOptimizer || jpegOptimizer;
            return this.execResizeImage(option, imageData);
        });

        if ( config.exists("reduce") ) {
            const reduce = config.get("reduce");

            if ( ! reduce.bucket ) {
                reduce.bucket = config.get("bucket");
            }
            reduce.jpegOptimizer = reduce.jpegOptimizer || jpegOptimizer;
            promiseList.unshift(this.execReduceImage(reduce, imageData));
        }

        if ( config.exists("backup") ) {
            const backup = config.get("backup");

            if ( ! backup.bucket ) {
                backup.bucket = config.get("bucket");
            }
            promiseList.unshift(this.execBackupImage(backup, imageData));
        }

        return Promise.all(promiseList);
    }

    /**
     * Execute resize image
     *
     * @public
     * @param Object option
     * @param imageData imageData
     * @return Promise
     */
    execResizeImage(option, imageData) {
        const resizer = new ImageResizer(option);

        return resizer.exec(imageData)
        .then((resizedImage) => {
            const reducer = new ImageReducer(option);

            return reducer.exec(resizedImage);
        });
    }

    /**
     * Execute reduce image
     *
     * @public
     * @param Object option
     * @param ImageData imageData
     * @return Promise
     */
    execReduceImage(option, imageData) {
        const reducer = new ImageReducer(option);

        return reducer.exec(imageData);
    }

    execBackupImage(option, image) {
        let dir;

        if ( option.directory ) {
            if ( option.directory.match(/^\.\//) ) {
                dir = image.dirName + "/" + option.directory.replace(/^\.\//, '') + "/";
            } else {
                dir = option.directory + "/" + image.dirName + "/";
            }
        } else {
            dir = image.dirName + "/";
        }

        dir = dir.replace(/[\/]+/g, "/");

        return new Promise((resolve, reject) => {
            resolve(
                new ImageData(
                    dir + image.baseName,
                    option.bucket || image.bucketName,
                    image.data,
                    image.headers,
                    image.acl
                )
            );
        });
    }
}

module.exports = ImageProcessor;
<|endoftext|>


<commit_before>const db = require('../db');

module.exports = {

  fetchLatest: function(key, amount, callback) {
    var data = []
    db.conn.all(
      "SELECT message.id, message.data, message.timestamp, \
        chat.name AS chat_name, user.name AS user_name, \
        user.first_name AS first_name, user.last_name AS last_name, \
        message_type.name AS message_type \
      FROM message \
      JOIN chat ON message.chat_id=chat.id \
      JOIN user ON message.user_id=user.id \
      JOIN message_type ON message.message_type_id=message_type.id \
      WHERE chat_id=(SELECT id FROM chat WHERE api_key=?) \
      ORDER BY timestamp DESC \
      LIMIT ?", key, amount, function(err, rows) {
      rows.forEach(function(row) {
        data.push(row)
      })
      callback(data)
    })
  },

  searchForMessages: function(key, amount, str, callback) {
    var data = []
    db.conn.all(
      "SELECT message.id, message.data, message.timestamp, \
        chat.name AS chat_name, user.name AS user_name, \
        user.first_name AS first_name, user.last_name AS last_name, \
        message_type.name AS message_type \
      FROM message \
      JOIN chat ON message.chat_id=chat.id \
      JOIN user ON message.user_id=user.id \
      JOIN message_type ON message.message_type_id=message_type.id \
      WHERE chat_id=(SELECT id FROM chat WHERE api_key=?) AND \
        (message.data LIKE ? OR \
        message.data LIKE ? OR \
        message.data LIKE ? OR \
        message.data LIKE ?) \
      ORDER BY timestamp DESC \
      LIMIT ?", key, str, '%'+str, str+'%', '%'+str+'%', amount, function(err, rows) {
        rows.forEach(function(row) {
          data.push(row)
        })
        callback(data)
      })
    },

    validateApiKey: function(key, callback) {
      db.conn.all("SELECT rowid FROM chat WHERE name != '' AND api_key=? LIMIT 1", key, function(err, row) {
        var status = false;
        if(row.length >= 1) {
          status = true;
        }
        callback([{'status': status}]);
      })
    }
}
<commit_msg>made amount in /api/recent an optional argument<commit_after>const db = require('../db');

module.exports = {

  fetchLatest: function(key, amount, callback) {
    var data = []
    const query = "SELECT message.id, message.data, message.timestamp, \
        chat.name AS chat_name, user.name AS user_name, \
        user.first_name AS first_name, user.last_name AS last_name, \
        message_type.name AS message_type \
      FROM message \
      JOIN chat ON message.chat_id=chat.id \
      JOIN user ON message.user_id=user.id \
      JOIN message_type ON message.message_type_id=message_type.id \
      WHERE chat_id=(SELECT id FROM chat WHERE api_key=?) \
      ORDER BY timestamp DESC"
    if(amount) {
      // An amount limit was specified
      const queryLimit = query + " LIMIT ?"
      db.conn.all(queryLimit, key, amount, function(err, rows) {
        rows.forEach(function(row) {
          data.push(row)
        })
        callback(data)
      })
    } else {
      // Return all the messeges we've got
      db.conn.all(query, key, function(err, rows) {
        rows.forEach(function(row) {
          data.push(row)
        })
        callback(data)
      })
    }
  },

  searchForMessages: function(key, amount, str, callback) {
    var data = []
    db.conn.all(
      "SELECT message.id, message.data, message.timestamp, \
        chat.name AS chat_name, user.name AS user_name, \
        user.first_name AS first_name, user.last_name AS last_name, \
        message_type.name AS message_type \
      FROM message \
      JOIN chat ON message.chat_id=chat.id \
      JOIN user ON message.user_id=user.id \
      JOIN message_type ON message.message_type_id=message_type.id \
      WHERE chat_id=(SELECT id FROM chat WHERE api_key=?) AND \
        (message.data LIKE ? OR \
        message.data LIKE ? OR \
        message.data LIKE ? OR \
        message.data LIKE ?) \
      ORDER BY timestamp DESC \
      LIMIT ?", key, str, '%'+str, str+'%', '%'+str+'%', amount, function(err, rows) {
        rows.forEach(function(row) {
          data.push(row)
        })
        callback(data)
      })
    },

    validateApiKey: function(key, callback) {
      db.conn.all("SELECT rowid FROM chat WHERE name != '' AND api_key=? LIMIT 1", key, function(err, row) {
        var status = false
        if(row.length >= 1) {
          status = true
        }
        callback([{'status': status}])
      })
    }
}
<|endoftext|>


<commit_before>'use strict';

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

var slugger = require('uslug');

/**
 * Defines a set of functions usable in all swig templates, are merged into context on render
 * @param  {Object}   swig        Swig engine
 */
module.exports.swigFunctions = function(swig) {

  var self = this;

  this.context = {};
  this.data = {};
  this.settings = {};
  this.typeInfo = {};

  this.paginate = false;
  this.curPage = 1;
  this.maxPage = -1;
  this.pageUrl = 'page-';
  this.paginationBaseUrl = null;
  this.cachedData = {};
  this.CURRENT_URL = '/';

  /**
   * Returns a standard url for a given object, only works for standard scaffolding url structure
   * @param  {Object}   object     Object to generate url for
   * @returns {String}   Url for the object passed in
   */
  var url = function(object) {
    var slug = object.slug ? object.slug : (object.name ? slugger(object.name).toLowerCase() : null);
    var prefix = object._type ? object._type : '';

    if(object._type) {
      if(self.typeInfo[object._type].customUrls &&  self.typeInfo[object._type].customUrls.individualUrl) {
        prefix = utils.parseCustomUrl(self.typeInfo[object._type].customUrls.individualUrl, object);
      }
    } else {
      if(self.typeInfo[object.slug].customUrls && self.typeInfo[object.slug].customUrls.listUrl) {
        slug = self.typeInfo[object.slug].customUrls.listUrl;
      }
    }

    var url = '';
    if(prefix) {
      url = '/' + prefix + '/' + slug + '/';
    } else {
      url = '/' + slug + '/';
    }

    return url;
  };

  /**
   * Sets the data set used by all the functions in this class
   * @param  {Object}   data   The data to be used by all functions in this class
   */
  this.setData = function(data) {
    self.cachedData = {};
    self.data = data;
  };

  /**
   * Sets the type info used by all the functions in this class
   * @param  {Object}   typeInfo   The type info to be used by all functions in this class
   */
  this.setTypeInfo = function(typeInfo) {
    self.typeInfo = typeInfo;
  };

  /**
   * Sets the settings used by all the functions in this class
   * @param  {Object}   settings   The settings to be used by all functions in this class
   */
  this.setSettings = function(settings) {
    self.settings = settings;
  };

  /**
   * Returns all content types for a given site
   * @returns  {Array}  An array of type object (slug and name of type)
   */
  var getTypes = function(returnOneOffs) {
    var types = [];

    for(var key in self.typeInfo) {
      if(returnOneOffs || !self.typeInfo[key].oneOff) {
        types.push({ slug: key, name: self.typeInfo[key].name });
      }
    }

    return types;
  };

  /**
   * Returns a published item based off its type and id or a relation string from the CMS
   * @param    {String} Can either be a relation string (from the CMS) or a type name
   * @param    {String} (OPTIONAL) If the first parameter was the type, this must be the ID of the item
   * @returns  {Object} The published item specified by the type/id or relation string passed in
   */
  var getItem = function(type, key) {
    if(!type) {
      return {};
    }

    if(!key) {
      if(Array.isArray(type)) {
        if(type.length > 0) {
          type = type[0];
        } else {
          return {};
        }
      }
      var parts = type.split(" ", 2);
      if(parts.length !== 2) {
        return {};
      }

      type = parts[0];
      key = parts[1];
    }

    if(!self.typeInfo[type]) {
      return {};
    }

    var item = self.data[type][key];

    if(!item) {
      return {};
    }

    if(!self.typeInfo[type].oneOff) {
      if(!item.publish_date) {
        return {};
      }

      var now = Date.now();
      var pdate = Date.parse(item.publish_date);

      if(pdate > now + (1 * 60 * 1000)) {
        return {};
      }
    }

    item._type = type;
    return item;
  };

  /**
   * Returns an array of items from a relation
   * @param    {Array}  An array of relation strings from the CMS
   * @returns  {Array}  All published items specified by relation strings
   */
  var getItems = function(arr) {
    if(!arr) {
      return [];
    }
    var items = [];
    arr.forEach(function(itm) {
      var obj = getItem(itm);
      if(!_.isEmpty(obj)) {
        items.push(getItem(itm));
      }
    });

    return items;
  }

  /**
   * Returns all the data specified by the arguments
   * @param    {String} Name of type to retrieve data for
   * @param    {String} (optional) Other type to return with this data, can specifiy as many types as needed
   * @returns  {Array}  All items from type (or types)
   */
  var getCombined = function() {
    var names = [].slice.call(arguments, 0);

    if(self.cachedData[names.join(',')])
    {
      return self.cachedData[names.join(',')];
    }

    // TODO, SLUG NAME THE SAME WAS CMS DOES

    var data = [];
    names.forEach(function(name) {
      var tempData = self.data[name] || {};

      if(self.typeInfo[name] && self.typeInfo[name].oneOff) {
        data = tempData;
        return;
      }

      tempData = _.omit(tempData, function(value, key) { return key.indexOf('_') === 0; });

      // convert it into an array
      tempData = _.map(tempData, function(value, key) {
        value._id = key;
        value._type = name;
        if(value.name && !value.slug)
          value.slug = slugger(value.name).toLowerCase();
        return value
      });
      tempData = _.filter(tempData, function(item) {
        if(!item.publish_date) {
          return false;
        }

        var now = Date.now();
        var pdate = Date.parse(item.publish_date);

        if(pdate > now + (1 * 60 * 1000)) {
          return false;
        }

        return true;
      });

      data = data.concat(tempData);
    });

    self.cachedData[names.join(',')] = data;

    return data;
  };

  var paginate = function(data, perPage, pageName) {
    if(self.curPage === 1 && self.paginate === true)
    {
      throw new Error('Can only paginate one set of data in a template.');
    }

    var items = utils.slice(data, perPage, perPage * (self.curPage-1));
    self.paginate = true;

    if(self.paginationBaseUrl === null) {
      self.paginationBaseUrl = self.CURRENT_URL;
    }

    self.pageUrl = pageName || self.pageUrl;
    self.maxPage = Math.ceil(_(data).size() / perPage);

    return items;
  };

  var getCurPage = function() {
    return self.curPage;
  };

  var getMaxPage = function() {
    return self.maxPage;
  };

  var getPageUrl = function(pageNum) {
    if(pageNum == 1) {
      return self.paginationBaseUrl;
    }

    return self.paginationBaseUrl + self.pageUrl + pageNum + '/';
  };

  var getCurrentUrl = function() {
    return self.CURRENT_URL;
  };

  var getSetting = function(key) {
    if(!self.settings.general) {
      return null;
    }

    return self.settings.general[key];
  };

  var randomElement = function(array) {
    if(!array || !_.isArray(array)) {
      return null;
    }

    var index = [Math.floor(Math.random() * array.length)];
    return array[index];
  };

  var sortItems = function(input, property, reverse) {

    if(_.size(input) === 0) {
      return input;
    }

    var first = input[0];
    var sortProperty = '_sort_' + property;

    if(first[sortProperty]) {
      property = sortProperty;
    }

    if(reverse) {
      return _.sortBy(input, property).reverse();
    }

    return _.sortBy(input, property)
  };

  var nextItem = function(item, sort_name, reverse_sort) {
    var type = item._type;
    var items = getCombined(type);

    if(sort_name) {
      items = sortItems(items, sort_name, reverse_sort);
    }

    var nextItem = null;
    var previousItem = null;

    items.some(function(itm) {
      if(previousItem && previousItem.name == item.name) {
        nextItem = itm;
        return true;
      }

      previousItem = itm;
    });

    return nextItem;
  };

  var prevItem = function(item, sort_name, reverse_sort) {
    var type = item._type;
    var items = getCombined(type);

    if(sort_name) {
      items = sortItems(items, sort_name, reverse_sort);
    }

    var returnItem = null;
    var previousItem = null;

    items.some(function(itm) {
      if(itm.name == item.name) {
        returnItem = previousItem;
        return true;
      }

      previousItem = itm;
    });

    return returnItem;
  };

  var merge = function() {
    var arrs = [].slice.call(arguments, 0);

    var newArr = [];

    arrs.forEach(function(arr) {
      newArr = newArr.concat(arr);
    })

    return newArr;
  }

  // FUNCTIONS USED FOR PAGINATION HELPING, IGNORE FOR MOST CASES
  this.shouldPaginate = function() {
    return self.curPage <= self.maxPage;
  };

  // Reset initial data
  this.init = function() {
    self.paginate = false;
    self.curPage = 1;
    self.pageUrl = 'page-'
    self.maxPage = -1;
    self.paginationBaseUrl = null;
  };

  this.increasePage = function() {
    self.curPage = self.curPage + 1;
  };

  this.setParams = function(params) {
    for(var key in params) {
      self[key] = params[key];
    }
  };

  this.getFunctions = function() {
    return {
      get: getCombined,
      getItem: getItem,
      getItems: getItems,
      getTypes: getTypes,
      paginate: paginate,
      getCurPage: getCurPage,
      getMaxPage: getMaxPage,
      getPageUrl: getPageUrl,
      url: url,
      getCurrentUrl: getCurrentUrl,
      getSetting: getSetting,
      random: randomElement,
      cmsVersion: 'v2',
      merge: merge,
      nextItem: nextItem,
      prevItem: prevItem
    };
  };

  return this;
};<commit_msg>string to object<commit_after>'use strict';

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

var slugger = require('uslug');

/**
 * Defines a set of functions usable in all swig templates, are merged into context on render
 * @param  {Object}   swig        Swig engine
 */
module.exports.swigFunctions = function(swig) {

  var self = this;

  this.context = {};
  this.data = {};
  this.settings = {};
  this.typeInfo = {};

  this.paginate = false;
  this.curPage = 1;
  this.maxPage = -1;
  this.pageUrl = 'page-';
  this.paginationBaseUrl = null;
  this.cachedData = {};
  this.CURRENT_URL = '/';

  /**
   * Returns a standard url for a given object, only works for standard scaffolding url structure
   * @param  {Object}   object     Object to generate url for
   * @returns {String}   Url for the object passed in
   */
  var url = function(object) {
    if(typeof object === 'string') {
      object = { slug: object, name: object };
    }

    var slug = object.slug ? object.slug : (object.name ? slugger(object.name).toLowerCase() : null);
    var prefix = object._type ? object._type : '';

    if(object._type) {
      if(self.typeInfo[object._type].customUrls &&  self.typeInfo[object._type].customUrls.individualUrl) {
        prefix = utils.parseCustomUrl(self.typeInfo[object._type].customUrls.individualUrl, object);
      }
    } else {
      if(self.typeInfo[object.slug].customUrls && self.typeInfo[object.slug].customUrls.listUrl) {
        slug = self.typeInfo[object.slug].customUrls.listUrl;
      }
    }

    var url = '';
    if(prefix) {
      url = '/' + prefix + '/' + slug + '/';
    } else {
      url = '/' + slug + '/';
    }

    return url;
  };

  /**
   * Sets the data set used by all the functions in this class
   * @param  {Object}   data   The data to be used by all functions in this class
   */
  this.setData = function(data) {
    self.cachedData = {};
    self.data = data;
  };

  /**
   * Sets the type info used by all the functions in this class
   * @param  {Object}   typeInfo   The type info to be used by all functions in this class
   */
  this.setTypeInfo = function(typeInfo) {
    self.typeInfo = typeInfo;
  };

  /**
   * Sets the settings used by all the functions in this class
   * @param  {Object}   settings   The settings to be used by all functions in this class
   */
  this.setSettings = function(settings) {
    self.settings = settings;
  };

  /**
   * Returns all content types for a given site
   * @returns  {Array}  An array of type object (slug and name of type)
   */
  var getTypes = function(returnOneOffs) {
    var types = [];

    for(var key in self.typeInfo) {
      if(returnOneOffs || !self.typeInfo[key].oneOff) {
        types.push({ slug: key, name: self.typeInfo[key].name });
      }
    }

    return types;
  };

  /**
   * Returns a published item based off its type and id or a relation string from the CMS
   * @param    {String} Can either be a relation string (from the CMS) or a type name
   * @param    {String} (OPTIONAL) If the first parameter was the type, this must be the ID of the item
   * @returns  {Object} The published item specified by the type/id or relation string passed in
   */
  var getItem = function(type, key) {
    if(!type) {
      return {};
    }

    if(!key) {
      if(Array.isArray(type)) {
        if(type.length > 0) {
          type = type[0];
        } else {
          return {};
        }
      }
      var parts = type.split(" ", 2);
      if(parts.length !== 2) {
        return {};
      }

      type = parts[0];
      key = parts[1];
    }

    if(!self.typeInfo[type]) {
      return {};
    }

    var item = self.data[type][key];

    if(!item) {
      return {};
    }

    if(!self.typeInfo[type].oneOff) {
      if(!item.publish_date) {
        return {};
      }

      var now = Date.now();
      var pdate = Date.parse(item.publish_date);

      if(pdate > now + (1 * 60 * 1000)) {
        return {};
      }
    }

    item._type = type;
    return item;
  };

  /**
   * Returns an array of items from a relation
   * @param    {Array}  An array of relation strings from the CMS
   * @returns  {Array}  All published items specified by relation strings
   */
  var getItems = function(arr) {
    if(!arr) {
      return [];
    }
    var items = [];
    arr.forEach(function(itm) {
      var obj = getItem(itm);
      if(!_.isEmpty(obj)) {
        items.push(getItem(itm));
      }
    });

    return items;
  }

  /**
   * Returns all the data specified by the arguments
   * @param    {String} Name of type to retrieve data for
   * @param    {String} (optional) Other type to return with this data, can specifiy as many types as needed
   * @returns  {Array}  All items from type (or types)
   */
  var getCombined = function() {
    var names = [].slice.call(arguments, 0);

    if(self.cachedData[names.join(',')])
    {
      return self.cachedData[names.join(',')];
    }

    // TODO, SLUG NAME THE SAME WAS CMS DOES

    var data = [];
    names.forEach(function(name) {
      var tempData = self.data[name] || {};

      if(self.typeInfo[name] && self.typeInfo[name].oneOff) {
        data = tempData;
        return;
      }

      tempData = _.omit(tempData, function(value, key) { return key.indexOf('_') === 0; });

      // convert it into an array
      tempData = _.map(tempData, function(value, key) {
        value._id = key;
        value._type = name;
        if(value.name && !value.slug)
          value.slug = slugger(value.name).toLowerCase();
        return value
      });
      tempData = _.filter(tempData, function(item) {
        if(!item.publish_date) {
          return false;
        }

        var now = Date.now();
        var pdate = Date.parse(item.publish_date);

        if(pdate > now + (1 * 60 * 1000)) {
          return false;
        }

        return true;
      });

      data = data.concat(tempData);
    });

    self.cachedData[names.join(',')] = data;

    return data;
  };

  var paginate = function(data, perPage, pageName) {
    if(self.curPage === 1 && self.paginate === true)
    {
      throw new Error('Can only paginate one set of data in a template.');
    }

    var items = utils.slice(data, perPage, perPage * (self.curPage-1));
    self.paginate = true;

    if(self.paginationBaseUrl === null) {
      self.paginationBaseUrl = self.CURRENT_URL;
    }

    self.pageUrl = pageName || self.pageUrl;
    self.maxPage = Math.ceil(_(data).size() / perPage);

    return items;
  };

  var getCurPage = function() {
    return self.curPage;
  };

  var getMaxPage = function() {
    return self.maxPage;
  };

  var getPageUrl = function(pageNum) {
    if(pageNum == 1) {
      return self.paginationBaseUrl;
    }

    return self.paginationBaseUrl + self.pageUrl + pageNum + '/';
  };

  var getCurrentUrl = function() {
    return self.CURRENT_URL;
  };

  var getSetting = function(key) {
    if(!self.settings.general) {
      return null;
    }

    return self.settings.general[key];
  };

  var randomElement = function(array) {
    if(!array || !_.isArray(array)) {
      return null;
    }

    var index = [Math.floor(Math.random() * array.length)];
    return array[index];
  };

  var sortItems = function(input, property, reverse) {

    if(_.size(input) === 0) {
      return input;
    }

    var first = input[0];
    var sortProperty = '_sort_' + property;

    if(first[sortProperty]) {
      property = sortProperty;
    }

    if(reverse) {
      return _.sortBy(input, property).reverse();
    }

    return _.sortBy(input, property)
  };

  var nextItem = function(item, sort_name, reverse_sort) {
    var type = item._type;
    var items = getCombined(type);

    if(sort_name) {
      items = sortItems(items, sort_name, reverse_sort);
    }

    var nextItem = null;
    var previousItem = null;

    items.some(function(itm) {
      if(previousItem && previousItem.name == item.name) {
        nextItem = itm;
        return true;
      }

      previousItem = itm;
    });

    return nextItem;
  };

  var prevItem = function(item, sort_name, reverse_sort) {
    var type = item._type;
    var items = getCombined(type);

    if(sort_name) {
      items = sortItems(items, sort_name, reverse_sort);
    }

    var returnItem = null;
    var previousItem = null;

    items.some(function(itm) {
      if(itm.name == item.name) {
        returnItem = previousItem;
        return true;
      }

      previousItem = itm;
    });

    return returnItem;
  };

  var merge = function() {
    var arrs = [].slice.call(arguments, 0);

    var newArr = [];

    arrs.forEach(function(arr) {
      newArr = newArr.concat(arr);
    })

    return newArr;
  }

  // FUNCTIONS USED FOR PAGINATION HELPING, IGNORE FOR MOST CASES
  this.shouldPaginate = function() {
    return self.curPage <= self.maxPage;
  };

  // Reset initial data
  this.init = function() {
    self.paginate = false;
    self.curPage = 1;
    self.pageUrl = 'page-'
    self.maxPage = -1;
    self.paginationBaseUrl = null;
  };

  this.increasePage = function() {
    self.curPage = self.curPage + 1;
  };

  this.setParams = function(params) {
    for(var key in params) {
      self[key] = params[key];
    }
  };

  this.getFunctions = function() {
    return {
      get: getCombined,
      getItem: getItem,
      getItems: getItems,
      getTypes: getTypes,
      paginate: paginate,
      getCurPage: getCurPage,
      getMaxPage: getMaxPage,
      getPageUrl: getPageUrl,
      url: url,
      getCurrentUrl: getCurrentUrl,
      getSetting: getSetting,
      random: randomElement,
      cmsVersion: 'v2',
      merge: merge,
      nextItem: nextItem,
      prevItem: prevItem
    };
  };

  return this;
};<|endoftext|>


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

/** @class
 * Implements a view of a web page in an IFrame that presents a loading message
 * and an error message, if the load fails. In particular, if the load of a
 * page from another origin fails, the underlying message will be visible. We
 * won't be able to interrogate the IFrame, so the error message will be the
 * only indication the user has of the failure.
 * @extends SC.View
 */
DG.WebView = SC.View.extend(
/** @scope DG.WebView.prototype */ {
      classNames: ['dg-web-view'],
      childViews: ['loadingView', 'webView'],

      /**
       * The URL provided.
       * @type {String}
       */
      value: '',

      /**
       * The URL to load.
       *
       * We load protocol relative URLs to maximize the likelihood of success.
       * See: https://www.paulirish.com/2010/the-protocol-relative-url/
       *
       * @type {String)
       */
      _url: function () {
        return this.get('value').replace(/^https?:/, '');
      }.property('value'),

      /**
       * Whether we are loading.
       * @type {boolean}
       */
      isLoading: true,

      loadingMessage: function () {
        return this.isLoading ? 'DG.GameView.loading'.loc() : 'DG.GameView.loadError'.loc();
      }.property('isLoading'),

      /**
       * The purpose of this view is to provide a background to the WebView
       * while it is loading and, if it fails, provide an error message.
       * When the iframe loads, if it loads correctly, it will cover this view.
       */
      loadingView: SC.View.extend({
        childViews: ['urlLabel', 'messageLabel'],
        isLoadingBinding: '*parentView.isLoading',
        classNames: ['dg-web-view-backdrop'],
        classNameBindings: [
          'isLoading:dg-interactive-loading'
        ],
        urlLabel: SC.LabelView.extend({
          layout: { left: 10, right: 0, top: 0, height: 36 },
          valueBinding: '*parentView.parentView.value',
          classNames: ['dg-web-view-url']
        }),
        messageLabel: SC.LabelView.extend({
          layout: { left: 20, right: 20, top: 40, height: 40 },
          valueBinding: '*parentView.parentView.loadingMessage',
          classNames: ['dg-web-view-message']
        })
      }),

      webView: SC.WebView.extend({
        classNames: ['dg-web-view-frame'],

        value: function () {
          return this.getPath('parentView._url');
        }.property(),

        /**
         * @override SC.WebView.iframeDidLoad
         */
        iframeDidLoad: function () {
          if (!SC.none(this.value)) {
            this.setPath('parentView.isLoading', false);
          }
          sc_super();
        }
      })
});
<commit_msg>[#141720239] Fetched URL for plugin should match CODAP scheme. Fix loading webview from file.<commit_after>// ==========================================================================
//                          DG.WebView
//
//  Copyright (c) 2014 by The Concord Consortium, Inc. All rights reserved.
//
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
// ==========================================================================

/** @class
 * Implements a view of a web page in an IFrame that presents a loading message
 * and an error message, if the load fails. In particular, if the load of a
 * page from another origin fails, the underlying message will be visible. We
 * won't be able to interrogate the IFrame, so the error message will be the
 * only indication the user has of the failure.
 * @extends SC.View
 */
DG.WebView = SC.View.extend(
/** @scope DG.WebView.prototype */ {
      classNames: ['dg-web-view'],
      childViews: ['loadingView', 'webView'],

      /**
       * The URL provided.
       * @type {String}
       */
      value: '',

      /**
       * The URL to load.
       *
       * We load protocol relative URLs to maximize the likelihood of success.
       * See: https://www.paulirish.com/2010/the-protocol-relative-url/
       *
       * @type {String)
       */
      _url: function () {
        return this.get('value').replace(/^https?:/, '');
      }.property('value'),

      /**
       * Whether we are loading.
       * @type {boolean}
       */
      isLoading: true,

      loadingMessage: function () {
        return this.isLoading ? 'DG.GameView.loading'.loc() : 'DG.GameView.loadError'.loc();
      }.property('isLoading'),

      /**
       * The purpose of this view is to provide a background to the WebView
       * while it is loading and, if it fails, provide an error message.
       * When the iframe loads, if it loads correctly, it will cover this view.
       */
      loadingView: SC.View.extend({
        childViews: ['urlLabel', 'messageLabel'],
        isLoadingBinding: '*parentView.isLoading',
        classNames: ['dg-web-view-backdrop'],
        classNameBindings: [
          'isLoading:dg-interactive-loading'
        ],
        urlLabel: SC.LabelView.extend({
          layout: { left: 10, right: 0, top: 0, height: 36 },
          valueBinding: '*parentView.parentView.value',
          classNames: ['dg-web-view-url']
        }),
        messageLabel: SC.LabelView.extend({
          layout: { left: 20, right: 20, top: 40, height: 40 },
          valueBinding: '*parentView.parentView.loadingMessage',
          classNames: ['dg-web-view-message']
        })
      }),

      webView: SC.WebView.extend({
        classNames: ['dg-web-view-frame'],

        value: function () {
          return this.getPath('parentView._url');
        }.property(),

        urlDidChange: function () {
          this.notifyPropertyChange('value');
        }.observes('*parentView.value'),

        /**
         * @override SC.WebView.iframeDidLoad
         */
        iframeDidLoad: function () {
          if (!SC.none(this.value)) {
            this.setPath('parentView.isLoading', false);
          }
          sc_super();
        }
      })
});
<|endoftext|>


<commit_before><commit_msg>minor update<commit_after><|endoftext|>


<commit_before><commit_msg>Added mapping for SOAJS_GIT_COMMIT in redeployService()<commit_after><|endoftext|>


<commit_before>/**
 * A service for interacting with a CNC machine.
 */
app.service('machineService', function($rootScope, warningService) {
  // TODO: make this configurable.
  // NOTE: A scrollback of 1000 causes chromebooks to stutter once full.
  var CONSOLE_MAX_SCROLLBACK = 120;

  var connectionId = null;

  var connect = function(port, baud) {
    api.isBusy = true;

    var options = {
      "bitrate":baud,
      "ctsFlowControl":false,
      "dataBits":"eight",
      "parityBit":"no",
      "stopBits":"one"
    };
    console.log("connecting to '" + port + "' with options: " + JSON.stringify(options));
    chrome.serial.connect(port, options, function(info) {
      if (!info) {
        warningService.warn("connection", "Unable to connect to '" + port + "'");
        api.isBusy = false;
        api.isConnected = false;
        $rootScope.$apply();
        return;
      }
      console.log("serial connection obtained:\n" + JSON.stringify(info));

      for (var k in options) {
        if (options[k] != info[k]) {
          warningService.warn("connection", "Chrome did not use requested serial connection option. [" +
              k + "; expected:" + options[k] + ", actual:" + info[k] + "]");
        }
      }

      connectionId = info.connectionId;
      api.isBusy = false;
      api.isConnected = true;
      api.commandQueue = [];
      api.pendingAck = false;
      $rootScope.$apply();

      // Don't fall asleep while controlling a machine.
      chrome.power.requestKeepAwake("system");
    });
  };

  var disconnect = function() {
    // If we're disconnected, we don't need to keep the system awake.
    chrome.power.releaseKeepAwake();

    // It's misleading to think the command queue will be applied on reconnect.
    api.commandQueue = [];

    // fast user feedback that something happened.
    if (connectionId) {
      console.log("disconnecting connection " + connectionId);
      api.isBusy = true;
      chrome.serial.disconnect(connectionId, function(result) {
        connectionId = null;
        api.isConnected = false;
        api.isBusy = false;
        $rootScope.$apply();
      });
    }
  };

  var enqueueCommands = function(cmds) {
    for (var i = 0; i < cmds.length; i++) {
      api.commandQueue.push(cmds[i]);
    }
  }

  /**
   * Convert a string to an ArrayBuffer.
   */
  var str2ab = function(str) {
    var buf = new ArrayBuffer(str.length);
    var bufView = new Uint8Array(buf);
    for (var i = 0; i < str.length; i++) {
      bufView[i] = str.charCodeAt(i);
    }
    return buf;
  };

  /**
   * Convert an ArrayBuffer to a string.
   */
  var ab2str = function(buf) {
    return String.fromCharCode.apply(null, new Uint8Array(buf));
  };

  /**
   * Ensure a string is human readable by rendering all non-printable characters
   * with a hex escaping.
   */
  function makeHumanReadable(str) {
    var parts = [];
    for (var j = 0; j < str.length; j++) {
      var d = str.charCodeAt(j);
      if (d < 32) {
        parts.push("\\x" + d.toString(16));
      } else {
        parts.push(str.charAt(j));
      }
    }
    return parts.join("");
  }

  var incomingCommandLookbackChar = '';

  /**
   * Log a command to the console display.
   *
   * @param {string} cmd The command that was sent or received
   * @param {bool} isSend True if the message was outgoing
   */
  var logCommand = function(cmd, isSend) {
    // Determine the node to add the incoming text to. Since incoming text
    // can be broken into multiple calls to this funciton, we want to join
    // blocks and only split when we detect interleving or a newline.
    var nodeToWriteTo;
    var lastChild = api.logs[api.logs.length - 1];
    if (!isSend && lastChild && lastChild.remoteSource
        && incomingCommandLookbackChar != "\n") {
      // incoming data may be split, so grab the last element instead of a new one.
      nodeToWriteTo = lastChild;
    } else if (lastChild && !lastChild.msg) {
      lastChild.remoteSource = !isSend;
      nodeToWriteTo = lastChild;
    } else {
      nodeToWriteTo = {remoteSource: !isSend, msg: ""}
      api.logs.push(nodeToWriteTo);
    }

    // For commands received, we want to look for an 'ok' to clear
    // our command block.
    if (!isSend) {
      // The lookback character is needed because the 2 byte 'ok' can be split.
      if ((incomingCommandLookbackChar + cmd).indexOf("ok") != -1) {
        api.pendingAck = false;
      }
      if (cmd.length > 0) {
        incomingCommandLookbackChar = cmd.charAt(cmd.length - 1);
      }
    }

    // Add each line to the console output.
    lines = cmd.split("\n");
    for (var i = 0; i < lines.length; i++) {
      var line = lines[i];
      line = line.replace("\r", "");
      nodeToWriteTo.msg = nodeToWriteTo.msg + makeHumanReadable(line);

      // Tag nodes which are just an ack.
      if (!isSend) {
        nodeToWriteTo.isAck = (nodeToWriteTo.msg == "ok");
      }

      if (i < lines.length - 1) {
        nodeToWriteTo = {remoteSource: !isSend, msg: ""}
        api.logs.push(nodeToWriteTo);
      }
    }

    // Limit our history (it could be megs of data when processing a file).
    while (api.logs.length > CONSOLE_MAX_SCROLLBACK) {
      api.logs.shift();
    }
  }

  /**
   * Send a command to an active serial connection.
   */
  var sendCommandToSerialConnection = function(cmd) {
    if (cmd.indexOf("G90") != -1) {
      api.isRelativeMode = false;
    } else if (cmd.indexOf("G91") != -1) {
      api.isRelativeMode = true;
    } else if (cmd.indexOf("G20") != -1) {
      api.isMm = false;
    } else if (cmd.indexOf("G21") != -1) {
      api.isMm = true;
    }

    // make sure we have a device available.
    if (!connectionId) {
      warningService.warn("cmd", "no device connection available.");
      return;
    }

    // Actually send the command.
    chrome.serial.send(connectionId, str2ab(cmd + "\n"), function(info) {
      if (info.error) {
        warningService.warn("cmd", "failed to send command: " + info.error);
      }
    });

    logCommand(cmd, true);
  }

  /**
   * Process one element of the command queue.
   */
  var processCommandQueue = function() {
    // Only process the queue if we are connected.
    // Don't process anymore commands until we have received an 'ok' from the workspace.
    if (api.commandQueue.length === 0 || !connectionId || api.pendingAck) {
      return;
    }

    // Pop the first element off the queue and send it to the serial line.
    api.pendingAck = true;
    sendCommandToSerialConnection(api.commandQueue.shift());
    $rootScope.$apply();
  }

  // Process an element from the command queue every few ms.
  window.setInterval(processCommandQueue, 10);

  // Configure the console panel to display incoming messages.
  chrome.serial.onReceive.addListener(function(info) {
    logCommand(ab2str(info.data), false);
    $rootScope.$apply();
  });

  // Log errors
  chrome.serial.onReceiveError.addListener(function(info) {
    warningService.warn("connection", "error with serial communication: " + info.error);
    $rootScope.$apply();
  });

  /**
   * Perform an emergency machine stop. This will send a M112 command, clear the
   * command queue, and disconnect from the machine.
   *
   * Per documentation, the machine will likely need to be manually reset on
   * the controller board before it can be used again.
   */
  var emergencyStop = function() {
    console.error("!!!emergency stop activated!!!");

    // Clear the command queue.
    api.commandQueue = [];

    // Send the command to perform an emergency stop.
    sendCommandToSerialConnection("M112", true);

    // Send an ascii cancel command.
    sendCommandToSerialConnection("\x18", true);
  }

  // Return the "API" for this service.
  var api = {
    isBusy:false,
    isConnected:false,
    isRelativeMode: false,
    isMm: false,
    pendingAck:false,
    logs:[],
    commandQueue:[],
    connect:connect,
    disconnect:disconnect,
    enqueueCommands:enqueueCommands,
    emergencyStop:emergencyStop
  };
  return api;
});
<commit_msg>immediately try next command on serial.onReceive<commit_after>/**
 * A service for interacting with a CNC machine.
 */
app.service('machineService', function($rootScope, $timeout, warningService) {
  // TODO: make this configurable.
  // NOTE: A scrollback of 1000 causes chromebooks to stutter once full.
  var CONSOLE_MAX_SCROLLBACK = 120;

  var connectionId = null;

  var connect = function(port, baud) {
    api.isBusy = true;

    var options = {
      "bitrate":baud,
      "ctsFlowControl":false,
      "dataBits":"eight",
      "parityBit":"no",
      "stopBits":"one"
    };
    console.log("connecting to '" + port + "' with options: " + JSON.stringify(options));
    chrome.serial.connect(port, options, function(info) {
      if (!info) {
        warningService.warn("connection", "Unable to connect to '" + port + "'");
        api.isBusy = false;
        api.isConnected = false;
        $rootScope.$apply();
        return;
      }
      console.log("serial connection obtained:\n" + JSON.stringify(info));

      for (var k in options) {
        if (options[k] != info[k]) {
          warningService.warn("connection", "Chrome did not use requested serial connection option. [" +
              k + "; expected:" + options[k] + ", actual:" + info[k] + "]");
        }
      }

      connectionId = info.connectionId;
      api.isBusy = false;
      api.isConnected = true;
      api.commandQueue = [];
      api.pendingAck = false;
      $rootScope.$apply();

      // Don't fall asleep while controlling a machine.
      chrome.power.requestKeepAwake("system");
    });
  };

  var disconnect = function() {
    // If we're disconnected, we don't need to keep the system awake.
    chrome.power.releaseKeepAwake();

    // It's misleading to think the command queue will be applied on reconnect.
    api.commandQueue = [];

    // fast user feedback that something happened.
    if (connectionId) {
      console.log("disconnecting connection " + connectionId);
      api.isBusy = true;
      chrome.serial.disconnect(connectionId, function(result) {
        connectionId = null;
        api.isConnected = false;
        api.isBusy = false;
        $rootScope.$apply();
      });
    }
  };

  var enqueueCommands = function(cmds) {
    for (var i = 0; i < cmds.length; i++) {
      api.commandQueue.push(cmds[i]);
    }
  }

  /**
   * Convert a string to an ArrayBuffer.
   */
  var str2ab = function(str) {
    var buf = new ArrayBuffer(str.length);
    var bufView = new Uint8Array(buf);
    for (var i = 0; i < str.length; i++) {
      bufView[i] = str.charCodeAt(i);
    }
    return buf;
  };

  /**
   * Convert an ArrayBuffer to a string.
   */
  var ab2str = function(buf) {
    return String.fromCharCode.apply(null, new Uint8Array(buf));
  };

  /**
   * Ensure a string is human readable by rendering all non-printable characters
   * with a hex escaping.
   */
  function makeHumanReadable(str) {
    var parts = [];
    for (var j = 0; j < str.length; j++) {
      var d = str.charCodeAt(j);
      if (d < 32) {
        parts.push("\\x" + d.toString(16));
      } else {
        parts.push(str.charAt(j));
      }
    }
    return parts.join("");
  }

  var incomingCommandLookbackChar = '';

  /**
   * Log a command to the console display.
   *
   * @param {string} cmd The command that was sent or received
   * @param {bool} isSend True if the message was outgoing
   */
  var logCommand = function(cmd, isSend) {
    // Determine the node to add the incoming text to. Since incoming text
    // can be broken into multiple calls to this funciton, we want to join
    // blocks and only split when we detect interleving or a newline.
    var nodeToWriteTo;
    var lastChild = api.logs[api.logs.length - 1];
    if (!isSend && lastChild && lastChild.remoteSource
        && incomingCommandLookbackChar != "\n") {
      // incoming data may be split, so grab the last element instead of a new one.
      nodeToWriteTo = lastChild;
    } else if (lastChild && !lastChild.msg) {
      lastChild.remoteSource = !isSend;
      nodeToWriteTo = lastChild;
    } else {
      nodeToWriteTo = {remoteSource: !isSend, msg: ""}
      api.logs.push(nodeToWriteTo);
    }

    // For commands received, we want to look for an 'ok' to clear
    // our command block.
    if (!isSend) {
      // The lookback character is needed because the 2 byte 'ok' can be split.
      if ((incomingCommandLookbackChar + cmd).indexOf("ok") != -1) {
        api.pendingAck = false;
      }
      if (cmd.length > 0) {
        incomingCommandLookbackChar = cmd.charAt(cmd.length - 1);
      }
    }

    // Add each line to the console output.
    lines = cmd.split("\n");
    for (var i = 0; i < lines.length; i++) {
      var line = lines[i];
      line = line.replace("\r", "");
      nodeToWriteTo.msg = nodeToWriteTo.msg + makeHumanReadable(line);

      // Tag nodes which are just an ack.
      if (!isSend) {
        nodeToWriteTo.isAck = (nodeToWriteTo.msg == "ok");
      }

      if (i < lines.length - 1) {
        nodeToWriteTo = {remoteSource: !isSend, msg: ""}
        api.logs.push(nodeToWriteTo);
      }
    }

    // Limit our history (it could be megs of data when processing a file).
    while (api.logs.length > CONSOLE_MAX_SCROLLBACK) {
      api.logs.shift();
    }
  }

  /**
   * Send a command to an active serial connection.
   */
  var sendCommandToSerialConnection = function(cmd) {
    if (cmd.indexOf("G90") != -1) {
      api.isRelativeMode = false;
    } else if (cmd.indexOf("G91") != -1) {
      api.isRelativeMode = true;
    } else if (cmd.indexOf("G20") != -1) {
      api.isMm = false;
    } else if (cmd.indexOf("G21") != -1) {
      api.isMm = true;
    }

    // make sure we have a device available.
    if (!connectionId) {
      warningService.warn("cmd", "no device connection available.");
      return;
    }

    // Actually send the command.
    chrome.serial.send(connectionId, str2ab(cmd + "\n"), function(info) {
      if (info.error) {
        warningService.warn("cmd", "failed to send command: " + info.error);
      }
    });

    logCommand(cmd, true);
  }

  /**
   * Process one element of the command queue.
   */
  var processCommandQueue = function() {
    // Only process the queue if we are connected.
    // Don't process anymore commands until we have received an 'ok' from the workspace.
    if (api.commandQueue.length === 0 || !connectionId || api.pendingAck) {
      return;
    }

    // Pop the first element off the queue and send it to the serial line.
    api.pendingAck = true;
    sendCommandToSerialConnection(api.commandQueue.shift());
    $rootScope.$apply();
  }

  // Process an element from the command queue every few ms.
  window.setInterval(processCommandQueue, 50);

  // Configure the console panel to display incoming messages.
  chrome.serial.onReceive.addListener(function(info) {
    logCommand(ab2str(info.data), false);
    $timeout(processCommandQueue);
    $rootScope.$apply();
  });

  // Log errors
  chrome.serial.onReceiveError.addListener(function(info) {
    warningService.warn("connection", "error with serial communication: " + info.error);
    $rootScope.$apply();
  });

  /**
   * Perform an emergency machine stop. This will send a M112 command, clear the
   * command queue, and disconnect from the machine.
   *
   * Per documentation, the machine will likely need to be manually reset on
   * the controller board before it can be used again.
   */
  var emergencyStop = function() {
    console.error("!!!emergency stop activated!!!");

    // Clear the command queue.
    api.commandQueue = [];

    // Send the command to perform an emergency stop.
    sendCommandToSerialConnection("M112", true);

    // Send an ascii cancel command.
    sendCommandToSerialConnection("\x18", true);
  }

  // Return the "API" for this service.
  var api = {
    isBusy:false,
    isConnected:false,
    isRelativeMode: false,
    isMm: false,
    pendingAck:false,
    logs:[],
    commandQueue:[],
    connect:connect,
    disconnect:disconnect,
    enqueueCommands:enqueueCommands,
    emergencyStop:emergencyStop
  };
  return api;
});
<|endoftext|>


<commit_before>import angular from 'angular';
import ngeoMiscFeatureHelper, {FeatureFormatType} from 'ngeo/misc/FeatureHelper.js';
import {getUid as olUtilGetUid} from 'ol/util.js';

/**
 * @type {angular.IModule}
 * @hidden
 */
const module = angular.module('ngeoExportfeatures', [
  ngeoMiscFeatureHelper.name
]);

/**
 * Directive used to export vector features in different types of format.
 * To configure which formats to use, define the `ngeoExportFeatureFormats`
 * value, as such:
 *
 *     app.module.value('ngeoExportFeatureFormats', [
 *         ngeo.misc.FeatureHelper.FormatType.KML,
 *         ngeo.misc.FeatureHelper.FormatType.GPX
 *     ]);
 *
 * Example:
 *
 *     <button
 *       ngeo-exportfeatures
 *       ngeo-exportfeatures-features="ctrl.features"
 *       class="btn btn-link">Export</button>
 *
 * @htmlAttribute {import("ol/Collection.js").default<import('ol/Feature.js').default<import("ol/geom/Geometry.js").default>>}
 *    ngeo-exportfeatures-features The features to export
 * @return {angular.IDirective} The directive specs.
 * @ngInject
 * @ngdoc directive
 * @ngname ngeoExportfeatures
 */
function editingExportFeaturesComponent() {
  return {
    controller: 'ngeoExportfeaturesController as efCtrl',
    scope: true,
    bindToController: {
      'features': '=ngeoExportfeaturesFeatures'
    }
  };
}

module.directive('ngeoExportfeatures', editingExportFeaturesComponent);

/**
 * @param {JQuery} $element Element.
 * @param {angular.auto.IInjectorService} $injector Main injector.
 * @param {angular.IScope} $scope Angular scope.
 * @param {import("ngeo/misc/FeatureHelper.js").FeatureHelper} ngeoFeatureHelper Ngeo feature helper service.
 * @constructor
 * @private
 * @hidden
 * @ngInject
 * @ngdoc controller
 * @ngname ngeoExportfeaturesController
 */
function Controller($element, $injector, $scope, ngeoFeatureHelper) {

  /**
   * @type {?import("ol/Collection.js").default<import('ol/Feature.js').default<import("ol/geom/Geometry.js").default>>}
   * @private
   */
  this.features = null;

  /**
   * @type {JQuery}
   * @private
   */
  this.element_ = $element;

  const uid = olUtilGetUid(this);
  const id = ['ngeo-exportfeature', uid].join('-');

  /**
   * @type {string}
   * @private
   */
  this.id_ = id;

  /**
   * @type {import("ngeo/misc/FeatureHelper.js").FeatureHelper}
   * @private
   */
  this.featureHelper_ = ngeoFeatureHelper;

  /** @type {string[]} */
  let formats;
  if ($injector.has('ngeoExportFeatureFormats')) {
    formats = $injector.get('ngeoExportFeatureFormats');
  } else {
    formats = [FeatureFormatType.KML];
  }

  /**
   * @type {?JQuery}
   * @private
   */
  this.menu_ = null;

  /**
   * @type {JQuery[]}
   * @private
   */
  this.items_ = [];

  // build the drop-down menu and items if there's more than one format
  if (formats.length > 1) {
    $element.attr('id', id);
    const $menu = $('<ul />', {
      'class': 'dropdown-menu',
      'aria-labelledby': id
    }).appendTo($element.parent()[0]);

    this.menu_ = $menu;
    let $item;

    formats.forEach((format) => {
      $item = $('<li />')
        .appendTo($menu)
        .append($('<a />', {
          'href': '#',
          'text': format
        })
          .on(
            ['click', id].join('.'),
            this.handleMenuItemClick_.bind(this, format)
          )
        );
      this.items_.push($item);
    });
  }

  /**
   * @type {string[]}
   * @private
   */
  this.formats_ = formats;

  $element.on(['click', id].join('.'), this.handleElementClick_.bind(this));

  $scope.$on('$destroy', this.handleDestroy_.bind(this));
}

/**
 * Called when the element bound to this directive is clicked. Use the feature
 * helper to export the feature(s) depending on the format(s) available(s).
 * If there's only one, the call to the export method is direct, otherwise
 * a drop-down menu is show to let the user choose the format of the export.
 * Finally, if there's only one feature in the collection to export and there's
 * more than one format set, some formats may not support the type of geometry.
 * If that's the case, then disable each format item in the drop-down menu
 * that doesn't support the type of geometry.
 * @private
 */
Controller.prototype.handleElementClick_ = function() {
  if (!this.features) {
    throw new Error('Missing features');
  }

  const features = this.features.getArray();

  if (this.formats_.length === 1) {
    this.featureHelper_.export(features, this.formats_[0]);
  } else if (features.length === 1) {
    const feature = features[0];
    const geometry = feature.getGeometry();
    if (!geometry) {
      throw new Error('Missing geometry');
    }
    const geometryType = geometry.getType();
    let $item;
    this.formats_.forEach((format, i) => {
      $item = this.items_[i];
      if (format === FeatureFormatType.GPX) {
        if (geometryType === 'Point' || geometryType === 'LineString') {
          $item.removeClass('disabled');
        } else {
          $item.addClass('disabled');
        }
      }
    });
  }
};

/**
 * Called when a menu item is clicked. Export the features to the selected
 * format.
 * @param {string} format Format.
 * @param {JQueryEventObject} event Event.
 * @private
 */
Controller.prototype.handleMenuItemClick_ = function(format, event) {
  if (!this.features) {
    throw new Error('Missing features');
  }
  if (!event.target.parentElement) {
    throw new Error('Missing event.target.parentElement');
  }
  if (!$(event.target.parentElement).hasClass('disabled')) {
    const features = this.features.getArray();
    this.featureHelper_.export(features, format);
  }
};

/**
 * Cleanup event listeners and remove the menu from DOM, if any.
 * @private
 */
Controller.prototype.handleDestroy_ = function() {
  const id = this.id_;

  this.element_.off(['click', id].join('.'));

  if (this.menu_) {
    this.menu_.remove();
    this.items_.forEach(($item) => {
      $item.off(['click', id].join('.'));
    });
    this.items_.length = 0;
    this.menu_ = null;
  }
};

module.controller('ngeoExportfeaturesController', Controller);

export default module;
<commit_msg>Fix dropdown-menu in export features<commit_after>import angular from 'angular';
import ngeoMiscFeatureHelper, {FeatureFormatType} from 'ngeo/misc/FeatureHelper.js';
import {getUid as olUtilGetUid} from 'ol/util.js';

/**
 * @type {angular.IModule}
 * @hidden
 */
const module = angular.module('ngeoExportfeatures', [
  ngeoMiscFeatureHelper.name
]);

/**
 * Directive used to export vector features in different types of format.
 * To configure which formats to use, define the `ngeoExportFeatureFormats`
 * value, as such:
 *
 *     app.module.value('ngeoExportFeatureFormats', [
 *         ngeo.misc.FeatureHelper.FormatType.KML,
 *         ngeo.misc.FeatureHelper.FormatType.GPX
 *     ]);
 *
 * Example:
 *
 *     <button
 *       ngeo-exportfeatures
 *       ngeo-exportfeatures-features="ctrl.features"
 *       class="btn btn-link">Export</button>
 *
 * @htmlAttribute {import("ol/Collection.js").default<import('ol/Feature.js').default<import("ol/geom/Geometry.js").default>>}
 *    ngeo-exportfeatures-features The features to export
 * @return {angular.IDirective} The directive specs.
 * @ngInject
 * @ngdoc directive
 * @ngname ngeoExportfeatures
 */
function editingExportFeaturesComponent() {
  return {
    controller: 'ngeoExportfeaturesController as efCtrl',
    scope: true,
    bindToController: {
      'features': '=ngeoExportfeaturesFeatures'
    }
  };
}

module.directive('ngeoExportfeatures', editingExportFeaturesComponent);

/**
 * @param {JQuery} $element Element.
 * @param {angular.auto.IInjectorService} $injector Main injector.
 * @param {angular.IScope} $scope Angular scope.
 * @param {import("ngeo/misc/FeatureHelper.js").FeatureHelper} ngeoFeatureHelper Ngeo feature helper service.
 * @constructor
 * @private
 * @hidden
 * @ngInject
 * @ngdoc controller
 * @ngname ngeoExportfeaturesController
 */
function Controller($element, $injector, $scope, ngeoFeatureHelper) {

  /**
   * @type {?import("ol/Collection.js").default<import('ol/Feature.js').default<import("ol/geom/Geometry.js").default>>}
   * @private
   */
  this.features = null;

  /**
   * @type {JQuery}
   * @private
   */
  this.element_ = $element;

  const uid = olUtilGetUid(this);
  const id = ['ngeo-exportfeature', uid].join('-');

  /**
   * @type {string}
   * @private
   */
  this.id_ = id;

  /**
   * @type {import("ngeo/misc/FeatureHelper.js").FeatureHelper}
   * @private
   */
  this.featureHelper_ = ngeoFeatureHelper;

  /** @type {string[]} */
  let formats;
  if ($injector.has('ngeoExportFeatureFormats')) {
    formats = $injector.get('ngeoExportFeatureFormats');
  } else {
    formats = [FeatureFormatType.KML];
  }

  /**
   * @type {?JQuery}
   * @private
   */
  this.menu_ = null;

  /**
   * @type {JQuery[]}
   * @private
   */
  this.items_ = [];

  // build the drop-down menu and items if there's more than one format
  if (formats.length > 1) {
    $element.attr('id', id);
    const $menu = $('<div />', {
      'class': 'dropdown-menu',
      'aria-labelledby': id
    }).appendTo($element.parent()[0]);

    this.menu_ = $menu;

    formats.forEach((format) => {
      const item = $('<a />', {
        'href': '#',
        'class': 'dropdown-item',
        'text': format
      });
      item.appendTo($menu);
      item.on(`click.${id}`, this.handleMenuItemClick_.bind(this, format));
      this.items_.push(item);
    });
  }

  /**
   * @type {string[]}
   * @private
   */
  this.formats_ = formats;

  $element.on(['click', id].join('.'), this.handleElementClick_.bind(this));

  $scope.$on('$destroy', this.handleDestroy_.bind(this));
}

/**
 * Called when the element bound to this directive is clicked. Use the feature
 * helper to export the feature(s) depending on the format(s) available(s).
 * If there's only one, the call to the export method is direct, otherwise
 * a drop-down menu is show to let the user choose the format of the export.
 * Finally, if there's only one feature in the collection to export and there's
 * more than one format set, some formats may not support the type of geometry.
 * If that's the case, then disable each format item in the drop-down menu
 * that doesn't support the type of geometry.
 * @private
 */
Controller.prototype.handleElementClick_ = function() {
  if (!this.features) {
    throw new Error('Missing features');
  }

  const features = this.features.getArray();

  if (this.formats_.length === 1) {
    this.featureHelper_.export(features, this.formats_[0]);
  } else if (features.length === 1) {
    const feature = features[0];
    const geometry = feature.getGeometry();
    if (!geometry) {
      throw new Error('Missing geometry');
    }
    const geometryType = geometry.getType();
    let $item;
    this.formats_.forEach((format, i) => {
      $item = this.items_[i];
      if (format === FeatureFormatType.GPX) {
        if (geometryType === 'Point' || geometryType === 'LineString') {
          $item.removeClass('disabled');
        } else {
          $item.addClass('disabled');
        }
      }
    });
  }
};

/**
 * Called when a menu item is clicked. Export the features to the selected
 * format.
 * @param {string} format Format.
 * @param {JQueryEventObject} event Event.
 * @private
 */
Controller.prototype.handleMenuItemClick_ = function(format, event) {
  if (!this.features) {
    throw new Error('Missing features');
  }
  if (!event.target.parentElement) {
    throw new Error('Missing event.target.parentElement');
  }
  if (!$(event.target.parentElement).hasClass('disabled')) {
    const features = this.features.getArray();
    this.featureHelper_.export(features, format);
  }
};

/**
 * Cleanup event listeners and remove the menu from DOM, if any.
 * @private
 */
Controller.prototype.handleDestroy_ = function() {
  const id = this.id_;

  this.element_.off(['click', id].join('.'));

  if (this.menu_) {
    this.menu_.remove();
    this.items_.forEach(($item) => {
      $item.off(['click', id].join('.'));
    });
    this.items_.length = 0;
    this.menu_ = null;
  }
};

module.controller('ngeoExportfeaturesController', Controller);

export default module;
<|endoftext|>


<commit_before>/**
 * Limb Web Application Framework
 *
 * @link http://limb-project.com
 *
 * @copyright  Copyright © 2004-2007 BIT
 * @license    LGPL http://www.gnu.org/copyleft/lesser.html
 * @version    $Id: Limb.js 5444 2007-03-30 11:28:01Z tony $
 * @package    js
 */

if(Limb == undefined) var Limb = {};

String.prototype.trim = function()
{
  var r=/^\s+|\s+$/;
  return this.replace(r,'');
}

Limb.define = function(name, value)
{
  var parts = name.split('.');
  var var_name = parts.pop();

  var namespace = Limb.namespace(parts.join('.'));
  namespace[var_name] = value;
}

Limb.namespace = function(name)
{
  var parts = name.split('.');
  var parent = window;
  for(var i=0; i<parts.length; i++)
  {
    if(!parts[i])
      continue;

    if(!parent[parts[i]])
      parent[parts[i]] = {};

    parent = parent[parts[i]];
  }

  return parent;
}

Limb.require = function(package_name)
{
  document.write('<script type="text/javascript" src="' + package_name + '"></script>');
}

Limb.isset = function(variable)
{
  return typeof(variable) != 'undefined' && variable != null;
}

Limb.is_object = function(variable)
{
  return typeof(variable) == 'object';
}

Limb.is_function = function(variable)
{
  return typeof(variable) == 'function';
}
<commit_msg>[svn r5568] -- remove ugly code from Limb.require. it does not work at all (and it not worked before). It needs to be written from the scratch or may be ported from 2.x<commit_after>/**
 * Limb Web Application Framework
 *
 * @link http://limb-project.com
 *
 * @copyright  Copyright © 2004-2007 BIT
 * @license    LGPL http://www.gnu.org/copyleft/lesser.html
 * @version    $Id: Limb.js 5568 2007-04-09 08:17:15Z wiliam $
 * @package    js
 */

if(Limb == undefined) var Limb = {};

String.prototype.trim = function()
{
  var r=/^\s+|\s+$/;
  return this.replace(r,'');
}

Limb.define = function(name, value)
{
  var parts = name.split('.');
  var var_name = parts.pop();

  var namespace = Limb.namespace(parts.join('.'));
  namespace[var_name] = value;
}

Limb.namespace = function(name)
{
  var parts = name.split('.');
  var parent = window;
  for(var i=0; i<parts.length; i++)
  {
    if(!parts[i])
      continue;

    if(!parent[parts[i]])
      parent[parts[i]] = {};

    parent = parent[parts[i]];
  }

  return parent;
}

Limb.require = function(package_name)
{
  //no working function for now. It needs to be written from the scratch or may be ported from 2.x
}

Limb.isset = function(variable)
{
  return typeof(variable) != 'undefined' && variable != null;
}

Limb.is_object = function(variable)
{
  return typeof(variable) == 'object';
}

Limb.is_function = function(variable)
{
  return typeof(variable) == 'function';
}
<|endoftext|>