<commit_before>//> This file is part of Ymacs, an Emacs-like editor for the Web
//> http://www.ymacs.org/
//>
//> Copyright (c) 2009-2012, Mihai Bazon, Dynarch.com.  All rights reserved.
//>
//> Redistribution and use in source and binary forms, with or without
//> modification, are permitted provided that the following conditions are
//> met:
//>
//>     * Redistributions of source code must retain the above copyright
//>       notice, this list of conditions and the following disclaimer.
//>
//>     * Redistributions in binary form must reproduce the above copyright
//>       notice, this list of conditions and the following disclaimer in
//>       the documentation and/or other materials provided with the
//>       distribution.
//>
//>     * Neither the name of Dynarch.com nor the names of its contributors
//>       may be used to endorse or promote products derived from this
//>       software without specific prior written permission.
//>
//> THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
//> EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
//> IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//> PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE
//> FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
//> CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
//> SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
//> INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
//> CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
//> ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
//> THE POSSIBILITY OF SUCH DAMAGE.

// @require ymacs-buffer.js
// @require ymacs-keymap.js

Ymacs_Buffer.newMode("minibuffer_mode", function(){
    var marker = this.createMarker(0, true);
    var changed_vars = this.setq({
        minibuffer_end_marker: marker
    });
    var keymap = Ymacs_Keymap_Minibuffer();
    this.pushKeymap(keymap);
    return function() {
        this.setq(changed_vars);
        marker.destroy();
        this.popKeymap(keymap);
    };
});

(function(){

    var $popupActive = false;
    var $menu = null, $item = null;
    function popupCompletionMenu(frame, list) {
        var self = this;        // minibuffer
        if ($menu)
            $menu.destroy();
        $menu = new DlVMenu({});
        list.foreach(function(item, index){
            var data = item;
            if (typeof item != "string") {
                data = item.completion;
                item = item.label;
            }
            new DlMenuItem({ parent: $menu, label: item.htmlEscape(), data: data, name: index })
                .addEventListener("onMouseEnter", function(){
                    if ($item != index) {
                        if ($item != null) {
                            $menu.children($item).callHooks("onMouseLeave");
                        }
                        $item = index;
                    }
                });
        });
        $menu.addEventListener({
            onSelect: function(index, item){
                $item = index;
                handle_enter.call(self);
            }
        });
        var popup = Ymacs_Completion_Popup.get();
        popup.popup({
            timeout: 0,
            content: $menu,
            align: {
		prefer: "Tr",
		fallX1: "_r",
		fallX2: "_L",
		fallY1: "B_",
		fallY2: "T_"
	    },
            anchor: frame.getCaretElement(),
            widget: frame,
            onHide: function() {
                $popupActive = false;
                // $menu.destroy();
                $item = null;
                $menu = null;
            },
            isContext: true
        });
        $popupActive = true;

        handle_arrow_down.call(self); // autoselect the first one anyway
    };

    function read_with_continuation(completions, cont, validate) {
        this.whenMinibuffer(function(mb){
            var changed_vars = mb.setq({
                completion_list: completions,
                minibuffer_validation: function(what, cont2){
                    if (what == null)
                        what = mb.cmd("minibuffer_contents");
                    if (validate)
                        validate.call(this, mb, what, cont2);
                    else
                        cont2(true); // accept anything by default
                }.$(this),
                minibuffer_continuation: function(what){
                    mb.setq(changed_vars);
                    if (cont)
                        cont.call(this, what);
                }.$(this)
            });
        });
    };

    function filename_completion(mb, str, re, cont) {

        var self = this;
        var lastslash = str.lastIndexOf("/");
        var dir = str.slice(0, lastslash+1);
        var partial = str.slice(lastslash+1);
        self.ymacs.fs_getDirectory(dir, function (files) {

            function add_trailing_slash_to_dir(name) {
                return (files[name].type == "directory") ? name+"/" : name;
            }

            if (!files) {
                mb.signalError("Not found");
                cont(null);
            } else {
                var completions = [];
                for (var f in files) {
                    if (f.indexOf(partial) == 0) {
                        completions.push(add_trailing_slash_to_dir(f));
                    }
                }
                if (completions.length == 0) {
                    cont([]);
                } else {
                    var prefix = completions.common_prefix();
                    if (prefix != partial) {
                        mb.cmd("minibuffer_replace_input", dir+prefix);
                        cont(null);
                    } else if (completions.length == 1) {
                        cont([str]);
                    } else {
                        completions = completions.map(function(name){
                            return {label: name, completion: dir+name};
                        });
                        popupCompletionMenu.call(self, self.getMinibufferFrame(), completions);
                        cont(null);
                    }
                }
            }
        });
    };

    Ymacs_Buffer.newCommands({

        minibuffer_prompt: function(prompt, nofocus) {
            this.whenMinibuffer(function(mb){
                var f = this.getMinibufferFrame();
                this.ymacs.setInputFrame(f);
                mb.setCode("");
                mb.cmd("prevent_undo", function(){
                    mb.cmd("insert", prompt);
                });
                mb.getq("minibuffer_end_marker").setPosition(mb.point());
                f._redrawCaret(true);
                if (!nofocus)
                    f.focus();
            });
        },

        minibuffer_yn: function(prompt, cont) {
            this.cmd("minibuffer_prompt", prompt + " (yes or no) ");
            this.cmd("minibuffer_read_yn", function (text) {
                cont(text == "yes");
            });
        },

        minibuffer_read_yn: function(cont) {
            read_with_continuation.call(this, null, cont, function(mb, text, cont2){
                if (text == "yes" || text == "no")
                    cont2(true);
                else
                    mb.signalError("Please enter yes or no");
            });
        },

        minibuffer_read_number: function(cont) {
            read_with_continuation.call(this, null, cont, function(mb, text, cont2){
                var n = parseInt(text, 10);
                if (isNaN(n))
                    mb.signalError("Please enter a number");
                cont2(!isNaN(n));
            });
        },

        minibuffer_read_command: function(cont) {
            var commandNames = Array.hashKeys(this.COMMANDS).grep(function(cmd){
                return this.COMMANDS[cmd].ymacsInteractive;
            }, this).sort();
            read_with_continuation.call(this, commandNames, cont, function(mb, name, cont2){
                var cmd = this.COMMANDS[name],
                ret = cmd && cmd.ymacsInteractive;
                if (!ret) {
                    mb.signalError("No such command: " + name);
                }
                cont2(ret);
            });
        },

        minibuffer_read_function: function(cont) {
            var commandNames = Array.hashKeys(this.COMMANDS).sort();
            read_with_continuation.call(this, commandNames, cont, function(mb, name, cont2){
                var cmd = this.COMMANDS[name],
                ret = !!cmd;
                if (!ret)
                    mb.signalError("No such function: " + name);
                cont2(ret);
            });
        },

        minibuffer_read_buffer: function(cont) {
            this.whenYmacs(function(ymacs){
                var bufferNames = ymacs.buffers.map("name");
                bufferNames.push(bufferNames.shift());
                read_with_continuation.call(this, bufferNames, cont);
                handle_tab.call(this);
            });
        },

        minibuffer_read_string: function(completions, cont) {
            read_with_continuation.call(this, completions, cont);
        },

        minibuffer_read_variable: function(cont) {
            var tmp = this.globalVariables;
            Object.merge(tmp, this.variables);
            var completions = Array.hashKeys(tmp).grep(function(name){
                return !/^\*/.test(name);
            }).sort();
            read_with_continuation.call(this, completions, cont
                                        // XXX: seems like a good idea, but it doesn't work
                                        // XXX: need to refactor the signalInfo stuff.  It doesn't show up
                                        //      currently because the buffer frame is not active, or something...
                                        // , function(mb, name){
                                        //         var val = this.getq(name);
                                        //         mb.signalInfo("Current value of " + name + ": " + val);
                                        //         return true;
                                        // }
                                       );
        },

        minibuffer_read_existing_file: function(cont) {
            var self = this;
            self.cmd("minibuffer_replace_input_by_current_dir", function () {
                read_with_continuation.call(self, filename_completion, cont, function(mb, name, cont2){
                    self.ymacs.fs_fileType(name, function (type) {
                        if (type == null) {
                            mb.signalError("No such file: " + name);
                            cont2(false);
                        } else {
                            cont2(true);
                        }
                    });
                });
            });
        },

        minibuffer_read_file: function(cont) {
            var self = this;
            self.cmd("minibuffer_replace_input_by_current_dir", function () {
                read_with_continuation.call(self, filename_completion, cont);
            });
        },

        minibuffer_read_file_or_directory: function(cont) {
            var self = this;
            self.cmd("minibuffer_replace_input_by_current_dir", function () {
                read_with_continuation.call(self, filename_completion, cont);
            });
        },

        minibuffer_read_directory: function(cont) {
            var self = this;
            self.cmd("minibuffer_replace_input_by_current_dir", function () {
                read_with_continuation.call(self, filename_completion, cont);
            });
        },

        minibuffer_prompt_end: function() {
            return this.whenMinibuffer(function(mb){
                return mb.getq("minibuffer_end_marker").getPosition();
            });
        },

        minibuffer_contents: function() {
            return this.whenMinibuffer(function(mb){
                return mb._bufferSubstring(mb.getq("minibuffer_end_marker"));
            });
        },

        minibuffer_replace_input: function(value) {
            this.whenMinibuffer(function(mb){
                mb._replaceText(mb.getq("minibuffer_end_marker"), mb.getCodeSize(), value);
                this.getMinibufferFrame()._redrawCaret(true);
            });
        },

        minibuffer_replace_input_by_current_dir: function (cont) {
            this.whenYmacs(function(ymacs){
                var self = this;
                var name = ymacs.getActiveBuffer().name;
                var dir = name.slice(0, name.lastIndexOf("/")+1);
                ymacs.fs_remapDir(dir, function (dir) {
                    self.cmd("minibuffer_replace_input", dir);
                    cont();
                });
            });
        },

        minibuffer_complete: function() {
            var self = this;
            self.whenMinibuffer(function(mb){

                function complete(a) {
                    if (!a || a.length == 0) {
                        mb.signalError("No completions");
                    }
                    else {
                        var prefix = a.common_prefix();
                        if (prefix != str) {
                            mb.cmd("minibuffer_replace_input", prefix);
                        }
                        else if (a.length == 1) {
                            mb.signalError("Sole completion");
                        }
                        else {
                            popupCompletionMenu.call(self, self.getMinibufferFrame(), a);
                        }
                    }
                }

                var a = mb.getq("completion_list"),
                str = mb.cmd("minibuffer_contents"),
                re = str.replace(/([\[\]\(\)\{\}\.\*\+\?\|\\])/g, "\\$1").replace(/([_-])/g, "[^_-]*[_-]");
                re = new RegExp("^" + re, "i");
                if (a instanceof Function) {
                    a.call(self, mb, str, re, function (a) {
                        if (a)
                            complete(a);
                    });
                }
                else if (a && a.length > 0) {
                    a = a.grep(function(cmd){
                        return re.test(cmd);
                    });
                    complete(a);
                }
                else
                    complete(a);
            });
        },

        minibuffer_complete_and_exit: function() {
            var self = this;
            self.whenMinibuffer(function(mb){
                mb.getq("minibuffer_validation").call(mb, null, function (valid) {
                    if (valid)
                        mb.cmd("minibuffer_keyboard_quit", self.getq("minibuffer_continuation"));
                });
            });
        },

        minibuffer_keyboard_quit: function(cont) {
            this.whenMinibuffer(function(mb){
                var text = this.cmd("minibuffer_contents");
                mb.setCode("");
                this.ymacs.setInputFrame(this.ymacs.getActiveFrame());
                this.ymacs.getActiveFrame().focus();
                (function(text){
                    if (cont)
                        cont.call(this, text);
                    this.getPrefixArg();
                }).delayed(1, this, text);
            });
            DlPopup.clearAllPopups();
        }

    });

    function handle_completion(how) {
        var old_item = $item, w;
        switch (how) {
          case "next":
            if ($item == null)
                $item = -1;
            $item = $menu.children().rotateIndex(++$item);
            break;
          case "prev":
            if ($item == null)
                $item = 0;
            $item = $menu.children().rotateIndex(--$item);
            break;
        }
        if (old_item != null) {
            w = $menu.children(old_item);
	    w.callHooks("onMouseLeave");
        }
        old_item = $item;
        w = $menu.children($item);
	w.callHooks("onMouseEnter");
    };

    function handle_arrow_down() {
        if ($popupActive) {
            return handle_completion.call(this, "next");
        }
    };

    function handle_arrow_up() {
        if ($popupActive) {
            return handle_completion.call(this, "prev");
        }
    };

    function handle_enter() {
        if ($popupActive) {
            if ($item != null) {
                this.cmd("minibuffer_replace_input", $menu.children()[$item].userData);
                DlPopup.clearAllPopups();
            } else {
                this.signalError("Select something...");
            }
        } else {
            this.cmd("minibuffer_complete_and_exit");
        }
    };

    function handle_tab() {
        if (!$popupActive)
            this.cmd("minibuffer_complete");
        else
            handle_arrow_down.call(this);
    };

    function handle_s_tab() {
        handle_arrow_up.call(this);
    };

    function handle_escape() {
        if ($popupActive) {
            DlPopup.clearAllPopups();
        } else {
            this.cmd("minibuffer_keyboard_quit");
        }
    };

    DEFINE_SINGLETON("Ymacs_Keymap_Minibuffer", Ymacs_Keymap, function(D, P){

        D.KEYS = {
            "C-g"                                : "minibuffer_keyboard_quit",
            "TAB"                                : handle_tab,
            "S-TAB"                              : handle_s_tab,
            "ARROW_DOWN && ARROW_RIGHT && C-f"   : handle_arrow_down,
            "ARROW_UP && ARROW_LEFT && C-b"      : handle_arrow_up,
            "ENTER"                              : handle_enter,
            "ESCAPE"                             : handle_escape
        };

        P.defaultHandler = [ function() {
            DlPopup.clearAllPopups();
            return false; // say it's not handled though
        } ];

    });

})();

