<commit_before>var WordCount = (function () {
    function WordCount() {
    }
    WordCount.prototype.map =  function(item, emit) {
        var splitted = item.split(/\s/g);
        splitted.forEach(function(word){
            emit(word,1)
        })
    };

    WordCount.prototype.reduce = function(key, values, emit) {

        //emit({ key: key, count: values.length });
        var sum = values.reduce(function(a,b){
            return a+b;
        });

        emit(key,sum);
    };

    return WordCount;
})();

var mapReduceTask = new WordCount();

var MapReduce = (function () {
    function MapReduce(task) {
        this.task = task;
        this.intermediate = {};
    }

    MapReduce.prototype.map =  function(input){
        var that = this;
        var intermediates = {};
        input.forEach(function(item){
            that.task.map(item,function(key,value){
                if(typeof (intermediates[key])==="undefined"){
                    intermediates[key]=[];
                }
                intermediates[key].push(value)
            });

        });
        return intermediates;
    };

    MapReduce.prototype.reduce = function(intermediate) {
        var that = this;
        for(var key in intermediate){
            this.task.reduce(key,intermediate[key],function(key,value){
                intermediate[key] = [value];
            })
        }
    };

    return MapReduce;
})();

var mapReduce = new MapReduce(mapReduceTask);

self.onmessage = function(event){
    if(typeof event.data ==="object"){
        var msg = event.data;
        switch (msg.command){
            case "map":
                if(msg.dataset){
                    var intermediates = mapReduce.map(msg.dataset);
                    self.postMessage({
                       command:"intermediates",
                       intermediates:intermediates
                    });
                }
                break;
            case "reduce":
                if(msg.intermediate){
                    mapReduce.reduce();
                }
                break;
            default:
        }
    }
};<commit_msg>Clean code up<commit_after>var WordCount = (function () {
    function WordCount() {
    }
    WordCount.prototype.map =  function(item, emit) {
        var splitted = item.split(/\s/g);
        splitted.forEach(function(word){
            emit(word,1)
        })
    };

    WordCount.prototype.reduce = function(key, values, emit) {

        //emit({ key: key, count: values.length });
        var sum = values.reduce(function(a,b){
            return a+b;
        });

        emit(key,sum);
    };

    return WordCount;
})();

var mapReduceTask = new WordCount();

var MapReduce = (function () {
    function MapReduce(task) {
        this.task = task;
        this.intermediate = {};
    }

    MapReduce.prototype.map =  function(input){
        var that = this;
        var intermediates = {};
        input.forEach(function(item){
            that.task.map(item,function(key,value){
                if(typeof (intermediates[key])==="undefined"){
                    intermediates[key]=[];
                }
                intermediates[key].push(value)
            });

        });
        return intermediates;
    };

    MapReduce.prototype.reduce = function(intermediate) {
        var that = this;
        for(var key in intermediate){
            this.task.reduce(key,intermediate[key],function(key,value){
                intermediate[key] = [value];
            })
        }
    };

    return MapReduce;
})();

var mapReduce = new MapReduce(mapReduceTask);

self.onmessage = function(event){
    if(typeof event.data ==="object"){
        var msg = event.data;
        switch (msg.command){
            case "map":
                if(msg.dataset){
                    self.postMessage({
                       command:"intermediates",
                       intermediates:mapReduce.map(msg.dataset)
                    });
                }
                break;
            case "reduce":
                if(msg.intermediate){
                    mapReduce.reduce();
                }
                break;
            default:
        }
    }
};<|endoftext|>


<commit_before>'use strict';

const OperationIterator = require('../iterator');
const StringDelta = require('./delta');
const ops = require('./ops');

/**
 * Compose two operations by stepping through operations to figure out how
 * the combined result should look like.
 */
module.exports = function(left, right) {
	left = new OperationIterator(left);
	right = new OperationIterator(right);

	const delta = new StringDelta();

	function handleRetain(op1, op2) {
		const length1 = op1.length;

		if(op2 instanceof ops.Retain) {
			const length2 = op2.length;

			if(length1 < length2) {
				// Left operation is shorter, retain left count and rewrite right
				delta.retain(length1);

				right.replace(new ops.Retain(length2 - length1));
			} else if(length1 > length2) {
				// Right operation is shorter, retain right and rewrite left
				delta.retain(length2);

				left.replace(new ops.Retain(length1 - length2));
			} else {
				// Matching lengths, no need to do anything special
				delta.retain(length1);
			}
		} else if(op2 instanceof ops.Insert) {
			// Right operation is a insert, insert and handle this retain again
			delta.insert(op2.value);

			left.back();
		} else if(op2 instanceof ops.Delete) {
			// Right operation is a delete, add it to the delta and replace ourselves

			const value2 = op2.value;
			const length2 = value2.length;

			delta.delete(value2);

			if(length2 < length1) {
				// Only replace if we deleted less than we retain
				left.replace(new ops.Retain(length1 - length2));
			}
		}
	}

	function handleInsert(op1, op2) {
		const value1 = op1.value;
		const length1 = op1.value.length;

		if(op2 instanceof ops.Retain) {
			const length2 = op2.length;

			if(length1 < length2) {
				/*
				 * Left can fit into the right retain, insert all of it and
				 * replace right with leftover retain count.
				 */

				delta.insert(value1);
				right.replace(new ops.Retain(length2 - length1));
			} else if(length1 > length2) {
				/*
				 * Left is longer than right. Insert substring of left and
				 * replace with rest of value.
				 */
				delta.insert(value1.substring(0, length2));

				left.replace(new ops.Insert(value1.substring(length2)));
			} else {
				// Both left and right have the same length
				delta.insert(value1);
			}

		} else if(op2 instanceof ops.Insert) {
			/*
			 * Two inserts, right is inserted first and the we handle left
			 * again.
			 */
			delta.insert(op2.value);
			left.back();
		} else if(op2 instanceof ops.Delete) {
			const value2 = op2.value;
			const length2 = value2.length;

			if(length1 > length2) {
				/*
				 * Left insert is longer than right delete, replace left with
				 * remaining text from left.
				 */
				left.replace(new ops.Insert(value1.substring(length2)));
			} else if(length1 < length2) {
				/*
				 * Left insert is shorther than right delete, replace right with
				 * remaining text from right.
				 */
				right.replace(new ops.Delete(value2.substring(length1)));
			} else {
				// Exact same length, do nothing as they cancel each other
			}
		}
	}

	function handleDelete(op1, op2) {
		const value1 = op1.value;
		const length1 = value1.length;

		if(op2 instanceof ops.Retain) {
			/*
			 * Right operation is a retain, delete left and back up one to
			 * handle right retain again.
			 */
			delta.delete(value1);

			right.back();
		} else if(op2 instanceof ops.Insert) {
			/*
			 * Right opreation is an insert, push left delete and right insert
			 * onto the delta.
			 */
			delta.delete(value1);
			delta.insert(op2.value);
		} else if(op2 instanceof ops.Delete) {
			/*
			 * Right operation is also a delete. Push left delete and handle
			 * right delete again.
			 */
			delta.delete(value1);
			right.back();
		}
	}

	while(left.hasNext && right.hasNext) {
		const op1 = left.next();
		const op2 = right.next();

		if(op1 instanceof ops.Retain) {
			handleRetain(op1, op2);
		} else if(op1 instanceof ops.Insert) {
			handleInsert(op1, op2);
		} else if(op1 instanceof ops.Delete) {
			handleDelete(op1, op2);
		}
	}

	if(left.hasNext) {
		throw 'Composition failure: Operation size mismatch';
	}

	while(right.hasNext) {
		const op2 = right.next();
		op2.apply(delta);
	}

	return delta.done();
};
<commit_msg>Bugfix for string compose with retain vs delete<commit_after>'use strict';

const OperationIterator = require('../iterator');
const StringDelta = require('./delta');
const ops = require('./ops');

/**
 * Compose two operations by stepping through operations to figure out how
 * the combined result should look like.
 */
module.exports = function(left, right) {
	left = new OperationIterator(left);
	right = new OperationIterator(right);

	const delta = new StringDelta();

	function handleRetain(op1, op2) {
		const length1 = op1.length;

		if(op2 instanceof ops.Retain) {
			const length2 = op2.length;

			if(length1 < length2) {
				// Left operation is shorter, retain left count and rewrite right
				delta.retain(length1);

				right.replace(new ops.Retain(length2 - length1));
			} else if(length1 > length2) {
				// Right operation is shorter, retain right and rewrite left
				delta.retain(length2);

				left.replace(new ops.Retain(length1 - length2));
			} else {
				// Matching lengths, no need to do anything special
				delta.retain(length1);
			}
		} else if(op2 instanceof ops.Insert) {
			// Right operation is a insert, insert and handle this retain again
			delta.insert(op2.value);

			left.back();
		} else if(op2 instanceof ops.Delete) {
			// Right operation is a delete, add it to the delta and replace ourselves

			const value2 = op2.value;
			const length2 = value2.length;

			delta.delete(value2);

			if(length1 < length2) {
				delta.delete(value2.substring(0, length1));
				right.replace(new ops.Delete(value2.substring(length1)));
			} else if(length2 < length1) {
				// Only replace if we deleted less than we retain
				delta.delete(value2);
				left.replace(new ops.Retain(length1 - length2));
			} else {
				delta.delete(value2);
			}
		}
	}

	function handleInsert(op1, op2) {
		const value1 = op1.value;
		const length1 = op1.value.length;

		if(op2 instanceof ops.Retain) {
			const length2 = op2.length;

			if(length1 < length2) {
				/*
				 * Left can fit into the right retain, insert all of it and
				 * replace right with leftover retain count.
				 */

				delta.insert(value1);
				right.replace(new ops.Retain(length2 - length1));
			} else if(length1 > length2) {
				/*
				 * Left is longer than right. Insert substring of left and
				 * replace with rest of value.
				 */
				delta.insert(value1.substring(0, length2));

				left.replace(new ops.Insert(value1.substring(length2)));
			} else {
				// Both left and right have the same length
				delta.insert(value1);
			}

		} else if(op2 instanceof ops.Insert) {
			/*
			 * Two inserts, right is inserted first and the we handle left
			 * again.
			 */
			delta.insert(op2.value);
			left.back();
		} else if(op2 instanceof ops.Delete) {
			const value2 = op2.value;
			const length2 = value2.length;

			if(length1 > length2) {
				/*
				 * Left insert is longer than right delete, replace left with
				 * remaining text from left.
				 */
				left.replace(new ops.Insert(value1.substring(length2)));
			} else if(length1 < length2) {
				/*
				 * Left insert is shorther than right delete, replace right with
				 * remaining text from right.
				 */
				right.replace(new ops.Delete(value2.substring(length1)));
			} else {
				// Exact same length, do nothing as they cancel each other
			}
		}
	}

	function handleDelete(op1, op2) {
		const value1 = op1.value;
		const length1 = value1.length;

		if(op2 instanceof ops.Retain) {
			/*
			 * Right operation is a retain, delete left and back up one to
			 * handle right retain again.
			 */
			delta.delete(value1);

			right.back();
		} else if(op2 instanceof ops.Insert) {
			/*
			 * Right opreation is an insert, push left delete and right insert
			 * onto the delta.
			 */
			delta.delete(value1);
			delta.insert(op2.value);
		} else if(op2 instanceof ops.Delete) {
			/*
			 * Right operation is also a delete. Push left delete and handle
			 * right delete again.
			 */
			delta.delete(value1);
			right.back();
		}
	}

	while(left.hasNext && right.hasNext) {
		const op1 = left.next();
		const op2 = right.next();

		if(op1 instanceof ops.Retain) {
			handleRetain(op1, op2);
		} else if(op1 instanceof ops.Insert) {
			handleInsert(op1, op2);
		} else if(op1 instanceof ops.Delete) {
			handleDelete(op1, op2);
		}
	}

	if(left.hasNext) {
		throw 'Composition failure: Operation size mismatch';
	}

	while(right.hasNext) {
		const op2 = right.next();
		op2.apply(delta);
	}

	return delta.done();
};
<|endoftext|>


