<commit_before>//#musty.js

//A single global variable contains all functionality

var musty = (function(){

	//Factory for building regex-based replacer functions

	function replacer(regex,fn){
		return function(str){
			return (''+str).replace(regex,fn);
		}
	}

	//Function to determine the iterationCount
	//key in conditional and inverted sections.
	//Takes the key value as argument.

	function truthyLoop(obj){
		var i, t = typeof(obj);
		//If array or object and not null
		if(t == 'object' && obj){
			//If array
			if(obj.splice) return obj.length;
			//Else
			for(i in obj){
				//If non-empty object
				return 1;
			}
			//Else, empty object
			return 0;
		}
		//Else
		return !obj && (t !='number' || isNaN(obj))?
			//If falsy and not a number
			0:
			//Otherwise, truthy
			1;
	}

	//Function to sanitize html,
	//converts `<>"'&/` to html encoding
	var htmlSafe = replacer(/[\"\/\\<>&\']/g,
		function(m){
			return '&#'+m.charCodeAt(0)+';';
		}
	);

	var rightTrim = replacer(/\s*$/,'');

	//Function to convert a single character to hex encoding
	function stringifyReplace(m){
		return '\\x'+('0'+m.charCodeAt(0).toString(16)).slice(-2);
	}

	//Function to encode string to a javascript-encoded string,
	//converts non-printable characters, `"`, `/`, and `\` to
	//hex-encoded characters
	var stringify = replacer(/[\x00-\x1f\"\/\\]/g, stringifyReplace);

	//Function to build source code for accessing a given key from
	//the current context + any custom functions and parameters to apply
	function datacall(params){
		//Split params by delimiter (@)
		params = rightTrim(params).split('@');
		//Stringify all params
		for(var l = params.length; l--;){
			params[l] = '"'+stringify(params[l])+'"';
		}
		//Return source code string
		return 'g(d,['+params+'])';
	}

	//Regex to tokenize mustache syntax
	//Identifies
	//1. {{{keys in triple braces}}}
	//2. {{tokens in double braces: #, ^, /, ! or >}}
	//3. {{keys in double braces}}
	//4. characters in need of escaping in javascript source code
	var parseRegex = /\{\{\{\s*((?:\}{0,2}[^\}])*)\}\}\}|\{\{([#\/\^\!>]?)\s*((?:\}?[^\}])*)\}\}|([\x00-\x1f\"\/\\])/g;

	//Token handler, takes tokens as input, returns replacement source code
	function templateParser(m, unescapedKey, sectionToken, escapedKey, specialChar){
		//If section closing tag
		return (sectionToken == '!')? '':
			(sectionToken == '>')? '"+g(d,[".","'+stringify(rightTrim(escapedKey))+'",0,d])+"':
				(sectionToken == '\/')?
					//source code to close any section
					'"}return s})(d)+"':
					//else if any of the section opening tokens
					(sectionToken)?
						//sections are compiled to immediately invoked
						//functions
						'"+(function(d){'+
						//get the value of the current key
						'var k='+datacall(escapedKey)+
						//create a string buffer and an iterator variable
						',s="",i,c=d,'+
						//call truthyLoop to get parameters:
						//1: is it a non-empty array?
						//2: how many times to iterate the section body?
						'p=t(k);'+
						((sectionToken == '#')?
							//if conditional section, setup a for loop
							'for(i=0;i<p;i++){d=[k.splice?k[i]:k].concat(c);':
							//if inverted conditional section, test if iteration count is 0
							'if(!p){'
						)+
						//capture subsequent syntax in string buffer
						's+="':
						(unescapedKey)?
							//call value of key in current context
							//without HTML sanitization
							'"+'+datacall(unescapedKey)+'+"':
							(escapedKey)?
								//call value of key in current context
								//with HTML sanitization
								'"+h('+datacall(escapedKey)+')+"':
								(specialChar)?
									//escape special characters
									stringifyReplace(specialChar):
									'';
	}

	//Parser function for template strings,
	//transforms the string to a function body
	var parse = replacer(parseRegex, templateParser);

	//return the compilation function, takes a template string
	//and an optional object with custom functions,
	//returns a compiled template as a function
	return function(tmplStr, fnObj){
		/* return template processor */
		//use try/catch to detect compilation failure
		try{
			//create a compiled template as a function
			var fn = new Function('d', 'g', 'h', 't', 'return "'+parse(tmplStr)+'"');
			//bind the functions getData, htmlSafe and truthyLoop to the scope of
			//the compiled template,
			//assigned to the variables `g`, `h` and `t`,
			//and return the compiled template function
			return function(dataObj, fnObj2, contextChain){
				//Function to access data from the current context
				function getData(contextChain, params){
					//key is the first parameter, name of any custom function is the second
					var key = params[0],
						fn = (fnObj2 && fnObj2[params[1]]) || (fnObj && fnObj[params[1]]),
						value, data, i,
						l = contextChain.length;
					for(i = 0; i < l; i++){
						if(contextChain[i] && contextChain[i].hasOwnProperty(key)){
							break;
						}
					}
					data = contextChain[i];
					//assign value if key exists
					value = i < l?
						typeof data[key] == 'function'?
							//if function, assign return value
							data[key]():
							//else assign value
							data[key]:
						//if key does not exist
						(key == '.'?
							//if dot, assign current context
							contextChain[0]:
							//else, assign empty string
							'');
					if(fn) value = fn.apply(null, (params.splice(0, 2, value), params));
					return truthyLoop(value)? value: '';
				}
				return fn(contextChain || [dataObj], getData, htmlSafe, truthyLoop);
			}
		}catch(e){
			//return false if compilation fails
			return false;
		}
	}
})();
<commit_msg>Update musty.dev.js<commit_after>//#musty.js

//A single global variable contains all functionality

var musty = (function(){

	//Factory for building regex-based replacer functions

	function replacer(regex,fn){
		return function(str){
			return (''+str).replace(regex,fn);
		}
	}

	//Function to determine the iterationCount
	//in conditional and inverted sections.
	//Takes the key value as argument.

	function truthyLoop(obj){
		var i, t = typeof(obj);
		//If array or object and not null
		if(t == 'object' && obj){
			//If array
			if(obj.splice) return obj.length;
			//Else
			for(i in obj){
				//If non-empty object
				return 1;
			}
			//Else, empty object
			return 0;
		}
		//Else if falsy and not a number
		return !obj && (t !='number' || isNaN(obj))?
			0:
			//Otherwise
			1;
	}

	//Function to sanitize html.
	//Converts `<>"'&/` to html encoding

	var htmlSafe = replacer(/[\"\/\\<>&\']/g,
		function(m){
			return '&#'+m.charCodeAt(0)+';';
		}
	);

	//Function to trim string for trailing whitespace.

	var rightTrim = replacer(/\s*$/,'');

	//Function to convert a single character to hex encoding (\xFF).

	function stringifyReplace(m){
		return '\\x'+('0'+m.charCodeAt(0).toString(16)).slice(-2);
	}

	//Function to encode string to a javascript-encoded string,
	//converts non-printable characters, `"`, `/`, and `\` to
	//hex-encoded characters

	var stringify = replacer(/[\x00-\x1f\"\/\\]/g, stringifyReplace);

	//Function to build source code for accessing a given key from
	//the current context + any custom functions and parameters to apply

	function datacall(params){
		//Split params by delimiter (@)
		params = rightTrim(params).split('@');
		//Format all params items as javascript strings
		for(var l = params.length; l--;){
			params[l] = '"'+stringify(params[l])+'"';
		}
		//Return source code string
		return 'g(d,['+params+'])';
	}

	//Regex to tokenize mustache syntax
	//
	//Identifies
	//
	//1. {{{keys in triple braces}}}
	//2. {{tokens in double braces: #, ^, /, ! or >}}
	//3. {{keys in double braces}}
	//4. characters in need of escaping in javascript source code

	var parseRegex = /\{\{\{\s*((?:\}{0,2}[^\}])*)\}\}\}|\{\{([#\/\^\!>]?)\s*((?:\}?[^\}])*)\}\}|([\x00-\x1f\"\/\\])/g;

	//Token handler, takes tokens as input, returns replacement source code
	function templateParser(m, unescapedKey, sectionToken, escapedKey, specialChar){
		//If section closing tag
		return (sectionToken == '!')? '':
			(sectionToken == '>')? '"+g(d,[".","'+stringify(rightTrim(escapedKey))+'",0,d])+"':
				(sectionToken == '\/')?
					//source code to close any section
					'"}return s})(d)+"':
					//else if any of the section opening tokens
					(sectionToken)?
						//sections are compiled to immediately invoked
						//functions
						'"+(function(d){'+
						//get the value of the current key
						'var k='+datacall(escapedKey)+
						//create a string buffer and an iterator variable
						',s="",i,c=d,'+
						//call truthyLoop to get parameters:
						//1: is it a non-empty array?
						//2: how many times to iterate the section body?
						'p=t(k);'+
						((sectionToken == '#')?
							//if conditional section, setup a for loop
							'for(i=0;i<p;i++){d=[k.splice?k[i]:k].concat(c);':
							//if inverted conditional section, test if iteration count is 0
							'if(!p){'
						)+
						//capture subsequent syntax in string buffer
						's+="':
						(unescapedKey)?
							//call value of key in current context
							//without HTML sanitization
							'"+'+datacall(unescapedKey)+'+"':
							(escapedKey)?
								//call value of key in current context
								//with HTML sanitization
								'"+h('+datacall(escapedKey)+')+"':
								(specialChar)?
									//escape special characters
									stringifyReplace(specialChar):
									'';
	}

	//Parser function for template strings,
	//transforms the string to a function body
	var parse = replacer(parseRegex, templateParser);

	//return the compilation function, takes a template string
	//and an optional object with custom functions,
	//returns a compiled template as a function
	return function(tmplStr, fnObj){
		/* return template processor */
		//use try/catch to detect compilation failure
		try{
			//create a compiled template as a function
			var fn = new Function('d', 'g', 'h', 't', 'return "'+parse(tmplStr)+'"');
			//bind the functions getData, htmlSafe and truthyLoop to the scope of
			//the compiled template,
			//assigned to the variables `g`, `h` and `t`,
			//and return the compiled template function
			return function(dataObj, fnObj2, contextChain){
				//Function to access data from the current context
				function getData(contextChain, params){
					//key is the first parameter, name of any custom function is the second
					var key = params[0],
						fn = (fnObj2 && fnObj2[params[1]]) || (fnObj && fnObj[params[1]]),
						value, data, i,
						l = contextChain.length;
					for(i = 0; i < l; i++){
						if(contextChain[i] && contextChain[i].hasOwnProperty(key)){
							break;
						}
					}
					data = contextChain[i];
					//assign value if key exists
					value = i < l?
						typeof data[key] == 'function'?
							//if function, assign return value
							data[key]():
							//else assign value
							data[key]:
						//if key does not exist
						(key == '.'?
							//if dot, assign current context
							contextChain[0]:
							//else, assign empty string
							'');
					if(fn) value = fn.apply(null, (params.splice(0, 2, value), params));
					return truthyLoop(value)? value: '';
				}
				return fn(contextChain || [dataObj], getData, htmlSafe, truthyLoop);
			}
		}catch(e){
			//return false if compilation fails
			return false;
		}
	}
})();
<|endoftext|>


<commit_before>/**
 * Copyright 2013,2015, 2016 IBM Corp.
 *
 * 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.
 **/

// Watson Visual Recognition functions supported by this node
/*var FEATURE_RESPONSES = {
  classifyImage: 'classifyImage',
  detectFaces: 'detectFaces',
  recognizeText: 'recognizeText',
  createClassifier: 'createClassifier',
  retrieveClassifiersList: 'retrieveClassifiersList',
  retrieveClassifierDetails: 'retrieveClassifierDetails',
  deleteClassifier: 'deleteClassifier'
};*/

module.exports = function (RED) {
  var cfenv = require('cfenv');
  var watson = require('watson-developer-cloud');

  var imageType = require('image-type');
  var url = require('url');
  var temp = require('temp');
  var fileType = require('file-type');
  var fs = require('fs');
  var async = require('async');

  // temp is being used for file streaming to allow the file to arrive so it can be processed.
  temp.track();

  // Require the Cloud Foundry Module to pull credentials from bound service
  // If they are found then the api key is stored in the variable s_apikey.
  //
  // This separation between s_apikey and apikey is to allow
  // the end user to modify the key credentials when the service is not bound.
  // Otherwise, once set apikey is never reset, resulting in a frustrated
  // user who, when he errenously enters bad credentials, can't figure out why
  // the edited ones are not being taken.

  // Taking this line out as codacy was complaining about it.
  // var services = cfenv.getAppEnv().services,

  var apikey, s_apikey;

  var service = cfenv.getAppEnv().getServiceCreds(/visual recognition/i);

  if (service) {
    s_apikey = service.apikey;
  }

  RED.httpAdmin.get('/watson-visual-recognition/vcap', function (req, res) {
    res.json(service ? {bound_service: true} : null);
  });

  // Utility functions that check for image buffers, urls and stream data in

  function imageCheck(data) {
    return data instanceof Buffer && imageType(data) !== null;
  };

  function urlCheck(str) {
    var parsed = url.parse(str);
    return (!!parsed.hostname && !!parsed.protocol && str.indexOf(' ') < 0);
  };

  function stream_buffer(file, contents, cb) {
    fs.writeFile(file, contents, function (err) {
      if (err) throw err;
      cb();
    });
  };

  // Utility function that performs the Watson Visual Recognition call.
  // the cleanup removes the temp storage, and I am not sure whether
  // it should be called here or after alchemy returns and passed
  // control back to cbdone.

  function performAction(params, feature, cbdone) {
    var visualRecognition = watson.visual_recognition({
      api_key: apikey,
      version: 'v3',
      version_date: '2016-05-19'
    });

    switch(feature)
    {
      case 'classifyImage' :
        visualRecognition.classify(params, cbdone);
        break;
      case 'detectFaces':
        visualRecognition.detectFaces(params, cbdone);
        break;
      case 'recognizeText':
        visualRecognition.recognizeText(params, cbdone);
        break;
      case 'createClassifier':
        visualRecognition.createClassifier(params, cbdone);
        break;
      case 'retrieveClassifiersList':
        visualRecognition.listClassifiers(params, cbdone);
        break;
      case 'retrieveClassifierDetails':
        visualRecognition.getClassifier(params, cbdone);
        break;
      case 'deleteClassifier':
        visualRecognition.deleteClassifier(params, cbdone);
        break;
    }
  }

  // This is the Watson Visual Recognition V3 Node
  function WatsonVisualRecognitionV3Node (config) {
    RED.nodes.createNode(this, config);
    var node = this;
    var message;
    this.on('input', function (msg)
    {
      // Check which single feature has been requested.
      var feature = config['image-feature'];
      node.status({});
      // so there is at most 1 temp file at a time (did not found a better solution...)
      temp.cleanup();

      if (!msg.payload) {
        this.status({fill:'red', shape:'ring', text:'missing payload'});
        message = 'Missing property: msg.payload';
        node.error(message, msg);
        return;
      }
      if (feature !== 'retrieveClassifiersList' && feature !== 'retrieveClassifierDetails'
          && feature !== 'deleteClassifier')
      {
        if (typeof msg.payload === 'boolean' || typeof msg.payload === 'number')
        {
          this.status({fill:'red', shape:'ring', text:'bad format payload'});
          message = 'Bad format : msg.payload must be a URL string or a Node.js Buffer';
          node.error(message, msg);
          return;
        }
      }

      // If it is present the newly provided user entered key
      // takes precedence over the existing one.
      apikey = s_apikey || this.credentials.apikey;
      this.status({});

      if (!apikey) {
        this.status({fill:'red', shape:'ring', text:'missing credentials'});
        message ='Missing Watson Visual Recognition API service credentials';
        node.error(message, msg);
        return;
      }

      var params = {};

      // This is the callback after the call to the watson service.
      // Set up as a var within this scope, so it has access to node, msg etc.
      // in preparation for the Watson service action
      var actionComplete = function(err, body, other) {

        if (err != null && body==null)
        {
          node.status({fill:'red', shape:'ring',
                       text:'call to watson visual recognition v3 service failed'});
          msg.result = {};
          msg.result['error_code']= err.code;
          if (!err.error)
            msg.result['error']= err.error;
          console.log('Error:', err.code);
          node.error('Error code : ' +  err.code);
          return;
        }
        else if (body.images[0].error)
        {
          var err_desc = body.images[0].error.description;
          var err_id = body.images[0].error.error_id;
          node.status({fill:'red', shape:'ring', text:'call to watson visual recognition v3 service failed'});
          msg.result = {};
          msg.result['error_id']= err_id;
          msg.result['error']= err_desc;
          console.log('Error:', err_desc);
          msg.payload='see msg.result.error';
          node.send(msg);
        }
        else {
          msg.result = {};
          msg.result['all'] = body;
          msg.payload='see msg.result'; // to remove any Buffer that could remains
          node.send(msg);
          node.status({});
        }
      }; // actionComplete

      var actionComplete2 = function(err, body, other) {

        if (err != null && body==null)
        {
          node.status({fill:'red', shape:'ring', text:'call to watson visual recognition v3 service failed'});
          msg.result = {};
          msg.result['error_code']= err.code;
          if (!err.error)
            msg.result['error']= err.error;
          console.log('Error:', err.code);
          node.error('Error code : ' +  err.code);
          return;
        }
        else {
          msg.result = {};
          msg.result['all'] = body;
          msg.payload='see msg.result'; // to remove any Buffer that could remains
          node.send(msg);
          node.status({});
        }
      }; // actionComplete2

      var actionCompleteDeleteClassifier = function(err, body, other) {

        if (err != null && body==null)
        {
          node.status({fill:'red', shape:'ring', text:'call to watson visual recognition v3 service failed'});
          msg.result = {};
          msg.result['error_code']= err.code;
          if (!err.error)
            msg.result['error']= err.error;
          console.log('Error:', err.code);
          node.error('Error code : ' +  err.code);
          return;
        }
        else {
          msg.result = 'Deleted classifier_id';
          msg.payload='see msg.result';
          node.send(msg);
          node.status({});
        }
      }; // actionCompleteDeleteClassifier

      // If the input is an image, need to stream the input in, giving time for the
      // data to arrive, before invoking the service.
      node.status({fill:'blue', shape:'dot', text:'Calling '+ feature + ' ...'});
      if (imageCheck(msg.payload)) {
        temp.open({suffix: '.' + fileType(msg.payload).ext}, function (err, info) {
          if (err) {
            this.status({fill:'red', shape:'ring', text:'unable to open image stream'});
            message ='Node has been unable to open the image stream';
            node.error(message, msg);
            return;
          }
          stream_buffer(info.path, msg.payload, function () {
          params['images_file'] = fs.createReadStream(info.path);
          if ( msg.params != null && msg.params.classifier_ids != null)
            params['classifier_ids']=msg.params['classifier_ids'];
          if ( msg.params != null && msg.params.owners != null)
            params['owners']=msg.params['owners'];
          if ( msg.params != null && msg.params.threshold != null)
            params['threshold']=msg.params['threshold'];
          performAction(params, feature, actionComplete);
          });
        }); // temp
      } else if (feature==='createClassifier') {
          var list_params = {};
          var asyncTasks = [];
          var prop = null;
          for (var k in msg.params)
          {
            prop = k;
            if (prop.indexOf('_examples')>=0)
            {
              // before pushing the function into the task array wrap the push
              // in an IIFE function, passing in the 'prop' parameter
              (function(prop, list_params, msg) {

               asyncTasks.push(function (callback) {
                  var buffer = msg.params[prop];
                  temp.open({suffix: '.' + fileType(buffer).ext}, function (err, info) {
                    if (err) {
                      this.status({fill:'red', shape:'ring',
                                   text:'unable to open image stream'});
                      var message ='Node has been unable to open the image stream';
                      node.error(message, msg);
                      callback('open error on '+prop);
                    }
                    stream_buffer(info.path, msg.params[prop], function () {
                      list_params[prop]=fs.createReadStream(info.path);
                      callback(null, prop);
                    });
                  }); // temp.open
              }); // asyncTasks.push

              })(prop, list_params, msg);

            } else if (prop==='name') {
              list_params[prop]=msg.params[prop];
            }
          } // for

          async.parallel(asyncTasks, function(error, results){
            // when all temp local copies are ready,
            // copy of all parameters and request to watson api
            console.log(error, results);
            if (error)
            {
              console.log('Parallel ended with error ' + error);
              throw error;
            }
            for (p in list_params)
              params[p]=list_params[p];
            performAction(params, feature, actionComplete2);
          });
      }
        else if (feature === 'retrieveClassifiersList') {
          performAction(params, feature, actionComplete2);
      }
        else if (feature === 'retrieveClassifierDetails') {
          params['classifier_id']=msg.params['classifier_id'];
          performAction(params, feature, actionComplete2);
      }
        else if (feature === 'deleteClassifier') {
        params['classifier_id']=msg.params['classifier_id'];
        performAction(params, feature, actionCompleteDeleteClassifier);

      } else if (urlCheck(msg.payload)) {
        params['url'] = msg.payload;
        if ( msg.params != null && msg.params.classifier_ids != null)
            params['classifier_ids']=msg.params['classifier_ids'];
        if ( msg.params != null && msg.params.owners != null)
            params['owners']=msg.params['owners'];
        if ( msg.params != null && msg.params.threshold != null)
            params['threshold']=msg.params['threshold'];
        performAction(params, feature, actionComplete);
      } else {
        this.status({fill:'red', shape:'ring', text:'payload is invalid'});
        message ='Payload must be either an image buffer or a string representing a url';
        node.error(message, msg);
        return;
      }

    });
  }

  RED.nodes.registerType('visual-recognition-v3', WatsonVisualRecognitionV3Node, {
    credentials: {
      apikey: {type:'password'}
    }
  });

RED.nodes.registerType('visual-recognition-util-v3', WatsonVisualRecognitionV3Node, {
    credentials: {
      apikey: {type:'password'}
    }
  });

};
<commit_msg>codacy inspired changes<commit_after>/**
 * Copyright 2013,2015, 2016 IBM Corp.
 *
 * 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.
 **/

// Watson Visual Recognition functions supported by this node
/*var FEATURE_RESPONSES = {
  classifyImage: 'classifyImage',
  detectFaces: 'detectFaces',
  recognizeText: 'recognizeText',
  createClassifier: 'createClassifier',
  retrieveClassifiersList: 'retrieveClassifiersList',
  retrieveClassifierDetails: 'retrieveClassifierDetails',
  deleteClassifier: 'deleteClassifier'
};*/

module.exports = function (RED) {
  var cfenv = require('cfenv');
  var watson = require('watson-developer-cloud');

  var imageType = require('image-type');
  var url = require('url');
  var temp = require('temp');
  var fileType = require('file-type');
  var fs = require('fs');
  var async = require('async');

  // temp is being used for file streaming to allow the file to arrive so it can be processed.
  temp.track();

  // Require the Cloud Foundry Module to pull credentials from bound service
  // If they are found then the api key is stored in the variable sAPIKey.
  //
  // This separation between sAPIKey and apikey is to allow
  // the end user to modify the key credentials when the service is not bound.
  // Otherwise, once set apikey is never reset, resulting in a frustrated
  // user who, when he errenously enters bad credentials, can't figure out why
  // the edited ones are not being taken.

  // Taking this line out as codacy was complaining about it.
  // var services = cfenv.getAppEnv().services,

  var apikey, sAPIKey;

  var service = cfenv.getAppEnv().getServiceCreds(/visual recognition/i);

  if (service) {
    sAPIKey = service.apikey;
  }

  RED.httpAdmin.get('/watson-visual-recognition/vcap', function (req, res) {
    res.json(service ? {bound_service: true} : null);
  });

  // Utility functions that check for image buffers, urls and stream data in

  function imageCheck(data) {
    return data instanceof Buffer && imageType(data) !== null;
  };

  function urlCheck(str) {
    var parsed = url.parse(str);
    return (!!parsed.hostname && !!parsed.protocol && str.indexOf(' ') < 0);
  };

  function stream_buffer(file, contents, cb) {
    fs.writeFile(file, contents, function (err) {
      if (err) throw err;
      cb();
    });
  };

  // Utility function that performs the Watson Visual Recognition call.
  // the cleanup removes the temp storage, and I am not sure whether
  // it should be called here or after alchemy returns and passed
  // control back to cbdone.

  function performAction(params, feature, cbdone) {
    var visualRecognition = watson.visual_recognition({
      api_key: apikey,
      version: 'v3',
      version_date: '2016-05-19'
    });

    switch(feature)
    {
      case 'classifyImage' :
        visualRecognition.classify(params, cbdone);
        break;
      case 'detectFaces':
        visualRecognition.detectFaces(params, cbdone);
        break;
      case 'recognizeText':
        visualRecognition.recognizeText(params, cbdone);
        break;
      case 'createClassifier':
        visualRecognition.createClassifier(params, cbdone);
        break;
      case 'retrieveClassifiersList':
        visualRecognition.listClassifiers(params, cbdone);
        break;
      case 'retrieveClassifierDetails':
        visualRecognition.getClassifier(params, cbdone);
        break;
      case 'deleteClassifier':
        visualRecognition.deleteClassifier(params, cbdone);
        break;
    }
  }

  // This is the Watson Visual Recognition V3 Node
  function WatsonVisualRecognitionV3Node (config) {
    RED.nodes.createNode(this, config);
    var node = this;
    var message;
    this.on('input', function (msg)
    {
      // Check which single feature has been requested.
      var feature = config['image-feature'];
      node.status({});
      // so there is at most 1 temp file at a time (did not found a better solution...)
      temp.cleanup();

      if (!msg.payload) {
        this.status({fill:'red', shape:'ring', text:'missing payload'});
        message = 'Missing property: msg.payload';
        node.error(message, msg);
        return;
      }
      if (feature !== 'retrieveClassifiersList' && feature !== 'retrieveClassifierDetails'
          && feature !== 'deleteClassifier')
      {
        if (typeof msg.payload === 'boolean' || typeof msg.payload === 'number')
        {
          this.status({fill:'red', shape:'ring', text:'bad format payload'});
          message = 'Bad format : msg.payload must be a URL string or a Node.js Buffer';
          node.error(message, msg);
          return;
        }
      }

      // If it is present the newly provided user entered key
      // takes precedence over the existing one.
      apikey = sAPIKey || this.credentials.apikey;
      this.status({});

      if (!apikey) {
        this.status({fill:'red', shape:'ring', text:'missing credentials'});
        message ='Missing Watson Visual Recognition API service credentials';
        node.error(message, msg);
        return;
      }

      var params = {};

      // This is the callback after the call to the watson service.
      // Set up as a var within this scope, so it has access to node, msg etc.
      // in preparation for the Watson service action
      var actionComplete = function(err, body, other) {

        if (err != null && body==null)
        {
          node.status({fill:'red', shape:'ring',
                       text:'call to watson visual recognition v3 service failed'});
          msg.result = {};
          msg.result['error_code']= err.code;
          if (!err.error)
            msg.result['error']= err.error;
          console.log('Error:', err.code);
          node.error('Error code : ' +  err.code);
          return;
        }
        else if (body.images[0].error)
        {
          var err_desc = body.images[0].error.description;
          var err_id = body.images[0].error.error_id;
          node.status({fill:'red', shape:'ring',
                       text:'call to watson visual recognition v3 service failed'});
          msg.result = {};
          msg.result['error_id']= err_id;
          msg.result['error']= err_desc;
          console.log('Error:', err_desc);
          msg.payload='see msg.result.error';
          node.send(msg);
        }
        else {
          msg.result = {};
          msg.result['all'] = body;
          msg.payload='see msg.result'; // to remove any Buffer that could remains
          node.send(msg);
          node.status({});
        }
      }; // actionComplete

      var actionComplete2 = function(err, body, other) {

        if (err != null && body==null)
        {
          node.status({fill:'red', shape:'ring', text:'call to watson visual recognition v3 service failed'});
          msg.result = {};
          msg.result['error_code']= err.code;
          if (!err.error)
            msg.result['error']= err.error;
          console.log('Error:', err.code);
          node.error('Error code : ' +  err.code);
          return;
        }
        else {
          msg.result = {};
          msg.result['all'] = body;
          msg.payload='see msg.result'; // to remove any Buffer that could remains
          node.send(msg);
          node.status({});
        }
      }; // actionComplete2

      var actionCompleteDeleteClassifier = function(err, body, other) {

        if (err != null && body==null)
        {
          node.status({fill:'red', shape:'ring', text:'call to watson visual recognition v3 service failed'});
          msg.result = {};
          msg.result['error_code']= err.code;
          if (!err.error)
            msg.result['error']= err.error;
          console.log('Error:', err.code);
          node.error('Error code : ' +  err.code);
          return;
        }
        else {
          msg.result = 'Deleted classifier_id';
          msg.payload='see msg.result';
          node.send(msg);
          node.status({});
        }
      }; // actionCompleteDeleteClassifier

      // If the input is an image, need to stream the input in, giving time for the
      // data to arrive, before invoking the service.
      node.status({fill:'blue', shape:'dot', text:'Calling '+ feature + ' ...'});
      if (imageCheck(msg.payload)) {
        temp.open({suffix: '.' + fileType(msg.payload).ext}, function (err, info) {
          if (err) {
            this.status({fill:'red', shape:'ring', text:'unable to open image stream'});
            message ='Node has been unable to open the image stream';
            node.error(message, msg);
            return;
          }
          stream_buffer(info.path, msg.payload, function () {
          params['images_file'] = fs.createReadStream(info.path);
          if ( msg.params != null && msg.params.classifier_ids != null)
            params['classifier_ids']=msg.params['classifier_ids'];
          if ( msg.params != null && msg.params.owners != null)
            params['owners']=msg.params['owners'];
          if ( msg.params != null && msg.params.threshold != null)
            params['threshold']=msg.params['threshold'];
          performAction(params, feature, actionComplete);
          });
        }); // temp
      } else if (feature==='createClassifier') {
          var listParams = {};
          var asyncTasks = [];
          var prop = null;
          for (var k in msg.params)
          {
            prop = k;
            if (prop.indexOf('_examples')>=0)
            {
              // before pushing the function into the task array wrap the push
              // in an IIFE function, passing in the 'prop' parameter
              (function(prop, listParams, msg) {

               asyncTasks.push(function (callback) {
                  var buffer = msg.params[prop];
                  temp.open({suffix: '.' + fileType(buffer).ext}, function (err, info) {
                    if (err) {
                      this.status({fill:'red', shape:'ring',
                                   text:'unable to open image stream'});
                      var message ='Node has been unable to open the image stream';
                      node.error(message, msg);
                      callback('open error on '+prop);
                    }
                    stream_buffer(info.path, msg.params[prop], function () {
                      listParams[prop]=fs.createReadStream(info.path);
                      callback(null, prop);
                    });
                  }); // temp.open
              }); // asyncTasks.push

              })(prop, listParams, msg);

            } else if (prop==='name') {
              listParams[prop]=msg.params[prop];
            }
          } // for

          async.parallel(asyncTasks, function(error, results){
            // when all temp local copies are ready,
            // copy of all parameters and request to watson api
            console.log(error, results);
            if (error)
            {
              console.log('Parallel ended with error ' + error);
              throw error;
            }
            for (p in listParams)
              params[p]=listParams[p];
            performAction(params, feature, actionComplete2);
          });
      }
        else if (feature === 'retrieveClassifiersList') {
          performAction(params, feature, actionComplete2);
      }
        else if (feature === 'retrieveClassifierDetails') {
          params['classifier_id']=msg.params['classifier_id'];
          performAction(params, feature, actionComplete2);
      }
        else if (feature === 'deleteClassifier') {
        params['classifier_id']=msg.params['classifier_id'];
        performAction(params, feature, actionCompleteDeleteClassifier);

      } else if (urlCheck(msg.payload)) {
        params['url'] = msg.payload;
        if ( msg.params != null && msg.params.classifier_ids != null)
            params['classifier_ids']=msg.params['classifier_ids'];
        if ( msg.params != null && msg.params.owners != null)
            params['owners']=msg.params['owners'];
        if ( msg.params != null && msg.params.threshold != null)
            params['threshold']=msg.params['threshold'];
        performAction(params, feature, actionComplete);
      } else {
        this.status({fill:'red', shape:'ring', text:'payload is invalid'});
        message ='Payload must be either an image buffer or a string representing a url';
        node.error(message, msg);
        return;
      }

    });
  }

  RED.nodes.registerType('visual-recognition-v3', WatsonVisualRecognitionV3Node, {
    credentials: {
      apikey: {type:'password'}
    }
  });

RED.nodes.registerType('visual-recognition-util-v3', WatsonVisualRecognitionV3Node, {
    credentials: {
      apikey: {type:'password'}
    }
  });

};
<|endoftext|>


<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

exports.didCreateDocumentElement = function() {
  var root = new WebKitShadowRoot(document.childNodes[0]);
  root.appendChild(document.createElement('style')).innerText =
      // TODO(jeremya): switch this to use automatic inlining once grit
      // supports inlining into JS. See http://crbug.com/146319.
      "x-titlebar { height: 24px; width: 100%; " +
      "position: absolute; left: 0; top: 0; }\n" +
      "div { padding-top: 24px; }\n" +
      ":-webkit-full-screen * { display: none; }\n" +
      ":-webkit-full-screen-document * { display: none; }\n" +
      "div:-webkit-full-screen, div:-webkit-full-screen-document { " +
      "padding-top: 0; }\n" +
      "button { -webkit-widget-region: region(control rectangle); }\n" +
      "button.close { border: 0; background-color: transparent; " +
      "width: 16px; height: 16px; " +
      "position: absolute; right: 4px; top: 4px; }\n" +
      "button.close { background-image: url(data:image/png;base64," +
      "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAA9ElEQVQ4T7VTQQ6CMBCk0H" +
      "AyIfAQbiZ+QHyDL/QLxqvx4MWDB+MvFAWMAuKsacmmSjkQSDbQ2Z3Z3WkQzsBHDOQ7owgs" +
      "MdUacTGmi3BeIFYcNycgciGlfFRVtcd3qoojz/PmdV0XOD8RGy1iCoQgT5G8IyREjni7IC" +
      "cg58ilwA7A8i4BwgMUxkKIV9M0PggTAoFlJpnwLhO5iEuFapq2s20CyoWIGbpeaRICyrI8" +
      "89FtA tqwGxdQ65yYsV8NcwVN5obR/uTJW4mQsfp2fgToGjPqbBjWeoJVfNRsbSskSO7+7" +
      "BsAiznZdgu6Qe97lH+htysv+AA10msRAt5JYQAAAABJRU5ErkJggg==); }\n" +
      "button.close:hover { background-image: url(data:image/png;base64," +
      "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABTElEQVQ4T2NkoBAwUqifAc" +
      "WA////KwANFAPiV4yMjA+QDcclBzcApCA6Otpz2bJluQkJCf3z58/fDTMEnxyyAWZADQuA" +
      "tj4B4ncpKSnbZs+efQjkCqjBmUDmMyD+ADSwD6j2FEgOxQWJiYmuCxYscIYawpWamnr89+" +
      "/fHECxbKjmB2VlZbs6OzsvwFyHEQZATXZz5syxAGr4BMR8QCwJDYvn1dXVO1taWi4ihw9G" +
      "LID8m5aWZgt0viXUEBaQAUDNh9E1o3gBFuIgA6Be8QKK3QXiLyA5oNMvIDsdph7DC9AASw" +
      "cquI9sAJDNk5GRcX769OlHsXoBKapAoQ2KiQcgPwMDkbGrq8sGyP8DChNQwM6aNeswRiAC" +
      "DYBF4yOgwnuwAAM5NTMz03rGjBnWsIAFql2ANxqB/l2B7F/kgCUYjUBbyEvKsFAllaY4Nw" +
      "IAmJDPEd+LFvYAAAAASUVORK5CYII=); }\n" +
      "button.close:active { background-image: url(data:image/png;base64," +
      "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAZ0lEQVQ4T2NkoBAwUqifge" +
      "oG2AFd1AfERUB8CM11WOXQXXAGSROyITDNMGkTGAPdAHSFIENAAOQqGEBxHbYwQDcE2ScY" +
      "XsMViNgMwRYuOGOBIgMo8gLFgUi1aCQ7IZGcNaieF0h2AQCMABwRdsuhtQAAAABJRU5Erk" +
      "Jggg==); }\n"
  var container = root.appendChild(document.createElement('div'));
  var titlebar = container.appendChild(document.createElement('x-titlebar'));
  var closeButton = titlebar.appendChild(document.createElement('button'));
  closeButton.setAttribute('class', 'close');
  closeButton.addEventListener('click', function() { window.close(); });
  container.appendChild(document.createElement('content'));
}
<commit_msg>Fix inlined image in inject_app_titlebar.js<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

exports.didCreateDocumentElement = function() {
  var root = new WebKitShadowRoot(document.childNodes[0]);
  root.appendChild(document.createElement('style')).innerText =
      // TODO(jeremya): switch this to use automatic inlining once grit
      // supports inlining into JS. See http://crbug.com/146319.
      "x-titlebar { height: 24px; width: 100%; " +
      "position: absolute; left: 0; top: 0; }\n" +
      "div { padding-top: 24px; }\n" +
      ":-webkit-full-screen * { display: none; }\n" +
      ":-webkit-full-screen-document * { display: none; }\n" +
      "div:-webkit-full-screen, div:-webkit-full-screen-document { " +
      "padding-top: 0; }\n" +
      "button { -webkit-widget-region: region(control rectangle); }\n" +
      "button.close { border: 0; background-color: transparent; " +
      "width: 16px; height: 16px; " +
      "position: absolute; right: 4px; top: 4px; }\n" +
      "button.close { background-image: url(data:image/png;base64," +
      "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAA9ElEQVQ4T7VTQQ6CMBCk0H" +
      "AyIfAQbiZ+QHyDL/QLxqvx4MWDB+MvFAWMAuKsacmmSjkQSDbQ2Z3Z3WkQzsBHDOQ7owgs" +
      "MdUacTGmi3BeIFYcNycgciGlfFRVtcd3qoojz/PmdV0XOD8RGy1iCoQgT5G8IyREjni7IC" +
      "cg58ilwA7A8i4BwgMUxkKIV9M0PggTAoFlJpnwLhO5iEuFapq2s20CyoWIGbpeaRICyrI8" +
      "89FtAtqwGxdQ65yYsV8NcwVN5obR/uTJW4mQsfp2fgToGjPqbBjWeoJVfNRsbSskSO7+7B" +
      "sAiznZdgu6Qe97lH+htysv+AA10msRAt5JYQAAAABJRU5ErkJggg==); }\n" +
      "button.close:hover { background-image: url(data:image/png;base64," +
      "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABTElEQVQ4T2NkoBAwUqifAc" +
      "WA////KwANFAPiV4yMjA+QDcclBzcApCA6Otpz2bJluQkJCf3z58/fDTMEnxyyAWZADQuA" +
      "tj4B4ncpKSnbZs+efQjkCqjBmUDmMyD+ADSwD6j2FEgOxQWJiYmuCxYscIYawpWamnr89+" +
      "/fHECxbKjmB2VlZbs6OzsvwFyHEQZATXZz5syxAGr4BMR8QCwJDYvn1dXVO1taWi4ihw9G" +
      "LID8m5aWZgt0viXUEBaQAUDNh9E1o3gBFuIgA6Be8QKK3QXiLyA5oNMvIDsdph7DC9AASw" +
      "cquI9sAJDNk5GRcX769OlHsXoBKapAoQ2KiQcgPwMDkbGrq8sGyP8DChNQwM6aNeswRiAC" +
      "DYBF4yOgwnuwAAM5NTMz03rGjBnWsIAFql2ANxqB/l2B7F/kgCUYjUBbyEvKsFAllaY4Nw" +
      "IAmJDPEd+LFvYAAAAASUVORK5CYII=); }\n" +
      "button.close:active { background-image: url(data:image/png;base64," +
      "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAZ0lEQVQ4T2NkoBAwUqifge" +
      "oG2AFd1AfERUB8CM11WOXQXXAGSROyITDNMGkTGAPdAHSFIENAAOQqGEBxHbYwQDcE2ScY" +
      "XsMViNgMwRYuOGOBIgMo8gLFgUi1aCQ7IZGcNaieF0h2AQCMABwRdsuhtQAAAABJRU5Erk" +
      "Jggg==); }\n"
  var container = root.appendChild(document.createElement('div'));
  var titlebar = container.appendChild(document.createElement('x-titlebar'));
  var closeButton = titlebar.appendChild(document.createElement('button'));
  closeButton.setAttribute('class', 'close');
  closeButton.addEventListener('click', function() { window.close(); });
  container.appendChild(document.createElement('content'));
}
<|endoftext|>


<commit_before>function ddg_spice_canistreamit(movies) {
      // console.log(xk);

      var result,img,snippet,link,div;
      var items = new Array();
      for(var i = 0; i<movies.length; i++)
      {
          result = movies[i];

          // Make title for header
          var header = 'Watch ' + result.title + " ("+result.year+")";

          // Call nra function as per Spice Plugin Guidelines

          var item = new Array();
          var content = "
Starring: "+result.actors+".
";
          content += "
Streaming: ";
          var count = 0;
          for(var subtype in result.affiliates)
          {
              var service = result.affiliates[subtype];
              content += ""+service.friendlyName;
              var price = parseFloat(service.price);
              if(price > 0)
              content += " ($"+service.price+")";

              content += ", "
              count++;
          }
          if(count > 0)
            content = content.substring(0,content.length-2);

          content += ".
"

          item['a'] = content;

          item['h'] = header;

          // Source name and url for the More at X link.
          item['s'] = 'CanIStream.It';
          item['u'] = result.links.shortUrl;

          // Force no compression.
          item['f'] = 1;

          // Thumbnail url
          item['i'] = result.image;

          items.push(item);

      }
      // The rendering function is nra.
      nra(items);
}

<commit_msg>Removed affiliate links, broke out rental and streaming options.<commit_after>function ddg_spice_canistreamit(movies) {
      // console.log(xk);

      var result,img,snippet,link,div;
      var items = new Array();
      for(var i = 0; i<movies.length; i++)
      {
          result = movies[i];

          // Make title for header
          var header = 'Watch ' + result.title + " ("+result.year+")";

          var item = new Array();
          var content = "
Starring: "+result.actors+".
";
          var streamingStr = "";
          var rentalStr = "";
          var streamingCount = 0;
          var rentalCount = 0;
          for(var subtype in result.affiliates)
          {
              var service = result.affiliates[subtype];
              var price = parseFloat(service.price);
              if(price > 0)
              {
                  rentalStr += service.friendlyName.replace("Rental","");
                  rentalStr += "($"+service.price+")";
                  rentalStr += ", ";
                  rentalCount++;
              }
              else
              {
                  streamingStr += service.friendlyName;
                  streamingStr += ", ";
                  streamingCount++;
              }
          }
          if(streamingCount > 0)
          {
            content += "
Streaming on "+streamingStr.substring(0,streamingStr.length-2)+".
";
          }
          if(rentalCount > 0)
          {
            content += "
Rent from  "+rentalStr.substring(0,rentalStr.length-2)+".
";
          }

          item['a'] = content;

          item['h'] = header;

          // Source name and url for the More at X link.
          item['s'] = 'CanIStream.It';
          item['u'] = result.links.shortUrl;

          // Force no compression.
          item['f'] = 1;

          // Thumbnail url
          item['i'] = result.image;

          items.push(item);

      }
      // The rendering function is nra.
      nra(items);
}

<|endoftext|>


<commit_before>function ddg_spice_khan_academy(res) {

  // Make sure a property is defined on an object
  function isProp(obj, prop) {
    prop = prop.split('.')
    for (var i = 0, len = prop.length; i < len; i++) {
      if ((obj = obj[prop[i]]) === undefined)
        return false
    }
    return true
  }

  // If we have a video to display
  if (res && isProp(res, 'feed.entry') && res.feed.entry.length > 0) {
    var vid = res.feed.entry[0]

    var title = d.getElementById('search_form_input').value
    if (isProp(vid, 'title.$t')) title = vid.title.$t

    if (!isProp(vid, 'id.$t')) return
    var embed = d.createElement('iframe')
    embed.src = 'http://www.youtube.com/embed/'
              + vid.id.$t.split(':').pop()
    embed.allowFullScreen = 'allowFullScreen'
    embed.frameBorder = 0

    YAHOO.util.Dom.setStyle(embed, 'width', '320px')
    YAHOO.util.Dom.setStyle(embed, 'height', '240px')

    var div = d.createElement('div')
    div.appendChild(embed)

    var items = [{
      f: 1,
      a: div,
      h: title,
      s: 'Khan Academy',
      u: 'http://www.khanacademy.org/'
    }]
    nra(items)
  }

}<commit_msg>better urls<commit_after>function ddg_spice_khan_academy(res) {

  // Make sure a property is defined on an object
  function isProp(obj, prop) {
    prop = prop.split('.')
    for (var i = 0, len = prop.length; i < len; i++) {
      if ((obj = obj[prop[i]]) === undefined)
        return false
    }
    return true
  }

  // If we have a video to display
  if (res && isProp(res, 'feed.entry') && res.feed.entry.length > 0) {
    var vid = res.feed.entry[0]

    var title = d.getElementById('search_form_input').value
    if (isProp(vid, 'title.$t')) title = vid.title.$t

    if (!isProp(vid, 'id.$t')) return
    var id = vid.id.$t.split(':').pop()

    var embed = d.createElement('iframe')
    embed.src = 'http://www.youtube.com/embed/' + id
    embed.allowFullScreen = 'allowFullScreen'
    embed.frameBorder = 0

    YAHOO.util.Dom.setStyle(embed, 'width', '320px')
    YAHOO.util.Dom.setStyle(embed, 'height', '240px')

    var div = d.createElement('div')
    div.appendChild(embed)

    var items = [{
      f: 1,
      a: div,
      h: title,
      s: 'Khan Academy',
      u: 'http://khanacademy.org/video?v=' + id
    }]
    nra(items)
  }

}<|endoftext|>


<commit_before>// @flow
import React from 'react'
import Text from './text'
import {globalColors} from '../styles'

export type Props = {
  key: string,
  username: string,
  theme: 'follow' | 'nonFollow' | 'highlight' | 'none',
  onClick: ?() => void,
  style?: ?Object,
}

const mentionStyles = {
  follow: {
    color: globalColors.green2,
  },
  nonFollow: {
    color: globalColors.blue,
  },
  highlight: {
    backgroundColor: globalColors.yellow,
  },
  none: {},
}

export default ({key, username, theme, style, onClick}: Props) => (
  <Text
    type="BodySemibold"
    onClick={onClick || undefined}
    key={key}
    style={{...style, ...mentionStyles[theme]}}
  >
    @{username}
  </Text>
)
<commit_msg>add underline on hover for mentions (#8569)<commit_after>// @flow
import React from 'react'
import Text from './text'
import {globalColors} from '../styles'
import {isMobile} from '../constants/platform'

export type Props = {
  key: string,
  username: string,
  theme: 'follow' | 'nonFollow' | 'highlight' | 'none',
  onClick: ?() => void,
  style?: ?Object,
}

const mentionStyles = {
  follow: {
    color: globalColors.green2,
  },
  nonFollow: {
    color: globalColors.blue,
  },
  highlight: {
    backgroundColor: globalColors.yellow,
  },
  none: {},
}

export default ({key, username, theme, style, onClick}: Props) => (
  <Text
    type="BodySemibold"
    onClick={onClick || undefined}
    key={key}
    className={isMobile ? undefined : 'hover-underline'}
    style={{...style, ...mentionStyles[theme]}}
  >
    @{username}
  </Text>
)
<|endoftext|>


<commit_before>let webpack = require('webpack');
let yargs = require('yargs');
let { sigmaSrcRoot, sigmaDistRoot, sigmaPluginsRoot } = require('../config/paths')

let options = yargs
  .alias('p', 'optimize-minimize')
  .alias('d', 'debug')
  .argv;

let jsLoader = 'babel?cacheDirectory';

module.exports = {
  options: options,

  entry: {
    'main': sigmaSrcRoot + '/main.js',
    'webgl': sigmaSrcRoot + '/webgl.js',
    'edges': sigmaSrcRoot + '/edges.js',
    'nodes': sigmaSrcRoot + '/nodes.js',
    'parsers.json': sigmaPluginsRoot + '/sigma.parsers.json/sigma.parsers.json.js',
    'parsers.gexf': [ sigmaPluginsRoot + '/sigma.parsers.gexf/gexf-parser.js',
                      sigmaPluginsRoot + '/sigma.parsers.gexf/sigma.parsers.gexf.js' ],
    'neo4j.cypher': sigmaPluginsRoot + '/sigma.neo4j.cypher/sigma.neo4j.cypher.js',
    'plugins.filter': sigmaPluginsRoot + '/sigma.plugins.filter/sigma.plugins.filter.js',
    'layout.forceAtlas2': [ sigmaPluginsRoot + '/sigma.layout.forceAtlas2/supervisor.js',
                            sigmaPluginsRoot + '/sigma.layout.forceAtlas2/worker.js'],
    'plugins.animate': sigmaPluginsRoot + '/sigma.plugins.animate/sigma.plugins.animate.js',
    'layout.noverlap': sigmaPluginsRoot + '/sigma.layout.noverlap/sigma.layout.noverlap.js',
    'plugins.relativeSize': sigmaPluginsRoot + '/sigma.plugins.relativeSize/sigma.plugins.relativeSize.js',
    // add any extra sigma modules here
  },

  output: {
    path: sigmaDistRoot,
    filename: options.optimizeMinimize ? '[name].min.js' : '[name].js',
    library: 'Sigma',
    libraryTarget: 'umd',
  },

  externals: undefined,

  module: {
    loaders: [
      { test: /\.js/, loader: jsLoader, exclude: [/node_modules/] },
      { test: /sigma\-react\/.*\.js/, loader: 'imports?this=>window' },
    ]
  },

  plugins: [
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: JSON.stringify(options.optimizeMinimize ? 'production' : 'development')
      }
    })
  ]
};
<commit_msg>fixed sigma files build, removed unnecessary min<commit_after>let webpack = require('webpack');
let yargs = require('yargs');
let { sigmaSrcRoot, sigmaDistRoot, sigmaPluginsRoot } = require('../config/paths')

let options = yargs
  .alias('p', 'optimize-minimize')
  .alias('d', 'debug')
  .argv;

let jsLoader = 'babel?cacheDirectory';

module.exports = {
  options: options,

  entry: {
    'main': sigmaSrcRoot + '/main.js',
    'webgl': sigmaSrcRoot + '/webgl.js',
    'edges': sigmaSrcRoot + '/edges.js',
    'nodes': sigmaSrcRoot + '/nodes.js',
    'parsers.json': sigmaPluginsRoot + '/sigma.parsers.json/sigma.parsers.json.js',
    'parsers.gexf': [ sigmaPluginsRoot + '/sigma.parsers.gexf/gexf-parser.js',
                      sigmaPluginsRoot + '/sigma.parsers.gexf/sigma.parsers.gexf.js' ],
    'neo4j.cypher': sigmaPluginsRoot + '/sigma.neo4j.cypher/sigma.neo4j.cypher.js',
    'plugins.filter': sigmaPluginsRoot + '/sigma.plugins.filter/sigma.plugins.filter.js',
    'layout.forceAtlas2': [ sigmaPluginsRoot + '/sigma.layout.forceAtlas2/supervisor.js',
                            sigmaPluginsRoot + '/sigma.layout.forceAtlas2/worker.js'],
    'plugins.animate': sigmaPluginsRoot + '/sigma.plugins.animate/sigma.plugins.animate.js',
    'layout.noverlap': sigmaPluginsRoot + '/sigma.layout.noverlap/sigma.layout.noverlap.js',
    'plugins.relativeSize': sigmaPluginsRoot + '/sigma.plugins.relativeSize/sigma.plugins.relativeSize.js',
    // add any extra sigma modules here
  },

  output: {
    path: sigmaDistRoot,
    filename: '[name].js',
    library: 'Sigma',
    libraryTarget: 'umd',
  },

  externals: undefined,

  module: {
    loaders: [
      { test: /\.js/, loader: jsLoader, exclude: [/node_modules/] },
      { test: /sigma\-react\/.*\.js/, loader: 'imports?this=>window' },
    ]
  },

  plugins: [
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: JSON.stringify(options.optimizeMinimize ? 'production' : 'development')
      }
    })
  ]
};
<|endoftext|>


<commit_before>function getElementPageY(element, root = document.body) {
  let totalOffsetTop = 0
  let ele = element

  while (ele !== root) {
    totalOffsetTop += ele.offsetTop
    ele = ele.parentNode
  }

  return totalOffsetTop
}
class SourceCode {
  setSize() {
    const lineCodeBox = $$('.codeline-frame > .linecode', this.container)
    const codeFrame = $$('code', this.container)

    let last_width = 0
    const resizeHandle = e => {
      if (window.innerWidth !== last_width) {
        last_width = window.innerWidth
      } else {
        return
      }

      let maxWidth = 0
      $('code > .inline', this.container).forEach(inlineEle => {
        if (inlineEle.scrollWidth > maxWidth) {
          maxWidth = inlineEle.scrollWidth
        }
        // inlineEle.style.width = `${ScrollWidth}px`
      })

      $('code > .inline', this.container).forEach(inlineEle => {
        inlineEle.style.minWidth = `${maxWidth}px`
        // inlineEle.style.height = `${lineCodeBox.offsetHeight}px`
        // inlineEle.style.lineHeight = `${lineCodeBox.offsetHeight}px`
      })
      // codeFrame.style.minWidth = `${maxWidth}px`
    }
    window.addEventListener('resize', resizeHandle)
    resizeHandle()
  }
  constructor(container) {
    this.container = container

    this.setSize()

    const sourceCodeContainer_list = $('.source-code', this.container)
    sourceCodeContainer_list.forEach((sourceCodeContainer, cursor) => {
      const lineCode_list = $('.codeline-frame > .linecode', sourceCodeContainer)
      const codelines = $('code > .inline', sourceCodeContainer)

      let ScrollInterval = 4
      let scrollDirect = 0
      let scrollContext = null
      setInterval(() => {
        if (!scrollContext) { return }
        if (scrollDirect < 0) {
          document.body.scrollTop += ScrollInterval

          const {clientY, pageY} = scrollContext.touches[0]
          touchMiddle({
            touches: [{
              clientY,
              pageY: pageY + ScrollInterval,
            }]
          })
        } else if (scrollDirect > 0) {
          document.body.scrollTop -= ScrollInterval

          const {clientY, pageY} = scrollContext.touches[0]
          touchMiddle({
            touches: [{
              clientY,
              pageY: pageY - ScrollInterval,
            }]
          })
        }
      }, 16.7)

      let firstLineCodeIndex = null
      let lastLineCode = null
      let lastLineCodeIndex = -1
      let modelStart = null
      let modelEnd = 0
      function touchMiddle(e) {
        const {clientY, pageY} = e.touches[0]

        lineCode_list.forEach((lineCodeEle, cursor) => {
          let direct = 0
          const linePageY = getElementPageY(lineCodeEle)
          if ((pageY >= linePageY) && (pageY < (linePageY + lineCodeEle.offsetHeight))) {
            if (lastLineCode === lineCodeEle) {
              return
            } else {
              lastLineCode = lineCodeEle

              if (cursor > lastLineCodeIndex) {
                direct = -1
              } else {
                direct = 1
              }

              lastLineCodeIndex = cursor
            }

            if (firstLineCodeIndex === null) firstLineCodeIndex = cursor

            if (cursor < firstLineCodeIndex) {
              // 在觸摸初始位置的上面
              modelStart = cursor
            } else if (cursor > firstLineCodeIndex) {
              // ~下面
              modelEnd = cursor + 1
            } else {
              // 同個位置
              modelStart = cursor
              modelEnd = cursor + 1
            }
          }
          if ((cursor >= modelStart) && (cursor < modelEnd)) {
            lineCodeEle.classList.add('clicked')
          } else {
            lineCodeEle.classList.remove('clicked')
          }
        })

        if (clientY < 48) {
          // 手指在上邊緣
          scrollContext = e
          scrollDirect = 1
        } else if (clientY > window.innerHeight - 48) {
          //~下邊緣
          scrollContext = e
          scrollDirect = -1
        } else {
          scrollContext = null
        }
      }

      const codelineFrame = $$('.codeline-frame', sourceCodeContainer)
      codelineFrame.addEventListener('touchstart', e => {
        e.preventDefault()

        // 觸摸開始，清除掉所有的 clicked
        lineCode_list.forEach(lineCodeEle => {
          lineCodeEle.classList.remove('clicked')
        })

        touchMiddle(e)
        console.info('touchstart', e)
      })

      codelineFrame.addEventListener('touchmove', e => {
        e.preventDefault()
        touchMiddle(e)
      })
      codelineFrame.addEventListener('touchend', e => {
        e.preventDefault()
        scrollDirect = 0
        scrollContext = null
        firstLineCodeIndex = null

        modelStart = null
        modelEnd = 0
        console.warn('touchend', e)
      })

      codelines.forEach((line, lineCursor) => {
        line.addEventListener('click', e => {
          const lineCode = lineCode_list[lineCursor]
          if (lineCode.className.indexOf('clicked') !== -1) {
            lineCode.classList.remove('clicked')
          } else {
            lineCode.classList.add('clicked')
          }
        })
      })
    })
  }
}
<commit_msg>解耦觸摸處理函數<commit_after>function getElementPageY(element, root = document.body) {
  let totalOffsetTop = 0
  let ele = element

  while (ele !== root) {
    totalOffsetTop += ele.offsetTop
    ele = ele.parentNode
  }

  return totalOffsetTop
}
class SourceCode {
  setSize() {
    const lineCodeBox = $$('.codeline-frame > .linecode', this.container)
    const codeFrame = $$('code', this.container)

    let last_width = 0
    const resizeHandle = e => {
      if (window.innerWidth !== last_width) {
        last_width = window.innerWidth
      } else {
        return
      }

      let maxWidth = 0
      $('code > .inline', this.container).forEach(inlineEle => {
        if (inlineEle.scrollWidth > maxWidth) {
          maxWidth = inlineEle.scrollWidth
        }
        // inlineEle.style.width = `${ScrollWidth}px`
      })

      $('code > .inline', this.container).forEach(inlineEle => {
        inlineEle.style.minWidth = `${maxWidth}px`
        // inlineEle.style.height = `${lineCodeBox.offsetHeight}px`
        // inlineEle.style.lineHeight = `${lineCodeBox.offsetHeight}px`
      })
      // codeFrame.style.minWidth = `${maxWidth}px`
    }
    window.addEventListener('resize', resizeHandle)
    resizeHandle()
  }
  constructor(container) {
    this.container = container

    this.setSize()

    const sourceCodeContainer_list = $('.source-code', this.container)
    sourceCodeContainer_list.forEach((sourceCodeContainer, cursor) => {
      const lineCode_list = $('.codeline-frame > .linecode', sourceCodeContainer)
      const codelines = $('code > .inline', sourceCodeContainer)

      let ScrollInterval = 4
      let scrollDirect = 0
      let scrollContext = null
      setInterval(() => {
        if (!scrollContext) { return }
        if (scrollDirect < 0) {
          document.body.scrollTop += ScrollInterval

          const {clientY, pageY} = scrollContext
          touchMiddle({
            clientY,
            pageY: pageY + ScrollInterval,
          })
        } else if (scrollDirect > 0) {
          document.body.scrollTop -= ScrollInterval

          const {clientY, pageY} = scrollContext
          touchMiddle({
            clientY,
            pageY: pageY - ScrollInterval,
          })
        }
      }, 16.7)

      let firstLineCodeIndex = null
      let lastLineCode = null
      let lastLineCodeIndex = -1
      let modelStart = null
      let modelEnd = 0
      function touchMiddle(tap_point) {
        const {clientY, pageY} = tap_point

        lineCode_list.forEach((lineCodeEle, cursor) => {
          let direct = 0
          const linePageY = getElementPageY(lineCodeEle)
          if ((pageY >= linePageY) && (pageY < (linePageY + lineCodeEle.offsetHeight))) {
            if (lastLineCode === lineCodeEle) {
              return
            } else {
              lastLineCode = lineCodeEle

              if (cursor > lastLineCodeIndex) {
                direct = -1
              } else {
                direct = 1
              }

              lastLineCodeIndex = cursor
            }

            if (firstLineCodeIndex === null) firstLineCodeIndex = cursor

            if (cursor < firstLineCodeIndex) {
              // 在觸摸初始位置的上面
              modelStart = cursor
            } else if (cursor > firstLineCodeIndex) {
              // ~下面
              modelEnd = cursor + 1
            } else {
              // 同個位置
              modelStart = cursor
              modelEnd = cursor + 1
            }
          }
          if ((cursor >= modelStart) && (cursor < modelEnd)) {
            lineCodeEle.classList.add('clicked')
          } else {
            lineCodeEle.classList.remove('clicked')
          }
        })

        if (clientY < 48) {
          // 手指在上邊緣
          scrollContext = tap_point
          scrollDirect = 1
        } else if (clientY > window.innerHeight - 48) {
          //~下邊緣
          scrollContext = tap_point
          scrollDirect = -1
        } else {
          scrollContext = null
        }
      }

      const codelineFrame = $$('.codeline-frame', sourceCodeContainer)
      codelineFrame.addEventListener('touchstart', e => {
        e.preventDefault()

        // 觸摸開始，清除掉所有的 clicked
        lineCode_list.forEach(lineCodeEle => {
          lineCodeEle.classList.remove('clicked')
        })

        touchMiddle(e.touches[0])
        console.info('touchstart', e)
      })

      codelineFrame.addEventListener('touchmove', e => {
        e.preventDefault()
        touchMiddle(e.touches[0])
      })
      codelineFrame.addEventListener('touchend', e => {
        e.preventDefault()
        scrollDirect = 0
        scrollContext = null
        firstLineCodeIndex = null

        modelStart = null
        modelEnd = 0
        console.warn('touchend', e)
      })

      codelines.forEach((line, lineCursor) => {
        line.addEventListener('click', e => {
          const lineCode = lineCode_list[lineCursor]
          if (lineCode.className.indexOf('clicked') !== -1) {
            lineCode.classList.remove('clicked')
          } else {
            lineCode.classList.add('clicked')
          }
        })
      })
    })
  }
}
<|endoftext|>


<commit_before>var settings_notifications = (function () {

var exports = {};

var stream_notification_settings = [
    {setting: "enable_stream_desktop_notifications", notifications:"desktop_notifications"},
    {setting: "enable_stream_push_notifications", notifications:"push_notifications"},
    {setting: "enable_stream_sounds", notifications:"audible_notifications"},
];

var pm_mention_notification_settings = [
    "enable_desktop_notifications",
    "enable_offline_email_notifications",
    "enable_offline_push_notifications",
    "enable_online_push_notifications",
    "enable_sounds",
    "pm_content_in_desktop_notifications",
];

var other_notification_settings = [
    "enable_digest_emails",
    "realm_name_in_notifications",
    "message_content_in_email_notifications",
];

exports.notification_settings = other_notification_settings.concat(
    pm_mention_notification_settings,
    _.pluck(stream_notification_settings, 'setting')
);

function maybe_bulk_update_stream_notification_setting(notification_checkbox,
                                                       propagate_setting_function) {
    var html = templates.render("propagate_notification_change");
    // TODO: This seems broken!!!
    var group = notification_checkbox.closest(".input-group");
    var checkbox_status = notification_checkbox.prop('checked');
    group.find(".propagate_stream_notifications_change").html(html);
    group.find(".yes_propagate_notifications").on("click", function () {
        propagate_setting_function(checkbox_status);
        group.find(".propagate_stream_notifications_change").empty();
    });
    group.find(".no_propagate_notifications").on("click", function () {
        group.find(".propagate_stream_notifications_change").empty();
    });
}

function change_notification_setting(setting, setting_data, status_element) {
    var data = {};
    data[setting] = JSON.stringify(setting_data);
    settings_ui.do_settings_change(channel.patch, '/json/settings/notifications', data, status_element);
}

exports.set_up = function () {
    if (!page_params.realm_show_digest_email) {
        $("#digest_container").hide();
    }

    _.each(pm_mention_notification_settings, function (setting) {
        $("#" + setting).change(function () {
            change_notification_setting(setting, $(this).prop('checked'),
                                        "#pm-mention-notify-settings-status");
        });
    });

    _.each(other_notification_settings, function (setting) {
        $("#" + setting).change(function () {
            change_notification_setting(setting, $(this).prop('checked'),
                                        "#other-notify-settings-status");
        });
    });

    _.each(stream_notification_settings, function (stream_setting) {
        var setting = stream_setting.setting;
        $("#" + setting).change(function () {
            var setting_data = $(this).prop('checked');
            change_notification_setting(setting, setting_data, "#stream-notify-settings-status");
            maybe_bulk_update_stream_notification_setting($('#' + setting), function () {
                stream_edit.set_notification_setting_for_all_streams(
                    stream_setting.notifications, setting_data);
            });
        });
    });

    $("#enable_desktop_notifications").change(function () {
        settings_ui.disable_sub_setting_onchange(this.checked, "pm_content_in_desktop_notifications", true);
    });

    $("#enable_offline_push_notifications").change(function () {
        settings_ui.disable_sub_setting_onchange(this.checked, "enable_online_push_notifications", true);
    });
};

function _update_page() {
    _.each(exports.notification_settings, function (setting) {
        $("#" + setting).prop('checked', page_params[setting]);
    });
}

exports.update_page = function () {
    i18n.ensure_i18n(_update_page);
};

return exports;
}());

if (typeof module !== 'undefined') {
    module.exports = settings_notifications;
}
<commit_msg>settings_notifications: Remove now-unnecessary ensure_i18n.<commit_after>var settings_notifications = (function () {

var exports = {};

var stream_notification_settings = [
    {setting: "enable_stream_desktop_notifications", notifications:"desktop_notifications"},
    {setting: "enable_stream_push_notifications", notifications:"push_notifications"},
    {setting: "enable_stream_sounds", notifications:"audible_notifications"},
];

var pm_mention_notification_settings = [
    "enable_desktop_notifications",
    "enable_offline_email_notifications",
    "enable_offline_push_notifications",
    "enable_online_push_notifications",
    "enable_sounds",
    "pm_content_in_desktop_notifications",
];

var other_notification_settings = [
    "enable_digest_emails",
    "realm_name_in_notifications",
    "message_content_in_email_notifications",
];

exports.notification_settings = other_notification_settings.concat(
    pm_mention_notification_settings,
    _.pluck(stream_notification_settings, 'setting')
);

function maybe_bulk_update_stream_notification_setting(notification_checkbox,
                                                       propagate_setting_function) {
    var html = templates.render("propagate_notification_change");
    // TODO: This seems broken!!!
    var group = notification_checkbox.closest(".input-group");
    var checkbox_status = notification_checkbox.prop('checked');
    group.find(".propagate_stream_notifications_change").html(html);
    group.find(".yes_propagate_notifications").on("click", function () {
        propagate_setting_function(checkbox_status);
        group.find(".propagate_stream_notifications_change").empty();
    });
    group.find(".no_propagate_notifications").on("click", function () {
        group.find(".propagate_stream_notifications_change").empty();
    });
}

function change_notification_setting(setting, setting_data, status_element) {
    var data = {};
    data[setting] = JSON.stringify(setting_data);
    settings_ui.do_settings_change(channel.patch, '/json/settings/notifications', data, status_element);
}

exports.set_up = function () {
    if (!page_params.realm_show_digest_email) {
        $("#digest_container").hide();
    }

    _.each(pm_mention_notification_settings, function (setting) {
        $("#" + setting).change(function () {
            change_notification_setting(setting, $(this).prop('checked'),
                                        "#pm-mention-notify-settings-status");
        });
    });

    _.each(other_notification_settings, function (setting) {
        $("#" + setting).change(function () {
            change_notification_setting(setting, $(this).prop('checked'),
                                        "#other-notify-settings-status");
        });
    });

    _.each(stream_notification_settings, function (stream_setting) {
        var setting = stream_setting.setting;
        $("#" + setting).change(function () {
            var setting_data = $(this).prop('checked');
            change_notification_setting(setting, setting_data, "#stream-notify-settings-status");
            maybe_bulk_update_stream_notification_setting($('#' + setting), function () {
                stream_edit.set_notification_setting_for_all_streams(
                    stream_setting.notifications, setting_data);
            });
        });
    });

    $("#enable_desktop_notifications").change(function () {
        settings_ui.disable_sub_setting_onchange(this.checked, "pm_content_in_desktop_notifications", true);
    });

    $("#enable_offline_push_notifications").change(function () {
        settings_ui.disable_sub_setting_onchange(this.checked, "enable_online_push_notifications", true);
    });
};

exports.update_page = function () {
    _.each(exports.notification_settings, function (setting) {
        $("#" + setting).prop('checked', page_params[setting]);
    });
};

return exports;
}());

if (typeof module !== 'undefined') {
    module.exports = settings_notifications;
}
<|endoftext|>


<commit_before>define({
    "BTN_CANCEL":                   "Abbrechen",
    "BTN_CLOSE":                    "Schließen",
    "BTN_OK":                       "OK",
    "BTN_SAVE_DEFAULTS":            "Standardeinstellungen speichern",
    "BTN_SET_DEFAULTS":             "Standardeinstellungen setzen",
    "CMD_EXPORT_PDF":               "Als PDF exportieren\u2026",
    "DIALOG_TITLE":                 "{0} als PDF exportieren",
    "DIALOG_PREFERENCES_TITLE":     "PDF Export: Standardeinstellungen",
    "ERROR_PDFKIT_MSG":             "There was an error while creating the PDF document for {0}.",
    "ERROR_PDFKIT_MSG_WITH_ERROR":  "There was an error while creating the PDF document due to {0}. Please try again. ",
    "ERROR_PDFKIT_TITLE":           "Unerwarteter Fehler",
    "ERROR_UNSUPPORTED_FILE_MSG":   "The following file is not supported and can not be exported as a PDF document: {0}",
    "ERROR_UNSUPPORTED_FILE_TITLE": "Nicht unterstütztes Dateiformat",
    "ERROR_WRITE_MSG":              "There was an error while creating your PDF document. Please try again later. If this keeps happening, please open an issue in our Github repository. ({0})",
    "LABEL_FONTSIZE":               "Schriftgröße",
    "LABEL_EXPORT_RANGE":           "Bereich exportieren",
    "LABEL_EXPORT_SELECTION":       "Auswahl exportieren",
    "LABEL_EXPORT_CURRENT_FILE":    "Aktuelle Datei exportieren",
    "LABEL_INCLUDE_PAGES_FOOTER":   "Seitenzahl in die Fußzeile einfügen",
    "LABEL_MARGINS":                "Ränder (in Druckerpunkten)",
    "LABEL_MARGIN_BOTTOM":          "Unterer Rand",
    "LABEL_MARGIN_LEFT":            "Linker Rand",
    "LABEL_MARGIN_RIGHT":           "Rechter Rand",
    "LABEL_MARGIN_TOP":             "Oberer Rand",
    "LABEL_OPENPDF":                "PDF nach Export öffnen",
    "LABEL_SELECTION":              "Auswahl",
    "LABEL_SYNTAX_HIGHLIGHT":       "Syntaxhervorhebung benutzen",
    "LABEL_WHOLEFILE":              "Ganze Datei"
});
<commit_msg>Update de.js<commit_after>define({
    "BTN_CANCEL":                   "Abbrechen",
    "BTN_CLOSE":                    "Schließen",
    "BTN_OK":                       "OK",
    "BTN_SAVE_DEFAULTS":            "Standardeinstellungen speichern",
    "BTN_SET_DEFAULTS":             "Standardeinstellungen setzen",
    "CMD_EXPORT_PDF":               "Als PDF exportieren\u2026",
    "DIALOG_TITLE":                 "{0} als PDF exportieren",
    "DIALOG_PREFERENCES_TITLE":     "PDF Export: Standardeinstellungen",
    "ERROR_PDFKIT_MSG":             "Ein Fehler ist beim erstellen des PDF Dokuments  {0}.",
    "ERROR_PDFKIT_MSG_WITH_ERROR":  "There was an error while creating the PDF document due to {0}. Please try again. ",
    "ERROR_PDFKIT_TITLE":           "Unerwarteter Fehler",
    "ERROR_UNSUPPORTED_FILE_MSG":   "Die folgende Datei ist nicht unterstützt und kann nicht als PDF exportiert werden: {0}",
    "ERROR_UNSUPPORTED_FILE_TITLE": "Nicht unterstützter Dateityp",
    "ERROR_WRITE_MSG":              "There was an error while creating your PDF document. Please try again later. If this keeps happening, please open an issue in our Github repository. ({0})",
    "LABEL_FONTSIZE":               "Schriftgröße",
    "LABEL_EXPORT_RANGE":           "Bereich exportieren",
    "LABEL_EXPORT_SELECTION":       "Auswahl exportieren",
    "LABEL_EXPORT_CURRENT_FILE":    "Aktuelle Datei exportieren",
    "LABEL_INCLUDE_PAGES_FOOTER":   "Seitenzahl in die Fußzeile einfügen",
    "LABEL_MARGINS":                "Ränder (in Druckerpunkten)",
    "LABEL_MARGIN_BOTTOM":          "Unterer Rand",
    "LABEL_MARGIN_LEFT":            "Linker Rand",
    "LABEL_MARGIN_RIGHT":           "Rechter Rand",
    "LABEL_MARGIN_TOP":             "Oberer Rand",
    "LABEL_OPENPDF":                "PDF nach Export öffnen",
    "LABEL_SELECTION":              "Auswahl",
    "LABEL_SYNTAX_HIGHLIGHT":       "Syntaxhervorhebung benutzen",
    "LABEL_WHOLEFILE":              "Ganze Datei"
});
<|endoftext|>


<commit_before>/**
 * @fileOverview Requirejs modifier for animations based on scroll offsets
 *
 * @preserve Copyright (c) 2013 British Broadcasting Corporation
 * (http://www.bbc.co.uk) and TAL Contributors (1)
 *
 * (1) TAL Contributors are listed in the AUTHORS file and at
 *     https://github.com/fmtvp/TAL/AUTHORS - please extend this file,
 *     not this notice.
 *
 * @license 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.
 *
 * All rights reserved
 * Please contact us for an alternative licence
 */

require.def(
	'antie/devices/anim/tween',
	[
		'antie/devices/browserdevice',
		'antie/lib/shifty'
	],
	function(Device, Tweenable) {
	    // A set of queues of DOM updates to perform. Each animation framerate gets its own queue
	    // so they are in sync between themselves.
	    var animQueues = {};
	    var UPDATETYPE_STEP = 'step';
	    var UPDATETYPE_COMPLETE = 'complete';

	    /**
	     * Internal function: given a new tween value for an animation, add it to a queue
	     * of DOM manipulations to be performed at the next update. If there is no queue yet,
	     * create it and start the update cycle after half a frame has elapsed, to give other
	     * animation updates a chance to come in.
	     */
	    function addTweenToQueue(fps, options, tweenValues, type) {
	        // A separate queue exists for each framerate. Get or create the appropriate queue.
	        var queueKey = 'fps' + fps;
	        var frameIntervalMs = 1000 / fps;
	        var queue = animQueues[queueKey];

	        // Create a new queue if one doesn't already exist (implemented as an array).
	        if (!queue) {
	            queue = [];
	            animQueues[queueKey] = queue;
	        }

            // Start processing the queue periodically if we're not already.
            // Wait half a frame before starting the first cycle - gives other animation updates at
            // the same frame rate a chance to come in.
	        if (!queue.isProcessing) {
	            queue.isProcessing = true;
	            setTimeout(function() { startIntervalTimer(queue, frameIntervalMs); }, frameIntervalMs / 2);

	            // First tween in a cycle should be applied immediately. It contains initial values.
                step(options, tweenValues, type);
	        }
           else {
                // Queue is already being processed. Add the new entry to the queue.
                queue.push({options: options, values: tweenValues, type: type});
            }

	    }

	    /**
	     * Internal function. Start a periodic interval timer for a given framerate.
	     */
	    function startIntervalTimer(queue, period) {
	        // Store timer ID with the queue to allow it to be stopped later.
	        queue.intervalId = setInterval(function() { processQueue(queue); }, period);
	    }

	    /**
	     * Internal function. To be called periodically on a queue of operations. Apply each update to the
	     * DOM, then clear the queue ready to be refilled. Stop the periodic timer if the queue remains empty.
	     */
	    function processQueue(queue) {
	        // Is the queue still empty after it was last cleared? Stop the timer - the animations have
	        // probably finished and will not provide any further updates.
	        if (queue.length === 0) {
	            clearInterval(queue.intervalId);
	            queue.isProcessing = false;
	            delete queue.intervalId;
	        }
	        else {
	            // We have some DOM updates to do. Do each one in sequence, then clear the queue ready for the next round.
	            try {
	                for (var i = 0; i < queue.length; i++) {
	                    var q = queue[i];
                        step(q.options, q.values, q.type);
	                }
	            }
	            finally {
	                // Truncating the array length to zero clears it.
	                queue.length = 0;
	            }
	        }
	    }

	    /**
	     * Internal function. Perform the DOM updates required for the update.
	     */
	    function step(options, tweenValues, type) {
            if (type === UPDATETYPE_STEP) {
                for (var p in options.to) {
                    if (tweenValues[p] !== null && tweenValues[p] !== undefined) {
                        if (/scroll/.test(p)) {
                            options.el[p] = tweenValues[p];
                        } else {
                            options.el.style[p] = tweenValues[p];
                        }
                    }
                }
            }
            else if (type === UPDATETYPE_COMPLETE) {
                if (typeof options.onComplete === 'function') {
                    options.onComplete();
                }
            }
	    }

		Device.prototype._tween = function (options) {
			var anim = new Tweenable(options);
			var self = this;

			var opts = {
					initialState: options.from || {},
					from: options.from || {},
					to: options.to || {},
					duration: options.duration || 840,
					easing: options.easing || 'easeFromTo',
					fps: options.fps || 25,
					start: function() {
						if (options.className) {
							self.removeClassFromElement(options.el, "not" + options.className);
							self.addClassToElement(options.el,  options.className);
						}
						self.removeClassFromElement(self.getTopLevelElement(), "notanimating");
						self.addClassToElement(self.getTopLevelElement(), "animating");
						if (options.onStart) {
							options.onStart();
						}
					},
					step: function () {
						addTweenToQueue(opts.fps, options, this, UPDATETYPE_STEP);
					},
					callback: function () {
						if(options.className) {
							self.removeClassFromElement(options.el, options.className);
							self.addClassToElement(options.el, "not" + options.className);
						}
						self.removeClassFromElement(self.getTopLevelElement(), "animating");
						self.addClassToElement(self.getTopLevelElement(), "notanimating");
						addTweenToQueue(opts.fps, options, null, UPDATETYPE_COMPLETE);
					}
				};

			anim.tween(opts);

			return anim;
		};
	}
);<commit_msg>Reformat indentation with spaces for consistency.<commit_after>/**
 * @fileOverview Requirejs modifier for animations based on scroll offsets
 *
 * @preserve Copyright (c) 2013 British Broadcasting Corporation
 * (http://www.bbc.co.uk) and TAL Contributors (1)
 *
 * (1) TAL Contributors are listed in the AUTHORS file and at
 *     https://github.com/fmtvp/TAL/AUTHORS - please extend this file,
 *     not this notice.
 *
 * @license 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.
 *
 * All rights reserved
 * Please contact us for an alternative licence
 */

require.def(
    'antie/devices/anim/tween',
    [
     'antie/devices/browserdevice',
     'antie/lib/shifty'
     ],
     function(Device, Tweenable) {
        // A set of queues of DOM updates to perform. Each animation framerate gets its own queue
        // so they are in sync between themselves.
        var animQueues = {};
        var UPDATETYPE_STEP = 'step';
        var UPDATETYPE_COMPLETE = 'complete';

        /**
         * Internal function: given a new tween value for an animation, add it to a queue
         * of DOM manipulations to be performed at the next update. If there is no queue yet,
         * create it and start the update cycle after half a frame has elapsed, to give other
         * animation updates a chance to come in.
         */
        function addTweenToQueue(fps, options, tweenValues, type) {
            // A separate queue exists for each framerate. Get or create the appropriate queue.
            var queueKey = 'fps' + fps;
            var frameIntervalMs = 1000 / fps;
            var queue = animQueues[queueKey];

            // Create a new queue if one doesn't already exist (implemented as an array).
            if (!queue) {
                queue = [];
                animQueues[queueKey] = queue;
            }

            // Start processing the queue periodically if we're not already.
            // Wait half a frame before starting the first cycle - gives other animation updates at
            // the same frame rate a chance to come in.
            if (!queue.isProcessing) {
                queue.isProcessing = true;
                setTimeout(function() { startIntervalTimer(queue, frameIntervalMs); }, frameIntervalMs / 2);

                // First tween in a cycle should be applied immediately. It contains initial values.
                step(options, tweenValues, type);
            }
            else {
                // Queue is already being processed. Add the new entry to the queue.
                queue.push({options: options, values: tweenValues, type: type});
            }

        }

        /**
         * Internal function. Start a periodic interval timer for a given framerate.
         */
        function startIntervalTimer(queue, period) {
            // Store timer ID with the queue to allow it to be stopped later.
            queue.intervalId = setInterval(function() { processQueue(queue); }, period);
        }

        /**
         * Internal function. To be called periodically on a queue of operations. Apply each update to the
         * DOM, then clear the queue ready to be refilled. Stop the periodic timer if the queue remains empty.
         */
        function processQueue(queue) {
            // Is the queue still empty after it was last cleared? Stop the timer - the animations have
            // probably finished and will not provide any further updates.
            if (queue.length === 0) {
                clearInterval(queue.intervalId);
                queue.isProcessing = false;
                delete queue.intervalId;
            }
            else {
                // We have some DOM updates to do. Do each one in sequence, then clear the queue ready for the next round.
                try {
                    for (var i = 0; i < queue.length; i++) {
                        var q = queue[i];
                        step(q.options, q.values, q.type);
                    }
                }
                finally {
                    // Truncating the array length to zero clears it.
                    queue.length = 0;
                }
            }
        }

        /**
         * Internal function. Perform the DOM updates required for the update.
         */
        function step(options, tweenValues, type) {
            if (type === UPDATETYPE_STEP) {
                for (var p in options.to) {
                    if (tweenValues[p] !== null && tweenValues[p] !== undefined) {
                        if (/scroll/.test(p)) {
                            options.el[p] = tweenValues[p];
                        } else {
                            options.el.style[p] = tweenValues[p];
                        }
                    }
                }
            }
            else if (type === UPDATETYPE_COMPLETE) {
                if (typeof options.onComplete === 'function') {
                    options.onComplete();
                }
            }
        }

        Device.prototype._tween = function (options) {
            var anim = new Tweenable(options);
            var self = this;

            var opts = {
                    initialState: options.from || {},
                    from: options.from || {},
                    to: options.to || {},
                    duration: options.duration || 840,
                    easing: options.easing || 'easeFromTo',
                    fps: options.fps || 25,
                    start: function() {
                        if (options.className) {
                            self.removeClassFromElement(options.el, "not" + options.className);
                            self.addClassToElement(options.el,  options.className);
                        }
                        self.removeClassFromElement(self.getTopLevelElement(), "notanimating");
                        self.addClassToElement(self.getTopLevelElement(), "animating");
                        if (options.onStart) {
                            options.onStart();
                        }
                    },
                    step: function () {
                        addTweenToQueue(opts.fps, options, this, UPDATETYPE_STEP);
                    },
                    callback: function () {
                        if(options.className) {
                            self.removeClassFromElement(options.el, options.className);
                            self.addClassToElement(options.el, "not" + options.className);
                        }
                        self.removeClassFromElement(self.getTopLevelElement(), "animating");
                        self.addClassToElement(self.getTopLevelElement(), "notanimating");
                        addTweenToQueue(opts.fps, options, null, UPDATETYPE_COMPLETE);
                    }
            };

            anim.tween(opts);

            return anim;
        };
    }
);<|endoftext|>