DEFINE_CLASS("Ymacs_Completion_Popup", DlCompletionPopup);
<commit_msg>add C-n and C-p to minibuffer completion keybindings<commit_after>//> This file is part of Ymacs, an Emacs-like editor for the Web
//> http://www.ymacs.org/
//>
//> Copyright (c) 2009-2012, Mihai Bazon, Dynarch.com.  All rights reserved.
//>
//> Redistribution and use in source and binary forms, with or without
//> modification, are permitted provided that the following conditions are
//> met:
//>
//>     * Redistributions of source code must retain the above copyright
//>       notice, this list of conditions and the following disclaimer.
//>
//>     * Redistributions in binary form must reproduce the above copyright
//>       notice, this list of conditions and the following disclaimer in
//>       the documentation and/or other materials provided with the
//>       distribution.
//>
//>     * Neither the name of Dynarch.com nor the names of its contributors
//>       may be used to endorse or promote products derived from this
//>       software without specific prior written permission.
//>
//> THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
//> EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
//> IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//> PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE
//> FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
//> CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
//> SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
//> INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
//> CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
//> ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
//> THE POSSIBILITY OF SUCH DAMAGE.

// @require ymacs-buffer.js
// @require ymacs-keymap.js

Ymacs_Buffer.newMode("minibuffer_mode", function(){
    var marker = this.createMarker(0, true);
    var changed_vars = this.setq({
        minibuffer_end_marker: marker
    });
    var keymap = Ymacs_Keymap_Minibuffer();
    this.pushKeymap(keymap);
    return function() {
        this.setq(changed_vars);
        marker.destroy();
        this.popKeymap(keymap);
    };
});