<commit_before>{% load i18n %}
{% load inventree_extras %}

/* globals
*/

/* exported
    inventreeGet,
    inventreeDelete,
    inventreeFormDataUpload,
    showApiError,
*/

$.urlParam = function(name) {
    // eslint-disable-next-line no-useless-escape
    var results = new RegExp('[\?&]' + name + '=([^&#]*)').exec(window.location.href);

    if (results == null) {
        return null;
    }

    return decodeURI(results[1]) || 0;
};

// using jQuery
function getCookie(name) {
    var cookieValue = null;
    if (document.cookie && document.cookie != '') {
        var cookies = document.cookie.split(';');
        for (var i = 0; i < cookies.length; i++) {
            var cookie = jQuery.trim(cookies[i]);
            // Does this cookie string begin with the name we want?
            if (cookie.substring(0, name.length + 1) == (name + '=')) {
                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                break;
            }
        }
    }
    return cookieValue;
}

function inventreeGet(url, filters={}, options={}) {

    // Middleware token required for data update
    var csrftoken = getCookie('csrftoken');

    return $.ajax({
        beforeSend: function(xhr) {
            xhr.setRequestHeader('X-CSRFToken', csrftoken);
        },
        url: url,
        type: 'GET',
        data: filters,
        dataType: 'json',
        contentType: 'application/json',
        async: (options.async == false) ? false : true,
        success: function(response) {
            if (options.success) {
                options.success(response);
            }
        },
        error: function(xhr, ajaxOptions, thrownError) {
            console.error('Error on GET at ' + url);

            if (thrownError) {
                console.error('Error: ' + thrownError);
            }

            if (options.error) {
                options.error({
                    error: thrownError
                });
            } else {
                showApiError(xhr, url);
            }
        }
    });
}

function inventreeFormDataUpload(url, data, options={}) {
    /* Upload via AJAX using the FormData approach.
     *
     * Note that the following AJAX parameters are required for FormData upload
     *
     * processData: false
     * contentType: false
     */

    // CSRF cookie token
    var csrftoken = getCookie('csrftoken');

    return $.ajax({
        beforeSend: function(xhr) {
            xhr.setRequestHeader('X-CSRFToken', csrftoken);
        },
        url: url,
        method: options.method || 'POST',
        data: data,
        processData: false,
        contentType: false,
        success: function(data, status, xhr) {
            if (options.success) {
                options.success(data, status, xhr);
            }
        },
        error: function(xhr, status, error) {
            console.error('Form data upload failure: ' + status);

            if (options.error) {
                options.error(xhr, status, error);
            } else {
                showApiError(xhr, url);
            }
        }
    });
}

function inventreePut(url, data={}, options={}) {

    var method = options.method || 'PUT';

    // Middleware token required for data update
    var csrftoken = getCookie('csrftoken');

    return $.ajax({
        beforeSend: function(xhr) {
            xhr.setRequestHeader('X-CSRFToken', csrftoken);
        },
        url: url,
        type: method,
        data: JSON.stringify(data),
        dataType: 'json',
        contentType: 'application/json',
        success: function(response, status) {
            if (options.success) {
                options.success(response, status);
            }
            if (options.reloadOnSuccess) {
                location.reload();
            }
        },
        error: function(xhr, ajaxOptions, thrownError) {
            if (options.error) {
                options.error(xhr, ajaxOptions, thrownError);
            } else {
                console.error(`Error on ${method} to '${url}' - STATUS ${xhr.status}`);
                console.error(thrownError);

                showApiError(xhr, url);
            }
        },
        complete: function(xhr, status) {
            if (options.complete) {
                options.complete(xhr, status);
            }
        }
    });
}

function inventreeDelete(url, options={}) {
    /*
     * Delete a record
     */

    options = options || {};

    options.method = 'DELETE';

    return inventreePut(url, {}, options);
}

/*
 * Display a notification with error information
 */
function showApiError(xhr, url) {

    var title = null;
    var message = null;

    if (xhr.statusText == 'abort') {
        // Don't show errors for requests which were intentionally aborted
        return;
    }

    switch (xhr.status || 0) {
    // No response
    case 0:
        title = '{% trans "No Response" %}';
        message = '{% trans "No response from the InvenTree server" %}';
        break;
    // Bad request
    case 400:
        // Note: Normally error code 400 is handled separately,
        //       and should now be shown here!
        title = '{% trans "Error 400: Bad request" %}';
        message = '{% trans "API request returned error code 400" %}';
        break;
    // Not authenticated
    case 401:
        title = '{% trans "Error 401: Not Authenticated" %}';
        message = '{% trans "Authentication credentials not supplied" %}';
        break;
    // Permission denied
    case 403:
        title = '{% trans "Error 403: Permission Denied" %}';
        message = '{% trans "You do not have the required permissions to access this function" %}';
        break;
    // Resource not found
    case 404:
        title = '{% trans "Error 404: Resource Not Found" %}';
        message = '{% trans "The requested resource could not be located on the server" %}';
        break;
    // Method not allowed
    case 405:
        title = '{% trans "Error 405: Method Not Allowed" %}';
        message = '{% trans "HTTP method not allowed at URL" %}';
        break;
    // Timeout
    case 408:
        title = '{% trans "Error 408: Timeout" %}';
        message = '{% trans "Connection timeout while requesting data from server" %}';
        break;
    default:
        title = '{% trans "Unhandled Error Code" %}';
        message = `{% trans "Error code" %}: ${xhr.status}`;
        break;
    }

    if (url) {
        message += '
';
        message += `URL: ${url}`;
    }

    showMessage(title, {
        style: 'danger',
        icon: 'fas fa-server icon-red',
        details: message,
    });
}
<commit_msg>Display API error information if available<commit_after>{% load i18n %}
{% load inventree_extras %}

/* globals
*/

/* exported
    inventreeGet,
    inventreeDelete,
    inventreeFormDataUpload,
    showApiError,
*/

$.urlParam = function(name) {
    // eslint-disable-next-line no-useless-escape
    var results = new RegExp('[\?&]' + name + '=([^&#]*)').exec(window.location.href);

    if (results == null) {
        return null;
    }

    return decodeURI(results[1]) || 0;
};

// using jQuery
function getCookie(name) {
    var cookieValue = null;
    if (document.cookie && document.cookie != '') {
        var cookies = document.cookie.split(';');
        for (var i = 0; i < cookies.length; i++) {
            var cookie = jQuery.trim(cookies[i]);
            // Does this cookie string begin with the name we want?
            if (cookie.substring(0, name.length + 1) == (name + '=')) {
                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                break;
            }
        }
    }
    return cookieValue;
}

function inventreeGet(url, filters={}, options={}) {

    // Middleware token required for data update
    var csrftoken = getCookie('csrftoken');

    return $.ajax({
        beforeSend: function(xhr) {
            xhr.setRequestHeader('X-CSRFToken', csrftoken);
        },
        url: url,
        type: 'GET',
        data: filters,
        dataType: 'json',
        contentType: 'application/json',
        async: (options.async == false) ? false : true,
        success: function(response) {
            if (options.success) {
                options.success(response);
            }
        },
        error: function(xhr, ajaxOptions, thrownError) {
            console.error('Error on GET at ' + url);

            if (thrownError) {
                console.error('Error: ' + thrownError);
            }

            if (options.error) {
                options.error({
                    error: thrownError
                });
            } else {
                showApiError(xhr, url);
            }
        }
    });
}

function inventreeFormDataUpload(url, data, options={}) {
    /* Upload via AJAX using the FormData approach.
     *
     * Note that the following AJAX parameters are required for FormData upload
     *
     * processData: false
     * contentType: false
     */

    // CSRF cookie token
    var csrftoken = getCookie('csrftoken');

    return $.ajax({
        beforeSend: function(xhr) {
            xhr.setRequestHeader('X-CSRFToken', csrftoken);
        },
        url: url,
        method: options.method || 'POST',
        data: data,
        processData: false,
        contentType: false,
        success: function(data, status, xhr) {
            if (options.success) {
                options.success(data, status, xhr);
            }
        },
        error: function(xhr, status, error) {
            console.error('Form data upload failure: ' + status);

            if (options.error) {
                options.error(xhr, status, error);
            } else {
                showApiError(xhr, url);
            }
        }
    });
}

