<commit_before>/**
 * A panel that displays information about multple groups.
 */
Ext.define('devilry_subjectadmin.view.managestudents.MultipleGroupsSelectedView' ,{
    extend: 'Ext.panel.Panel',
    alias: 'widget.multiplegroupsview',
    cls: 'devilry_subjectadmin_multiplegroupsview',
    ui: 'transparentpanel',
    requires: [
        'devilry_theme.Icons',
        'devilry_extjsextras.form.Help',
        'devilry_extjsextras.PrimaryButton'
    ],

    /**
     * @cfg {string} topMessage (required)
     */

    /**
     * @cfg {string} multiselectHowto (required)
     */

    merge_groups_explained: [
        gettext('Any student in the group will be able to make deliveries on behalf of the group.'),
        gettext('Feedback will be given to the group as a whole, not to individual students in the group.'),
        gettext('If any of the selected groups already have any deadlines, deliveries or feedback, they will be moved into the new group.'),
        gettext('You can split up a group later, however any deliveries and feedback will follow all students on the group, even if they where made before you merged the groups into a single group in the first place.'),
        gettext('The name of the group and open/closed status will be copied from the first group you selected.')
    ],

    _createMergeHelp: function() {
        return Ext.create('Ext.XTemplate',
            '
',
                '<tpl for="notes">',
                    '
{.}
',
                '</tpl>',
            '
'
        ).apply({
            notes: this.merge_groups_explained
        });
    },

    initComponent: function() {
        var buttonmargin = '30 0 0 0';
        var helpmargin = '4 0 0 0';
        this.mergehelp = this._createMergeHelp();

        Ext.apply(this, {
            layout: {
                type: 'vbox',
                align: 'stretch'
            },
            items: [{
                //region: 'center',
                minHeight: 100,
                flex: 6,
                xtype: 'container',
                padding: 20,
                layout: 'anchor',
                itemId: 'scrollableBodyContainer',
                autoScroll: true,
                items: [{
                    xtype: 'alertmessage',
                    cls: 'top_infobox',
                    type: 'info',
                    message: [this.topMessage, this.multiselectHowto].join(' ')

                // Set examiners
                }, {
                    xtype: 'splitbutton',
                    margin: 0,
                    scale: 'medium',
                    text: gettext('Set examiner(s)'),
                    itemId: 'setExaminersButton',
                    menu: [{
                        text: gettext('Add examiner(s)'),
                        itemId: 'addExaminersButton',
                        tooltip: gettext('Add one or more examiner(s) to the selected groups.')
                    }, {
                        text: gettext('Clear examiners'),
                        itemId: 'clearExaminersButton',
                        icon: devilry_theme.Icons.DELETE_SMALL,
                        tooltip: gettext('Remove/clear all examiners from the selected groups.')
                    }]
                }, {
                    xtype: 'formhelp',
                    margin: helpmargin,
                    anchor: '100%',
                    html: gettext('Assign one or more examiner(s) to the selected groups. Use the arrow button for methods of setting examiners. Setting examiners replaces the current examiners.')

                // Set Tags
                }, {
                    xtype: 'box',
                    cls: 'bootstrap',
                    margin: buttonmargin,
                    tpl: [
                        '
',
                            '{heading}',
                        '
'
                    ],
                    data: {
                        heading: gettext('Set tag(s)'),
                    }
                }, {
                    xtype: 'container',
                    items: [{
                        xtype: 'panel',
                        border: false,
                        frame: false,
                        layout: 'fit',
                        dockedItems: [{
                            xtype: 'toolbar',
                            dock: 'top',
                            ui: 'footer',
                            padding: 0,
                            defaults: {
                                xtype: 'button',
                                scale: 'medium',
                                minWidth: 100
                            },
                            items: [{
                                text: gettext('Set tag(s)'),
                                itemId: 'setTagsButton',
                                tooltip: gettext('Replace the tags on the selected groups with one or more new tag(s).')
                            }, {
                                text: gettext('Add tag(s)'),
                                itemId: 'addTagsButton',
                                tooltip: gettext('Add one or more tag(s) to the selected groups.')
                            }, {
                                text: gettext('Clear tags'),
                                itemId: 'clearTagsButton',
                                icon: devilry_theme.Icons.DELETE_SMALL,
                                tooltip: gettext('Remove/clear all tags from the selected groups.')
                            }]
                        }],
                        items: {
                            xtype: 'box',
                            margin: '10 0 0 0',
                            cls: 'bootstrap',
                            html: [
                                '
',
                                    gettext('Assign one or more tag(s) to the selected groups. Use the arrow button for methods of setting tags, such as random and by tags. Setting tags replaces the current tags.'),
                                '
'
                            ]
                        }
                    }]

                // Merge groups
                }, {
                    xtype: 'box',
                    cls: 'bootstrap',
                    margin: buttonmargin,
                    tpl: [
                        '
',
                            '{heading}',
                            ' - {subheading}',
                        '
'
                    ],
                    data: {
                        heading: gettext('Create project group'),
                        subheading: gettext('Merge selected into one group')
                    }
                }, {
                    xtype: 'box',
                    itemId: 'mergeGroupsHelp',
                    margin: helpmargin,
                    anchor: '100%',
                    cls: 'merge_groups_helpbox bootstrap',
                    html: ['
', this.mergehelp, '
'].join('')
                }, {
                    xtype: 'button',
                    scale: 'medium',
                    cls: 'merge_groups_button',
                    text: gettext('Create project group'),
                    itemId: 'mergeGroupsButton'
                }, {
                    xtype: 'panel',
                    margin: helpmargin,
                    anchor: '100%',
                    cls: 'bootstrap merge_groups_confirmcontainer',
                    itemId: 'confirmMergeGroupsContainer',
                    layout: 'fit',
                    hidden: true,
                    bodyPadding: 10,
                    items: {
                        xtype: 'box',
                        cls: 'bootstrap',
                        tpl: [
                            gettext('Merge selected groups into a single group?'),
                            '{mergehelp}'
                        ],
                        data: {
                            mergehelp: this.mergehelp
                        }
                    },
                    fbar: [{
                        xtype: 'button',
                        itemId: 'mergeGroupsCancelButton',
                        cls: 'merge_groups_cancel_button',
                        text: gettext('Cancel'),
                        margin: '0 10 0 0'
                    }, {
                        xtype: 'primarybutton',
                        itemId: 'mergeGroupsConfirmButton',
                        cls: 'merge_groups_confirm_button',
                        minWidth: 200,
                        text: gettext('Create project group')
                    }]
                }]
            }, {
                flex: 4,
                minHeight: 150,
                xtype: 'selectedgroupssummarygrid'
            }]
        });
        this.callParent(arguments);
    }
});
<commit_msg>devilry_subjectadmin: About tags on assignment.<commit_after>/**
 * A panel that displays information about multple groups.
 */
Ext.define('devilry_subjectadmin.view.managestudents.MultipleGroupsSelectedView' ,{
    extend: 'Ext.panel.Panel',
    alias: 'widget.multiplegroupsview',
    cls: 'devilry_subjectadmin_multiplegroupsview',
    ui: 'transparentpanel',
    requires: [
        'devilry_theme.Icons',
        'devilry_extjsextras.form.Help',
        'devilry_extjsextras.PrimaryButton'
    ],

    /**
     * @cfg {string} topMessage (required)
     */

    /**
     * @cfg {string} multiselectHowto (required)
     */

    merge_groups_explained: [
        gettext('Any student in the group will be able to make deliveries on behalf of the group.'),
        gettext('Feedback will be given to the group as a whole, not to individual students in the group.'),
        gettext('If any of the selected groups already have any deadlines, deliveries or feedback, they will be moved into the new group.'),
        gettext('You can split up a group later, however any deliveries and feedback will follow all students on the group, even if they where made before you merged the groups into a single group in the first place.'),
        gettext('The name of the group and open/closed status will be copied from the first group you selected.')
    ],

    _createMergeHelp: function() {
        return Ext.create('Ext.XTemplate',
            '
',
                '<tpl for="notes">',
                    '
{.}
',
                '</tpl>',
            '
'
        ).apply({
            notes: this.merge_groups_explained
        });
    },

    initComponent: function() {
        var buttonmargin = '30 0 0 0';
        var helpmargin = '4 0 0 0';
        this.mergehelp = this._createMergeHelp();

        Ext.apply(this, {
            layout: {
                type: 'vbox',
                align: 'stretch'
            },
            items: [{
                //region: 'center',
                minHeight: 100,
                flex: 6,
                xtype: 'container',
                padding: 20,
                layout: 'anchor',
                itemId: 'scrollableBodyContainer',
                autoScroll: true,
                items: [{
                    xtype: 'alertmessage',
                    cls: 'top_infobox',
                    type: 'info',
                    message: [this.topMessage, this.multiselectHowto].join(' ')

                // Set examiners
                }, {
                    xtype: 'splitbutton',
                    margin: 0,
                    scale: 'medium',
                    text: gettext('Set examiner(s)'),
                    itemId: 'setExaminersButton',
                    menu: [{
                        text: gettext('Add examiner(s)'),
                        itemId: 'addExaminersButton',
                        tooltip: gettext('Add one or more examiner(s) to the selected groups.')
                    }, {
                        text: gettext('Clear examiners'),
                        itemId: 'clearExaminersButton',
                        icon: devilry_theme.Icons.DELETE_SMALL,
                        tooltip: gettext('Remove/clear all examiners from the selected groups.')
                    }]
                }, {
                    xtype: 'formhelp',
                    margin: helpmargin,
                    anchor: '100%',
                    html: gettext('Assign one or more examiner(s) to the selected groups. Use the arrow button for methods of setting examiners. Setting examiners replaces the current examiners.')

                // Set Tags
                }, {
                    xtype: 'box',
                    cls: 'bootstrap',
                    margin: buttonmargin,
                    tpl: [
                        '
',
                            '{heading}',
                        '
'
                    ],
                    data: {
                        heading: gettext('Set tag(s)'),
                    }
                }, {
                    xtype: 'container',
                    items: [{
                        xtype: 'panel',
                        border: false,
                        frame: false,
                        layout: 'fit',
                        dockedItems: [{
                            xtype: 'toolbar',
                            dock: 'bottom',
                            ui: 'footer',
                            padding: 0,
                            defaults: {
                                xtype: 'button',
                                scale: 'medium',
                                minWidth: 100
                            },
                            items: [{
                                text: gettext('Set tag(s)'),
                                itemId: 'setTagsButton',
                                tooltip: gettext('Replace the tags on the selected groups with one or more new tag(s).')
                            }, {
                                text: gettext('Add tag(s)'),
                                itemId: 'addTagsButton',
                                tooltip: gettext('Add one or more tag(s) to the selected groups.')
                            }, {
                                text: gettext('Clear tags'),
                                itemId: 'clearTagsButton',
                                icon: devilry_theme.Icons.DELETE_SMALL,
                                tooltip: gettext('Remove/clear all tags from the selected groups.')
                            }]
                        }],
                        items: {
                            xtype: 'box',
                            margin: '10 0 0 0',
                            cls: 'bootstrap',
                            tpl: [
                                '
',
                                    '
',
                                        gettext('{Tags_term} is a flexible method of organizing {groups_term}. Only administrators can see {tags_term}. You can search and select {groups_term} by their {tags_term}. Common use-cases are:'),
                                    '
',
                                    '
',
                                        '
',
                                            gettext('Mark groups with special needs.'),
                                        '
',
                                        '
',
                                            gettext('Organize {groups_term} attending the same classroom sessions.'),
                                        '
',
                                        '
',
                                            gettext('Mark suspected cheaters.'),
                                        '
',
                                    '
',
                                    '
',
                                        gettext('NOTE: {Tags_term} on {groups_term} must not be confused with {tags_term} on {students_term} and {examiners_term} on a {period_term}. Those {tags_term} are used to automate assigning examiners to students. {Tags_term} from the {period_term} may have been included when you added {groups_term} to this {assignment_term}, however you can safely edit {tags_term} on {groups_term} without affecting the {tags_term} on the {period_term}.'),
                                    '
',
                                '
'
                            ],
                            data: {
                                Tags_term: gettext('Tags'),
                                groups_term: gettext('groups'),
                                tags_term: gettext('tags'),
                                examiners_term: gettext('examiners'),
                                students_term: gettext('students'),
                                period_term: gettext('period'),
                                assignment_term: gettext('assignment')
                            }
                        }
                    }]

                // Merge groups
                }, {
                    xtype: 'box',
                    cls: 'bootstrap',
                    margin: buttonmargin,
                    tpl: [
                        '
',
                            '{heading}',
                            ' - {subheading}',
                        '
'
                    ],
                    data: {
                        heading: gettext('Create project group'),
                        subheading: gettext('Merge selected into one group')
                    }
                }, {
                    xtype: 'box',
                    itemId: 'mergeGroupsHelp',
                    margin: helpmargin,
                    anchor: '100%',
                    cls: 'merge_groups_helpbox bootstrap',
                    html: ['
', this.mergehelp, '
'].join('')
                }, {
                    xtype: 'button',
                    scale: 'medium',
                    cls: 'merge_groups_button',
                    text: gettext('Create project group'),
                    itemId: 'mergeGroupsButton'
                }, {
                    xtype: 'panel',
                    margin: helpmargin,
                    anchor: '100%',
                    cls: 'bootstrap merge_groups_confirmcontainer',
                    itemId: 'confirmMergeGroupsContainer',
                    layout: 'fit',
                    hidden: true,
                    bodyPadding: 10,
                    items: {
                        xtype: 'box',
                        cls: 'bootstrap',
                        tpl: [
                            gettext('Merge selected groups into a single group?'),
                            '{mergehelp}'
                        ],
                        data: {
                            mergehelp: this.mergehelp
                        }
                    },
                    fbar: [{
                        xtype: 'button',
                        itemId: 'mergeGroupsCancelButton',
                        cls: 'merge_groups_cancel_button',
                        text: gettext('Cancel'),
                        margin: '0 10 0 0'
                    }, {
                        xtype: 'primarybutton',
                        itemId: 'mergeGroupsConfirmButton',
                        cls: 'merge_groups_confirm_button',
                        minWidth: 200,
                        text: gettext('Create project group')
                    }]
                }]
            }, {
                flex: 4,
                minHeight: 150,
                xtype: 'selectedgroupssummarygrid'
            }]
        });
        this.callParent(arguments);
    }
});
<|endoftext|>


<commit_before>/* eslint-env node */
module.exports = {
  test_page: 'tests/index.html?hidepassed',
  disable_watching: true,
  launch_in_ci: [
    'PhantomJS'
  ],
  launch_in_dev: [
    'PhantomJS',
    'Chrome'
  ]
};
<commit_msg>Switch to headless Chrome from Phantom<commit_after>/* eslint-env node */
module.exports = {
  test_page: 'tests/index.html?hidepassed',
  disable_watching: true,
  launch_in_ci: [
    'Chrome'
  ],
  launch_in_dev: [
    'Chrome'
  ],
  "browser_args": {
    "Chrome": [ '--headless', '--disable-gpu', '--remote-debugging-port=9222' ]
  }
};
<|endoftext|>


<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 */

// creating the namespace
var org = org || {};
org.apache = org.apache || {};
org.apache.sling = org.apache.sling || {};
org.apache.sling.reseditor = org.apache.sling.reseditor || {};

/*
 JSTreeAdapter - It adapts the JSTree library for the use in the Sling Resource Editor.
 This JSTreeAdapter contains as less logic as needed to configure the JSTree for the Sling Resource Editor. For
 everything that goes beyond that and contains more functionality, the other Sling Resource Editor controllers are called.
*/

//defining the module
org.apache.sling.reseditor.JSTreeAdapter = (function() {

	function JSTreeAdapter(settings, treeController, mainController){
		this.settings = settings;
		this.treeController = treeController;
		this.mainController = mainController;

		var thisJSTreeAdapter = this;

$(document).ready(function() {
	$(window).resize( function() {
		thisJSTreeAdapter.mainController.adjust_height();
	});

	var scrollToPathFinished=false;

	thisJSTreeAdapter.mainController.adjust_height();

	// TO CREATE AN INSTANCE
	// select the tree container using jQuery
	$("#tree")
	.bind("loaded.jstree", function (event, data) {
		var pathElements = treeController.getPathElements(settings.resourcePath);

		if (pathElements.length >= 1 && pathElements[0] != "") {
			treeController.openElement($("#tree > ul > li[nodename=''] > ul"), pathElements);
		}

		// position the info-icon
		$('#tree-info-icon').show();
		$('#root i:first').before($('#tree-info-icon'));
	})
	// call `.jstree` with the options object
	.jstree({
		"core"      : {
		    "check_callback" : true,
		    multiple: true,
			animation: 600,
			'data' : {
				'url' : function (liJson) {
					// initial call for the root element
					if (liJson.id === '#'){
						return settings.contextPath+"/reseditor/.rootnodes.json";
					} else {
						// the li the user clicked on.
						var li = $('#'+liJson.id);
						return treeController.get_uri_from_li(li,".nodes.json");
					}
				},
			    'data' : function (node) {
			        return { 'id' : node.id };
			      }
			}
		},
		"ui"      : {
			"select_limit" : 2
		},
		"crrm"      : {
			"move" : {
				"always_copy" : false,
		        "check_move"  : function (m) {
			        // you find the member description here
			        // http://www.jstree.com/documentation/core.html#_get_move
		        	// TODO refactor to the new jsTree version
			        var src_li = m.o;
			        var src_nt = mainController.getNTFromLi(src_li);
			        var src_nodename = src_li.attr("nodename");

			        var new_parent_ul = m.np.children("ul");
			        var calculated_position = m.cp;
			        var liAlreadySelected = new_parent_ul.length==0 && m.np.prop("tagName").toUpperCase() == 'LI';
			        var dest_li = liAlreadySelected ? m.np : new_parent_ul.children("li:eq("+(calculated_position-1)+")");
			        var dest_nt = mainController.getNTFromLi(dest_li);
					var result;
					if (dest_nt != null){
						result = dest_nt.canAddChildNode(src_nodename, src_nt);
					}
                    return result;
                  }
			}
		},
		"dnd" : {
			"drop_finish" : function () {
				console.log("drop");
			},
			"drag_finish" : function (data) {
				console.log("drag");
			}
		},
		// the `plugins` array allows you to configure the active plugins on this instance
		"plugins" : [ "themes", "ui", "core", "hotkeys", "crrm", "dnd"]
    }).bind("rename_node.jstree", function (e, data) {
    	treeController.renameNode(e, data);
    }).bind("move_node.jstree", function (e, data) {
    	// see http://www.jstree.com/documentation/core ._get_move()
    	// TODO refactor to the new jsTree version
    	var src_li = data.rslt.o;
    	var src_path = ""+settings.contextPath+src_li.children("a").attr("target");
    	var dest_li = data.rslt.np; // new parent .cr - same as np, but if a root node is created this is -1
    	var dest_li_path = dest_li.children("a").attr("target") == "/" ? "" : dest_li.children("a").attr("target");
    	var dest_path = ""+settings.contextPath+dest_li_path+"/"+src_li.attr("nodename");
    	var original_parent = data.rslt.op;
    	var is_copy = data.rslt.cy;
    	var position = data.rslt.cp;
    	$.ajax({
      	  type: 'POST',
		  url: src_path,
		  dataType: "json",
      	  success: function(server_data) {
        		var target = ""+settings.contextPath+dest_path;
            	location.href=target+".reseditor.html";
    		  },
      	  error: function(errorJson) {
      			displayAlert(errorJson);
    		  },
      	  data: {
       		":operation": "move",
//          	":order": position,
      		":dest": dest_path
      		  }
      	});
    }).on('hover_node.jstree', function (event, nodeObj) {
        //noop
    }).on('keydown.jstree', 'a.jstree-anchor', function (e) {
    	treeController.configureKeyListeners(e);
    }).on('select_node.jstree', function (e, data) {
    	;
    }).on('after_open.jstree', function(e, data){
    	treeController.afterOpen(data.node);
    }).on('close_node.jstree', function(e, data){
    	treeController.beforeClose(data.node);
    });
});

	};
	return JSTreeAdapter;
}());
<commit_msg>Resource Editor: Fixed bug on rename of a node.<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 */

// creating the namespace
var org = org || {};
org.apache = org.apache || {};
org.apache.sling = org.apache.sling || {};
org.apache.sling.reseditor = org.apache.sling.reseditor || {};

/*
 JSTreeAdapter - It adapts the JSTree library for the use in the Sling Resource Editor.
 This JSTreeAdapter contains as less logic as needed to configure the JSTree for the Sling Resource Editor. For
 everything that goes beyond that and contains more functionality, the other Sling Resource Editor controllers are called.
*/

//defining the module
org.apache.sling.reseditor.JSTreeAdapter = (function() {

	function JSTreeAdapter(settings, treeController, mainController){
		this.settings = settings;
		this.treeController = treeController;
		this.mainController = mainController;

		var thisJSTreeAdapter = this;

$(document).ready(function() {
	$(window).resize( function() {
		thisJSTreeAdapter.mainController.adjust_height();
	});

	var scrollToPathFinished=false;

	thisJSTreeAdapter.mainController.adjust_height();

	// TO CREATE AN INSTANCE
	// select the tree container using jQuery
	$("#tree")
	.bind("loaded.jstree", function (event, data) {
		var pathElements = treeController.getPathElements(settings.resourcePath);

		if (pathElements.length >= 1 && pathElements[0] != "") {
			treeController.openElement($("#tree > ul > li[nodename=''] > ul"), pathElements);
		}

		// position the info-icon
		$('#tree-info-icon').show();
		$('#root i:first').before($('#tree-info-icon'));
	})
	// call `.jstree` with the options object
	.jstree({
		"core"      : {
		    "check_callback" : true,
		    multiple: true,
			animation: 600,
			'dblclick_toggle': false,
			'data' : {
				'url' : function (liJson) {
					// initial call for the root element
					if (liJson.id === '#'){
						return settings.contextPath+"/reseditor/.rootnodes.json";
					} else {
						// the li the user clicked on.
						var li = $('#'+liJson.id);
						return treeController.get_uri_from_li(li,".nodes.json");
					}
				},
			    'data' : function (node) {
			        return { 'id' : node.id };
			      }
			}
		},
		"ui"      : {
			"select_limit" : 2
		},
		"crrm"      : {
			"move" : {
				"always_copy" : false,
		        "check_move"  : function (m) {
			        // you find the member description here
			        // http://www.jstree.com/documentation/core.html#_get_move
		        	// TODO refactor to the new jsTree version
			        var src_li = m.o;
			        var src_nt = mainController.getNTFromLi(src_li);
			        var src_nodename = src_li.attr("nodename");

			        var new_parent_ul = m.np.children("ul");
			        var calculated_position = m.cp;
			        var liAlreadySelected = new_parent_ul.length==0 && m.np.prop("tagName").toUpperCase() == 'LI';
			        var dest_li = liAlreadySelected ? m.np : new_parent_ul.children("li:eq("+(calculated_position-1)+")");
			        var dest_nt = mainController.getNTFromLi(dest_li);
					var result;
					if (dest_nt != null){
						result = dest_nt.canAddChildNode(src_nodename, src_nt);
					}
                    return result;
                  }
			}
		},
		"dnd" : {
			"drop_finish" : function () {
				console.log("drop");
			},
			"drag_finish" : function (data) {
				console.log("drag");
			}
		},
		// the `plugins` array allows you to configure the active plugins on this instance
		"plugins" : [ "themes", "ui", "core", "hotkeys", "crrm", "dnd"]
    }).bind("rename_node.jstree", function (e, data) {
    	treeController.renameNode(e, data);
    }).bind("move_node.jstree", function (e, data) {
    	// see http://www.jstree.com/documentation/core ._get_move()
    	// TODO refactor to the new jsTree version
    	var src_li = data.rslt.o;
    	var src_path = ""+settings.contextPath+src_li.children("a").attr("target");
    	var dest_li = data.rslt.np; // new parent .cr - same as np, but if a root node is created this is -1
    	var dest_li_path = dest_li.children("a").attr("target") == "/" ? "" : dest_li.children("a").attr("target");
    	var dest_path = ""+settings.contextPath+dest_li_path+"/"+src_li.attr("nodename");
    	var original_parent = data.rslt.op;
    	var is_copy = data.rslt.cy;
    	var position = data.rslt.cp;
    	$.ajax({
      	  type: 'POST',
		  url: src_path,
		  dataType: "json",
      	  success: function(server_data) {
        		var target = ""+settings.contextPath+dest_path;
            	location.href=target+".reseditor.html";
    		  },
      	  error: function(errorJson) {
      			displayAlert(errorJson);
    		  },
      	  data: {
       		":operation": "move",
//          	":order": position,
      		":dest": dest_path
      		  }
      	});
    }).on('hover_node.jstree', function (event, nodeObj) {
        //noop
    }).on('keydown.jstree', 'a.jstree-anchor', function (e) {
    	treeController.configureKeyListeners(e);
    }).on('select_node.jstree', function (e, data) {
    	//noop
    	;
    }).on('after_open.jstree', function(e, data){
    	treeController.afterOpen(data.node);
    }).on('close_node.jstree', function(e, data){
    	treeController.beforeClose(data.node);
    });
});

	};
	return JSTreeAdapter;
}());
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2015 Internet of Protocols Alliance (IOPA)
 *
 * 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.
 */

const FreeList = require('../util/freelist').FreeList,
    Events = require('events'),
    URL = require('url'),

    Cancellation = require('../util/cancellation').default,
    contextExtensionsAddTo = require('./contextExtensions').addTo,

    constants = require('./constants'),
    IOPA = constants.IOPA,
    SERVER = constants.SERVER,

    mergeContext = require('../util/shallow').mergeContext,
    cloneDoubleLayer = require('../util/shallow').cloneDoubleLayer,
    merge = require('../util/shallow').merge

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

/* *********************************************************
 * IOPA CONTEXT
 * ********************************************************* */

/**
 * Represents IOPA Context object for any REST Request/Response
 * See http://iopa.io for further details
 *
 * @class IopaContext
 * @constructor
 */
function IopaContext() {
    return this;
}

/**
* Initialize blank IopaContext object
* Generic properties common to all server types included
*
* @method Init
*/
IopaContext.prototype.init = function init() {
    this[IOPA.Version] = "1.2";
    var _cancellationTokenSource = Cancellation();
    this[SERVER.CallCancelledSource] = _cancellationTokenSource;
    this[SERVER.Capabilities] = {};
    this[IOPA.CallCancelled] = _cancellationTokenSource.token;
    this[IOPA.Events] = new Events.EventEmitter();
    this[IOPA.Seq] = "#" + _nextSequence();
    return this;
};

// INITIALIZATION
contextExtensionsAddTo(IopaContext.prototype);

/**
 * Represents IopaContext Factory of up to 100 items
 *
 * @instance IopaContextFactory

 * @method alloc()  get new IopaContext from pool or by creation if none available; remember to call context.init();
 * @method free(context)   return IopaContext to the pool for reuse
 */
function Factory(options) {
    _classCallCheck(this, Factory);

    options = options || {};
    var size = options["factory.Size"] || 100;

    this._logger = options[SERVER.Logger] || console;

    this._factory = new FreeList('IopaContext', size, function () { return IopaContext.apply(Object.create(IopaContext.prototype)); });
}

Object.defineProperty(Factory.prototype, SERVER.Logger, {
    get: function () { return this._logger; },
    set: function (value) { this._logger = value; }
});

/**
* Create a new barebones IOPA Request with or without a response record
*/
Factory.prototype._create = function factory_create() {
    var context = this._factory.alloc().init();
    context.dispose = this._dispose.bind(this, context);
    context[SERVER.Logger] = this._logger;
    context[SERVER.Factory] = this;
     return context;
};

/**
* Release the memory used by a given IOPA Context
*
* @param context the context to free
*/
Factory.prototype._dispose = function factory_dispose(context) {
    if (context == null || context[IOPA.Seq] == null)
        return;

    if (context.response) {
        var response = context.response;
        for (var prop in response) { if (response.hasOwnProperty(prop)) { response[prop] = null; } }
        this._factory.free(response);
    }

    for (var prop in context) { if (context.hasOwnProperty(prop)) { context[prop] = null; } };

    this._factory.free(context);
};

/**
* Create a new IOPA Context, with default [iopa.*] values populated
*/
Factory.prototype.createContext = function factory_createContext() {
    var context = this._create();
    var response = this._create();
    context.response = response;
    context.response[SERVER.ParentContext] = context;

    context[IOPA.Headers] = {};
    context[IOPA.Method] = "";
    context[IOPA.Host] = "";
    context[IOPA.Path] = "";
    context[IOPA.PathBase] = "";
    context[IOPA.Protocol] = "";
    context[IOPA.QueryString] = "";
    context[IOPA.Scheme] = "";
    context[IOPA.Body] = null;

    response[IOPA.Headers] = {};
    response[IOPA.StatusCode] = null;
    response[IOPA.ReasonPhrase] = "";
    response[IOPA.Protocol] = "";
    response[IOPA.Body] = null;
    response[IOPA.Headers]["Content-Length"] = "-1";

    return context;
};

/**
* Create a new IOPA Context, with default [iopa.*] values populated
*/
Factory.prototype.mergeCapabilities = function factory_mergeCapabilities(childContext, parentContext) {

    childContext[SERVER.ParentContext] = parentContext;
    merge(childContext[SERVER.Capabilities], cloneDoubleLayer(parentContext[SERVER.Capabilities]));

    if (childContext.response)
       merge(childContext[SERVER.Capabilities], cloneDoubleLayer(parentContext[SERVER.Capabilities]));

};

/**
* Create a new IOPA Context, with default [iopa.*] values populated
*/
Factory.prototype.createRequest = function createRequest(urlStr, options, withResponse) {

    if (typeof options === 'string' || options instanceof String)
        options = { "iopa.Method": options };

    options = options || {};

    var context = this._create();
    context[SERVER.IsLocalOrigin] = true;
    context[SERVER.IsRequest] = true;
    context[SERVER.OriginalUrl] = urlStr;
    context[IOPA.Method] = options[IOPA.Method] || IOPA.METHODS.GET;

    var urlParsed = URL.parse(urlStr);
    context[IOPA.PathBase] = "";
    context[IOPA.Path] = urlParsed.pathname || "";
    context[IOPA.QueryString] = urlParsed.query;
    context[IOPA.Scheme] = urlParsed.protocol;
    context[SERVER.RemoteAddress] = urlParsed.hostname;
    context[IOPA.Host] = urlParsed.hostname;
    context[IOPA.Headers] = {};
    context[IOPA.Body] = null;

    const SCHEMES = IOPA.SCHEMES,
        PROTOCOLS = IOPA.PROTOCOLS,
        PORTS = IOPA.PORTS

    switch (urlParsed.protocol) {
        case SCHEMES.HTTP:
            context[IOPA.Protocol] = PROTOCOLS.HTTP;
            context[SERVER.TLS] = false;
            context[IOPA.Headers]["Host"] = context[IOPA.Host];
            context[SERVER.RemotePort] = urlParsed.port || PORTS.HTTP;
            break;
        case SCHEMES.HTTPS:
            context[IOPA.Protocol] = PROTOCOLS.HTTP;
            context[SERVER.TLS] = true;
            context[IOPA.Headers]["Host"] = context[IOPA.Host];
            context[SERVER.RemotePort] = urlParsed.port || PORTS.HTTPS;
            break;
        case SCHEMES.COAP:
            context[IOPA.Protocol] = PROTOCOLS.COAP;
            context[SERVER.TLS] = false;
            context[SERVER.RemotePort] = urlParsed.port || PORTS.COAP;
            break;
        case SCHEMES.COAPS:
            context[IOPA.Protocol] = PROTOCOLS.COAP;
            context[SERVER.TLS] = true;
            context[SERVER.RemotePort] = urlParsed.port || PORTS.COAPS;
            break;
        case SCHEMES.MQTT:
            context[IOPA.Protocol] = PROTOCOLS.MQTT;
            context[SERVER.TLS] = false;
            context[SERVER.RemotePort] = urlParsed.port || PORTS.MQTT;
            break;
        case SCHEMES.MQTTS:
            context[IOPA.Protocol] = PROTOCOLS.MQTT;
            context[SERVER.TLS] = true;
            context[SERVER.RemotePort] = urlParsed.port || PORTS.MQTTS;
            break;
        default:
            context[IOPA.Protocol] = urlParsed.protocol;
            context[SERVER.TLS] = false;
            context[SERVER.RemotePort] = urlParsed.port || 0;
    };

    mergeContext(context, options);

    return context;
};

/**
* Create a new IOPA Context, with default [iopa.*] values populated
*/
Factory.prototype.createRequestResponse = function createRequestResponse(urlStr, options) {
    var context = this.createRequest(urlStr, options);

    var response = this._create();
    context.response = response;
    context.response[SERVER.ParentContext] = context;

    response[IOPA.Headers] = {};
    response[IOPA.StatusCode] = null;
    response[IOPA.ReasonPhrase] = "";
    response[IOPA.Protocol] = context[IOPA.Protocol];
    response[IOPA.Body] = null;
    response[SERVER.TLS] = context[SERVER.TLS];
    response[SERVER.RemoteAddress] = context[SERVER.RemoteAddress];
    response[SERVER.RemotePort] = context[SERVER.RemotePort];
    response[SERVER.IsLocalOrigin] = false;
    response[SERVER.IsRequest] = false;
    response[SERVER.Logger] = context[SERVER.Logger];

    return context;
}

const maxSequence = Math.pow(2, 16);
var _lastSequence = Math.floor(Math.random() * (maxSequence - 1));

function _nextSequence() {
    if (++_lastSequence === maxSequence)
        _lastSequence = 1;

    return _lastSequence.toString();
};

// EXPORTS
exports.default = Factory;<commit_msg>dev test<commit_after>/*
 * Copyright (c) 2015 Internet of Protocols Alliance (IOPA)
 *
 * 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.
 */

const FreeList = require('../util/freelist').FreeList,
    Events = require('events'),
    URL = require('url'),

    Cancellation = require('../util/cancellation').default,
    contextExtensionsAddTo = require('./contextExtensions').addTo,

    constants = require('./constants'),
    IOPA = constants.IOPA,
    SERVER = constants.SERVER,

    mergeContext = require('../util/shallow').mergeContext,
    cloneDoubleLayer = require('../util/shallow').cloneDoubleLayer,
    merge = require('../util/shallow').merge

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

/* *********************************************************
 * IOPA CONTEXT
 * ********************************************************* */

/**
 * Represents IOPA Context object for any REST Request/Response
 * See http://iopa.io for further details
 *
 * @class IopaContext
 * @constructor
 */
function IopaContext() {
    return this;
}

/**
* Initialize blank IopaContext object
* Generic properties common to all server types included
*
* @method Init
*/
IopaContext.prototype.init = function init() {
    this[IOPA.Version] = "1.2";
    var _cancellationTokenSource = Cancellation();
    this[SERVER.CallCancelledSource] = _cancellationTokenSource;
    this[SERVER.Capabilities] = {};
    this[IOPA.CallCancelled] = _cancellationTokenSource.token;
    this[IOPA.Events] = new Events.EventEmitter();
    this[IOPA.Seq] = "#" + _nextSequence();
    return this;
};

// INITIALIZATION
contextExtensionsAddTo(IopaContext.prototype);

/**
 * Represents IopaContext Factory of up to 100 items
 *
 * @instance IopaContextFactory

 * @method alloc()  get new IopaContext from pool or by creation if none available; remember to call context.init();
 * @method free(context)   return IopaContext to the pool for reuse
 */
function Factory(options) {
    _classCallCheck(this, Factory);

    options = options || {};
    var size = options["factory.Size"] || 100;

    this._logger = options[SERVER.Logger] || console;

    this._factory = new FreeList('IopaContext', size, function () { return IopaContext.apply(Object.create(IopaContext.prototype)); });
}

Object.defineProperty(Factory.prototype, SERVER.Logger, {
    get: function () { return this._logger; },
    set: function (value) { this._logger = value; }
});

/**
* Create a new barebones IOPA Request with or without a response record
*/
Factory.prototype._create = function factory_create() {
    var context = this._factory.alloc().init();
    context.dispose = this._dispose.bind(this, context);
    context[SERVER.Logger] = this._logger;
    context[SERVER.Factory] = this;
     return context;
};

/**
* Release the memory used by a given IOPA Context
*
* @param context the context to free
*/
Factory.prototype._dispose = function factory_dispose(context) {
    if (context == null || context[IOPA.Seq] == null)
        return;

    if (context.response) {
        var response = context.response;
        for (var prop in response) { if (response.hasOwnProperty(prop)) { response[prop] = null; } }
        this._factory.free(response);
    }

    for (var prop in context) { if (context.hasOwnProperty(prop)) { context[prop] = null; } };

    this._factory.free(context);
};

/**
* Create a new IOPA Context, with default [iopa.*] values populated
*/
Factory.prototype.createContext = function factory_createContext() {
    var context = this._create();
    var response = this._create();
    context.response = response;
    context.response[SERVER.ParentContext] = context;

    context[IOPA.Headers] = {};
    context[IOPA.Method] = "";
    context[IOPA.Host] = "";
    context[IOPA.Path] = "";
    context[IOPA.PathBase] = "";
    context[IOPA.Protocol] = "";
    context[IOPA.QueryString] = "";
    context[IOPA.Scheme] = "";
    context[IOPA.Body] = null;

    response[IOPA.Headers] = {};
    response[IOPA.StatusCode] = null;
    response[IOPA.ReasonPhrase] = "";
    response[IOPA.Protocol] = "";
    response[IOPA.Body] = null;
    response[IOPA.Headers]["Content-Length"] = "-1";

    return context;
};

/**
* Create a new IOPA Context, with default [iopa.*] values populated
*/
Factory.prototype.mergeCapabilities = function factory_mergeCapabilities(childContext, parentContext) {

    childContext[SERVER.ParentContext] = parentContext;
    merge(childContext[SERVER.Capabilities], cloneDoubleLayer(parentContext[SERVER.Capabilities]));

    if (childContext.response)
       merge(childContext[SERVER.Capabilities], cloneDoubleLayer(parentContext[SERVER.Capabilities]));

};

/**
* Create a new IOPA Context, with default [iopa.*] values populated
*/
Factory.prototype.createRequest = function createRequest(urlStr, options) {

    if (typeof options === 'string' || options instanceof String)
        options = { "iopa.Method": options };

    options = options || {};

    var context = this._create();
    context[SERVER.IsLocalOrigin] = true;
    context[SERVER.IsRequest] = true;
    context[SERVER.OriginalUrl] = urlStr;
    context[IOPA.Method] = options[IOPA.Method] || IOPA.METHODS.GET;

    var urlParsed = URL.parse(urlStr);
    context[IOPA.PathBase] = "";
    context[IOPA.Path] = urlParsed.pathname || "";
    context[IOPA.QueryString] = urlParsed.query;
    context[IOPA.Scheme] = urlParsed.protocol;
    context[SERVER.RemoteAddress] = urlParsed.hostname;
    context[IOPA.Host] = urlParsed.hostname;
    context[IOPA.Headers] = {};
    context[IOPA.Body] = null;

    const SCHEMES = IOPA.SCHEMES,
        PROTOCOLS = IOPA.PROTOCOLS,
        PORTS = IOPA.PORTS

    switch (urlParsed.protocol) {
        case SCHEMES.HTTP:
            context[IOPA.Protocol] = PROTOCOLS.HTTP;
            context[SERVER.TLS] = false;
            context[IOPA.Headers]["Host"] = context[IOPA.Host];
            context[SERVER.RemotePort] = urlParsed.port || PORTS.HTTP;
            break;
        case SCHEMES.HTTPS:
            context[IOPA.Protocol] = PROTOCOLS.HTTP;
            context[SERVER.TLS] = true;
            context[IOPA.Headers]["Host"] = context[IOPA.Host];
            context[SERVER.RemotePort] = urlParsed.port || PORTS.HTTPS;
            break;
        case SCHEMES.COAP:
            context[IOPA.Protocol] = PROTOCOLS.COAP;
            context[SERVER.TLS] = false;
            context[SERVER.RemotePort] = urlParsed.port || PORTS.COAP;
            break;
        case SCHEMES.COAPS:
            context[IOPA.Protocol] = PROTOCOLS.COAP;
            context[SERVER.TLS] = true;
            context[SERVER.RemotePort] = urlParsed.port || PORTS.COAPS;
            break;
        case SCHEMES.MQTT:
            context[IOPA.Protocol] = PROTOCOLS.MQTT;
            context[SERVER.TLS] = false;
            context[SERVER.RemotePort] = urlParsed.port || PORTS.MQTT;
            break;
        case SCHEMES.MQTTS:
            context[IOPA.Protocol] = PROTOCOLS.MQTT;
            context[SERVER.TLS] = true;
            context[SERVER.RemotePort] = urlParsed.port || PORTS.MQTTS;
            break;
        default:
            context[IOPA.Protocol] = urlParsed.protocol;
            context[SERVER.TLS] = false;
            context[SERVER.RemotePort] = urlParsed.port || 0;
    };

    mergeContext(context, options);

    return context;
};

/**
* Create a new IOPA Context, with default [iopa.*] values populated
*/
Factory.prototype.createRequestResponse = function createRequestResponse(urlStr, options) {
    var context = this.createRequest(urlStr, options);

    var response = this._create();
    context.response = response;
    context.response[SERVER.ParentContext] = context;

    response[IOPA.Headers] = {};
    response[IOPA.StatusCode] = null;
    response[IOPA.ReasonPhrase] = "";
    response[IOPA.Protocol] = context[IOPA.Protocol];
    response[IOPA.Body] = null;
    response[SERVER.TLS] = context[SERVER.TLS];
    response[SERVER.RemoteAddress] = context[SERVER.RemoteAddress];
    response[SERVER.RemotePort] = context[SERVER.RemotePort];
    response[SERVER.IsLocalOrigin] = false;
    response[SERVER.IsRequest] = false;
    response[SERVER.Logger] = context[SERVER.Logger];

    return context;
}

const maxSequence = Math.pow(2, 16);
var _lastSequence = Math.floor(Math.random() * (maxSequence - 1));

function _nextSequence() {
    if (++_lastSequence === maxSequence)
        _lastSequence = 1;

    return _lastSequence.toString();
};

// EXPORTS
exports.default = Factory;<|endoftext|>


<commit_before>"use strict";

var cluster = require('cluster');
var _ = require('underscore'),
	fs = require('fs'),
	mime = require('mime'),
	crypto = require('crypto');
var view = require('./view');

var resource_path, resource_url, debug_mode;
var resources;

function Renderer () { };

exports.Renderer = Renderer;

Renderer.prototype.render = function (name, args) {
	if(!this._target_view) throw new Error('target view is not set');

	if(typeof name === 'object' && !args) {
		args = name;
		name = null;
	}

	var target_view = this._target_view;

	if(!target_view._content_func || !target_view._mime_func) {
		this.error('template ' + (name ? '"' + name + '" ' : '') + 'is not defined in ' + target_view._filename);
		return this;
	}

	var mime = target_view._mime_func(name),
		content = target_view._content_func(name, this._response_locale);

	if(target_view._isTemplate && target_view._isString) {
		if(args) {
			try {
				content = new Buffer(_.template(content, args), 'utf8');
			} catch(e) {
				this.error('templating error in ' + name + ': ' + e.toString());
				return this;
			}
		} else
			content = new Buffer(content, 'utf8');
	} else if(target_view._isTemplate == false) {
		content = content(args);
		if(mime === 'application/json' && typeof content === 'object') content = new Buffer(JSON.stringify(content));
	}

	return this.body(content).contentType(mime);
};

exports.interceptResourceRequest = function (request, response) {
	if(!resources) return false;

	var path = request.pathname(),
		method = request.method(),
		accept = request.accept();

	if(!path || !method || !accept || method !== 'GET')
		return false;

	for(var i=0; i<resource_url.length; i++) {
		if(i >= path.length) return false;
		if(resource_url[i] !== path[i]) return false;
	}

	if(debug_mode) {
		path = resource_path + path.substring(resource_url.length, path.length);
		var item = readFile(path, true);
		if(!item) return response.NotFound().commit();

		response.OK()
		        .body(item.content)
		        .contentType(item.content_type)
		        .commit();
		return true;
	}

	var item = resources[path];
	if(item) {
		var item_accept = item.content_type.split('/');

		for(var i=0; i<accept.length; i++) {
			var _accept = accept[i].split('/');
			_accept[0] = _accept[0] && _accept[0].trim();
			_accept[1] = _accept[1] && _accept[1].trim();

			if((_accept[0] === '*' || item_accept[0] === _accept[0]) &&
					(_accept[1] === '*' || item_accept[1] === _accept[1])) {
				if(request.isModified(item.etag, item.last_modified)) {
					response.OK()
							.body(item.content)
							.contentType(item.content_type)
							.cacheFor(item.etag, item.last_modified)
							.commit();
				} else
					response.NotModified(item.etag, item.last_modified).commit();
				return true;
			}
		}
	}

	return false;
};

exports.bindResources = function (resourcepath, bindurl, debug) {
	var fs_queue = [], file_count = 0, byte_count = 0;
	resource_path = resourcepath;
	resource_url = bindurl;
	resources = {};

	if(debug === true) {
		if(cluster.isMaster) global.gozy.info('Static resources will not be cached since debug mode is enabled');
		debug_mode = true;
		return this;
	}

	fs.readdirSync(resource_path).forEach(function (file_name) {
		fs_queue.push(resource_path + '/' + file_name);
	});

	while(fs_queue.length > 0) {
		var path = fs_queue.pop();
		var stat = fs.statSync(path);

		if(stat.isDirectory()) {
			fs.readdirSync(path).forEach(function (file_name) {
				fs_queue.push(path + '/' + file_name);
			});
		} else if(stat.isFile()) {
			var name = path.substring(resource_path.length, path.length);

			file = readFile(path);
			if(!file) continue;

			resources[resource_url + name] = file;

			byte_count += file.content.length;
			file_count++;
		}
	}

	if(cluster.isMaster) global.gozy.info(file_count + ' static resources (' +  parseInt(byte_count / 1024) + ' kB) cached');
	return this;
};

function readFile(path, disableHash) {
	var exist = fs.existsSync(path);
	if(!exist) return null;
	var stat = stat = fs.statSync(path);
	if(!stat.isFile()) return null;
	var buf = fs.readFileSync(path)

	return {
		'content': buf,
		'etag': disableHash === true ? null : getHash(buf),
		'last_modified': stat.mtime.toUTCString(),
		'content_type': mime.lookup(path)
	};
}

function getHash(buf) {
	var sha1 = crypto.createHash('sha1');
	sha1.update(buf);
	return sha1.digest('base64');
}<commit_msg>fix strict issue<commit_after>"use strict";

var cluster = require('cluster');
var _ = require('underscore'),
	fs = require('fs'),
	mime = require('mime'),
	crypto = require('crypto');
var view = require('./view');

var resource_path, resource_url, debug_mode;
var resources;

function Renderer () { };

exports.Renderer = Renderer;

Renderer.prototype.render = function (name, args) {
	if(!this._target_view) throw new Error('target view is not set');

	if(typeof name === 'object' && !args) {
		args = name;
		name = null;
	}

	var target_view = this._target_view;

	if(!target_view._content_func || !target_view._mime_func) {
		this.error('template ' + (name ? '"' + name + '" ' : '') + 'is not defined in ' + target_view._filename);
		return this;
	}

	var mime = target_view._mime_func(name),
		content = target_view._content_func(name, this._response_locale);

	if(target_view._isTemplate && target_view._isString) {
		if(args) {
			try {
				content = new Buffer(_.template(content, args), 'utf8');
			} catch(e) {
				this.error('templating error in ' + name + ': ' + e.toString());
				return this;
			}
		} else
			content = new Buffer(content, 'utf8');
	} else if(target_view._isTemplate == false) {
		content = content(args);
		if(mime === 'application/json' && typeof content === 'object') content = new Buffer(JSON.stringify(content));
	}

	return this.body(content).contentType(mime);
};

exports.interceptResourceRequest = function (request, response) {
	if(!resources) return false;

	var path = request.pathname(),
		method = request.method(),
		accept = request.accept();

	if(!path || !method || !accept || method !== 'GET')
		return false;

	for(var i=0; i<resource_url.length; i++) {
		if(i >= path.length) return false;
		if(resource_url[i] !== path[i]) return false;
	}

	if(debug_mode) {
		path = resource_path + path.substring(resource_url.length, path.length);
		var item = readFile(path, true);
		if(!item) return response.NotFound().commit();

		response.OK()
		        .body(item.content)
		        .contentType(item.content_type)
		        .commit();
		return true;
	}

	var item = resources[path];
	if(item) {
		var item_accept = item.content_type.split('/');

		for(var i=0; i<accept.length; i++) {
			var _accept = accept[i].split('/');
			_accept[0] = _accept[0] && _accept[0].trim();
			_accept[1] = _accept[1] && _accept[1].trim();

			if((_accept[0] === '*' || item_accept[0] === _accept[0]) &&
					(_accept[1] === '*' || item_accept[1] === _accept[1])) {
				if(request.isModified(item.etag, item.last_modified)) {
					response.OK()
							.body(item.content)
							.contentType(item.content_type)
							.cacheFor(item.etag, item.last_modified)
							.commit();
				} else
					response.NotModified(item.etag, item.last_modified).commit();
				return true;
			}
		}
	}

	return false;
};

exports.bindResources = function (resourcepath, bindurl, debug) {
	var fs_queue = [], file_count = 0, byte_count = 0;
	resource_path = resourcepath;
	resource_url = bindurl;
	resources = {};

	if(debug === true) {
		if(cluster.isMaster) global.gozy.info('Static resources will not be cached since debug mode is enabled');
		debug_mode = true;
		return this;
	}

	fs.readdirSync(resource_path).forEach(function (file_name) {
		fs_queue.push(resource_path + '/' + file_name);
	});

	while(fs_queue.length > 0) {
		var path = fs_queue.pop();
		var stat = fs.statSync(path);

		if(stat.isDirectory()) {
			fs.readdirSync(path).forEach(function (file_name) {
				fs_queue.push(path + '/' + file_name);
			});
		} else if(stat.isFile()) {
			var name = path.substring(resource_path.length, path.length);

			var file = readFile(path);
			if(!file) continue;

			resources[resource_url + name] = file;

			byte_count += file.content.length;
			file_count++;
		}
	}

	if(cluster.isMaster) global.gozy.info(file_count + ' static resources (' +  parseInt(byte_count / 1024) + ' kB) cached');
	return this;
};

function readFile(path, disableHash) {
	var exist = fs.existsSync(path);
	if(!exist) return null;
	var stat = stat = fs.statSync(path);
	if(!stat.isFile()) return null;
	var buf = fs.readFileSync(path)

	return {
		'content': buf,
		'etag': disableHash === true ? null : getHash(buf),
		'last_modified': stat.mtime.toUTCString(),
		'content_type': mime.lookup(path)
	};
}

function getHash(buf) {
	var sha1 = crypto.createHash('sha1');
	sha1.update(buf);
	return sha1.digest('base64');
}<|endoftext|>


<commit_before><commit_msg>remove QA cads from example<commit_after><|endoftext|>


<commit_before>import { createActionType } from 'ethical-jobs-redux';
import Api from 'ethical-jobs-sdk';

/*
|--------------------------------------------------------------------------
| Action Types
|--------------------------------------------------------------------------
*/

export const FETCH_COLLECTION = createActionType('JOBS/FETCH_COLLECTION');
export const FETCH_ENTITY = createActionType('JOBS/FETCH_ENTITY');
export const SEARCH = createActionType('JOBS/SEARCH');
export const CREATE = createActionType('JOBS/CREATE');
export const UPDATE = createActionType('JOBS/UPDATE');
export const ARCHIVE = createActionType('JOBS/ARCHIVE');
export const RESTORE = createActionType('JOBS/RESTORE');
export const APPROVE = createActionType('JOBS/APPROVE');
export const EXPIRE = createActionType('JOBS/EXPIRE');
export const ATTACH = createActionType('JOBS/ATTACH');
export const DETACH = createActionType('JOBS/DETACH');
export const CLEAR_ENTITIES = createActionType('JOBS/CLEAR_ENTITIES');
export const UPDATE_FILTERS = createActionType('JOBS/UPDATE_FILTERS');
export const REPLACE_FILTERS = createActionType('JOBS/REPLACE_FILTERS');
export const CLEAR_FILTERS = createActionType('JOBS/CLEAR_FILTERS');
export const UPDATE_SYNC_FILTERS = createActionType('JOBS/UPDATE_SYNC_FILTERS');

/*
|--------------------------------------------------------------------------
| Async Actions
|--------------------------------------------------------------------------
*/

export const fetchCollection = params => ({
  type: FETCH_COLLECTION,
  payload: Api.get('/jobs', params),
});

export const searchCollection = params => ({
  type: SEARCH,
  payload: Api.search('jobs', params),
});

export const fetchEntity = id => ({
  type: FETCH_ENTITY,
  payload: Api.get(`/jobs/${id}`),
});

export const create = params => ({
  type: CREATE,
  payload: Api.post('/jobs', params),
});

export const draft = params => ({
  type: CREATE,
  payload: Api.post('/jobs/drafts', params),
});

export const update = (id, params) => ({
  type: UPDATE,
  payload: Api.put(`/jobs/${id}`, params),
});

export const archive = id => ({
  type: ARCHIVE,
  payload: Api.archive('jobs', id),
});

export const restore = id => ({
  type: RESTORE,
  payload: Api.restore('jobs', id),
});

export const approve = id => ({
  type: APPROVE,
  payload: Api.jobs.approve(id),
});

export const expire = id => ({
  type: EXPIRE,
  payload: Api.jobs.expire(id),
});

export const attachMedia = (id, file) => ({
  type: ATTACH,
  payload: Api.media.attach(file, 'jobs', id),
});

export const detachMedia = (id) => ({
  type: DETACH,
  payload: Api.media.detach(id, 'jobs'),
});

/*
|--------------------------------------------------------------------------
| Sync Actions
|--------------------------------------------------------------------------
*/

export const clear = () => ({
  type: CLEAR_ENTITIES,
});

export const updateFilters = filters => ({
  type: UPDATE_FILTERS,
  payload: filters,
});

export const replaceFilters = filters => ({
  type: REPLACE_FILTERS,
  payload: filters,
});

export const clearFilters = filters => ({
  type: CLEAR_FILTERS,
  payload: filters,
});

export const updateSyncFilters = filters => ({
  type: UPDATE_SYNC_FILTERS,
  payload: filters,
});
<commit_msg>Added the implementation of the actions<commit_after>import { createActionType } from 'ethical-jobs-redux';
import Api from 'ethical-jobs-sdk';

/*
|--------------------------------------------------------------------------
| Action Types
|--------------------------------------------------------------------------
*/

export const FETCH_COLLECTION = createActionType('JOBS/FETCH_COLLECTION');
export const FETCH_ENTITY = createActionType('JOBS/FETCH_ENTITY');
export const SEARCH = createActionType('JOBS/SEARCH');
export const CREATE = createActionType('JOBS/CREATE');
export const UPDATE = createActionType('JOBS/UPDATE');
export const ARCHIVE = createActionType('JOBS/ARCHIVE');
export const RESTORE = createActionType('JOBS/RESTORE');
export const APPROVE = createActionType('JOBS/APPROVE');
export const EXPIRE = createActionType('JOBS/EXPIRE');
export const ATTACH = createActionType('JOBS/ATTACH');
export const DETACH = createActionType('JOBS/DETACH');
export const LOCK = createActionType('JOBS/LOCK');
export const UNLOCK = createActionType('JOBS/UNLOCK');
export const CLEAR_ENTITIES = createActionType('JOBS/CLEAR_ENTITIES');
export const UPDATE_FILTERS = createActionType('JOBS/UPDATE_FILTERS');
export const REPLACE_FILTERS = createActionType('JOBS/REPLACE_FILTERS');
export const CLEAR_FILTERS = createActionType('JOBS/CLEAR_FILTERS');
export const UPDATE_SYNC_FILTERS = createActionType('JOBS/UPDATE_SYNC_FILTERS');

/*
|--------------------------------------------------------------------------
| Async Actions
|--------------------------------------------------------------------------
*/

export const fetchCollection = params => ({
  type: FETCH_COLLECTION,
  payload: Api.get('/jobs', params),
});

export const searchCollection = params => ({
  type: SEARCH,
  payload: Api.search('jobs', params),
});

export const fetchEntity = id => ({
  type: FETCH_ENTITY,
  payload: Api.get(`/jobs/${id}`),
});

export const create = params => ({
  type: CREATE,
  payload: Api.post('/jobs', params),
});

export const draft = params => ({
  type: CREATE,
  payload: Api.post('/jobs/drafts', params),
});

export const update = (id, params) => ({
  type: UPDATE,
  payload: Api.put(`/jobs/${id}`, params),
});

export const archive = id => ({
  type: ARCHIVE,
  payload: Api.archive('jobs', id),
});

export const restore = id => ({
  type: RESTORE,
  payload: Api.restore('jobs', id),
});

export const approve = id => ({
  type: APPROVE,
  payload: Api.jobs.approve(id),
});

export const expire = id => ({
  type: EXPIRE,
  payload: Api.jobs.expire(id),
});

export const attachMedia = (id, file) => ({
  type: ATTACH,
  payload: Api.media.attach(file, 'jobs', id),
});

export const detachMedia = (id) => ({
  type: DETACH,
  payload: Api.media.detach(id, 'jobs'),
});

export const lock = (params) => ({
  type: LOCK,
  payload: Api.post('/jobs/users', params),
});

export const unlock = (params) => ({
  type: UNLOCK,
  payload: Api.delete('/jobs/users', params),
});

/*
|--------------------------------------------------------------------------
| Sync Actions
|--------------------------------------------------------------------------
*/

export const clear = () => ({
  type: CLEAR_ENTITIES,
});

export const updateFilters = filters => ({
  type: UPDATE_FILTERS,
  payload: filters,
});

export const replaceFilters = filters => ({
  type: REPLACE_FILTERS,
  payload: filters,
});

export const clearFilters = filters => ({
  type: CLEAR_FILTERS,
  payload: filters,
});

export const updateSyncFilters = filters => ({
  type: UPDATE_SYNC_FILTERS,
  payload: filters,
});
<|endoftext|>


<commit_before>/*************************************************************************
 *   Copyright (C) 2011-2013 by Paul-Louis Ageneau                       *
 *   paul-louis (at) ageneau (dot) org                                   *
 *                                                                       *
 *   This file is part of TeapotNet.                                     *
 *                                                                       *
 *   TeapotNet is free software: you can redistribute it and/or modify   *
 *   it under the terms of the GNU Affero General Public License as      *
 *   published by the Free Software Foundation, either version 3 of      *
 *   the License, or (at your option) any later version.                 *
 *                                                                       *
 *   TeapotNet is distributed in the hope that it will be useful, but    *
 *   WITHOUT ANY WARRANTY; without even the implied warranty of          *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the        *
 *   GNU Affero General Public License for more details.                 *
 *                                                                       *
 *   You should have received a copy of the GNU Affero General Public    *
 *   License along with TeapotNet.                                       *
 *   If not, see <http://www.gnu.org/licenses/>.                         *
 *************************************************************************/

function listDirectory(url, object, showButtons) {

	$(object).empty();

	if(showButtons) {
		var location = url.split('?')[0];
		//var parentLink = (location[location.length-1] == '/' ? '..' : '.');
		$(object)
			//.append(' '+data.length+' files')
			//.append('')
			.append('');

		$(object).find('a.refreshlink').click(function() {
			listDirectory(url, object, showButtons);
			return false;
		});
	}

	$(object).append('

');

	listDirectoryRec(url, object);
}

function listDirectoryRec(url, object) {
	var table = $(object).find('table.files');
	var next = table.find('tr').length;

	$.ajax({
		url: url.appendParam("next", next),
		dataType: 'json',
		timeout: 300000
	})
	.done(function(data) {
		$(object).find('.gifloading').remove();

		if(data && data.length > 0) {

			if(table.length == 0) {
				$(object).append('

');
				table = $(object).find('table.files');
			}

			for(var i=0; i<data.length; i++) {
				var resource = data[i];

				var link = '/file/' + resource.digest;
				var line = '
';
				if(resource.type == "directory") {
					line+= '	';
					line+= ''+resource.name.escape()+'	';
					line+= '	';
				}
				else {
					var pos = resource.name.escape().lastIndexOf('.');
					var extension = (pos > 0 ? resource.name.escape().substring(pos+1,resource.name.escape().length) : '');
					var isPlayable = (resource.type != "directory") && isPlayableResource(resource.name);

					line+= '	';
					line+= ''+extension.toUpperCase()+' <a href="'+link.escape()+(isPlayable && deviceAgent.indexOf('android') < 0 ? '?play=1' : '')+'">'+resource.name.escape()+'	';
					line+= '';
					if(isPlayable) line+= '';
					line+= '	';
				}
				line+= '
';
				table.append(line);

				if(resource.name.length > 0 && (resource.name[0] == '_' || resource.name[0] == '.'))
					table.find('tr:last').hide();
			}

			table.find('tr').css('cursor', 'pointer').click(function() {
				window.location.href = $(this).find('a').attr('href');
			});

			// Order files
			table.html(table.find('tr').detach().sort(function(a,b){
				return $(a).find(".filename").text() > $(b).find(".filename").text();
			}));

			listDirectoryRec(url, object);
		}
		else {
			if(table.find('tr:visible').length == 0) {
				$(object).append('
No files
');
			}
		}
	})
	.fail(function(jqXHR, textStatus) {
		$(object).find('.gifloading').remove();

		if(table.find('tr:visible').length == 0) {
			$(object).append('
Unable to access files
');
		}
	});
}

function listFileSelector(url, object, input, inputName, parents) {

	$(object).html('');

	$.ajax({
		url: url,
		dataType: 'json',
		timeout: 30000
	})
	.done(function(data) {
		if(!data) data = [];

		$(object).html('
Select a file
')

		if(parents.length > 0) {
			$(object)
				.append(' '+data.length+' files')
				.append('')
				.find('a.parentlink').click(function() {
					var parentUrl = parents.pop();
					listFileSelector(parentUrl, object, input, inputName, parents);
					return false;
				});
		}

		$(object)
			.append('')
			.find('a.refreshlink').click(function() {
				listFileSelector(url, object, input, inputName, parents);
				return false;
			});

		//$(object).append('Choose another file');

		if(UrlUpload)
		{
			$(object).append('<form id="uploadform" action="'+UrlUpload+'" method="post" enctype="mutipart/form-data"><input type="hidden" name="token" value="'+TokenDirectory+'"><input type="file" id="selector_file" name="selector_file" size="30"></form>');
			$('#selector_file')
				.css('visibility', 'hidden').css('display', 'inline').css('width', '0px').css('margin', '0px').css('padding', '0px')
				.after('Other file')
				.change(function() {
					$(object).children().hide();
					$(object).append('Please wait...');

					$('#uploadform').ajaxSubmit({
						timeout: 600000,
						dataType: 'json',
						error: function() {
							alert('Unable to send the file.');
							$(inputName).val("").change();
							$(input).val("").change();
							$(object).remove();
						},
						success: function(resources) {
							if(resources != null && resources.length > 0)
							{
								var resource = resources[0];
								$(inputName).val(resource.name).change();
								$(input).val(resource.digest).change();
								$(object).remove();
							}
						}
					});
				});
		}

		$(object)
			.append('Cancel')
			.find('a.quitlink').click(function() {
				$(inputName).val("").change();
				$(input).val("").change();
				$(object).remove();
				return false;
			});

		$(object).append('

');
		var table = $(object).find('table');

		for(var i=0; i<data.length; i++) {
			var resource = data[i];

			var line = '
';
			var func;
			(function(resource) { // copy resource (only the reference is passed to callbacks)

			  	if(resource.name.length > 0 && (resource.name[0] == '_' || resource.name[0] == '.'))
					if(resource.name == "_upload") resource.name = "Sent files";
					else return;

				if(resource.type == "directory") {
					line+= '	';
					line+= ''+resource.name.escape()+'	';

					func = function() {
						var link = "/file/" + resource.digest + "?json";
						parents.push(url);
						listFileSelector(link, object, input, inputName, parents);
						return false;
					};
				}
				else {
					line+= '	';
					line+= ''+resource.name.escape()+'	';

					func = function() {
						$(inputName).val(resource.name).change();
						$(input).val(resource.digest).change();
						$(object).remove();
						return false;
					};
				}
			})(resource);
			line+= '
';
			table.append(line);
			table.find('tr:last').click(func).css('cursor', 'pointer');
			table.find('tr:last a').click(func);
		}
	})
	.fail(function(jqXHR, textStatus) {
		$(object)
			.html('')

		if(parents.length > 0) {
			$(object)
				.append('0 files')
				.append('')
				.find('a.parentlink').click(function() {
					var parentUrl = parents.pop();
					listFileSelector(parentUrl, object, input, inputName, parents);
					return false;
				});
		}

		$(object)
			.append('Retry')
			.append('Cancel')
			.append('
Unable to access files
')
			.find('a.refreshlink').click(function() {
				listFileSelector(url, object, input, inputName, parents);
				return false;
			})
			.find('a.quitlink').click(function() {
				$(inputName).val("").change();
				$(input).val("").change();
				$(object).remove();
				return false;
			});
	});
}

function createFileSelector(url, object, input, inputName)
{
	if($(object).html()) {
		$(object).html("");
		$(inputName).val("").change();
		$(input).val("").change();
		return;
	}

	$(object).show();
	$(object).html('

');
	var div = $(object).find('div');
	listFileSelector(url, div, input, inputName, []);
}

function isPlayableResource(fileName)
{
	return (isAudio(fileName) || isVideo(fileName));
}

function isAudio(fileName)
{
	var regexp = new RegExp("(mp3|ogg|ogga|flac|wav|ape|aac|m4a|mp4a|wma)$","i");
	return regexp.test(fileName);
}

function isVideo(fileName)
{
	var regexp = new RegExp("(avi|mkv|ogv|ogx|ogm|wmv|asf|flv|mpg|mpeg|mp4|m4v|mov|3gp|3g2|divx|xvid|rm|rv)$","i");
	return regexp.test(fileName);
}

<commit_msg>Fixed file ordering<commit_after>/*************************************************************************
 *   Copyright (C) 2011-2013 by Paul-Louis Ageneau                       *
 *   paul-louis (at) ageneau (dot) org                                   *
 *                                                                       *
 *   This file is part of TeapotNet.                                     *
 *                                                                       *
 *   TeapotNet is free software: you can redistribute it and/or modify   *
 *   it under the terms of the GNU Affero General Public License as      *
 *   published by the Free Software Foundation, either version 3 of      *
 *   the License, or (at your option) any later version.                 *
 *                                                                       *
 *   TeapotNet is distributed in the hope that it will be useful, but    *
 *   WITHOUT ANY WARRANTY; without even the implied warranty of          *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the        *
 *   GNU Affero General Public License for more details.                 *
 *                                                                       *
 *   You should have received a copy of the GNU Affero General Public    *
 *   License along with TeapotNet.                                       *
 *   If not, see <http://www.gnu.org/licenses/>.                         *
 *************************************************************************/

function listDirectory(url, object, showButtons) {

	$(object).empty();

	if(showButtons) {
		var location = url.split('?')[0];
		//var parentLink = (location[location.length-1] == '/' ? '..' : '.');
		$(object)
			//.append(' '+data.length+' files')
			//.append('')
			.append('');

		$(object).find('a.refreshlink').click(function() {
			listDirectory(url, object, showButtons);
			return false;
		});
	}

	$(object).append('

');

	listDirectoryRec(url, object);
}

function listDirectoryRec(url, object) {
	var table = $(object).find('table.files');
	var next = table.find('tr').length;

	$.ajax({
		url: url.appendParam("next", next),
		dataType: 'json',
		timeout: 300000
	})
	.done(function(data) {
		$(object).find('.gifloading').remove();

		if(data && data.length > 0) {

			if(table.length == 0) {
				$(object).append('

');
				table = $(object).find('table.files');
			}

			for(var i=0; i<data.length; i++) {
				var resource = data[i];

				var link = '/file/' + resource.digest;
				var line = '
';
				if(resource.type == "directory") {
					line+= '	';
					line+= ''+resource.name.escape()+'	';
					line+= '	';
				}
				else {
					var pos = resource.name.escape().lastIndexOf('.');
					var extension = (pos > 0 ? resource.name.escape().substring(pos+1,resource.name.escape().length) : '');
					var isPlayable = (resource.type != "directory") && isPlayableResource(resource.name);

					line+= '	';
					line+= ''+extension.toUpperCase()+' <a href="'+link.escape()+(isPlayable && deviceAgent.indexOf('android') < 0 ? '?play=1' : '')+'">'+resource.name.escape()+'	';
					line+= '';
					if(isPlayable) line+= '';
					line+= '	';
				}
				line+= '
';
				table.append(line);

				if(resource.name.length > 0 && (resource.name[0] == '_' || resource.name[0] == '.'))
					table.find('tr:last').hide();
			}

			table.find('tr').css('cursor', 'pointer').click(function() {
				window.location.href = $(this).find('a').attr('href');
			});

			// Order files
			table.html(table.find('tr').detach().sort(function(a,b){
				return $(a).find(".filename a").text() > $(b).find(".filename a").text();
			}));

			listDirectoryRec(url, object);
		}
		else {
			if(table.find('tr:visible').length == 0) {
				$(object).append('
No files
');
			}
		}
	})
	.fail(function(jqXHR, textStatus) {
		$(object).find('.gifloading').remove();

		if(table.find('tr:visible').length == 0) {
			$(object).append('
Unable to access files
');
		}
	});
}

function listFileSelector(url, object, input, inputName, parents) {

	$(object).html('');

	$.ajax({
		url: url,
		dataType: 'json',
		timeout: 30000
	})
	.done(function(data) {
		if(!data) data = [];

		$(object).html('
Select a file
')

		if(parents.length > 0) {
			$(object)
				.append(' '+data.length+' files')
				.append('')
				.find('a.parentlink').click(function() {
					var parentUrl = parents.pop();
					listFileSelector(parentUrl, object, input, inputName, parents);
					return false;
				});
		}

		$(object)
			.append('')
			.find('a.refreshlink').click(function() {
				listFileSelector(url, object, input, inputName, parents);
				return false;
			});

		//$(object).append('Choose another file');

		if(UrlUpload)
		{
			$(object).append('<form id="uploadform" action="'+UrlUpload+'" method="post" enctype="mutipart/form-data"><input type="hidden" name="token" value="'+TokenDirectory+'"><input type="file" id="selector_file" name="selector_file" size="30"></form>');
			$('#selector_file')
				.css('visibility', 'hidden').css('display', 'inline').css('width', '0px').css('margin', '0px').css('padding', '0px')
				.after('Other file')
				.change(function() {
					$(object).children().hide();
					$(object).append('Please wait...');

					$('#uploadform').ajaxSubmit({
						timeout: 600000,
						dataType: 'json',
						error: function() {
							alert('Unable to send the file.');
							$(inputName).val("").change();
							$(input).val("").change();
							$(object).remove();
						},
						success: function(resources) {
							if(resources != null && resources.length > 0)
							{
								var resource = resources[0];
								$(inputName).val(resource.name).change();
								$(input).val(resource.digest).change();
								$(object).remove();
							}
						}
					});
				});
		}

		$(object)
			.append('Cancel')
			.find('a.quitlink').click(function() {
				$(inputName).val("").change();
				$(input).val("").change();
				$(object).remove();
				return false;
			});

		$(object).append('

');
		var table = $(object).find('table');

		for(var i=0; i<data.length; i++) {
			var resource = data[i];

			var line = '
';
			var func;
			(function(resource) { // copy resource (only the reference is passed to callbacks)

			  	if(resource.name.length > 0 && (resource.name[0] == '_' || resource.name[0] == '.'))
					if(resource.name == "_upload") resource.name = "Sent files";
					else return;

				if(resource.type == "directory") {
					line+= '	';
					line+= ''+resource.name.escape()+'	';

					func = function() {
						var link = "/file/" + resource.digest + "?json";
						parents.push(url);
						listFileSelector(link, object, input, inputName, parents);
						return false;
					};
				}
				else {
					line+= '	';
					line+= ''+resource.name.escape()+'	';

					func = function() {
						$(inputName).val(resource.name).change();
						$(input).val(resource.digest).change();
						$(object).remove();
						return false;
					};
				}
			})(resource);
			line+= '
';
			table.append(line);
			table.find('tr:last').click(func).css('cursor', 'pointer');
			table.find('tr:last a').click(func);
		}
	})
	.fail(function(jqXHR, textStatus) {
		$(object)
			.html('')

		if(parents.length > 0) {
			$(object)
				.append('0 files')
				.append('')
				.find('a.parentlink').click(function() {
					var parentUrl = parents.pop();
					listFileSelector(parentUrl, object, input, inputName, parents);
					return false;
				});
		}

		$(object)
			.append('Retry')
			.append('Cancel')
			.append('
Unable to access files
')
			.find('a.refreshlink').click(function() {
				listFileSelector(url, object, input, inputName, parents);
				return false;
			})
			.find('a.quitlink').click(function() {
				$(inputName).val("").change();
				$(input).val("").change();
				$(object).remove();
				return false;
			});
	});
}

function createFileSelector(url, object, input, inputName)
{
	if($(object).html()) {
		$(object).html("");
		$(inputName).val("").change();
		$(input).val("").change();
		return;
	}

	$(object).show();
	$(object).html('

');
	var div = $(object).find('div');
	listFileSelector(url, div, input, inputName, []);
}

function isPlayableResource(fileName)
{
	return (isAudio(fileName) || isVideo(fileName));
}

function isAudio(fileName)
{
	var regexp = new RegExp("(mp3|ogg|ogga|flac|wav|ape|aac|m4a|mp4a|wma)$","i");
	return regexp.test(fileName);
}

function isVideo(fileName)
{
	var regexp = new RegExp("(avi|mkv|ogv|ogx|ogm|wmv|asf|flv|mpg|mpeg|mp4|m4v|mov|3gp|3g2|divx|xvid|rm|rv)$","i");
	return regexp.test(fileName);
}

<|endoftext|>


<commit_before>// This file was autogenerated by calcdeps.py
goog.addDependency("../../../../hutmap/src/js/third-party/soyutils_usegoog.js", ['soy', 'soy.StringBuilder', 'soy.esc', 'soydata', 'soydata.SanitizedHtml', 'soydata.SanitizedHtmlAttribute', 'soydata.SanitizedJs', 'soydata.SanitizedJsStrChars', 'soydata.SanitizedUri', 'soydata.VERY_UNSAFE'], ['goog.asserts', 'goog.dom.DomHelper', 'goog.format', 'goog.i18n.BidiFormatter', 'goog.i18n.bidi', 'goog.soy', 'goog.soy.data.SanitizedContentKind', 'goog.string', 'goog.string.StringBuffer']);
goog.addDependency("../../../../hutmap/src/js/third-party/wicket-gmap3.src.js", ['Wkt.gmap3'], []);
goog.addDependency("../../../../hutmap/src/js/third-party/utm.js", [], []);
goog.addDependency("../../../../hutmap/src/js/third-party/markerclusterer.js", ['markerclusterer.MarkerClusterer'], []);
goog.addDependency("../../../../hutmap/src/js/third-party/wicket.src.js", ['Wkt.Wkt'], []);
goog.addDependency("../../../../hutmap/src/js/hutmap/hut.js", ['hutmap.Hut'], []);
goog.addDependency("../../../../hutmap/src/js/hutmap/templates.js", ['hutmap.templates'], ['soy', 'soydata']);
goog.addDependency("../../../../hutmap/src/js/hutmap/filters.js", ['hutmap.filters'], []);
goog.addDependency("../../../../hutmap/src/js/hutmap_old/gconsts.js", ['hutmap.consts.g'], []);
goog.addDependency("../../../../hutmap/src/js/hutmap_old/consts.js", ['hutmap.consts'], []);
goog.addDependency("../../../../hutmap/src/js/hutmap_old/history.js", ['hutmap.History'], ['goog.Uri.QueryData', 'goog.debug.Logger']);
goog.addDependency("../../../../hutmap/src/js/hutmap_old/search.js", ['hutmap.Search'], ['goog.debug.Logger', 'goog.dom.DomHelper', 'goog.dom.forms', 'goog.ui.Css3ButtonRenderer', 'goog.ui.CustomButton', 'goog.Uri.QueryData', 'goog.string', 'goog.structs', 'hutmap.consts']);
goog.addDependency("../../../../hutmap/src/js/hutmap_old/huts.js", ['hutmap.Huts'], ['goog.array', 'goog.events', 'goog.events.EventTarget', 'goog.History', 'goog.history.EventType', 'goog.structs', 'goog.Uri.QueryData', 'goog.debug.Console', 'goog.debug.Logger', 'hutmap.Ajax', 'hutmap.History', 'hutmap.consts']);
goog.addDependency("../../../../hutmap/src/js/hutmap_old/ajax.js", ['hutmap.Ajax'], ['goog.dom', 'goog.net.XhrIo', 'goog.net.XhrIoPool', 'goog.net.EventType', 'goog.debug.Logger']);
goog.addDependency("../../../../hutmap/src/js/hutmap_old/map/filter.js", ['hutmap.map.Filter'], ['goog.array', 'goog.events', 'goog.debug.Logger', 'goog.dom', 'goog.ui.TwoThumbSlider', 'goog.ui.Slider', 'goog.ui.Checkbox', 'goog.ui.Component', 'hutmap.consts', 'hutmap.consts.g']);
goog.addDependency("../../../../hutmap/src/js/hutmap_old/map/types.js", ['hutmap.map.Types'], []);
goog.addDependency("../../../../hutmap/src/js/hutmap_old/map/sidebar.js", ['hutmap.map.Sidebar'], ['goog.dom', 'goog.object', 'goog.string', 'hutmap.consts', 'hutmap.consts.g', 'Wkt.Wkt', 'Wkt.gmap3']);
goog.addDependency("../../../../hutmap/src/js/hutmap_old/map/map.js", ['hutmap.map.Map'], ['goog.Uri.QueryData', 'goog.array', 'goog.debug.Logger', 'goog.dom', 'goog.iter', 'goog.structs', 'goog.structs.Map', 'Wkt.Wkt', 'Wkt.gmap3', 'hutmap.History', 'hutmap.Huts', 'hutmap.map.Filter', 'hutmap.map.Sidebar', 'hutmap.map.Types', 'markerclusterer.MarkerClusterer']);
goog.addDependency("../../../../hutmap/src/js/hutmap_old/init/map-init.js", ['hutmap.map'], ['hutmap.History', 'hutmap.Huts', 'hutmap.Search', 'hutmap.consts', 'hutmap.map.Map', 'goog.array', 'goog.debug.Logger', 'goog.dom', 'goog.style', 'goog.ui.Zippy', 'goog.ui.TwoThumbSlider']);
goog.addDependency("../../../../hutmap/src/js/hutmap_old/init/index-init.js", ['hutmap.index'], ['hutmap.Search']);
<commit_msg>Updated deps.js<commit_after>// This file was autogenerated by calcdeps.py
goog.addDependency("../../../../../vagrant/src/js/third-party/soyutils_usegoog.js", ['soy', 'soy.StringBuilder', 'soy.esc', 'soydata', 'soydata.SanitizedHtml', 'soydata.SanitizedHtmlAttribute', 'soydata.SanitizedJs', 'soydata.SanitizedJsStrChars', 'soydata.SanitizedUri', 'soydata.VERY_UNSAFE'], ['goog.asserts', 'goog.dom.DomHelper', 'goog.format', 'goog.i18n.BidiFormatter', 'goog.i18n.bidi', 'goog.soy', 'goog.soy.data.SanitizedContentKind', 'goog.string', 'goog.string.StringBuffer']);
goog.addDependency("../../../../../vagrant/src/js/third-party/wicket-gmap3.src.js", ['Wkt.gmap3'], []);
goog.addDependency("../../../../../vagrant/src/js/third-party/utm.js", [], []);
goog.addDependency("../../../../../vagrant/src/js/third-party/markerclusterer.js", ['markerclusterer.MarkerClusterer'], []);
goog.addDependency("../../../../../vagrant/src/js/third-party/wicket.src.js", ['Wkt.Wkt'], []);
goog.addDependency("../../../../../vagrant/src/js/hutmap/models.js", ['hutmap.Hut', 'hutmap.Agency', 'hutmap.Region'], []);
goog.addDependency("../../../../../vagrant/src/js/hutmap/tooltip.js", [], []);
goog.addDependency("../../../../../vagrant/src/js/hutmap/templates.js", ['hutmap.templates'], ['soy', 'soydata']);
goog.addDependency("../../../../../vagrant/src/js/hutmap/filters.js", ['hutmap.filters'], []);
goog.addDependency("../../../../../vagrant/src/js/hutmap/test.js", ['hutmap.test'], ['goog.events.EventType', 'goog.ui.AdvancedTooltip', 'hutmap.templates']);
goog.addDependency("../../../../../vagrant/src/js/hutmap_old/gconsts.js", ['hutmap.consts.g'], []);
goog.addDependency("../../../../../vagrant/src/js/hutmap_old/consts.js", ['hutmap.consts'], []);
goog.addDependency("../../../../../vagrant/src/js/hutmap_old/history.js", ['hutmap.History'], ['goog.Uri.QueryData', 'goog.debug.Logger']);
goog.addDependency("../../../../../vagrant/src/js/hutmap_old/search.js", ['hutmap.Search'], ['goog.debug.Logger', 'goog.dom.DomHelper', 'goog.dom.forms', 'goog.ui.Css3ButtonRenderer', 'goog.ui.CustomButton', 'goog.Uri.QueryData', 'goog.string', 'goog.structs', 'hutmap.consts']);
goog.addDependency("../../../../../vagrant/src/js/hutmap_old/huts.js", ['hutmap.Huts'], ['goog.array', 'goog.events', 'goog.events.EventTarget', 'goog.History', 'goog.history.EventType', 'goog.structs', 'goog.Uri.QueryData', 'goog.debug.Console', 'goog.debug.Logger', 'hutmap.Ajax', 'hutmap.History', 'hutmap.consts']);
goog.addDependency("../../../../../vagrant/src/js/hutmap_old/ajax.js", ['hutmap.Ajax'], ['goog.dom', 'goog.net.XhrIo', 'goog.net.XhrIoPool', 'goog.net.EventType', 'goog.debug.Logger']);
goog.addDependency("../../../../../vagrant/src/js/hutmap_old/map/filter.js", ['hutmap.map.Filter'], ['goog.array', 'goog.events', 'goog.debug.Logger', 'goog.dom', 'goog.ui.TwoThumbSlider', 'goog.ui.Slider', 'goog.ui.Checkbox', 'goog.ui.Component', 'hutmap.consts', 'hutmap.consts.g']);
goog.addDependency("../../../../../vagrant/src/js/hutmap_old/map/types.js", ['hutmap.map.Types'], []);
goog.addDependency("../../../../../vagrant/src/js/hutmap_old/map/sidebar.js", ['hutmap.map.Sidebar'], ['goog.dom', 'goog.object', 'goog.string', 'hutmap.consts', 'hutmap.consts.g', 'Wkt.Wkt', 'Wkt.gmap3']);
goog.addDependency("../../../../../vagrant/src/js/hutmap_old/map/map.js", ['hutmap.map.Map'], ['goog.Uri.QueryData', 'goog.array', 'goog.debug.Logger', 'goog.dom', 'goog.iter', 'goog.structs', 'goog.structs.Map', 'Wkt.Wkt', 'Wkt.gmap3', 'hutmap.History', 'hutmap.Huts', 'hutmap.map.Filter', 'hutmap.map.Sidebar', 'hutmap.map.Types', 'markerclusterer.MarkerClusterer']);
goog.addDependency("../../../../../vagrant/src/js/hutmap_old/init/map-init.js", ['hutmap.map'], ['hutmap.History', 'hutmap.Huts', 'hutmap.Search', 'hutmap.consts', 'hutmap.map.Map', 'goog.array', 'goog.debug.Logger', 'goog.dom', 'goog.style', 'goog.ui.Zippy', 'goog.ui.TwoThumbSlider']);
goog.addDependency("../../../../../vagrant/src/js/hutmap_old/init/index-init.js", ['hutmap.index'], ['hutmap.Search']);
<|endoftext|>


<commit_before>$(function() {

    var $chartContainer = $('#chart-container')

    function removeStringData(data) {
        var stringColumns = ['component', 'timezone'];
        var doomedIndexes = [];
        var series = data.series[0];
        _.each(series.columns, function(name, index) {
            if (_.contains(stringColumns, name)) {
                doomedIndexes.push(index);
            }
        });
        // Now that we know which indexes are doomed, we reverse the order so we
        // can extract them from the list from the end
        doomedIndexes = doomedIndexes.reverse();
        _.each(doomedIndexes, function(doomed) {
            series.columns.splice(doomed, 1);
        });
        _.each(series.values, function(row) {
            _.each(doomedIndexes, function(doomed) {
                row.splice(doomed, 1);
            });
        });
    }

    function convertJsonDataToCsv(data) {
        var rows = [];
        var series = data.series[0];

        var headers = series.columns;
        var values = series.values;

        rows.push(headers);

        _.each(values, function(values) {
            rows.push(values.join(','));
        });

        return rows.join('\n');
    }

    function prepareChartMarkup(id, name) {
        var $header = $('
' + name + '
');
        var $chart = $('

', {id: id, class: 'chart'});
        $chartContainer.append($header)
                       .append($chart);
    }

    function renderChart(id, data) {
        var el = document.getElementById(id);
        removeStringData(data);
        var csvString = convertJsonDataToCsv(data);
        return new Dygraph(el, csvString, {
            width: 1000,
            series: {
              anomalyScore: {
                axis: 'y2',
                color: 'orange'
              },
              anomalyLikelihood: {
                axis: 'y2',
                color: 'red'
              }
            }
        });
    }

    function renderSensorChart(name, data) {
        console.log(name);
        var id = name.replace('/', '_').replace(/\+/g, '-');
        prepareChartMarkup(id, name);
        renderChart(id, data);
    }

    $.getJSON('/_sensors', function(sensors) {
        _.each(sensors, function(sensorName) {
            $.getJSON('/_sensor/' + sensorName, function(sensorData) {
                renderSensorChart(sensorName, sensorData);
            });
        });
    });
});<commit_msg>Anomaly y axis range<commit_after>$(function() {

    var $chartContainer = $('#chart-container')

    function removeStringData(data) {
        var stringColumns = ['component', 'timezone'];
        var doomedIndexes = [];
        var series = data.series[0];
        _.each(series.columns, function(name, index) {
            if (_.contains(stringColumns, name)) {
                doomedIndexes.push(index);
            }
        });
        // Now that we know which indexes are doomed, we reverse the order so we
        // can extract them from the list from the end
        doomedIndexes = doomedIndexes.reverse();
        _.each(doomedIndexes, function(doomed) {
            series.columns.splice(doomed, 1);
        });
        _.each(series.values, function(row) {
            _.each(doomedIndexes, function(doomed) {
                row.splice(doomed, 1);
            });
        });
    }

    function convertJsonDataToCsv(data) {
        var rows = [];
        var series = data.series[0];

        var headers = series.columns;
        var values = series.values;

        rows.push(headers);

        _.each(values, function(values) {
            rows.push(values.join(','));
        });

        return rows.join('\n');
    }

    function prepareChartMarkup(id, name) {
        var $header = $('
' + name + '
');
        var $chart = $('

', {id: id, class: 'chart'});
        $chartContainer.append($header)
                       .append($chart);
    }

    function renderChart(id, data) {
        var el = document.getElementById(id);
        removeStringData(data);
        var csvString = convertJsonDataToCsv(data);
        return new Dygraph(el, csvString, {
            width: 1000,
            series: {
              anomalyScore: {
                axis: 'y2',
                color: 'orange'
              },
              anomalyLikelihood: {
                axis: 'y2',
                color: 'red'
              }
            },
            axes: {
              y2: {
                valueRange: [0.0, 1.0]
              }
            }
        });
    }

    function renderSensorChart(name, data) {
        console.log(name);
        var id = name.replace('/', '_').replace(/\+/g, '-');
        prepareChartMarkup(id, name);
        renderChart(id, data);
    }

    $.getJSON('/_sensors', function(sensors) {
        _.each(sensors, function(sensorName) {
            $.getJSON('/_sensor/' + sensorName, function(sensorData) {
                renderSensorChart(sensorName, sensorData);
            });
        });
    });
});<|endoftext|>