(function(){

    var $popupActive = false;
    var $menu = null, $item = null;
    function popupCompletionMenu(frame, list) {
        var self = this;        // minibuffer
        if ($menu)
            $menu.destroy();
        $menu = new DlVMenu({});
        list.foreach(function(item, index){
            var data = item;
            if (typeof item != "string") {
                data = item.completion;
                item = item.label;
            }
            new DlMenuItem({ parent: $menu, label: item.htmlEscape(), data: data, name: index })
                .addEventListener("onMouseEnter", function(){
                    if ($item != index) {
                        if ($item != null) {
                            $menu.children($item).callHooks("onMouseLeave");
                        }
                        $item = index;
                    }
                });
        });
        $menu.addEventListener({
            onSelect: function(index, item){
                $item = index;
                handle_enter.call(self);
            }
        });
        var popup = Ymacs_Completion_Popup.get();
        popup.popup({
            timeout: 0,
            content: $menu,
            align: {
		prefer: "Tr",
		fallX1: "_r",
		fallX2: "_L",
		fallY1: "B_",
		fallY2: "T_"
	    },
            anchor: frame.getCaretElement(),
            widget: frame,
            onHide: function() {
                $popupActive = false;
                // $menu.destroy();
                $item = null;
                $menu = null;
            },
            isContext: true
        });
        $popupActive = true;

        handle_arrow_down.call(self); // autoselect the first one anyway
    };

    function read_with_continuation(completions, cont, validate) {
        this.whenMinibuffer(function(mb){
            var changed_vars = mb.setq({
                completion_list: completions,
                minibuffer_validation: function(what, cont2){
                    if (what == null)
                        what = mb.cmd("minibuffer_contents");
                    if (validate)
                        validate.call(this, mb, what, cont2);
                    else
                        cont2(true); // accept anything by default
                }.$(this),
                minibuffer_continuation: function(what){
                    mb.setq(changed_vars);
                    if (cont)
                        cont.call(this, what);
                }.$(this)
            });
        });
    };

    function filename_completion(mb, str, re, cont) {

        var self = this;
        var lastslash = str.lastIndexOf("/");
        var dir = str.slice(0, lastslash+1);
        var partial = str.slice(lastslash+1);
        self.ymacs.fs_getDirectory(dir, function (files) {

            function add_trailing_slash_to_dir(name) {
                return (files[name].type == "directory") ? name+"/" : name;
            }

            if (!files) {
                mb.signalError("Not found");
                cont(null);
            } else {
                var completions = [];
                for (var f in files) {
                    if (f.indexOf(partial) == 0) {
                        completions.push(add_trailing_slash_to_dir(f));
                    }
                }
                if (completions.length == 0) {
                    cont([]);
                } else {
                    var prefix = completions.common_prefix();
                    if (prefix != partial) {
                        mb.cmd("minibuffer_replace_input", dir+prefix);
                        cont(null);
                    } else if (completions.length == 1) {
                        cont([str]);
                    } else {
                        completions = completions.map(function(name){
                            return {label: name, completion: dir+name};
                        });
                        popupCompletionMenu.call(self, self.getMinibufferFrame(), completions);
                        cont(null);
                    }
                }
            }
        });
    };

    Ymacs_Buffer.newCommands({

        minibuffer_prompt: function(prompt, nofocus) {
            this.whenMinibuffer(function(mb){
                var f = this.getMinibufferFrame();
                this.ymacs.setInputFrame(f);
                mb.setCode("");
                mb.cmd("prevent_undo", function(){
                    mb.cmd("insert", prompt);
                });
                mb.getq("minibuffer_end_marker").setPosition(mb.point());
                f._redrawCaret(true);
                if (!nofocus)
                    f.focus();
            });
        },

        minibuffer_yn: function(prompt, cont) {
            this.cmd("minibuffer_prompt", prompt + " (yes or no) ");
            this.cmd("minibuffer_read_yn", function (text) {
                cont(text == "yes");
            });
        },

        minibuffer_read_yn: function(cont) {
            read_with_continuation.call(this, null, cont, function(mb, text, cont2){
                if (text == "yes" || text == "no")
                    cont2(true);
                else
                    mb.signalError("Please enter yes or no");
            });
        },

        minibuffer_read_number: function(cont) {
            read_with_continuation.call(this, null, cont, function(mb, text, cont2){
                var n = parseInt(text, 10);
                if (isNaN(n))
                    mb.signalError("Please enter a number");
                cont2(!isNaN(n));
            });
        },

        minibuffer_read_command: function(cont) {
            var commandNames = Array.hashKeys(this.COMMANDS).grep(function(cmd){
                return this.COMMANDS[cmd].ymacsInteractive;
            }, this).sort();
            read_with_continuation.call(this, commandNames, cont, function(mb, name, cont2){
                var cmd = this.COMMANDS[name],
                ret = cmd && cmd.ymacsInteractive;
                if (!ret) {
                    mb.signalError("No such command: " + name);
                }
                cont2(ret);
            });
        },

        minibuffer_read_function: function(cont) {
            var commandNames = Array.hashKeys(this.COMMANDS).sort();
            read_with_continuation.call(this, commandNames, cont, function(mb, name, cont2){
                var cmd = this.COMMANDS[name],
                ret = !!cmd;
                if (!ret)
                    mb.signalError("No such function: " + name);
                cont2(ret);
            });
        },

        minibuffer_read_buffer: function(cont) {
            this.whenYmacs(function(ymacs){
                var bufferNames = ymacs.buffers.map("name");
                bufferNames.push(bufferNames.shift());
                read_with_continuation.call(this, bufferNames, cont);
                handle_tab.call(this);
            });
        },

        minibuffer_read_string: function(completions, cont) {
            read_with_continuation.call(this, completions, cont);
        },

        minibuffer_read_variable: function(cont) {
            var tmp = this.globalVariables;
            Object.merge(tmp, this.variables);
            var completions = Array.hashKeys(tmp).grep(function(name){
                return !/^\*/.test(name);
            }).sort();
            read_with_continuation.call(this, completions, cont
                                        // XXX: seems like a good idea, but it doesn't work
                                        // XXX: need to refactor the signalInfo stuff.  It doesn't show up
                                        //      currently because the buffer frame is not active, or something...
                                        // , function(mb, name){
                                        //         var val = this.getq(name);
                                        //         mb.signalInfo("Current value of " + name + ": " + val);
                                        //         return true;
                                        // }
                                       );
        },

        minibuffer_read_existing_file: function(cont) {
            var self = this;
            self.cmd("minibuffer_replace_input_by_current_dir", function () {
                read_with_continuation.call(self, filename_completion, cont, function(mb, name, cont2){
                    self.ymacs.fs_fileType(name, function (type) {
                        if (type == null) {
                            mb.signalError("No such file: " + name);
                            cont2(false);
                        } else {
                            cont2(true);
                        }
                    });
                });
            });
        },

        minibuffer_read_file: function(cont) {
            var self = this;
            self.cmd("minibuffer_replace_input_by_current_dir", function () {
                read_with_continuation.call(self, filename_completion, cont);
            });
        },

        minibuffer_read_file_or_directory: function(cont) {
            var self = this;
            self.cmd("minibuffer_replace_input_by_current_dir", function () {
                read_with_continuation.call(self, filename_completion, cont);
            });
        },

        minibuffer_read_directory: function(cont) {
            var self = this;
            self.cmd("minibuffer_replace_input_by_current_dir", function () {
                read_with_continuation.call(self, filename_completion, cont);
            });
        },

        minibuffer_prompt_end: function() {
            return this.whenMinibuffer(function(mb){
                return mb.getq("minibuffer_end_marker").getPosition();
            });
        },

        minibuffer_contents: function() {
            return this.whenMinibuffer(function(mb){
                return mb._bufferSubstring(mb.getq("minibuffer_end_marker"));
            });
        },

        minibuffer_replace_input: function(value) {
            this.whenMinibuffer(function(mb){
                mb._replaceText(mb.getq("minibuffer_end_marker"), mb.getCodeSize(), value);
                this.getMinibufferFrame()._redrawCaret(true);
            });
        },

        minibuffer_replace_input_by_current_dir: function (cont) {
            this.whenYmacs(function(ymacs){
                var self = this;
                var name = ymacs.getActiveBuffer().name;
                var dir = name.slice(0, name.lastIndexOf("/")+1);
                ymacs.fs_remapDir(dir, function (dir) {
                    self.cmd("minibuffer_replace_input", dir);
                    cont();
                });
            });
        },

        minibuffer_complete: function() {
            var self = this;
            self.whenMinibuffer(function(mb){

                function complete(a) {
                    if (!a || a.length == 0) {
                        mb.signalError("No completions");
                    }
                    else {
                        var prefix = a.common_prefix();
                        if (prefix != str) {
                            mb.cmd("minibuffer_replace_input", prefix);
                        }
                        else if (a.length == 1) {
                            mb.signalError("Sole completion");
                        }
                        else {
                            popupCompletionMenu.call(self, self.getMinibufferFrame(), a);
                        }
                    }
                }

                var a = mb.getq("completion_list"),
                str = mb.cmd("minibuffer_contents"),
                re = str.replace(/([\[\]\(\)\{\}\.\*\+\?\|\\])/g, "\\$1").replace(/([_-])/g, "[^_-]*[_-]");
                re = new RegExp("^" + re, "i");
                if (a instanceof Function) {
                    a.call(self, mb, str, re, function (a) {
                        if (a)
                            complete(a);
                    });
                }
                else if (a && a.length > 0) {
                    a = a.grep(function(cmd){
                        return re.test(cmd);
                    });
                    complete(a);
                }
                else
                    complete(a);
            });
        },

        minibuffer_complete_and_exit: function() {
            var self = this;
            self.whenMinibuffer(function(mb){
                mb.getq("minibuffer_validation").call(mb, null, function (valid) {
                    if (valid)
                        mb.cmd("minibuffer_keyboard_quit", self.getq("minibuffer_continuation"));
                });
            });
        },

        minibuffer_keyboard_quit: function(cont) {
            this.whenMinibuffer(function(mb){
                var text = this.cmd("minibuffer_contents");
                mb.setCode("");
                this.ymacs.setInputFrame(this.ymacs.getActiveFrame());
                this.ymacs.getActiveFrame().focus();
                (function(text){
                    if (cont)
                        cont.call(this, text);
                    this.getPrefixArg();
                }).delayed(1, this, text);
            });
            DlPopup.clearAllPopups();
        }

    });

    function handle_completion(how) {
        var old_item = $item, w;
        switch (how) {
          case "next":
            if ($item == null)
                $item = -1;
            $item = $menu.children().rotateIndex(++$item);
            break;
          case "prev":
            if ($item == null)
                $item = 0;
            $item = $menu.children().rotateIndex(--$item);
            break;
        }
        if (old_item != null) {
            w = $menu.children(old_item);
	    w.callHooks("onMouseLeave");
        }
        old_item = $item;
        w = $menu.children($item);
	w.callHooks("onMouseEnter");
    };

    function handle_arrow_down() {
        if ($popupActive) {
            return handle_completion.call(this, "next");
        }
    };

    function handle_arrow_up() {
        if ($popupActive) {
            return handle_completion.call(this, "prev");
        }
    };

    function handle_enter() {
        if ($popupActive) {
            if ($item != null) {
                this.cmd("minibuffer_replace_input", $menu.children()[$item].userData);
                DlPopup.clearAllPopups();
            } else {
                this.signalError("Select something...");
            }
        } else {
            this.cmd("minibuffer_complete_and_exit");
        }
    };

    function handle_tab() {
        if (!$popupActive)
            this.cmd("minibuffer_complete");
        else
            handle_arrow_down.call(this);
    };

    function handle_s_tab() {
        handle_arrow_up.call(this);
    };

    function handle_escape() {
        if ($popupActive) {
            DlPopup.clearAllPopups();
        } else {
            this.cmd("minibuffer_keyboard_quit");
        }
    };

    DEFINE_SINGLETON("Ymacs_Keymap_Minibuffer", Ymacs_Keymap, function(D, P){

        D.KEYS = {
            "C-g"                                : "minibuffer_keyboard_quit",
            "TAB"                                : handle_tab,
            "S-TAB"                              : handle_s_tab,
            "ARROW_DOWN && ARROW_RIGHT && C-n && C-f": handle_arrow_down,
            "ARROW_UP && ARROW_LEFT && C-p && C-b"   : handle_arrow_up,
            "ENTER"                              : handle_enter,
            "ESCAPE"                             : handle_escape
        };

        P.defaultHandler = [ function() {
            DlPopup.clearAllPopups();
            return false; // say it's not handled though
        } ];

    });

})();