function inventreePut(url, data={}, options={}) {

    var method = options.method || 'PUT';

    // Middleware token required for data update
    var csrftoken = getCookie('csrftoken');

    return $.ajax({
        beforeSend: function(xhr) {
            xhr.setRequestHeader('X-CSRFToken', csrftoken);
        },
        url: url,
        type: method,
        data: JSON.stringify(data),
        dataType: 'json',
        contentType: 'application/json',
        success: function(response, status) {
            if (options.success) {
                options.success(response, status);
            }
            if (options.reloadOnSuccess) {
                location.reload();
            }
        },
        error: function(xhr, ajaxOptions, thrownError) {
            if (options.error) {
                options.error(xhr, ajaxOptions, thrownError);
            } else {
                console.error(`Error on ${method} to '${url}' - STATUS ${xhr.status}`);
                console.error(thrownError);

                showApiError(xhr, url);
            }
        },
        complete: function(xhr, status) {
            if (options.complete) {
                options.complete(xhr, status);
            }
        }
    });
}

function inventreeDelete(url, options={}) {
    /*
     * Delete a record
     */

    options = options || {};

    options.method = 'DELETE';

    return inventreePut(url, {}, options);
}

/*
 * Display a notification with error information
 */
function showApiError(xhr, url) {

    var title = null;
    var message = null;

    if (xhr.statusText == 'abort') {
        // Don't show errors for requests which were intentionally aborted
        return;
    }

    switch (xhr.status || 0) {
    // No response
    case 0:
        title = '{% trans "No Response" %}';
        message = '{% trans "No response from the InvenTree server" %}';
        break;
    // Bad request
    case 400:
        // Note: Normally error code 400 is handled separately,
        //       and should now be shown here!
        title = '{% trans "Error 400: Bad request" %}';
        message = '{% trans "API request returned error code 400" %}';
        break;
    // Not authenticated
    case 401:
        title = '{% trans "Error 401: Not Authenticated" %}';
        message = '{% trans "Authentication credentials not supplied" %}';
        break;
    // Permission denied
    case 403:
        title = '{% trans "Error 403: Permission Denied" %}';
        message = '{% trans "You do not have the required permissions to access this function" %}';
        break;
    // Resource not found
    case 404:
        title = '{% trans "Error 404: Resource Not Found" %}';
        message = '{% trans "The requested resource could not be located on the server" %}';
        break;
    // Method not allowed
    case 405:
        title = '{% trans "Error 405: Method Not Allowed" %}';
        message = '{% trans "HTTP method not allowed at URL" %}';
        break;
    // Timeout
    case 408:
        title = '{% trans "Error 408: Timeout" %}';
        message = '{% trans "Connection timeout while requesting data from server" %}';
        break;
    default:
        title = '{% trans "Unhandled Error Code" %}';
        message = `{% trans "Error code" %}: ${xhr.status}`;

        var response = xhr.responseJSON;

        // The server may have provided some extra information about this error
        if (response) {
            if (response.error) {
                title = response.error
            }

            if (response.detail) {
                message = response.detail;
            }
        }

        break;
    }

    if (url) {
        message += '
';
        message += `URL: ${url}`;
    }

    showMessage(title, {
        style: 'danger',
        icon: 'fas fa-server icon-red',
        details: message,
    });
}
<|endoftext|>


<commit_before>/*
 * jQuery YQL plugin
 *
 * Copyright (c) 2010 Gabriel Falcão
 * Copyright (c) 2010 Lincoln de Sousa
 * Dual licensed under GPL 3+ license.
 *
 * http://www.gnu.org/copyleft/gpl.html
 *
 * Version: 0.2
 */

(function($){
     $.extend(
         {
             _prepareYQLQuery: function (query, params) {
                     $.each(
                         params, function (key) {
                             var name = "#{" + key + "}";
                             var value = this;
                             if (isNaN(parseInt(value))) {
                                 value = '"' + value + '"';
                             }
                             query = query.replace(name, value);
                         }
                     );
                 return query;
             },
             yql: function (query) {
                 var $self = this;
                 var params = {};
                 var successCallback = null;

                 if (typeof arguments[1] == 'object') {
                     query = $self._prepareYQLQuery(query, arguments[1]);
                     successCallback = arguments[2];
                 } else if (typeof arguments[1] == 'function') {
                     successCallback = arguments[1];
                 }

                 var doAsynchronously = successCallback != null;

                 $.ajax(
                     {
                         url: "http://query.yahooapis.com/v1/public/yql",
                         dataType: "jsonp",
                         success: successCallback,
                         async: doAsynchronously,
                         data: {
                             q: query,
                             format: "json",
                             env: 'store://datatables.org/alltableswithkeys',
                             callback: "?"
                         }
                     }
                 );
                 return $self.toReturn;
             }
         }
     );
 })(jQuery);
<commit_msg>using new version of jquery.yql<commit_after>/*
 * jQuery YQL plugin
 *
 * Copyright (c) 2010 Gabriel Falcão
 * Copyright (c) 2010 Lincoln de Sousa
 * Dual licensed under GPL 3+ license.
 *
 * http://www.gnu.org/copyleft/gpl.html
 *
 * Version: 0.2.1
 */

(function($){
     $.extend(
         {
             _prepareYQLQuery: function (query, params) {
                     $.each(
                         params, function (key) {
                             var name = "#{" + key + "}";
                             var value = $.trim(this);
                             if (!value.match(/^[0-9]+$/)) {
                                 value = '"' + value + '"';
                             }
                             query = query.replace(name, value);
                         }
                     );
                 return query;
             },
             yql: function (query) {
                 var $self = this;
                 var successCallback = null;

                 if (typeof arguments[1] == 'object') {
                     query = $self._prepareYQLQuery(query, arguments[1]);
                     successCallback = arguments[2];
                 } else if (typeof arguments[1] == 'function') {
                     successCallback = arguments[1];
                 }

                 var doAsynchronously = successCallback != null;

                 $.ajax(
                     {
                         url: "http://query.yahooapis.com/v1/public/yql",
                         dataType: "jsonp",
                         success: successCallback,
                         async: doAsynchronously,
                         data: {
                             q: query,
                             format: "json",
                             env: 'store://datatables.org/alltableswithkeys',
                             callback: "?"
                         }
                     }
                 );
                 return $self.toReturn;
             }
         }
     );
 })(jQuery);
<|endoftext|>


<commit_before>/**
 * Copyright 2004-present Facebook. All Rights Reserved.
 *
 * @providesModule deepDiffer
 * @flow
 */
'use strict';

/*
 * @returns {bool} true if different, false if equal
 */
var deepDiffer = function(one: any, two: any): bool {
  if (one === two) {
    // Short circuit on identical object references instead of traversing them.
    return false;
  }
  if ((typeof one === 'function') && (typeof two === 'function')) {
    // We consider all functions equal
    return false;
  }
  if ((typeof one !== 'object') || (one === null)) {
    // Primitives can be directly compared
    return one !== two;
  }
  if ((typeof two !== 'object') || (two === null)) {
    // We know they are different because the previous case would have triggered
    // otherwise.
    return true;
  }
  if (one.constructor !== two.constructor) {
    return true;
  }
  for (var key in one) {
    if (deepDiffer(one[key], two[key])) {
      return true;
    }
  }
  for (var twoKey in two) {
    // The only case we haven't checked yet is keys that are in two but aren't
    // in one, which means they are different.
    if (one[twoKey] === undefined) {
      return true;
    }
  }
  return false;
};

module.exports = deepDiffer;
<commit_msg>deepDiffer should support explicitly undefined values<commit_after>/**
 * Copyright 2004-present Facebook. All Rights Reserved.
 *
 * @providesModule deepDiffer
 * @flow
 */
'use strict';

/*
 * @returns {bool} true if different, false if equal
 */
var deepDiffer = function(one: any, two: any): bool {
  if (one === two) {
    // Short circuit on identical object references instead of traversing them.
    return false;
  }
  if ((typeof one === 'function') && (typeof two === 'function')) {
    // We consider all functions equal
    return false;
  }
  if ((typeof one !== 'object') || (one === null)) {
    // Primitives can be directly compared
    return one !== two;
  }
  if ((typeof two !== 'object') || (two === null)) {
    // We know they are different because the previous case would have triggered
    // otherwise.
    return true;
  }
  if (one.constructor !== two.constructor) {
    return true;
  }
  for (var key in one) {
    if (deepDiffer(one[key], two[key])) {
      return true;
    }
  }
  for (var twoKey in two) {
    // The only case we haven't checked yet is keys that are in two but aren't
    // in one, which means they are different.
    if (one[twoKey] === undefined && two[twoKey] !== undefined) {
      return true;
    }
  }
  return false;
};

module.exports = deepDiffer;
<|endoftext|>


<commit_before>/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @format
 * @noflow
 * @typecheck
 */

'use strict';

const EmitterSubscription = require('EmitterSubscription');
const EventSubscriptionVendor = require('EventSubscriptionVendor');

const invariant = require('invariant');

/**
 * @class EventEmitter
 * @description
 * An EventEmitter is responsible for managing a set of listeners and publishing
 * events to them when it is told that such events happened. In addition to the
 * data for the given event it also sends a event control object which allows
 * the listeners/handlers to prevent the default behavior of the given event.
 *
 * The emitter is designed to be generic enough to support all the different
 * contexts in which one might want to emit events. It is a simple multicast
 * mechanism on top of which extra functionality can be composed. For example, a
 * more advanced emitter may use an EventHolder and EventFactory.
 */
class EventEmitter {
  _subscriber: EventSubscriptionVendor;
  _currentSubscription: ?EmitterSubscription;

  /**
   * @constructor
   *
   * @param {EventSubscriptionVendor} subscriber - Optional subscriber instance
   *   to use. If omitted, a new subscriber will be created for the emitter.
   */
  constructor(subscriber: ?EventSubscriptionVendor) {
    this._subscriber = subscriber || new EventSubscriptionVendor();
  }

  /**
   * Adds a listener to be invoked when events of the specified type are
   * emitted. An optional calling context may be provided. The data arguments
   * emitted will be passed to the listener function.
   *
   * TODO: Annotate the listener arg's type. This is tricky because listeners
   *       can be invoked with varargs.
   *
   * @param {string} eventType - Name of the event to listen to
   * @param {function} listener - Function to invoke when the specified event is
   *   emitted
   * @param {*} context - Optional context object to use when invoking the
   *   listener
   */
  addListener(
    eventType: string,
    listener: Function,
    context: ?Object,
  ): EmitterSubscription {
    return (this._subscriber.addSubscription(
      eventType,
      new EmitterSubscription(this, this._subscriber, listener, context),
    ): any);
  }