DEFINE_CLASS("Ymacs_Completion_Popup", DlCompletionPopup);
<|endoftext|>


<commit_before>/**
 * DateTime/Date input combo initalization and handling
 */
bolt.datetimes = function () {
    /**
     * @typedef InputElements
     * @type {Object} data - Element holding the data
     * @type {Object} date - Date input element
     * @type {Object} time - Time input element
     * @type {Object} show - Show datepicker button
     * @type {Object} clear - Clear datepicker button
     * @type {boolean} hasTime - 'true' if it is a datetime input, else false
     */

     /**
     * Indicates if 24h or 12h time format should be used
     *
     * @type {boolean}
     * @private
     */
    var is24h;

    /**
     * Evaluate the value(s) from the input field(s) and writes it to the data field
     *
     * @param {InputElements} field
     * @private
     */
    function evaluate(field) {
        var date = moment(field.date.datepicker('getDate')),
            time = moment([2001, 11, 24]),
            hours = 0,
            minutes = 0;

        // Process time field
        if (field.hasTime) {
            res = field.time.val().match(/^\s*(?:(?:([01]?[0-9]|2[0-3])[:,.]([0-5]?[0-9]))|(1[012]|0?[1-9])[:,.]([0-5]?[0-9])(?:\s*([AP])[. ]?M\.?))\s*$/i);
            if (res) {
                hours = parseInt(res[1] ? res[1] :res[3]);
                minutes = parseInt(res[2] ? res[2] :res[4]);
                if ((res[5] === 'p' || res[5] === 'P') && hours !== 12) {
                    hours += 12;
                } else if ((res[5] === 'a' || res[5] === 'A') && hours === 12) {
                    hours -= 12;
                }
                time = moment([2001, 11, 24, hours, minutes]);
            }
        }

        // Set data field
        if (date.isValid()) {
            field.data.val(date.format('YYYY-MM-DD') + (field.hasTime ? ' ' + time.format('HH:mm:00') : ''));
        } else if (field.date.val() === '') {
            field.data.val('');
        } else {
            // Error
        }
    }

    /**
     * Displays the value read from the data field inside combos input field(s)
     *
     * @param {InputElements} field
     * @private
     */
    function display(field) {
        var date = '',
            time = '',
            hour,
            match;

        // Correct no depublish date
        if (field.data.attr('id') === 'datedepublish' && field.data.val() === '1900-01-01 00:00:00') {
            field.data.val('');
        }

        // If data field has a valid datetime or date
        match = field.data.val().match(/^(\d{4}-\d{2}-\d{2})(?: (\d{2}:\d{2}:\d{2}))?$/);
        if (match) {
            date = match[1];
            time = match[2] || '';
        }

        // Set date field
        field.date.datepicker('setDate', (date === '' || date === '0000-00-00') ? '' : $.datepicker.parseDate('yy-mm-dd', date));

        // Set time field
        if (field.hasTime) {
            if (time === '') {
                time = '';
            } else if (bolt.datetimes.is24h) {
                time = field.data.val().slice(11, 16);
            } else {
                hour = parseInt(time.slice(0, 2));
                time = (hour % 12 || 12) + time.slice(2, 5) + (hour < 12 ? ' AM' : ' PM');
            }
            field.time.val(time);
        }
    }

    /**
     * Binds the datepicker to the date input and initializes it
     *
     * @param {InputElements} field
     * @private
     */
    function bindDatepicker(field) {
        var fieldOptions = field.date.data('field-options'),
            options = {
                showOn: 'none'
            };

        for (key in fieldOptions) {
            if (fieldOptions.hasOwnProperty(key)) {
                options[key] = fieldOptions[key];
            }
        }
        // Bind datepicker button
        field.date.datepicker(options);
        // Bind show button
        field.show.click(function () {
            // Set the date to "today", if nothing has been picked yet.
            if (!field.date.datepicker('getDate')) {
                field.date.datepicker('setDate', "+0");
            }
            field.date.datepicker('show');
        });
        // Bind clear button
        field.clear.click(function () {
            field.data.val('');
            display(field);
        });
    }

    return {
        /**
         * Initialize the datetime and date input combos
         */
        init: function () {
            // Set global datepicker locale
            $.datepicker.setDefaults($.datepicker.regional[bolt.locale.long]);

            // Find out if locale uses 24h format
            this.is24h = moment.localeData()._longDateFormat.LT.replace(/\[.+?\]/gi, '').match(/A/) ? false : true;

            // Initialize each available date/datetime field
            $('.datepicker').each(function () {
                var id = $(this).attr('id').replace(/-date$/, ''),
                    field = {
                        data: $('#' + id),
                        date: $(this),
                        time: $('#' + id + '-time'),
                        show: $('#' + id + '-show'),
                        clear: $('#' + id + '-clear'),
                        hasTime: false
                    };

                field.hasTime = (field.time.length > 0);

                // Uncomment for debug purpose to make hidden datafields visible
                // field.data.attr('type', 'text');

                // Bind datepicker to date field and set options from field in contenttypes.yml
                bindDatepicker(field);

                display(field);

                // Bind change action to date and time field
                field.date.change(function () {
                    evaluate(field);
                    display(field);
                });
                field.time.change(function () {
                    evaluate(field);
                    display(field);
                });
            });
        },

        /**
         * Updates display of datetime and date inputs from their data fields
         */
        update: function () {
            $('.datepicker').each(function () {
                var id = $(this).attr('id').replace(/-date$/, ''),
                    field = {
                        data: $('#' + id),
                        date: $(this),
                        time: $('#' + id + '-time')
                    };

                display(field);
            });
        }
    };
} ();
<commit_msg>Correct usage of private property is24h<commit_after>/**
 * DateTime/Date input combo initalization and handling
 */
bolt.datetimes = function () {
    /**
     * @typedef InputElements
     * @type {Object} data - Element holding the data
     * @type {Object} date - Date input element
     * @type {Object} time - Time input element
     * @type {Object} show - Show datepicker button
     * @type {Object} clear - Clear datepicker button
     * @type {boolean} hasTime - 'true' if it is a datetime input, else false
     */

     /**
     * Indicates if 24h or 12h time format should be used
     *
     * @type {boolean}
     * @private
     */
    var is24h;

    /**
     * Evaluate the value(s) from the input field(s) and writes it to the data field
     *
     * @param {InputElements} field
     * @private
     */
    function evaluate(field) {
        var date = moment(field.date.datepicker('getDate')),
            time = moment([2001, 11, 24]),
            hours = 0,
            minutes = 0;

        // Process time field
        if (field.hasTime) {
            res = field.time.val().match(/^\s*(?:(?:([01]?[0-9]|2[0-3])[:,.]([0-5]?[0-9]))|(1[012]|0?[1-9])[:,.]([0-5]?[0-9])(?:\s*([AP])[. ]?M\.?))\s*$/i);
            if (res) {
                hours = parseInt(res[1] ? res[1] :res[3]);
                minutes = parseInt(res[2] ? res[2] :res[4]);
                if ((res[5] === 'p' || res[5] === 'P') && hours !== 12) {
                    hours += 12;
                } else if ((res[5] === 'a' || res[5] === 'A') && hours === 12) {
                    hours -= 12;
                }
                time = moment([2001, 11, 24, hours, minutes]);
            }
        }

        // Set data field
        if (date.isValid()) {
            field.data.val(date.format('YYYY-MM-DD') + (field.hasTime ? ' ' + time.format('HH:mm:00') : ''));
        } else if (field.date.val() === '') {
            field.data.val('');
        } else {
            // Error
        }
    }

    /**
     * Displays the value read from the data field inside combos input field(s)
     *
     * @param {InputElements} field
     * @private
     */
    function display(field) {
        var date = '',
            time = '',
            hour,
            match;

        // Correct no depublish date
        if (field.data.attr('id') === 'datedepublish' && field.data.val() === '1900-01-01 00:00:00') {
            field.data.val('');
        }

        // If data field has a valid datetime or date
        match = field.data.val().match(/^(\d{4}-\d{2}-\d{2})(?: (\d{2}:\d{2}:\d{2}))?$/);
        if (match) {
            date = match[1];
            time = match[2] || '';
        }

        // Set date field
        field.date.datepicker('setDate', (date === '' || date === '0000-00-00') ? '' : $.datepicker.parseDate('yy-mm-dd', date));

        // Set time field
        if (field.hasTime) {
            if (time === '') {
                time = '';
            } else if (is24h) {
                time = field.data.val().slice(11, 16);
            } else {
                hour = parseInt(time.slice(0, 2));
                time = (hour % 12 || 12) + time.slice(2, 5) + (hour < 12 ? ' AM' : ' PM');
            }
            field.time.val(time);
        }
    }

    /**
     * Binds the datepicker to the date input and initializes it
     *
     * @param {InputElements} field
     * @private
     */
    function bindDatepicker(field) {
        var fieldOptions = field.date.data('field-options'),
            options = {
                showOn: 'none'
            };

        for (key in fieldOptions) {
            if (fieldOptions.hasOwnProperty(key)) {
                options[key] = fieldOptions[key];
            }
        }
        // Bind datepicker button
        field.date.datepicker(options);
        // Bind show button
        field.show.click(function () {
            // Set the date to "today", if nothing has been picked yet.
            if (!field.date.datepicker('getDate')) {
                field.date.datepicker('setDate', "+0");
            }
            field.date.datepicker('show');
        });
        // Bind clear button
        field.clear.click(function () {
            field.data.val('');
            display(field);
        });
    }

    return {
        /**
         * Initialize the datetime and date input combos
         */
        init: function () {
            // Set global datepicker locale
            $.datepicker.setDefaults($.datepicker.regional[bolt.locale.long]);

            // Find out if locale uses 24h format
            is24h = moment.localeData()._longDateFormat.LT.replace(/\[.+?\]/gi, '').match(/A/) ? false : true;

            // Initialize each available date/datetime field
            $('.datepicker').each(function () {
                var id = $(this).attr('id').replace(/-date$/, ''),
                    field = {
                        data: $('#' + id),
                        date: $(this),
                        time: $('#' + id + '-time'),
                        show: $('#' + id + '-show'),
                        clear: $('#' + id + '-clear'),
                        hasTime: false
                    };

                field.hasTime = (field.time.length > 0);

                // Uncomment for debug purpose to make hidden datafields visible
                // field.data.attr('type', 'text');

                // Bind datepicker to date field and set options from field in contenttypes.yml
                bindDatepicker(field);

                display(field);

                // Bind change action to date and time field
                field.date.change(function () {
                    evaluate(field);
                    display(field);
                });
                field.time.change(function () {
                    evaluate(field);
                    display(field);
                });
            });
        },

        /**
         * Updates display of datetime and date inputs from their data fields
         */
        update: function () {
            $('.datepicker').each(function () {
                var id = $(this).attr('id').replace(/-date$/, ''),
                    field = {
                        data: $('#' + id),
                        date: $(this),
                        time: $('#' + id + '-time')
                    };

                display(field);
            });
        }
    };
} ();
<|endoftext|>


<commit_before>var utils  = require('../utils');

/**
 * dimensions and resolution
 *
 * Checks dimensions and resolution for x, y, z, and time across subjects to
 * ensure they are consistent.
 *
 * The fields we are interested in are all arrays and we are only looking at
 * the first for values in those arrays. To handle single values or longer
 * arrays more arguments will need to be added to headerField.
 */

var headerFields = function headerFields(headers) {
    var issues = [];
    issues = issues.concat(headerField(headers, 'dim'));
    issues = issues.concat(headerField(headers, 'pixdim'));
    return issues;
}

/**
 * Key to headerField working is the fact that we take and array of values
 * from the nifti header and convert it to a string. This string is used to
 * comapre the header field value against other header field values and is used
 * as an attribute in the object nifti_types. Nifti types refers to the
 * different types of nifti files we are comparing across subjects. Only the
 * dimensionality of similar anatomy/funtional/dwi headers are being compared.
 */

var headerField = function headerField(headers, field) {
    var nifti_types = {};
    var issues = [];
    for (var header_index in headers) {
        var badField = false;
        var field_value;
        var file = headers[header_index][0];
        var filename;
        var header = headers[header_index][1];
        var match;
        var path = utils.files.relativePath(file);
        var run;
        var subject;

        if (field === 'dim') {
            if ((typeof header[field]) === 'undefined' || header[field] === null || header[field].length < header[field][0]) {
                issues.push(new utils.Issue({
                        file: file,
                        code: 40
                }));
                continue;
            }
            field_value = header[field].slice(1, header[field][0]+1).toString();
        } else if (field === 'pixdim') {
            if ((typeof header['xyzt_units']) === 'undefined' || header['xyzt_units'] === null || header['xyzt_units'].length < 4) {
                issues.push(new utils.Issue({
                        file: file,
                        code: 41
                }));
                badField = true;
            }
            if ((typeof header['pixdim']) === 'undefined' || header['pixdim'] === null || header['pixdim'].length < 4) {
                console.log(header['pixdim']);
                issues.push(new utils.Issue({
                        file: file,
                        code: 42
                }));
                badField = true;
            }
            console.log(header['xyzt_units']);
            if (badField === true) {
                continue;
            }
            field_value = [];
            var pix_dim = header[field].slice(1,5);
            var units = header['xyzt_units'].slice(0,4);
            for (var i = 0; i < 4; i++) {
                field_value.push('' + pix_dim[i] + units[i]);
            }
            field_value = field_value.toString();
        } else {
            console.log("Checks against header field: " + field + " are currently unsupported.")
            return;
        }

        if (!file || (typeof window != 'undefined' && !file.webkitRelativePath)) {
            continue;
        }

        if (!utils.type.isBIDS(path)) {
            continue;
        }
        //match the subject identifier up to the '/' in the full path to a file.
        match = path.match(/sub-(.*?)(?=\/)/);
        if (match === null) {
            continue;
        } else {
            subject = match[0];
        }
        // files are prepended with subject name, the following two commands
        // remove the subject from the file name to allow filenames to be more
        // easily compared
        filename = path.substring(path.match(subject).index + subject.length);
        filename = filename.replace(subject, '<sub>');

        // generalize the run number so we can compare counts across all runs
        match = filename.match(/run-\d+/);
        if (match === null) {
            continue;
        } else {
            run = match[0];
        }

        filename = filename.substring(filename.match(run).index + run.length);
        filename = filename.replace(run, '<run>');

        if (!nifti_types.hasOwnProperty(filename)) {
            nifti_types[filename] = {}
            nifti_types[filename][field_value] = {'count': 1, 'files': [file]};
        } else {
            if (!nifti_types[filename].hasOwnProperty(field_value)) {
                nifti_types[filename][field_value] = {'count': 1, 'files': [file]};
            } else {
                nifti_types[filename][field_value].count += 1;
                nifti_types[filename][field_value].files.push(file);
            }
        }
    }
    for (var nifti_key in nifti_types) {
        nifti_type = nifti_types[nifti_key];
        var max_field_value = Object.keys(nifti_type)[0];
        for (var field_value_key in nifti_type) {
            var field_value = nifti_type[field_value_key];
            if (field_value.count > nifti_type[max_field_value].count) {
                max_field_value = field_value_key;
            }
        }
        for (var field_value_key in nifti_type) {
            var field_value = nifti_type[field_value_key];
            if (max_field_value !== field_value_key && headerFieldCompare(max_field_value, field_value_key)) {
                for (var nifti_file_index in field_value.files) {
                    var nifti_file = field_value.files[nifti_file_index];
                    var evidence;
                    if (field === 'dim') {
                        evidence = " The most common set of dimensions is: " +
                                  max_field_value + "(voxels), This file has the dimensions: " +
                                  field_value_key + "(voxels)"
                    } else if (field === 'pixdim') {
                        evidence = " The most common resolution is: " +
                                  max_field_value.replace(/,/g, ' x ') + ", This file has the resolution: " +
                                  field_value_key.replace(/,/g, ' x ')
                    }
                        issues.push(new utils.Issue({
                        file: nifti_file,
                        evidence: evidence,
                        code: 39
                    }));
                }
            }
        }
    }
    return issues;
};

/**
 * if elements of the two arrays differ by less than one we won't raise a
 * warning about them. There are a large number of floating point rounding
 * errors that cause resolutions to be slightly different. Returns true if
 * the two headers are signifigantly different
 */