  /**
   * Similar to addListener, except that the listener is removed after it is
   * invoked once.
   *
   * @param {string} eventType - Name of the event to listen to
   * @param {function} listener - Function to invoke only once when the
   *   specified event is emitted
   * @param {*} context - Optional context object to use when invoking the
   *   listener
   */
  once(
    eventType: string,
    listener: Function,
    context: ?Object,
  ): EmitterSubscription {
    return this.addListener(eventType, (...args) => {
      this.removeCurrentListener();
      listener.apply(context, args);
    });
  }

  /**
   * Removes all of the registered listeners, including those registered as
   * listener maps.
   *
   * @param {?string} eventType - Optional name of the event whose registered
   *   listeners to remove
   */
  removeAllListeners(eventType: ?string) {
    this._subscriber.removeAllSubscriptions(eventType);
  }

  /**
   * Provides an API that can be called during an eventing cycle to remove the
   * last listener that was invoked. This allows a developer to provide an event
   * object that can remove the listener (or listener map) during the
   * invocation.
   *
   * If it is called when not inside of an emitting cycle it will throw.
   *
   * @throws {Error} When called not during an eventing cycle
   *
   * @example
   *   var subscription = emitter.addListenerMap({
   *     someEvent: function(data, event) {
   *       console.log(data);
   *       emitter.removeCurrentListener();
   *     }
   *   });
   *
   *   emitter.emit('someEvent', 'abc'); // logs 'abc'
   *   emitter.emit('someEvent', 'def'); // does not log anything
   */
  removeCurrentListener() {
    invariant(
      !!this._currentSubscription,
      'Not in an emitting cycle; there is no current subscription',
    );
    this.removeSubscription(this._currentSubscription);
  }

  /**
   * Removes a specific subscription. Called by the `remove()` method of the
   * subscription itself to ensure any necessary cleanup is performed.
   */
  removeSubscription(subscription: EmitterSubscription) {
    invariant(
      subscription.emitter === this,
      'Subscription does not belong to this emitter.',
    );
    this._subscriber.removeSubscription(subscription);
  }

  /**
   * Returns an array of listeners that are currently registered for the given
   * event.
   *
   * @param {string} eventType - Name of the event to query
   * @returns {array}
   */
  listeners(eventType: string): [EmitterSubscription] {
    const subscriptions = this._subscriber.getSubscriptionsForType(eventType);
    return subscriptions
      ? subscriptions.map(subscription => subscription.listener)
      : [];
  }

  /**
   * Emits an event of the given type with the given data. All handlers of that
   * particular type will be notified.
   *
   * @param {string} eventType - Name of the event to emit
   * @param {...*} Arbitrary arguments to be passed to each registered listener
   *
   * @example
   *   emitter.addListener('someEvent', function(message) {
   *     console.log(message);
   *   });
   *
   *   emitter.emit('someEvent', 'abc'); // logs 'abc'
   */
  emit(eventType: string) {
    const subscriptions = this._subscriber.getSubscriptionsForType(eventType);
    if (subscriptions) {
      for (let i = 0, l = subscriptions.length; i < l; i++) {
        const subscription = subscriptions[i];

        // The subscription may have been removed during this event loop.
        if (subscription) {
          this._currentSubscription = subscription;
          subscription.listener.apply(
            subscription.context,
            Array.prototype.slice.call(arguments, 1),
          );
        }
      }
      this._currentSubscription = null;
    }
  }

  /**
   * Removes the given listener for event of specific type.
   *
   * @param {string} eventType - Name of the event to emit
   * @param {function} listener - Function to invoke when the specified event is
   *   emitted
   *
   * @example
   *   emitter.removeListener('someEvent', function(message) {
   *     console.log(message);
   *   }); // removes the listener if already registered
   *
   */
  removeListener(eventType: String, listener) {
    const subscriptions = this._subscriber.getSubscriptionsForType(eventType);
    if (subscriptions) {
      for (let i = 0, l = subscriptions.length; i < l; i++) {
        const subscription = subscriptions[i];

        // The subscription may have been removed during this event loop.
        // its listener matches the listener in method parameters
        if (subscription && subscription.listener === listener) {
          subscription.remove();
        }
      }
    }
  }
}