function headerFieldCompare(header1, header2) {
    hdr1 = header1.split(',');
    hdr2 = header2.split(',');
    for (var i = 0; i < hdr1.length; i++) {
        var hdr1_val = Number(hdr1[i].match(/-?\d*\.?\d*/));
        var hdr2_val  = Number(hdr2[i].match(/-?\d*\.?\d*/));
        // Matching alphas with * will return '' on headers without units
        var hdr1_unit = hdr1[i].match(/[A-Za-z]*$/)[0];
        var hdr2_unit = hdr2[i].match(/[A-Za-z]*$/)[0];
        if (Math.abs(hdr1_val - hdr2_val) > .00001) {
            return true;
        }
        if (hdr1_unit !== hdr2_unit) {
            return true;
        }
    }
    return false;
}

module.exports = headerFields;

<commit_msg>remove console logging used for testing<commit_after>var utils  = require('../utils');

/**
 * dimensions and resolution
 *
 * Checks dimensions and resolution for x, y, z, and time across subjects to
 * ensure they are consistent.
 *
 * The fields we are interested in are all arrays and we are only looking at
 * the first for values in those arrays. To handle single values or longer
 * arrays more arguments will need to be added to headerField.
 */

var headerFields = function headerFields(headers) {
    var issues = [];
    issues = issues.concat(headerField(headers, 'dim'));
    issues = issues.concat(headerField(headers, 'pixdim'));
    return issues;
}

/**
 * Key to headerField working is the fact that we take and array of values
 * from the nifti header and convert it to a string. This string is used to
 * comapre the header field value against other header field values and is used
 * as an attribute in the object nifti_types. Nifti types refers to the
 * different types of nifti files we are comparing across subjects. Only the
 * dimensionality of similar anatomy/funtional/dwi headers are being compared.
 */

var headerField = function headerField(headers, field) {
    var nifti_types = {};
    var issues = [];
    for (var header_index in headers) {
        var badField = false;
        var field_value;
        var file = headers[header_index][0];
        var filename;
        var header = headers[header_index][1];
        var match;
        var path = utils.files.relativePath(file);
        var run;
        var subject;

        if (field === 'dim') {
            if ((typeof header[field]) === 'undefined' || header[field] === null || header[field].length < header[field][0]) {
                issues.push(new utils.Issue({
                        file: file,
                        code: 40
                }));
                continue;
            }
            field_value = header[field].slice(1, header[field][0]+1).toString();
        } else if (field === 'pixdim') {
            if ((typeof header['xyzt_units']) === 'undefined' || header['xyzt_units'] === null || header['xyzt_units'].length < 4) {
                issues.push(new utils.Issue({
                        file: file,
                        code: 41
                }));
                badField = true;
            }
            if ((typeof header['pixdim']) === 'undefined' || header['pixdim'] === null || header['pixdim'].length < 4) {
                issues.push(new utils.Issue({
                        file: file,
                        code: 42
                }));
                badField = true;
            }
            if (badField === true) {
                continue;
            }
            field_value = [];
            var pix_dim = header[field].slice(1,5);
            var units = header['xyzt_units'].slice(0,4);
            for (var i = 0; i < 4; i++) {
                field_value.push('' + pix_dim[i] + units[i]);
            }
            field_value = field_value.toString();
        } else {
            console.log("Checks against header field: " + field + " are currently unsupported.")
            return;
        }

        if (!file || (typeof window != 'undefined' && !file.webkitRelativePath)) {
            continue;
        }

        if (!utils.type.isBIDS(path)) {
            continue;
        }
        //match the subject identifier up to the '/' in the full path to a file.
        match = path.match(/sub-(.*?)(?=\/)/);
        if (match === null) {
            continue;
        } else {
            subject = match[0];
        }
        // files are prepended with subject name, the following two commands
        // remove the subject from the file name to allow filenames to be more
        // easily compared
        filename = path.substring(path.match(subject).index + subject.length);
        filename = filename.replace(subject, '<sub>');

        // generalize the run number so we can compare counts across all runs
        match = filename.match(/run-\d+/);
        if (match === null) {
            continue;
        } else {
            run = match[0];
        }

        filename = filename.substring(filename.match(run).index + run.length);
        filename = filename.replace(run, '<run>');

        if (!nifti_types.hasOwnProperty(filename)) {
            nifti_types[filename] = {}
            nifti_types[filename][field_value] = {'count': 1, 'files': [file]};
        } else {
            if (!nifti_types[filename].hasOwnProperty(field_value)) {
                nifti_types[filename][field_value] = {'count': 1, 'files': [file]};
            } else {
                nifti_types[filename][field_value].count += 1;
                nifti_types[filename][field_value].files.push(file);
            }
        }
    }
    for (var nifti_key in nifti_types) {
        nifti_type = nifti_types[nifti_key];
        var max_field_value = Object.keys(nifti_type)[0];
        for (var field_value_key in nifti_type) {
            var field_value = nifti_type[field_value_key];
            if (field_value.count > nifti_type[max_field_value].count) {
                max_field_value = field_value_key;
            }
        }
        for (var field_value_key in nifti_type) {
            var field_value = nifti_type[field_value_key];
            if (max_field_value !== field_value_key && headerFieldCompare(max_field_value, field_value_key)) {
                for (var nifti_file_index in field_value.files) {
                    var nifti_file = field_value.files[nifti_file_index];
                    var evidence;
                    if (field === 'dim') {
                        evidence = " The most common set of dimensions is: " +
                                  max_field_value + "(voxels), This file has the dimensions: " +
                                  field_value_key + "(voxels)"
                    } else if (field === 'pixdim') {
                        evidence = " The most common resolution is: " +
                                  max_field_value.replace(/,/g, ' x ') + ", This file has the resolution: " +
                                  field_value_key.replace(/,/g, ' x ')
                    }
                        issues.push(new utils.Issue({
                        file: nifti_file,
                        evidence: evidence,
                        code: 39
                    }));
                }
            }
        }
    }
    return issues;
};

/**
 * if elements of the two arrays differ by less than one we won't raise a
 * warning about them. There are a large number of floating point rounding
 * errors that cause resolutions to be slightly different. Returns true if
 * the two headers are signifigantly different
 */
function headerFieldCompare(header1, header2) {
    hdr1 = header1.split(',');
    hdr2 = header2.split(',');
    for (var i = 0; i < hdr1.length; i++) {
        var hdr1_val = Number(hdr1[i].match(/-?\d*\.?\d*/));
        var hdr2_val  = Number(hdr2[i].match(/-?\d*\.?\d*/));
        // Matching alphas with * will return '' on headers without units
        var hdr1_unit = hdr1[i].match(/[A-Za-z]*$/)[0];
        var hdr2_unit = hdr2[i].match(/[A-Za-z]*$/)[0];
        if (Math.abs(hdr1_val - hdr2_val) > .00001) {
            return true;
        }
        if (hdr1_unit !== hdr2_unit) {
            return true;
        }
    }
    return false;
}

module.exports = headerFields;

<|endoftext|>


<commit_before>var MongoClient = require('mongodb').MongoClient;
var assert = require('assert');
var dnd_url = "mongodb://localhost:27017/dnd";
var express = require('express');
var app = express();

//========== Database functions ==========

var playerQuery = function(response,dbUrl,playerName) {

        MongoClient.connect(dbUrl,function(err,db) {

		if( err == null )
		{
			var cursor = db.collection('characters').find({"name":playerName}).toArray( function(err,doc) {
				assert.equal(err,null);
				if( doc != null ) {
					response.send(doc[0]);
				}
				db.close();
			});
		}
		else
		{
			response.send("Database error");
		}

        });
}

var campaignQuery = function(response,dbUrl,campaignName) {

	var playersBack = [];
	var players;

        MongoClient.connect(dbUrl,function(err,db) {

		if( err == null )
		{
			var cursor = db.collection('campaigns').findOne({"name":campaignName},function(err,doc) {
				console.log(doc);
				assert.equal(err,null);
				if( doc != null ) {
					playersBack.push(doc);
					players = doc['players'];
					db.close();
					console.log("============");
					console.log(players);
					console.log("============");
					MongoClient.connect(dbUrl,function(err,db) {

						if( err == null )
						{
							var playerPull = db.collection('characters').find({}).toArray(function(err,doc) {
								assert.equal(err,null);
								if( doc != null ) {
									playersBack.push(doc);
									response.send(playersBack);
								}
								db.close();
							});
						}
						else
						{
							response.send("Database error");
							return;
						}
					});

			}

		});
	}
	else
	{
		response.send("Database error");
		return;
	}

});

}

//========== REST functions ==========

app.get('/player/:name', function(request, response) {

response.header("Access-Control-Allow-Origin","*");
var msg = "received request - stats for player: " + request.params.name;
console.log(msg);
playerQuery(response,dnd_url,request.params.name);
})

app.get('/campaign/:name', function(request, response) {

	response.header("Access-Control-Allow-Origin","*");
	var msg = "received request - stats for campaign: " + request.params.name;
	console.log(msg);
	campaignQuery(response,dnd_url,request.params.name);
})
//==========  Node server ==========

var server = app.listen(18080, function() {
        var host = server.address().address
        var port = server.address().port

        console.log("Listening to port:", port)
});
<commit_msg>- Added command upload handler with shell command parser<commit_after>var MongoClient = require('mongodb').MongoClient;
var assert = require('assert');
var dnd_url = "mongodb://localhost:27017/dnd";
var express = require('express');
var app = express();

//========== Database functions ==========

var playerQuery = function(response,dbUrl,playerName) {

        MongoClient.connect(dbUrl,function(err,db) {

		if( err == null )
		{
			var cursor = db.collection('characters').find({"name":playerName}).toArray( function(err,doc) {
				assert.equal(err,null);
				if( doc != null ) {
					response.send(doc[0]);
				}
				db.close();
			});
		}
		else
		{
			response.send("Database error");
		}

        });
}

var campaignQuery = function(response,dbUrl,campaignName) {

	var playersBack = [];
	var players;

        MongoClient.connect(dbUrl,function(err,db) {

		if( err == null )
		{
			var cursor = db.collection('campaigns').findOne({"name":campaignName},function(err,doc) {
				console.log(doc);
				assert.equal(err,null);
				if( doc != null ) {
					playersBack.push(doc);
					players = doc['players'];
					db.close();
					console.log("============");
					console.log(players);
					console.log("============");
					MongoClient.connect(dbUrl,function(err,db) {

						if( err == null )
						{
							var playerPull = db.collection('characters').find({}).toArray(function(err,doc) {
								assert.equal(err,null);
								if( doc != null ) {
									playersBack.push(doc);
									response.send(playersBack);
								}
								db.close();
							});
						}
						else
						{
							response.send("Database error");
							return;
						}
					});
				}
			});
		}
		else
		{
			response.send("Database error");
			return;
		}
	});

}

var parseCommand = function(response,dbUrl,command) {

	var msg = "received command " + command + "\n";
	response.send(msg);
}

//========== REST functions ==========

app.get('/player/:name', function(request, response) {

	response.header("Access-Control-Allow-Origin","*");
	var msg = "received request - stats for player: " + request.params.name;
	console.log(msg);
	playerQuery(response,dnd_url,request.params.name);
})

app.get('/campaign/:name', function(request, response) {

	response.header("Access-Control-Allow-Origin","*");
	var msg = "received request - stats for campaign: " + request.params.name;
	console.log(msg);
	campaignQuery(response,dnd_url,request.params.name);
})

app.put('/command', function(request, response) {

	console.log("received command upload request");
	var body = [];

	request.on('data',function(chunk) {
		// callback for reading data that's being uploaded
		// place all data chunks in buffer
		body.push(chunk);

	}).on('end', function() {
		// callback when we're done reading uploaded data
		// assume that data uploaded is string, so we can easily convert the data into a string
		var command = body.toString();

		// send command to parser
		parseCommand(response,dnd_url,command);
	});
})

//==========  Node server ==========

var server = app.listen(18080, function() {
        var host = server.address().address
        var port = server.address().port

        console.log("Listening to port:", port)
});
<|endoftext|>


<commit_before>var qs = require("querystring"),
    url = require("url"),
    http = require("http"),
    om = require("./om");

module.exports = Rdio;

function Rdio(consumer, token) {
    this.consumer = consumer;
    this.token = token;
}

Rdio.prototype.beginAuthentication = function beginAuthentication(callbackUrl, callback) {
    var self = this;

    this._signedPost("http://api.rdio.com/oauth/request_token", {
        oauth_callback: callbackUrl
    }, function (err, body) {
        if (err) {
            callback(err, null);
        } else {
            var parsed = qs.parse(body);
            var token = [parsed.oauth_token, parsed.oauth_token_secret];
            var authUrl = parsed.login_url + "?oauth_token=" + parsed.oauth_token;
            // Save the token.
            self.token = token;
            // Call the callback with a URL the app can use to auth.
            callback(null, authUrl);
        }
    });
}

Rdio.prototype.completeAuthentication = function completeAuthentication(verifier, callback) {
    var self = this;

    this._signedPost("http://api.rdio.com/oauth/access_token", {
        oauth_verifier: verifier
    }, function (err, body) {
        if (err) {
            callback(err);
        } else {
            var parsed = qs.parse(body);
            var token = [parsed.oauth_token, parsed.oauth_token_secret];
            // Save the token.
            self.token = token;
            // Call the callback.
            callback(null);
        }
    });
}

Rdio.prototype.call = function call(method, params, callback) {
    if (typeof params == "function") {
        callback = params;
        params = null;
    }

    var copy = {};

    if (params) {
        for (var param in params) {
            copy[param] = params[param];
        }
    }

    copy.method = method;

    this._signedPost("http://api.rdio.com/1/", copy, function (err, body) {
        if (err) {
            callback(err, null);
        } else {
            callback(null, JSON.parse(body));
        }
    });
}

Rdio.prototype._signedPost = function signedPost(urlString, params, callback) {
    var auth = om(this.consumer, urlString, params, this.token);
    var parsed = url.parse(urlString);
    var content = qs.stringify(params);

    var req = http.request({
        method: "POST",
        host: parsed.host,
        port: parsed.port || "80",
        path: parsed.pathname,
        headers: {
            "Authorization": auth,
            "Content-Type": "application/x-www-form-urlencoded",
            "Content-Length": content.length.toString()
        }
    }, function (res) {
        var body = "";

        res.setEncoding("utf8");

        res.on("data", function (chunk) {
            body += chunk;
        });

        res.on("end", function () {
            callback(null, body);
        });
    });

    req.on("error", function (err) {
        callback(err);
    });

    req.end(content);
}
<commit_msg>Please the linter.<commit_after>var qs = require("querystring"),
    url = require("url"),
    http = require("http"),
    om = require("./om");

module.exports = Rdio;

function Rdio(consumer, token) {
    this.consumer = consumer;
    this.token = token;
}

Rdio.prototype.beginAuthentication = function beginAuthentication(callbackUrl, callback) {
    var self = this;

    this._signedPost("http://api.rdio.com/oauth/request_token", {
        oauth_callback: callbackUrl
    }, function (err, body) {
        if (err) {
            callback(err, null);
        } else {
            var parsed = qs.parse(body);
            var token = [parsed.oauth_token, parsed.oauth_token_secret];
            var authUrl = parsed.login_url + "?oauth_token=" + parsed.oauth_token;
            // Save the token.
            self.token = token;
            // Call the callback with a URL the app can use to auth.
            callback(null, authUrl);
        }
    });
};

Rdio.prototype.completeAuthentication = function completeAuthentication(verifier, callback) {
    var self = this;

    this._signedPost("http://api.rdio.com/oauth/access_token", {
        oauth_verifier: verifier
    }, function (err, body) {
        if (err) {
            callback(err);
        } else {
            var parsed = qs.parse(body);
            var token = [parsed.oauth_token, parsed.oauth_token_secret];
            // Save the token.
            self.token = token;
            // Call the callback.
            callback(null);
        }
    });
};

Rdio.prototype.call = function call(method, params, callback) {
    if (typeof params == "function") {
        callback = params;
        params = null;
    }

    var copy = {};

    if (params) {
        for (var param in params) {
            copy[param] = params[param];
        }
    }

    copy.method = method;

    this._signedPost("http://api.rdio.com/1/", copy, function (err, body) {
        if (err) {
            callback(err, null);
        } else {
            callback(null, JSON.parse(body));
        }
    });
};

Rdio.prototype._signedPost = function signedPost(urlString, params, callback) {
    var auth = om(this.consumer, urlString, params, this.token);
    var parsed = url.parse(urlString);
    var content = qs.stringify(params);

    var req = http.request({
        method: "POST",
        host: parsed.host,
        port: parsed.port || "80",
        path: parsed.pathname,
        headers: {
            "Authorization": auth,
            "Content-Type": "application/x-www-form-urlencoded",
            "Content-Length": content.length.toString()
        }
    }, function (res) {
        var body = "";

        res.setEncoding("utf8");

        res.on("data", function (chunk) {
            body += chunk;
        });

        res.on("end", function () {
            callback(null, body);
        });
    });

    req.on("error", function (err) {
        callback(err);
    });

    req.end(content);
};
<|endoftext|>