module.exports = EventEmitter;
<commit_msg>Update EventEmitter.js (#23047)<commit_after>/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @format
 * @noflow
 * @typecheck
 */

'use strict';

const EmitterSubscription = require('EmitterSubscription');
const EventSubscriptionVendor = require('EventSubscriptionVendor');

const invariant = require('invariant');

/**
 * @class EventEmitter
 * @description
 * An EventEmitter is responsible for managing a set of listeners and publishing
 * events to them when it is told that such events happened. In addition to the
 * data for the given event it also sends a event control object which allows
 * the listeners/handlers to prevent the default behavior of the given event.
 *
 * The emitter is designed to be generic enough to support all the different
 * contexts in which one might want to emit events. It is a simple multicast
 * mechanism on top of which extra functionality can be composed. For example, a
 * more advanced emitter may use an EventHolder and EventFactory.
 */
class EventEmitter {
  _subscriber: EventSubscriptionVendor;
  _currentSubscription: ?EmitterSubscription;

  /**
   * @constructor
   *
   * @param {EventSubscriptionVendor} subscriber - Optional subscriber instance
   *   to use. If omitted, a new subscriber will be created for the emitter.
   */
  constructor(subscriber: ?EventSubscriptionVendor) {
    this._subscriber = subscriber || new EventSubscriptionVendor();
  }

  /**
   * Adds a listener to be invoked when events of the specified type are
   * emitted. An optional calling context may be provided. The data arguments
   * emitted will be passed to the listener function.
   *
   * TODO: Annotate the listener arg's type. This is tricky because listeners
   *       can be invoked with varargs.
   *
   * @param {string} eventType - Name of the event to listen to
   * @param {function} listener - Function to invoke when the specified event is
   *   emitted
   * @param {*} context - Optional context object to use when invoking the
   *   listener
   */
  addListener(
    eventType: string,
    listener: Function,
    context: ?Object,
  ): EmitterSubscription {
    return (this._subscriber.addSubscription(
      eventType,
      new EmitterSubscription(this, this._subscriber, listener, context),
    ): any);
  }

  /**
   * Similar to addListener, except that the listener is removed after it is
   * invoked once.
   *
   * @param {string} eventType - Name of the event to listen to
   * @param {function} listener - Function to invoke only once when the
   *   specified event is emitted
   * @param {*} context - Optional context object to use when invoking the
   *   listener
   */
  once(
    eventType: string,
    listener: Function,
    context: ?Object,
  ): EmitterSubscription {
    return this.addListener(eventType, (...args) => {
      this.removeCurrentListener();
      listener.apply(context, args);
    });
  }

  /**
   * Removes all of the registered listeners, including those registered as
   * listener maps.
   *
   * @param {?string} eventType - Optional name of the event whose registered
   *   listeners to remove
   */
  removeAllListeners(eventType: ?string) {
    this._subscriber.removeAllSubscriptions(eventType);
  }

  /**
   * Provides an API that can be called during an eventing cycle to remove the
   * last listener that was invoked. This allows a developer to provide an event
   * object that can remove the listener (or listener map) during the
   * invocation.
   *
   * If it is called when not inside of an emitting cycle it will throw.
   *
   * @throws {Error} When called not during an eventing cycle
   *
   * @example
   *   var subscription = emitter.addListenerMap({
   *     someEvent: function(data, event) {
   *       console.log(data);
   *       emitter.removeCurrentListener();
   *     }
   *   });
   *
   *   emitter.emit('someEvent', 'abc'); // logs 'abc'
   *   emitter.emit('someEvent', 'def'); // does not log anything
   */
  removeCurrentListener() {
    invariant(
      !!this._currentSubscription,
      'Not in an emitting cycle; there is no current subscription',
    );
    this.removeSubscription(this._currentSubscription);
  }

  /**
   * Removes a specific subscription. Called by the `remove()` method of the
   * subscription itself to ensure any necessary cleanup is performed.
   */
  removeSubscription(subscription: EmitterSubscription) {
    invariant(
      subscription.emitter === this,
      'Subscription does not belong to this emitter.',
    );
    this._subscriber.removeSubscription(subscription);
  }

  /**
   * Returns an array of listeners that are currently registered for the given
   * event.
   *
   * @param {string} eventType - Name of the event to query
   * @returns {array}
   */
  listeners(eventType: string): [EmitterSubscription] {
    const subscriptions = this._subscriber.getSubscriptionsForType(eventType);
    return subscriptions
      ? subscriptions.map(subscription => subscription.listener)
      : [];
  }

  /**
   * Emits an event of the given type with the given data. All handlers of that
   * particular type will be notified.
   *
   * @param {string} eventType - Name of the event to emit
   * @param {...*} Arbitrary arguments to be passed to each registered listener
   *
   * @example
   *   emitter.addListener('someEvent', function(message) {
   *     console.log(message);
   *   });
   *
   *   emitter.emit('someEvent', 'abc'); // logs 'abc'
   */
  emit(eventType: string) {
    const subscriptions = this._subscriber.getSubscriptionsForType(eventType);
    if (subscriptions) {
      for (let i = 0, l = subscriptions.length; i < l; i++) {
        const subscription = subscriptions[i];

        // The subscription may have been removed during this event loop.
        if (subscription && subscription.listener) {
          this._currentSubscription = subscription;
          subscription.listener.apply(
            subscription.context,
            Array.prototype.slice.call(arguments, 1),
          );
        }
      }
      this._currentSubscription = null;
    }
  }

  /**
   * Removes the given listener for event of specific type.
   *
   * @param {string} eventType - Name of the event to emit
   * @param {function} listener - Function to invoke when the specified event is
   *   emitted
   *
   * @example
   *   emitter.removeListener('someEvent', function(message) {
   *     console.log(message);
   *   }); // removes the listener if already registered
   *
   */
  removeListener(eventType: String, listener) {
    const subscriptions = this._subscriber.getSubscriptionsForType(eventType);
    if (subscriptions) {
      for (let i = 0, l = subscriptions.length; i < l; i++) {
        const subscription = subscriptions[i];

        // The subscription may have been removed during this event loop.
        // its listener matches the listener in method parameters
        if (subscription && subscription.listener === listener) {
          subscription.remove();
        }
      }
    }
  }
}

module.exports = EventEmitter;
<|endoftext|>


<commit_before>// Copyright 2016 Google Inc.
//
// 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.

(function() {
  'use strict';

  var app = {
    isLoading: true,
    visibleCards: {},
    selectedCities: [],
    spinner: document.querySelector('.loader'),
    cardTemplate: document.querySelector('.cardTemplate'),
    container: document.querySelector('.main'),
    addDialog: document.querySelector('.dialog-container'),
    daysOfWeek: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
  };

  /*****************************************************************************
   *
   * Event listeners for UI elements
   *
   ****************************************************************************/

  document.getElementById('butRefresh').addEventListener('click', function() {
    // Refresh all of the forecasts
    app.updateForecasts();
  });

  document.getElementById('butAdd').addEventListener('click', function() {
    // Open/show the add new city dialog
    app.toggleAddDialog(true);
  });

  document.getElementById('butAddCity').addEventListener('click', function() {
    // Add the newly selected city
    var select = document.getElementById('selectCityToAdd');
    var selected = select.options[select.selectedIndex];
    var key = selected.value;
    var label = selected.textContent;
    // TODO init the app.selectedCities array here
    app.getForecast(key, label);
    // TODO push the selected city to the array and save here
    app.toggleAddDialog(false);
  });

  document.getElementById('butAddCancel').addEventListener('click', function() {
    // Close the add new city dialog
    app.toggleAddDialog(false);
  });

  /*****************************************************************************
   *
   * Methods to update/refresh the UI
   *
   ****************************************************************************/

  // Toggles the visibility of the add new city dialog.
  app.toggleAddDialog = function(visible) {
    if (visible) {
      app.addDialog.classList.add('dialog-container--visible');
    } else {
      app.addDialog.classList.remove('dialog-container--visible');
    }
  };

  // Updates a weather card with the latest weather forecast. If the card
  // doesn't already exist, it's cloned from the template.
  app.updateForecastCard = function(data) {
    var dataLastUpdated = new Date(data.created);
    var sunrise = data.channel.astronomy.sunrise;
    var sunset = data.channel.astronomy.sunset;
    var current = data.channel.item.condition;
    var humidity = data.channel.atmosphere.humidity;
    var wind = data.channel.wind;

    var card = app.visibleCards[data.key];
    if (!card) {
      card = app.cardTemplate.cloneNode(true);
      card.classList.remove('cardTemplate');
      card.querySelector('.location').textContent = data.label;
      card.removeAttribute('hidden');
      app.container.appendChild(card);
      app.visibleCards[data.key] = card;
    }

    // Verifies the data provide is newer than what's already visible
    // on the card, if it's not bail, if it is, continue and update the
    // time saved in the card
    var cardLastUpdatedElem = card.querySelector('.card-last-updated');
    var cardLastUpdated = cardLastUpdatedElem.textContent;
    if (cardLastUpdated) {
      cardLastUpdated = new Date(cardLastUpdated);
      // Bail if the card has more recent data then the data
      if (dataLastUpdated.getTime() < cardLastUpdated.getTime()) {
        return;
      }
    }
    cardLastUpdatedElem.textContent = data.created;

    card.querySelector('.description').textContent = current.text;
    card.querySelector('.date').textContent = current.date;
    card.querySelector('.current .icon').classList.add(app.getIconClass(current.code));
    card.querySelector('.current .temperature .value').textContent =
      Math.round(current.temp);
    card.querySelector('.current .sunrise').textContent = sunrise;
    card.querySelector('.current .sunset').textContent = sunset;
    card.querySelector('.current .humidity').textContent =
      Math.round(humidity) + '%';
    card.querySelector('.current .wind .value').textContent =
      Math.round(wind.speed);
    card.querySelector('.current .wind .direction').textContent = wind.direction;
    var nextDays = card.querySelectorAll('.future .oneday');
    var today = new Date();
    today = today.getDay();
    for (var i = 0; i < 7; i++) {
      var nextDay = nextDays[i];
      var daily = data.channel.item.forecast[i];
      if (daily && nextDay) {
        nextDay.querySelector('.date').textContent =
          app.daysOfWeek[(i + today) % 7];
        nextDay.querySelector('.icon').classList.add(app.getIconClass(daily.code));
        nextDay.querySelector('.temp-high .value').textContent =
          Math.round(daily.high);
        nextDay.querySelector('.temp-low .value').textContent =
          Math.round(daily.low);
      }
    }
    if (app.isLoading) {
      app.spinner.setAttribute('hidden', true);
      app.container.removeAttribute('hidden');
      app.isLoading = false;
    }
  };

  /*****************************************************************************
   *
   * Methods for dealing with the model
   *
   ****************************************************************************/

  /*
   * Gets a forecast for a specific city and updates the card with the data.
   * getForecast() first checks if the weather data is in the cache. If so,
   * then it gets that data and populates the card with the cached data.
   * Then, getForecast() goes to the network for fresh data. If the network
   * request goes through, then the card gets updated a second time with the
   * freshest data.
   */
  app.getForecast = function(key, label) {
    var statement = 'select * from weather.forecast where woeid=' + key;
    var url = 'https://query.yahooapis.com/v1/public/yql?format=json&q=' +
        statement;
    // TODO add cache logic here

    // Fetch the latest data.
    var request = new XMLHttpRequest();
    request.onreadystatechange = function() {
      if (request.readyState === XMLHttpRequest.DONE) {
        if (request.status === 200) {
          var response = JSON.parse(request.response);
          var results = response.query.results;
          results.key = key;
          results.label = label;
          results.created = response.query.created;
          app.updateForecastCard(results);
        }
      } else {
        // Return the initial weather forecast since no data is available.
        app.updateForecastCard(initialWeatherForecast);
      }
    };
    request.open('GET', url);
    request.send();
  };

  // Iterate all of the cards and attempt to get the latest forecast data
  app.updateForecasts = function() {
    var keys = Object.keys(app.visibleCards);
    keys.forEach(function(key) {
      app.getForecast(key);
    });
  };

  // TODO add saveSelectedCities function here

  app.getIconClass = function(weatherCode) {
    // Weather codes: https://developer.yahoo.com/weather/documentation.html#codes
    weatherCode = parseInt(weatherCode);
    switch (weatherCode) {
      case 25: // cold
      case 32: // sunny
      case 33: // fair (night)
      case 34: // fair (day)
      case 36: // hot
      case 3200: // not available
        return 'clear-day';
      case 0: // tornado
      case 1: // tropical storm
      case 2: // hurricane
      case 6: // mixed rain and sleet
      case 8: // freezing drizzle
      case 9: // drizzle
      case 10: // freezing rain
      case 11: // showers
      case 12: // showers
      case 17: // hail
      case 35: // mixed rain and hail
      case 40: // scattered showers
        return 'rain';
      case 3: // severe thunderstorms
      case 4: // thunderstorms
      case 37: // isolated thunderstorms
      case 38: // scattered thunderstorms
      case 39: // scattered thunderstorms (not a typo)
      case 45: // thundershowers
      case 47: // isolated thundershowers
        return 'thunderstorms';
      case 5: // mixed rain and snow
      case 7: // mixed snow and sleet
      case 13: // snow flurries
      case 14: // light snow showers
      case 16: // snow
      case 18: // sleet
      case 41: // heavy snow
      case 42: // scattered snow showers
      case 43: // heavy snow
      case 46: // snow showers
        return 'snow';
      case 15: // blowing snow
      case 19: // dust
      case 20: // foggy
      case 21: // haze
      case 22: // smoky
        return 'fog';
      case 24: // windy
      case 23: // blustery
        return 'windy';
      case 26: // cloudy
      case 27: // mostly cloudy (night)
      case 28: // mostly cloudy (day)
      case 31: // clear (night)
        return 'cloudy';
      case 29: // partly cloudy (night)
      case 30: // partly cloudy (day)
      case 44: // partly cloudy
        return 'partly-cloudy-day';
    }
  };

  /*
   * Fake weather data that is presented when the user first uses the app,
   * or when the user has not saved any cities. See startup code for more
   * discussion.
   */
  var initialWeatherForecast = {
    key: '2459115',
    label: 'New York, NY',
    created: '2016-07-22T01:00:00Z',
    channel: {
      astronomy: {
        sunrise: "5:43 am",
        sunset: "8:21 pm"
      },
      item: {
        condition: {
          text: "Windy",
          date: "Thu, 21 Jul 2016 09:00 PM EDT",
          temp: 56,
          code: 24
        },
        forecast: [
          {code: 44, high: 86, low: 70},
          {code: 44, high: 94, low: 73},
          {code: 4, high: 95, low: 78},
          {code: 24, high: 75, low: 89},
          {code: 24, high: 89, low: 77},
          {code: 44, high: 92, low: 79},
          {code: 44, high: 89, low: 77}
        ]
      },
      atmosphere: {
        humidity: 56
      },
      wind: {
        speed: 25,
        direction: 195
      }
    }
  };

  // TODO add startup code here

  // TODO add service worker code here
})();
<commit_msg>add city list persistence and startup code<commit_after>// Copyright 2016 Google Inc.
//
// 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.

(function() {
  'use strict';

  var app = {
    isLoading: true,
    visibleCards: {},
    selectedCities: [],
    spinner: document.querySelector('.loader'),
    cardTemplate: document.querySelector('.cardTemplate'),
    container: document.querySelector('.main'),
    addDialog: document.querySelector('.dialog-container'),
    daysOfWeek: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
  };

  /*****************************************************************************
   *
   * Event listeners for UI elements
   *
   ****************************************************************************/

  document.getElementById('butRefresh').addEventListener('click', function() {
    // Refresh all of the forecasts
    app.updateForecasts();
  });

  document.getElementById('butAdd').addEventListener('click', function() {
    // Open/show the add new city dialog
    app.toggleAddDialog(true);
  });

  document.getElementById('butAddCity').addEventListener('click', function() {
    // Add the newly selected city
    var select = document.getElementById('selectCityToAdd');
    var selected = select.options[select.selectedIndex];
    var key = selected.value;
    var label = selected.textContent;
    // TODO init the app.selectedCities array here
    app.getForecast(key, label);
    // TODO push the selected city to the array and save here
    app.toggleAddDialog(false);
  });

  document.getElementById('butAddCancel').addEventListener('click', function() {
    // Close the add new city dialog
    app.toggleAddDialog(false);
  });

  /*****************************************************************************
   *
   * Methods to update/refresh the UI
   *
   ****************************************************************************/

  // Toggles the visibility of the add new city dialog.
  app.toggleAddDialog = function(visible) {
    if (visible) {
      app.addDialog.classList.add('dialog-container--visible');
    } else {
      app.addDialog.classList.remove('dialog-container--visible');
    }
  };

  // Updates a weather card with the latest weather forecast. If the card
  // doesn't already exist, it's cloned from the template.
  app.updateForecastCard = function(data) {
    var dataLastUpdated = new Date(data.created);
    var sunrise = data.channel.astronomy.sunrise;
    var sunset = data.channel.astronomy.sunset;
    var current = data.channel.item.condition;
    var humidity = data.channel.atmosphere.humidity;
    var wind = data.channel.wind;

    var card = app.visibleCards[data.key];
    if (!card) {
      card = app.cardTemplate.cloneNode(true);
      card.classList.remove('cardTemplate');
      card.querySelector('.location').textContent = data.label;
      card.removeAttribute('hidden');
      app.container.appendChild(card);
      app.visibleCards[data.key] = card;
    }

    // Verifies the data provide is newer than what's already visible
    // on the card, if it's not bail, if it is, continue and update the
    // time saved in the card
    var cardLastUpdatedElem = card.querySelector('.card-last-updated');
    var cardLastUpdated = cardLastUpdatedElem.textContent;
    if (cardLastUpdated) {
      cardLastUpdated = new Date(cardLastUpdated);
      // Bail if the card has more recent data then the data
      if (dataLastUpdated.getTime() < cardLastUpdated.getTime()) {
        return;
      }
    }
    cardLastUpdatedElem.textContent = data.created;

    card.querySelector('.description').textContent = current.text;
    card.querySelector('.date').textContent = current.date;
    card.querySelector('.current .icon').classList.add(app.getIconClass(current.code));
    card.querySelector('.current .temperature .value').textContent =
      Math.round(current.temp);
    card.querySelector('.current .sunrise').textContent = sunrise;
    card.querySelector('.current .sunset').textContent = sunset;
    card.querySelector('.current .humidity').textContent =
      Math.round(humidity) + '%';
    card.querySelector('.current .wind .value').textContent =
      Math.round(wind.speed);
    card.querySelector('.current .wind .direction').textContent = wind.direction;
    var nextDays = card.querySelectorAll('.future .oneday');
    var today = new Date();
    today = today.getDay();
    for (var i = 0; i < 7; i++) {
      var nextDay = nextDays[i];
      var daily = data.channel.item.forecast[i];
      if (daily && nextDay) {
        nextDay.querySelector('.date').textContent =
          app.daysOfWeek[(i + today) % 7];
        nextDay.querySelector('.icon').classList.add(app.getIconClass(daily.code));
        nextDay.querySelector('.temp-high .value').textContent =
          Math.round(daily.high);
        nextDay.querySelector('.temp-low .value').textContent =
          Math.round(daily.low);
      }
    }
    if (app.isLoading) {
      app.spinner.setAttribute('hidden', true);
      app.container.removeAttribute('hidden');
      app.isLoading = false;
    }
  };

  /*****************************************************************************
   *
   * Methods for dealing with the model
   *
   ****************************************************************************/

  /*
   * Gets a forecast for a specific city and updates the card with the data.
   * getForecast() first checks if the weather data is in the cache. If so,
   * then it gets that data and populates the card with the cached data.
   * Then, getForecast() goes to the network for fresh data. If the network
   * request goes through, then the card gets updated a second time with the
   * freshest data.
   */
  app.getForecast = function(key, label) {
    var statement = 'select * from weather.forecast where woeid=' + key;
    var url = 'https://query.yahooapis.com/v1/public/yql?format=json&q=' +
        statement;
    // TODO add cache logic here

    // Fetch the latest data.
    var request = new XMLHttpRequest();
    request.onreadystatechange = function() {
      if (request.readyState === XMLHttpRequest.DONE) {
        if (request.status === 200) {
          var response = JSON.parse(request.response);
          var results = response.query.results;
          results.key = key;
          results.label = label;
          results.created = response.query.created;
          app.updateForecastCard(results);
        }
      } else {
        // Return the initial weather forecast since no data is available.
        app.updateForecastCard(initialWeatherForecast);
      }
    };
    request.open('GET', url);
    request.send();
  };

  // Iterate all of the cards and attempt to get the latest forecast data
  app.updateForecasts = function() {
    var keys = Object.keys(app.visibleCards);
    keys.forEach(function(key) {
      app.getForecast(key);
    });
  };

  // Save list of cities to localStorage.
  app.saveSelectedCities = function() {
    var selectedCities = JSON.stringify(app.selectedCities);
    localStorage.selectedCities = selectedCities;
  };

  app.getIconClass = function(weatherCode) {
    // Weather codes: https://developer.yahoo.com/weather/documentation.html#codes
    weatherCode = parseInt(weatherCode);
    switch (weatherCode) {
      case 25: // cold
      case 32: // sunny
      case 33: // fair (night)
      case 34: // fair (day)
      case 36: // hot
      case 3200: // not available
        return 'clear-day';
      case 0: // tornado
      case 1: // tropical storm
      case 2: // hurricane
      case 6: // mixed rain and sleet
      case 8: // freezing drizzle
      case 9: // drizzle
      case 10: // freezing rain
      case 11: // showers
      case 12: // showers
      case 17: // hail
      case 35: // mixed rain and hail
      case 40: // scattered showers
        return 'rain';
      case 3: // severe thunderstorms
      case 4: // thunderstorms
      case 37: // isolated thunderstorms
      case 38: // scattered thunderstorms
      case 39: // scattered thunderstorms (not a typo)
      case 45: // thundershowers
      case 47: // isolated thundershowers
        return 'thunderstorms';
      case 5: // mixed rain and snow
      case 7: // mixed snow and sleet
      case 13: // snow flurries
      case 14: // light snow showers
      case 16: // snow
      case 18: // sleet
      case 41: // heavy snow
      case 42: // scattered snow showers
      case 43: // heavy snow
      case 46: // snow showers
        return 'snow';
      case 15: // blowing snow
      case 19: // dust
      case 20: // foggy
      case 21: // haze
      case 22: // smoky
        return 'fog';
      case 24: // windy
      case 23: // blustery
        return 'windy';
      case 26: // cloudy
      case 27: // mostly cloudy (night)
      case 28: // mostly cloudy (day)
      case 31: // clear (night)
        return 'cloudy';
      case 29: // partly cloudy (night)
      case 30: // partly cloudy (day)
      case 44: // partly cloudy
        return 'partly-cloudy-day';
    }
  };

  /*
   * Fake weather data that is presented when the user first uses the app,
   * or when the user has not saved any cities. See startup code for more
   * discussion.
   */
  var initialWeatherForecast = {
    key: '2459115',
    label: 'New York, NY',
    created: '2016-07-22T01:00:00Z',
    channel: {
      astronomy: {
        sunrise: "5:43 am",
        sunset: "8:21 pm"
      },
      item: {
        condition: {
          text: "Windy",
          date: "Thu, 21 Jul 2016 09:00 PM EDT",
          temp: 56,
          code: 24
        },
        forecast: [
          {code: 44, high: 86, low: 70},
          {code: 44, high: 94, low: 73},
          {code: 4, high: 95, low: 78},
          {code: 24, high: 75, low: 89},
          {code: 24, high: 89, low: 77},
          {code: 44, high: 92, low: 79},
          {code: 44, high: 89, low: 77}
        ]
      },
      atmosphere: {
        humidity: 56
      },
      wind: {
        speed: 25,
        direction: 195
      }
    }
  };

  /************************************************************************
   *
   * Code required to start the app
   *
   * NOTE: To simplify this codelab, we've used localStorage.
   *   localStorage is a synchronous API and has serious performance
   *   implications. It should not be used in production applications!
   *   Instead, check out IDB (https://www.npmjs.com/package/idb) or
   *   SimpleDB (https://gist.github.com/inexorabletash/c8069c042b734519680c)
   ************************************************************************/

  app.selectedCities = localStorage.selectedCities;
  if (app.selectedCities) {
    app.selectedCities = JSON.parse(app.selectedCities);
    app.selectedCities.forEach(function(city) {
      app.getForecast(city.key, city.label);
    });
  } else {
    /* The user is using the app for the first time, or the user has not
     * saved any cities, so show the user some fake data. A real app in this
     * scenario could guess the user's location via IP lookup and then inject
     * that data into the page.
     */
    app.updateForecastCard(initialWeatherForecast);
    app.selectedCities = [
      {key: initialWeatherForecast.key, label: initialWeatherForecast.label}
    ];
    app.saveSelectedCities();
  }

  // TODO add service worker code here
})();
<|endoftext|>


<commit_before>var Ripple = require('ripple-lib')
var request = require('request')
var RippleAddress = require('../app/models/ripple_address.js');
var RippleTransaction = require('../app/models/ripple_transaction.js');
var RippleSimpleClient = require('../lib/ripple_simple_client.js');

var client = new RippleSimpleClient({
  apiUrl: process.env.RIPPLE_SIMPLE_API
});

// Proposed!!
/*
client.on('payment:inbound', function(payment) {

});

client.on('payment:outbound', function(payment) {

});

client.listener.start();
*/

getHotWallet(function(wallet){
  address = wallet.address;
  client.address = wallet.address;
  getNextNotification();
  console.log("listening for transactions to ", address);
});

function getNextNotification() {
  client.getNextNotification(function(err, notification){
    if (notification) {
      handlePayment(notification, function(){
        setTimeout(getNextNotification, 2000);
      });
    } else {
      setTimeout(getNextNotification, 2000);
    }
  });
}

function getHotWallet(fn) {
  RippleAddress.find({ where: { type: 'hot' }}).complete(function(err, address) {
    fn(address);
  });
}

function lookupTransaction(transactionHash, fn){
  RippleTransaction.find({ where: {
    transaction_hash: transactionHash
  }}).complete(fn);
}

function handleUnknownPayment(notification, fn) {
  client.getPayment(notification.tx_hash, function(err, payment) {
    if (payment.dst_tag) {
      RippleAddress.find({ where: {
        address: address,
        tag: payment.dst_tag.toString()
      }}).complete(function(err, address){
        if (address) {
          RippleTransaction.create({
            ripple_address_id: address.id,
            to_address: payment.dst_address,
            from_address: payment.src_address,
            from_amount: payment.src_amount.value,
            from_currency: payment.src_amount.currency,
            from_issuer: payment.src_amount.issuer,
            to_address: payment.dst_address,
            to_amount: payment.dst_amount.value,
            to_currency: payment.dst_amount.currency,
            to_issuer: payment.dst_amount.issuer,
            transaction_state: payment.tx_state,
            transaction_hash: payment.tx_hash,
            issuance: false
          }).complete(function(err, transaction) {
            console.log(err);
            console.log(transaction.toJSON());
            fn();
          });
        } else {
          console.log(err);
          fn();
        }
      });
    } else {
      console.log('no destination tag');
      fn();
    }
  });
}

function handleKnownPayment(notification, record, fn) {
  record.transaction_state = notification.tx_result;
  record.save().complete(fn);
}

function handlePayment(notification,fn) {
  if (notification.type == 'payment') {
    lookupTransaction(notification.tx_hash, function(err, transaction) {
      console.log(notification.tx_hash);
      if (transaction) {
        handleKnownPayment(notification, transaction, fn);
      } else {
        handleUnknownPayment(notification, fn);
      }
    });
  } else {
    fn();
  }
}

<commit_msg>[FEATURE] Check for payment and then payment.dst_tag.<commit_after>var Ripple = require('ripple-lib')
var request = require('request')
var RippleAddress = require('../app/models/ripple_address.js');
var RippleTransaction = require('../app/models/ripple_transaction.js');
var RippleSimpleClient = require('../lib/ripple_simple_client.js');

var client = new RippleSimpleClient({
  apiUrl: process.env.RIPPLE_SIMPLE_API
});

// Proposed!!
/*
client.on('payment:inbound', function(payment) {

});

client.on('payment:outbound', function(payment) {

});

client.listener.start();
*/

getHotWallet(function(wallet){
  address = wallet.address;
  client.address = wallet.address;
  getNextNotification();
  console.log("listening for transactions to ", address);
});

function getNextNotification() {
  client.getNextNotification(function(err, notification){
    if (notification) {
      handlePayment(notification, function(){
        setTimeout(getNextNotification, 2000);
      });
    } else {
      setTimeout(getNextNotification, 2000);
    }
  });
}

function getHotWallet(fn) {
  RippleAddress.find({ where: { type: 'hot' }}).complete(function(err, address) {
    fn(address);
  });
}

function lookupTransaction(transactionHash, fn){
  RippleTransaction.find({ where: {
    transaction_hash: transactionHash
  }}).complete(fn);
}

function handleUnknownPayment(notification, fn) {
  client.getPayment(notification.tx_hash, function(err, payment) {
    if (payment && payment.dst_tag) {
      RippleAddress.find({ where: {
        address: address,
        tag: payment.dst_tag.toString()
      }}).complete(function(err, address){
        if (address) {
          RippleTransaction.create({
            ripple_address_id: address.id,
            to_address: payment.dst_address,
            from_address: payment.src_address,
            from_amount: payment.src_amount.value,
            from_currency: payment.src_amount.currency,
            from_issuer: payment.src_amount.issuer,
            to_address: payment.dst_address,
            to_amount: payment.dst_amount.value,
            to_currency: payment.dst_amount.currency,
            to_issuer: payment.dst_amount.issuer,
            transaction_state: payment.tx_state,
            transaction_hash: payment.tx_hash,
            issuance: false
          }).complete(function(err, transaction) {
            console.log(err);
            console.log(transaction.toJSON());
            fn();
          });
        } else {
          console.log(err);
          fn();
        }
      });
    } else {
      console.log('no destination tag');
      fn();
    }
  });
}

function handleKnownPayment(notification, record, fn) {
  record.transaction_state = notification.tx_result;
  record.save().complete(fn);
}

function handlePayment(notification,fn) {
  if (notification.type == 'payment') {
    lookupTransaction(notification.tx_hash, function(err, transaction) {
      console.log(notification.tx_hash);
      if (transaction) {
        handleKnownPayment(notification, transaction, fn);
      } else {
        handleUnknownPayment(notification, fn);
      }
    });
  } else {
    fn();
  }
}

<|endoftext|>


<commit_before>#!/usr/bin/env node

var app = require('commander')

app
  .description('View tasks due today')
  .parse(process.argv)

// TODO
<commit_msg>adds filtering for today command<commit_after>#!/usr/bin/env node

var app = require('commander')
var moment = require('moment')
var lists = require('./lists')
var print = require('./print')

app
  .description('View tasks due today')
  .parse(process.argv)

lists(function (err, data) {
  if (err) process.exit(-1)

  var today = moment().format('YYYY-MM-DD')

  data.sort(function (a, b) {
    if (a.title === 'inbox') return -1
    if (b.title === 'inbox') return 1
    return a.title > b.title
  }).forEach(function (list) {
    list.tasks = list.tasks.filter(function(item) {
      if (! item.due_date) return false
      return item.due_date === today
    })

    print(list)
  })
})
<|endoftext|>


<commit_before>var mongoose = require('../libs/mongoose');
var helpers = require('../middleware/helpers');

var Module = require('../models/module').Module;
var Page = require('../models/page').Page;
var log = require('../libs/log')(module);
var async = require('async');
var _ = require('underscore');
var cache = require('node_cache');
var statusExport = require('../public/jsc/Models/statusList');
var statusList = new statusExport.Statuses();
var STATUS = require('../public/jsc/models/statusList').STATUS;

exports.getData = function (req, res) {

    cache.getData("waveData", function (setterCallback) {
        parsePages(function (data) {
            setterCallback(data);
        });
    }, function (value) { res.json(value); });
};

function CloudAppData() {
    this.cloudApp = [];
}

function parsePages(callback) {
    var cloudappdata = new CloudAppData();
    cloudappdata.cloudApp = [];

    async.series([
        function (callback) {
            Module.find({}).exec(function (err, modules) {
                async.series([
                    async.eachSeries(modules, function (module, callback) {
                        Page.find({ epicKey: module.key }).exec(function (err, pages) {
                            if (pages != null && pages.length > 0) {
                                async.eachSeries(pages, function (page, callback) {
                                    if (helpers.isActive(page.status, page.resolution)) {
                                        putDataPoint(cloudappdata, module, page);
                                    }
                                    callback();
                                },
                                    function () {
                                        callback();
                                    });
                            }
                            else {
                                callback();
                            }
                        });
                    },
                        function () {
                            callback();
                        })
                ],
                    function () {
                        callback();
                    });
            });
        },
        function () {
            cloudappdata.cloudApp.sort(function (a, b) {
                a = a.name;
                b = b.name;
                return a > b ? 1 : a < b ? -1 : 0;
            });
            updateChecklistsProgress(cloudappdata);
            callback(cloudappdata);
        }
    ]);
}

function updateChecklistsProgress(cloudappdata) {
    for (var i = 0; i < cloudappdata.cloudApp.length; i++) {
        var item = cloudappdata.cloudApp[i];
        var created = 0;
        var total = 0;
        for (var j = 0; j < item.checklistsProgress.length; j++) {
            if (item.checklistsProgress[j] == true) {
                created++;
            }
            total++;
        }
        cloudappdata.cloudApp[i].checklistsProgress = created * 100 / total;
    }
}

function putDataPoint(cloudAppData, module, page) {
    var initUri = "https://jira.epam.com/jira/issues/?jql=project = PLEX-UXC AND issuetype = Story AND labels in ('";
    var acceptanceUri = "https://jira.epam.com/jira/browse/" + page.acceptanceKey;

    var labels = module._doc.labels != null ? module._doc.labels : "";

    var teamName = helpers.getTeamName(page.labels);
    if (teamName == "" || teamName == "--") {
        var tname = helpers.getTeamName(labels);
        if (tname != "--") {
            teamName = tname;
        }
    }
    var streamName = helpers.getStreamName(page.labels);
    if (streamName == "" || streamName == "--") {
        var sname = helpers.getStreamName(labels);
        if (sname != "--") {
            streamName = sname;
        }
    }

    var smeName = module.assignee;
    var moduleGroupName = helpers.getModuleGroupName(page.labels);
    var cloudAppName = helpers.getCloudAppName(page.labels);
    var moduleName = module.summary;

    var priority = module.priority;
    var dueDateConfirmed = helpers.getDueDateConfirmed(labels);
    var isParentPage = helpers.isParentPage(page.labels);
    var fixVersions = module.fixVersions;

    var timeSpent = helpers.getTimeSpent(page);

    var storyPoints = page.storyPoints == null ? 0. : parseFloat(page.storyPoints);
    var progress = page.progress == null ? 0. : parseInt(page.progress);
    if (progress == 1.) {
        progress = 0.;
    }
    var calcStoryPoints = storyPoints * progress / 100.;

    var status = helpers.updateStatus(page);
    var fullUri = initUri + "CloudApp_" + cloudAppName + "') AND 'Epic Link' = " + module.key;
    var cloudApp;
    for (var i = 0; i < cloudAppData.cloudApp.length; i++) {
        if (cloudAppData.cloudApp[i].name == cloudAppName &&
            cloudAppData.cloudApp[i].moduleGroupName == moduleGroupName &&
            cloudAppData.cloudApp[i].moduleName == module.summary &&
            cloudAppData.cloudApp[i].fixVersions == fixVersions) {
            cloudApp = cloudAppData.cloudApp[i];
            cloudApp.reportedSP += calcStoryPoints;
            cloudApp.summarySP += storyPoints;
            if (storyPoints > 30) {
                cloudApp.xxl = true;
            }
            cloudApp.progress = cloudApp.reportedSP * 100. / cloudApp.summarySP;
            cloudApp.pages++;
            cloudApp.devTimeSpent += timeSpent.devTimeSpent;
            cloudApp.qaTimeSpent += timeSpent.qaTimeSpent;
            cloudApp.checklistsProgress.push(page.checklistCreated);
            cloudApp.teamName = teamName;
            cloudApp.streamName = streamName;
            if (isParentPage) {
                cloudApp.testingProgress = page.testingProgress;
                cloudApp.devfinish = page.devfinish;
                cloudApp.qafinish = page.qafinish;
                cloudApp.accfinish = page.accfinish;
                cloudApp.cusfinish = page.cusfinish;
                cloudApp.pmhfinish = page.pmhfinish;
                cloudApp.lafinish = page.lafinish;
                cloudApp.acceptanceUri = acceptanceUri;
                cloudApp.acceptanceAssignee = page.acceptanceAssignee;
            }

            var found = false;
            for (var j = 0; j < cloudApp.assignees.length; j++) {
                if (cloudApp.assignees[j] == page.assignee) {
                    found = true;
                    break;
                }
            }
            if (!found) {
                cloudApp.assignees.push(page.assignee);
            }
        }
    }

    if (!cloudApp) {
        cloudApp = {
            progress: progress,
            reportedSP: calcStoryPoints,
            summarySP: storyPoints,
            xxl: storyPoints > 30,
            name: cloudAppName,
            status: status,
            resolution: page.resolution,
            teamName: teamName,
            streamName: streamName,
            smeName: smeName,
            moduleGroupName: moduleGroupName,
            moduleName: moduleName,
            fixVersions: fixVersions,
            priority: priority,
            pages: 1,
            dueDateConfirmed: dueDateConfirmed,
            uri: fullUri,
            devTimeSpent: timeSpent.devTimeSpent,
            qaTimeSpent: timeSpent.qaTimeSpent,
            assignees: [smeName, page.assignee],
            testingProgress: isParentPage ? page.testingProgress : 0.,
            checklistsProgress: [page.checklistCreated],
            acceptanceUri: acceptanceUri,
            acceptanceAssignee: page.acceptanceAssignee
        };
        if (isParentPage) {
            cloudApp.testingProgress = page.testingProgress;
            cloudApp.devfinish = page.devfinish;
            cloudApp.qafinish = page.qafinish;
            cloudApp.accfinish = page.accfinish;
            cloudApp.cusfinish = page.cusfinish;
            cloudApp.pmhfinish = page.pmhfinish;
            cloudApp.lafinish = page.lafinish;
            cloudApp.acceptanceUri = acceptanceUri;
            cloudApp.acceptanceAssignee = page.acceptanceAssignee;
        }
        cloudAppData.cloudApp.push(cloudApp);
    }
    var cloudAppStatus = statusList.getStatusByName(cloudApp.status);
    var pageStatus = statusList.getStatusByName(status);

    if (pageStatus.weight < cloudAppStatus.weight) {
        cloudApp.status = status;
    }
}
<commit_msg>fix for virtual statuses<commit_after>var mongoose = require('../libs/mongoose');
var helpers = require('../middleware/helpers');

var Module = require('../models/module').Module;
var Page = require('../models/page').Page;
var log = require('../libs/log')(module);
var async = require('async');
var _ = require('underscore');
var cache = require('node_cache');
var statusExport = require('../public/jsc/Models/statusList');
var statusList = new statusExport.Statuses();
var STATUS = require('../public/jsc/models/statusList').STATUS;

exports.getData = function (req, res) {

    cache.getData("waveData", function (setterCallback) {
        parsePages(function (data) {
            setterCallback(data);
        });
    }, function (value) { res.json(value); });
};

function CloudAppData() {
    this.cloudApp = [];
}

function parsePages(callback) {
    var cloudappdata = new CloudAppData();
    cloudappdata.cloudApp = [];

    async.series([
        function (callback) {
            Module.find({}).exec(function (err, modules) {
                async.series([
                    async.eachSeries(modules, function (module, callback) {
                        Page.find({ epicKey: module.key }).exec(function (err, pages) {
                            if (pages != null && pages.length > 0) {
                                async.eachSeries(pages, function (page, callback) {
                                    if (helpers.isActive(page.status, page.resolution)) {
                                        putDataPoint(cloudappdata, module, page);
                                    }
                                    callback();
                                },
                                    function () {
                                        callback();
                                    });
                            }
                            else {
                                callback();
                            }
                        });
                    },
                        function () {
                            callback();
                        })
                ],
                    function () {
                        callback();
                    });
            });
        },
        function () {
            cloudappdata.cloudApp.sort(function (a, b) {
                a = a.name;
                b = b.name;
                return a > b ? 1 : a < b ? -1 : 0;
            });
            updateChecklistsProgress(cloudappdata);
            callback(cloudappdata);
        }
    ]);
}

function updateChecklistsProgress(cloudappdata) {
    for (var i = 0; i < cloudappdata.cloudApp.length; i++) {
        var item = cloudappdata.cloudApp[i];
        var created = 0;
        var total = 0;
        for (var j = 0; j < item.checklistsProgress.length; j++) {
            if (item.checklistsProgress[j] == true) {
                created++;
            }
            total++;
        }
        cloudappdata.cloudApp[i].checklistsProgress = created * 100 / total;
    }
}

function putDataPoint(cloudAppData, module, page) {
    var initUri = "https://jira.epam.com/jira/issues/?jql=project = PLEX-UXC AND issuetype = Story AND labels in ('";
    var acceptanceUri = "https://jira.epam.com/jira/browse/" + page.acceptanceKey;

    var labels = module._doc.labels != null ? module._doc.labels : "";

    var teamName = helpers.getTeamName(page.labels);
    if (teamName == "" || teamName == "--") {
        var tname = helpers.getTeamName(labels);
        if (tname != "--") {
            teamName = tname;
        }
    }
    var streamName = helpers.getStreamName(page.labels);
    if (streamName == "" || streamName == "--") {
        var sname = helpers.getStreamName(labels);
        if (sname != "--") {
            streamName = sname;
        }
    }

    var smeName = module.assignee;
    var moduleGroupName = helpers.getModuleGroupName(page.labels);
    var cloudAppName = helpers.getCloudAppName(page.labels);
    var moduleName = module.summary;

    var priority = module.priority;
    var dueDateConfirmed = helpers.getDueDateConfirmed(labels);
    var isParentPage = helpers.isParentPage(page.labels);
    var fixVersions = module.fixVersions;

    var timeSpent = helpers.getTimeSpent(page);

    var storyPoints = page.storyPoints == null ? 0. : parseFloat(page.storyPoints);
    var progress = page.progress == null ? 0. : parseInt(page.progress);
    if (progress == 1.) {
        progress = 0.;
    }
    var calcStoryPoints = storyPoints * progress / 100.;

    var status = helpers.updateStatus(page);
    var fullUri = initUri + "CloudApp_" + cloudAppName + "') AND 'Epic Link' = " + module.key;
    var cloudApp;
    for (var i = 0; i < cloudAppData.cloudApp.length; i++) {
        if (cloudAppData.cloudApp[i].name == cloudAppName &&
            cloudAppData.cloudApp[i].moduleGroupName == moduleGroupName &&
            cloudAppData.cloudApp[i].moduleName == module.summary &&
            cloudAppData.cloudApp[i].fixVersions == fixVersions) {
            cloudApp = cloudAppData.cloudApp[i];
            cloudApp.reportedSP += calcStoryPoints;
            cloudApp.summarySP += storyPoints;
            if (storyPoints > 30) {
                cloudApp.xxl = true;
            }
            cloudApp.progress = cloudApp.reportedSP * 100. / cloudApp.summarySP;
            cloudApp.pages++;
            cloudApp.devTimeSpent += timeSpent.devTimeSpent;
            cloudApp.qaTimeSpent += timeSpent.qaTimeSpent;
            cloudApp.checklistsProgress.push(page.checklistCreated);
            cloudApp.teamName = teamName;
            cloudApp.streamName = streamName;
            if (isParentPage) {
                cloudApp.testingProgress = page.testingProgress;
                cloudApp.devfinish = page.devfinish;
                cloudApp.qafinish = page.qafinish;
                cloudApp.accfinish = page.accfinish;
                cloudApp.cusfinish = page.cusfinish;
                cloudApp.pmhfinish = page.pmhfinish;
                cloudApp.lafinish = page.lafinish;
                cloudApp.acceptanceUri = acceptanceUri;
                cloudApp.acceptanceAssignee = page.acceptanceAssignee;
            }

            var found = false;
            for (var j = 0; j < cloudApp.assignees.length; j++) {
                if (cloudApp.assignees[j] == page.assignee) {
                    found = true;
                    break;
                }
            }
            if (!found) {
                cloudApp.assignees.push(page.assignee);
            }
        }
    }

    if (!cloudApp) {
        cloudApp = {
            progress: progress,
            reportedSP: calcStoryPoints,
            summarySP: storyPoints,
            xxl: storyPoints > 30,
            name: cloudAppName,
            status: status,
            resolution: page.resolution,
            teamName: teamName,
            streamName: streamName,
            smeName: smeName,
            moduleGroupName: moduleGroupName,
            moduleName: moduleName,
            fixVersions: fixVersions,
            priority: priority,
            pages: 1,
            dueDateConfirmed: dueDateConfirmed,
            uri: fullUri,
            devTimeSpent: timeSpent.devTimeSpent,
            qaTimeSpent: timeSpent.qaTimeSpent,
            assignees: [smeName, page.assignee],
            testingProgress: isParentPage ? page.testingProgress : 0.,
            checklistsProgress: [page.checklistCreated],
            acceptanceUri: acceptanceUri,
            acceptanceAssignee: page.acceptanceAssignee
        };
        if (isParentPage) {
            cloudApp.testingProgress = page.testingProgress;
            cloudApp.devfinish = page.devfinish;
            cloudApp.qafinish = page.qafinish;
            cloudApp.accfinish = page.accfinish;
            cloudApp.cusfinish = page.cusfinish;
            cloudApp.pmhfinish = page.pmhfinish;
            cloudApp.lafinish = page.lafinish;
            cloudApp.acceptanceUri = acceptanceUri;
            cloudApp.acceptanceAssignee = page.acceptanceAssignee;
        }
        cloudAppData.cloudApp.push(cloudApp);
    }
    var cloudAppStatus = statusList.getStatusByName(cloudApp.status);
    var pageStatus = statusList.getStatusByName(status);

    if (pageStatus.weight < cloudAppStatus.weight ||
        (isParentPage &&
        (status == STATUS.LAREADY.name ||
        status == STATUS.PMREVIEW.name))) {
        cloudApp.status = status;
    }
}
<|endoftext|>