<commit_before>/* http://github.com/avih/nopromise MIT */
(function(){

function NoPromise() {
    var async = setTimeout,
        _state,
        _output,
        _resolvers = [],
        new_promise = {
            resolve: _changeState.bind(1),
            reject:  _changeState.bind(2),
            then:    _then
        };
    return new_promise.promise = new_promise;

    function _changeState(value) {
        if (!_state) {
            _state = this;
            _output = value;
            _resolvers.forEach(async);
        }
    }

    function _then(onFulfilled, onRejected) {
        var promise2 = NoPromise();
        _state ? async(promise2Resolver) : _resolvers.push(promise2Resolver);
        return promise2;

        function promise2Resolver() {
            var handler = _state < 2 ? onFulfilled : onRejected;

            if (typeof handler != "function") {
                (_state < 2 ? promise2.resolve : promise2.reject)(_output);
            } else {
                promise2Resolution(0, handler);
            }
        }

        function promise2Resolution(x, handler) {
            var then,
                done = 0;

            function once(fn) {
                return function(v) { done++ || fn(v) }
            }

            try {
                if (handler)
                    x = handler(_output);

                if (x == promise2) {
                    promise2.reject(TypeError());

                } else if ((typeof x == "function" || x && typeof x == "object")
                           && typeof (then = x.then) == "function") {
                    then.call(x, once(promise2Resolution), once(promise2.reject));

                } else {
                    promise2.resolve(x);
                }

            } catch (e) {
                once(promise2.reject)(e);
            }
        }
    }
}

NoPromise.deferred = NoPromise;
try {
  module.exports = NoPromise;
} catch (e) {
  this.NoPromise = NoPromise;
}

})()<commit_msg>perf: unroll functions ~x2 - 950(188)/1550(438)<commit_after>/* http://github.com/avih/nopromise MIT */
(function(){

var async = setTimeout,
    FUNCTION = "function";

function NoPromise() {
    var _state,
        _output,
        _resolvers = [],
        new_promise = {
            resolve: _resolve,
            reject:  _reject,
            then:    _then
        };
    return new_promise.promise = new_promise;

    function _resolve(value) {
        if (!_state) {
            _state = 1;
            _output = value;
            _resolvers.forEach(async);
        }
    }
    function _reject(value) {
        if (!_state) {
            _state = 2;
            _output = value;
            _resolvers.forEach(async);
        }
    }

    function _then(onFulfilled, onRejected) {
        var promise2 = NoPromise();
        _state ? async(promise2Resolver) : _resolvers.push(promise2Resolver);
        return promise2;

        function promise2Resolver() {
            var handler = _state < 2 ? onFulfilled : onRejected;

            if (typeof handler != FUNCTION) {
                (_state < 2 ? promise2.resolve : promise2.reject)(_output);
            } else {
                promise2Resolution(0, handler);
            }
        }

        function promise2Resolution(x, handler) {
            var then,
                done = 0;

            try {
                if (handler)
                    x = handler(_output);

                if (x == promise2) {
                    promise2.reject(TypeError());

                } else if ((typeof x == FUNCTION || x && typeof x == "object")
                           && typeof (then = x.then) == FUNCTION) {
                    then.call(x, function(y) { done++ || promise2Resolution(y) },
                                 function(r) { done++ || promise2.reject(r)    });

                } else {
                    promise2.resolve(x);
                }

            } catch (e) {
                done++ || promise2.reject(e);
            }
        }
    }
}

NoPromise.deferred = NoPromise;
try {
  module.exports = NoPromise;
} catch (e) {
  this.NoPromise = NoPromise;
}

})()<|endoftext|>


<commit_before>/*
 * 大三下学期操作系统实训第二次上机作业
 * 段页式虚拟存储管理
 * 李文驰
 * 2018/6/14 10:33
 */
function fixed(n) {
    return parseFloat(n.toFixed(2));
}

function deepclone(obj) {
    return JSON.parse(JSON.stringify(obj));
}

let vm = new Vue({
    el: '#app',
    data: {
        pid: 1,
        segment_num: 1,
        segment_size: 1,
        resident: 8,
        process_queue: [],
        b2_2_queue: [],
        memory: Array(64),
        // false is fifo, true is lru
        mode: false,
    },
    created: function () {
        for (let i = 0; i < 64; i++) {
            this.memory[i] = -1;
        }
    },
    methods: {
        // 创建一个pcb进程
        create_process: function () {
            let new_process = {
                pid: this.pid,
                segment_num: this.segment_num,
                segment_size: this.segment_size,
                inmemory: Array(this.segment_num * this.segment_size),
                FIFO: [],
            };
            let size = new_process.segment_num * new_process.segment_size;
            for (let i = 0; i < size; i++) {
                new_process.inmemory[i] = -1;
            }
            // 如果进程总页数小于等于8，全部装入内存，否则装入前8页
            size = size > 8 ? 8 : size;
            for (let i = 0; i < size; i++) {
                for (let j = 0; j < 64; j++) {
                    // 在物理内存找到一个空的页
                    if (this.memory[j] == -1) {
                        this.memory[j] = [new_process.pid, parseInt(i / new_process.segment_size), i % new_process.segment_size];
                        new_process.inmemory[i] = j;
                        new_process.FIFO.push(i);
                        break;
                    }
                }
            }
            this.process_queue.push(new_process);
            this.pid++;
        },
        // 在b2-2展示
        show_in_b2_2: function (index) {
            this.b2_2_queue = [];
            let this_process = this.process_queue[index];
            let x = this_process.segment_num;
            let y = this_process.segment_size;
            for (let i = 0; i < x; i++) {
                for (let j = 0; j < y; j++) {
                    this.b2_2_queue.push({
                        pid: this_process.pid,
                        d: i,
                        y: j,
                        exist: this_process.inmemory[i * y + j] == -1 ? '否' : this_process.inmemory[i * y + j],
                    });
                }
            }
        },
        // 置换或提示已在驻留集中
        displace: function (pid, d, y) {
            let p = this.process_queue[pid - 1];
            let m = p.segment_size;
            // index为逻辑偏移量
            let index = d * m + y;
            if (p.inmemory[index] != -1) {
                this.$message('已在驻留集中');
                // LRU算法，要调换一次顺序
                if (this.mode == true) {
                    let pos = p.FIFO.findIndex(e => {
                        return e == index;
                    });
                    if (pos != -1) {
                        p.FIFO.push(p.FIFO[pos]);
                        p.FIFO.splice(pos, 1);
                    }
                }
            }
            else {
                // 替换
                let first_come_index = p.FIFO.shift();
                p.inmemory[index] = p.inmemory[first_come_index];
                p.inmemory[first_come_index] = -1;
                this.memory[p.inmemory[index]][1] = d;
                this.memory[p.inmemory[index]][2] = y;
                p.FIFO.push(index);
            }
            this.show_in_b2_2(pid - 1);
        },
    },
});<commit_msg>添加一些置换算法的注释<commit_after>/*
 * 大三下学期操作系统实训第二次上机作业
 * 段页式虚拟存储管理
 * 李文驰
 * 2018/6/14 10:33
 */
function fixed(n) {
    return parseFloat(n.toFixed(2));
}

function deepclone(obj) {
    return JSON.parse(JSON.stringify(obj));
}

let vm = new Vue({
    el: '#app',
    data: {
        pid: 1,
        segment_num: 1,
        segment_size: 1,
        resident: 8,
        process_queue: [],
        b2_2_queue: [],
        memory: Array(64),
        // false is fifo, true is lru
        mode: false,
    },
    created: function () {
        for (let i = 0; i < 64; i++) {
            this.memory[i] = -1;
        }
    },
    methods: {
        // 创建一个pcb进程
        create_process: function () {
            let new_process = {
                pid: this.pid,
                segment_num: this.segment_num,
                segment_size: this.segment_size,
                inmemory: Array(this.segment_num * this.segment_size),
                FIFO: [],
            };
            let size = new_process.segment_num * new_process.segment_size;
            for (let i = 0; i < size; i++) {
                new_process.inmemory[i] = -1;
            }
            // 如果进程总页数小于等于8，全部装入内存，否则装入前8页
            size = size > 8 ? 8 : size;
            for (let i = 0; i < size; i++) {
                for (let j = 0; j < 64; j++) {
                    // 在物理内存找到一个空的页
                    if (this.memory[j] == -1) {
                        this.memory[j] = [new_process.pid, parseInt(i / new_process.segment_size), i % new_process.segment_size];
                        new_process.inmemory[i] = j;
                        new_process.FIFO.push(i);
                        break;
                    }
                }
            }
            this.process_queue.push(new_process);
            this.pid++;
        },
        // 在b2-2展示
        show_in_b2_2: function (index) {
            this.b2_2_queue = [];
            let this_process = this.process_queue[index];
            let x = this_process.segment_num;
            let y = this_process.segment_size;
            for (let i = 0; i < x; i++) {
                for (let j = 0; j < y; j++) {
                    this.b2_2_queue.push({
                        pid: this_process.pid,
                        d: i,
                        y: j,
                        exist: this_process.inmemory[i * y + j] == -1 ? '否' : this_process.inmemory[i * y + j],
                    });
                }
            }
        },
        // 置换或提示已在驻留集中
        displace: function (pid, d, y) {
            let p = this.process_queue[pid - 1];
            let m = p.segment_size;
            // index为逻辑偏移量
            let index = d * m + y;
            // 已在内存中
            if (p.inmemory[index] != -1) {
                this.$message('已在驻留集中');
                // LRU算法，要调换一次顺序
                if (this.mode == true) {
                    let pos = p.FIFO.findIndex(e => {
                        return e == index;
                    });
                    if (pos != -1) {
                        p.FIFO.push(p.FIFO[pos]);
                        p.FIFO.splice(pos, 1);
                    }
                }
            }
            // 不在内存中
            else {
                // 替换
                let first_come_index = p.FIFO.shift();
                p.inmemory[index] = p.inmemory[first_come_index];
                p.inmemory[first_come_index] = -1;
                this.memory[p.inmemory[index]][1] = d;
                this.memory[p.inmemory[index]][2] = y;
                p.FIFO.push(index);
            }
            this.show_in_b2_2(pid - 1);
        },
    },
});<|endoftext|>